"""
행렬의 내적(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()


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

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


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


# 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


#! /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()


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

# Data preprocessing
data = pd.read_csv("RealEstate.csv")

# Converting Pandas dataframe to numpy array
X = data.Size.values
Y = data.Price.values

# Mean X and Y
mean_x = np.mean(X)
mean_y = np.mean(Y)

m = X.shape[0]  #  number of samples

# Using the OLS (Ordinary Least Squares)
# formula to calculate theta0 and theta1
numer = 0
denom = 0
for i in range(m):
    numer += (X[i] - mean_x) * (Y[i] - mean_y)
    denom += (X[i] - mean_x) ** 2
theta1 = numer / denom
theta0 = mean_y - (theta1 * mean_x)

# Printing coefficients
print(f"Coefficients theta0 = {theta0}, theta1 = {theta1} ")

# Predicted Values
Y_pred = theta0 + theta1 * X

# Model Evaluation
def rmse(Y, Y_pred):
    rmse = np.sqrt(sum((Y - Y_pred) ** 2) / Y.shape[0])
    return rmse

def r2_score(Y, Y_pred):
    mean_y = np.mean(Y)
    ss_tot = sum((Y - mean_y) ** 2)
    ss_res = sum((Y - Y_pred) ** 2)
    r2 = 1 - (ss_res / ss_tot)
    return r2

# Print Scores
print("RMSE = ", rmse(Y, Y_pred))
print("R2 Score = ", r2_score(Y, Y_pred))

# Visualization
# Ploting Regression Line
plt.plot(X, Y_pred, color='#c93e4e', label='Regression Line')
# Ploting Scatter Points
plt.scatter(X, Y, c='#54a774', label='Scatter Plot')
plt.xlabel('Size')
plt.ylabel('Price')
plt.legend()
plt.show()


import scipy.stats

def t(alpha, n):
    # if n samples pass n-1
    return scipy.stats.t.ppf(1-(alpha), n)

def norm(alpha):
    # if n samples pass n-1
    return scipy.stats.norm.ppf(1-(alpha))

ls = [3.27,
      16.25,
      15.19,
      7.24,
      2.93]

mean = sum(ls) / len(ls)
se = (sum([(x - sum(ls) / len(ls)) **
      2 for x in ls]) / (len(ls)-1)) ** 0.5 / (len(ls) ** 0.5)

print("mean:", mean)

print("standard deviation S:",
      (sum([(x - sum(ls) / len(ls)) ** 2 for x in ls]) / (len(ls)-1)) ** 0.5)

print("standard error S / (R^.5):", se)

level = t(0.025, len(ls)-1)
print("Confidence interval:", mean - level * se, "to", mean + level * se)


from math import sqrt
import matplotlib.pyplot as plt
import numpy as np
import random

def main():
    p = 1.5
    q = -10

    x = []
    y = []

    for a in range(0, 100, 5):
        x.append(a)

    for a in range(0, 100, 5):
        # y = (mx + c) + random value
        # The predicted line should have m close to p, c close to q
        y.append(p*a + q + float(random.randint(-100, 100)/10))

    # --------------------------------------------------------------------------
    # Predicted Line
    # y = mx + c
    m = 0
    c = 0

    learning_rate = 0.0000005
    epochs = 1000
    loss_value = epochs
    prev_loss = 0
    loss_diff = 1

    loss = []
    n_epoch = []

    # for e in range(epochs):
    e = 0
    while(loss_diff > 0.00001):
        dm = 0
        dc = 0
        sum1 = 0
        sum2 = 0
        err = 0
        prev_loss = loss_value
        e = e+1

        for k in range(len(x)):
            sum1 = sum1 + (x[k]*(y[k]-(m*x[k]+c)))
            sum2 = sum2 + (y[k]-(m*x[k]+c))
            err = err + ((y[k]-(m*x[k]+c))*(y[k]-(m*x[k]+c)))

        dm = (-2/len(x))*sum1
        dc = (-2/len(x))*sum2
        loss_value = err/len(x)
        m = m-learning_rate*dm
        c = c-learning_rate*dc

        n_epoch.append(e+1)
        loss.append(loss_value)
        loss_value = sqrt(loss_value)

        loss_diff = prev_loss - loss_value
        print(f"Epoch: {e}, loss: {loss_value}")

    print(f"m= {m}, c= {c}")

    y_preds = []
    for a in range(len(x)):
        y_preds.append(float(m*x[a] + c))

    # print(len(x), len(y_preds))
    plt.figure(1)
    plt.plot(n_epoch, loss, c="blue")
    plt.xlabel("Epochs")
    plt.ylabel("Loss")
    plt.title("Loss Curve")
    plt.grid(True)

    plt.figure(2)
    plt.plot(x, y_preds, c="red")
    plt.scatter(x, y, c="blue")
    plt.xlabel("X")
    plt.ylabel("Y")
    plt.title("Linear Regression")
    plt.grid(True)
    plt.show()

if __name__ == "__main__":
    main()
    # x = [1, 2, 3, 4, 5]
    # y = [2, 4, 6, 8, 10]
    # plt.plot(x, y)

    # plt.xlabel("X-Axis")
    # plt.ylabel("Y-Axis")
    # plt.title("Linear Regression")
    # plt.grid(True)
    # plt.show()


import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
from scipy.optimize import curve_fit
import matplotlib.colors as mcolors

#Write with LaTeX
rc('text', usetex=True)
rc('font', family='serif')

def func(x, a, b):
    return (a * x) + b

# Data
B1 = np.array([9.38, 12.46, 15.57])
dB1 = np.array([0.04, 0.04, 0.04])
r1 = np.array([0.217, 0.28, 0.38])
dr1 = np.array([0.024, 0.04, 0.07])

B2 = np.array([9.38, 12.46, 15.57])
dB2 = np.array([0.04, 0.04, 0.04])
r2 = np.array([0.2, 0.2500, 0.33])
dr2 = np.array([0.02, 0.03, 0.06])

# Fitting
x = np.linspace(0.15, 0.4, 5)

popt1, pcov1 = curve_fit(func, r1, B1, sigma=1./(dB1*dB1))
perr1 = np.sqrt(np.diag(pcov1))
popt2, pcov2 = curve_fit(func, r2, B2, sigma=1./(dB2*dB2))
perr2 = np.sqrt(np.diag(pcov2))

# Plot
fig, ax = plt.subplots(1, 1)

# B1 = B1(1/r1)
ax.errorbar(r1, B1, xerr = dr1, yerr = dB1, capsize=3, color='black', elinewidth=1, markeredgewidth=1, linestyle='None', marker='o', label='Calculated \n Values of $B_1$')
ax.plot(x, func(x, *popt1), color='orange', label='$B1 = B1(1/r_1)$', linewidth=1.5)

# B2 = B2(1/r2)
ax.errorbar(r2, B2, xerr = dr2, yerr = dB2, capsize=3, color='black', elinewidth=1, markeredgewidth=1, linestyle='None', marker='s', label='Calculated \n Values of $B_2$')
ax.plot(x, func(x, *popt2), color='royalblue', label='$B2 = B2(1/r_2)$', linewidth=1.5)

# Figure Specifications
ax.set_ylabel('$B$ $(\mathrm{10^{-4}\,\mathrm{T}})$')
ax.set_xlabel('$1/r$ $(\mathrm{1/\mathrm{cm}})$')

ax.legend(loc = 'upper left', prop={'size': 11})

# Show the major grid lines with dark grey lines
ax.grid(b=True, which='major', color='#666666', linestyle='--')

# Show the minor grid lines
ax.minorticks_on()
ax.grid(b=True, which='minor', color='#999999', linestyle='--', alpha=0.2)

# fix quality
fig.tight_layout()

plt.show()

# Print lines' slopes and constant coefficients
print(f"\n\n a1 = {'%0.5f'%popt1[0]} ± {'%0.5f'%perr1[0]}", f",b1 = {'%0.5f'%popt1[1]} ± {'%0.5f'%perr1[1]}")
print(f"\n\n a2 = {'%0.5f'%popt2[0]} ± {'%0.5f'%perr2[0]}", f",b2 = {'%0.5f'%popt2[1]} ± {'%0.5f'%perr2[1]}")


import numpy as np
from scipy.special import gamma

# package
from grAdapt.utils.sampling import bounds_range

def volume_hypersphere(dim, radius=1):
    """Calculates the volume of a hypersphere given the radius and the dimension

    Parameters
    ----------
    dim : int
    radius : float

    Returns
    -------
    float
    """
    return (radius ** dim) * np.pi**(dim/2) / (gamma(dim/2 + 1))

def volume_hyperrectangle(bounds):
    """Calculates the volume of a hyperrectangle of any dimension

    Parameters
    ----------
    bounds : list of tuples.
        Each tuple in the list defines the bounds for the corresponding variable
        Example: [(1, 2), (2, 3), (-1, 4)...]

    Returns
    -------

    """
    return np.prod(list(map(bounds_range, bounds)))


import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return (x**2)-3*x-10

# a:left bound
# b:right bound
# eps: the distance between a and b
def bisection(a,b,eps):
    #calculate the iteration time
    iteration=0
    while(1):
        x_0=0.5*(a+b)
        if f(a)*f(x_0)<0:
            b=x_0
        else:
            a=x_0

        iteration+=1

        if abs(a-b)<eps:
            break

    return a, iteration

#to generate the different eps
N=30
error=[]
for i in range(1,N,1):
    #eps from 10^-1 ~ 10^-N
    error.append((10**-i))

#to stroe the different iteration with the different eps
iteration_eps=[]

#to store the root of different eps
root=[]

#calculate the iteration times in different eps and the root
for i in error:
    rt,it=bisection(4.2,6.3,i)
    root.append(rt)
    iteration_eps.append(it)

print("the root in different eps is:")
print(root)
print("the iteration times in different eps is:")
print(iteration_eps)

#visualize the graph
x=np.arange(1,N,1)
plt.plot(x,iteration_eps)
plt.title("different eps $vs$ iteration times")
plt.xlabel("$-log(eps)$")
plt.ylabel("iteration times")
plt.show()

#conclusion:
#because the graph is almost a straight line with the x-axis in log scale
#therefore, we can figure that the iteration is almost increase in power scale


import numpy as np

# Define conversions in x and y from pixels space to meters
ym_per_pix = 30/720 # meters per pixel in y dimension
xm_per_pix = 3.7/700 # meters per pixel in x dimension

def measure(ploty, leftx, rightx):
	'''
	Calculates the curvature of polynomial functions in meters.
	'''

	left_fit_cr = np.polyfit(ploty*ym_per_pix, leftx*xm_per_pix, 2)
	right_fit_cr = np.polyfit(ploty*ym_per_pix, rightx*xm_per_pix, 2)

	# Define y-value where we want radius of curvature
	# We'll choose the maximum y-value, corresponding to the bottom of the image
	y_eval = np.max(ploty)

	##### Implement the calculation of R_curve (radius of curvature) #####
	left_curverad = ((1 + (2*left_fit_cr[0]*y_eval*ym_per_pix + left_fit_cr[1])**2)**1.5) / np.absolute(2*left_fit_cr[0])
	right_curverad = ((1 + (2*right_fit_cr[0]*y_eval*ym_per_pix + right_fit_cr[1])**2)**1.5) / np.absolute(2*right_fit_cr[0])

	return left_curverad, right_curverad

def distance(image, left_fitx, right_fitx):
	# get the center of the image
	image_size_x = image.shape[1]

	# get the last values of x from left and right
	left_x = left_fitx[-1]
	right_x = right_fitx[-1]

	# compute the value of the center of the lane
	center_x = left_x + ((right_x - left_x) / 2)

	# compute the offset and ocnvert it to meters
	offset = ((image_size_x / 2) - center_x) * xm_per_pix

	return offset


import numpy as np
import time

def job_pb1():
   f = open("jobs.txt","r")
   params = [line.rstrip('\n')  for line in f]
   f.close()

   job_list = []
   for ln in params[1:int(params[0])+1]:
       weight = float(ln.split()[0])
       length = float(ln.split()[1])
       job_list.append((weight - length,weight,length))

   # setting reverse=True sorts in descending order
   # key used for sorting can be a tuple. 1st element of tuple is used for sorting, 2nd element is used in case of tie to break the tie
   # Adding "-" before a tuple element reverses direction of sorting
   job_list.sort(reverse=True, key=lambda tuplee : (tuplee[0],tuplee[1]))
   sum = 0
   completion_time = 0
   for i in job_list:
       completion_time = completion_time + i[2]
       sum = sum + i[1]*completion_time

   return sum

def job_pb2():
   f = open("jobs.txt","r")
   params = [line.rstrip('\n')  for line in f]
   f.close()

   job_list = []
   for ln in params[1:int(params[0])+1]:
       weight = float(ln.split()[0])
       length = float(ln.split()[1])
       job_list.append((weight/length,weight,length))

   job_list.sort(reverse=True, key=lambda tuplee : (tuplee[0],tuplee[1]))

   sum = 0
   completion_time = 0
   for i in job_list:
       completion_time = completion_time + i[2]
       sum = sum + i[1]*completion_time

   return sum

def prim_pb3():
    f = open("edges.txt","r")
    params = [line.rstrip('\n')  for line in f]
    f.close()
    num_nodes = params[0].split()[0]
    num_edges = params[0].split()[1]

    graph = np.NaN*np.ones((int(num_nodes)+1,int(num_nodes)+1))
    for ln in params[1:len(params)]:
        start_node = int(ln.split()[0])
        end_node = int(ln.split()[1])
        edge_weight = int(ln.split()[2])
		# key concept: undirect graph adjacency matrix is symmetric, need to add edge_weight in both direction
		# Note that same will hold for an adjacency list
        graph[start_node][end_node] = edge_weight
        graph[end_node][start_node] = edge_weight

    X = {i for i in range(1,int(num_nodes)+1)}
    start_node = 1
    V = {start_node}
    X.remove(start_node)
    total_weight = 0
    while len(V) != int(num_nodes):
        min_weight = 1000000000000000
        for i in V:
            for j in X:
                if (np.isnan(graph[i][j]) == False):
                    if (graph[i][j] < min_weight):
                       min_weight = graph[i][j]
                       min_end_node = j
                       min_start_node = i
        V.add(min_end_node)
        X.remove(min_end_node)
        total_weight = total_weight + min_weight
        #print(total_weight, min_weight, min_end_node)

    return total_weight

def Swap(heap,idx1,idx2):
    temp = heap[idx1]
    heap[idx1] = heap[idx2]
    heap[idx2] = temp

def Insert(heap,ele):
    heap.append(ele)
    eidx = heap.index(ele)
    pidx = int((eidx-1)/2)
    while(heap[pidx][0] > heap[eidx][0]):
        Swap(heap,pidx,eidx)
        eidx = pidx
        pidx = int((eidx-1)/2)

def Extract_Min(heap):
    Swap(heap,0,len(heap)-1)
    ele = heap.pop()
    pidx = 0
    cidx1 = 1
    cidx2 = 2
    while(1):
       smallest = pidx
       if (cidx1 < len(heap)) and (heap[pidx][0] > heap[cidx1][0]):
          smallest = cidx1

       if (cidx2 < len(heap)) and (heap[smallest][0] > heap[cidx2][0]):
          smallest = cidx2

       if (smallest != pidx):
          Swap(heap,smallest,pidx)
          pidx = smallest
          cidx1 = 2*pidx+1
          cidx2 = 2*pidx+2
       else:
          break

    return ele

def Delete(heap,ele):
    # compute index in heap of node to be deleted
    k = int([i[1] for i in heap].index(ele))
    Swap(heap,k,len(heap)-1)
    ele = heap.pop()
    if (len(heap) == 0) or (k == len(heap)):
       return ele
    pidx = int((k-1)/2)
    cidx1 = 2*k+1
    cidx2 = 2*k+2
	# shift-up
    if heap[k][0] < heap[pidx][0]:
        eidx = k
        while(heap[pidx][0] > heap[eidx][0]):
            Swap(heap,pidx,eidx)
            eidx = pidx
            pidx = int((eidx-1)/2)
    # shift-down
    else:
        pidx = k
        cidx1 = 2*pidx+1
        cidx2 = 2*pidx+2
        while(1):
            smallest = pidx
            if (cidx1 < len(heap)) and (heap[pidx][0] > heap[cidx1][0]):
                smallest = cidx1

            if (cidx2 < len(heap)) and (heap[smallest][0] > heap[cidx2][0]):
                smallest = cidx2

            if (smallest != pidx):
                Swap(heap,smallest,pidx)
                pidx = smallest
                cidx1 = 2*pidx+1
                cidx2 = 2*pidx+2
            else:
                break

    return ele

def heapify(X,V,graph):
    heap = []
    for j in X:
        min_distance = 10000000
        for i in V:
            if(np.isnan(graph[i][j]) == False):
               min_distance = graph[i][j]
        Insert(heap, (min_distance,j))

    return heap

def prim_heap_impl():
    f = open("edges.txt","r")
    params = [line.rstrip('\n')  for line in f]
    f.close()
    num_nodes = params[0].split()[0]
    num_edges = params[0].split()[1]

    graph = np.NaN*np.ones((int(num_nodes)+1,int(num_nodes)+1))
    for ln in params[1:len(params)]:
        start_node = int(ln.split()[0])
        end_node = int(ln.split()[1])
        edge_weight = int(ln.split()[2])
		# key concept: undirect graph adjacency matrix is symmetric, need to add edge_weight in both direction
		# Note that same will hold for an adjacency list
        graph[start_node][end_node] = edge_weight
        graph[end_node][start_node] = edge_weight

    start_node = 1
    X = {i for i in range(1,int(num_nodes)+1)}
    X.remove(start_node)
    V = {start_node}
    heap = heapify(X,V,graph)

    total_weight = 0
    while len(V) != int(num_nodes):
        (dist, node) = Extract_Min(heap)  #find node with min distance
        V.add(node)     #add this node to set V
        X.remove(node)  #remove this node from set X
        total_weight = total_weight + dist
        #print(total_weight, dist, node)
        for j in X:
            if (np.isnan(graph[node][j]) == False):
                ele = Delete(heap, j) #delete from heap any nodes connected to node added to V
                min_distance = min(ele[0],graph[node][j]) #re-compute min_distance for node j
                Insert(heap, (min_distance, j)) #add node back to heap

    return total_weight

print(job_pb1())
print(job_pb2())
start = time.time()
print(prim_pb3())
print(time.time() - start)
start = time.time()
print(prim_heap_impl())
print(time.time() - start)

#5 - for every G and H, these edges are contained in some minimum spanning tree of H
#4 - T is always minimum spanning tree and P may not be always shortest path
#3 - Algorithm A always correctly determines whether a given graph is perfect matching or not; B does not
#2 - Schedule the requests in increasing order of deadline d^j
#1 - At each request pick the remaining request with the earliest finish time


# plots.py
"""Volume 1A: SVD and Image Compression. Plotting file."""
import matplotlib
matplotlib.rcParams = matplotlib.rc_params_from_file("../../../matplotlibrc")

import matplotlib.pyplot as plt
from scipy.linalg import svd
import numpy as np

def circles():
	A = np.array([[3,1],[1,3]])
	U, S, V = svd(A,full_matrices=False)
	S = np.diag(S)

	t = np.linspace(0,2*np.pi,100)
	pts = np.array([np.cos(t),np.sin(t)])
	v= V.dot(pts)
	sv = S.dot(v)
	a = U.dot(sv)

	unit_vecs = np.array([[1,0],[0,1]])
	vu = V.dot(unit_vecs)
	svu = S.dot(vu)
	au = U.dot(svu)

	plt.figure()
	plt.plot(pts[0],pts[1],'b')
	plt.plot([0,unit_vecs[0,0]],[0,unit_vecs[1,0]],'g')
	plt.plot([0,unit_vecs[0,1]],[0,unit_vecs[1,1]],'g')
	plt.axis('equal')
	plt.savefig('unit_circle.pdf')

	plt.figure()
	plt.plot(v[0],v[1],'b')
	plt.plot([0,vu[0,0]],[0,vu[1,0]],'g')
	plt.plot([0,vu[0,1]],[0,vu[1,1]],'g')
	plt.axis('equal')
	plt.savefig('vcircle.pdf')

	plt.figure()
	plt.plot(sv[0],sv[1],'b')
	plt.plot([0,svu[0,0]],[0,svu[1,0]],'g')
	plt.plot([0,svu[0,1]],[0,svu[1,1]],'g')
	plt.axis('equal')
	plt.savefig('svcircle.pdf')

	plt.figure()
	plt.plot(a[0],a[1],'b')
	plt.plot([0,au[0,0]],[0,au[1,0]],'g')
	plt.plot([0,au[0,1]],[0,au[1,1]],'g')
	plt.axis('equal')
	plt.savefig('full_transformation.pdf')

def svals(img):
    U, s, Vt = svd(img)
    s = np.sort(s)[::-1]
    plt.semilogy(s)
    plt.xlim([0,670])
    plt.xlabel('Matrix rank')
    plt.ylabel('Singular values')
    plt.savefig('hubble_svals.pdf')
    plt.close()

def lowrank(img, rankvals):
    U, s, Vt = svd(img)

    for n in rankvals:
        u1, s1, vt1 = U[:,0:n], np.diag(s[0:n]), Vt[0:n,:]
        plt.imsave("rank{}.png".format(n), u1.dot(s1).dot(vt1))

    plt.close()

if __name__ == "__main__":
    img = plt.imread('hubble_red.jpg')
    svals(img)
    lowrank(img, [1, 14, 27, 40])
    circles()
    plt.close()


from __future__ import division
import numpy as np
from field import Field, Space

def get_wave_field():
    #x = np.linspace(-2*np.pi, 2*np.pi, 100)
    x = np.linspace(0, np.pi, 100)
    y = np.linspace(-2*np.pi, 2*np.pi, 100)
    X, Y = np.meshgrid(x, y, indexing='ij')
    space = Space([x, y])
    space.set_elements_names(['x', 'y'])
    wave_field = Field([np.sin(X) * np.exp(Y / 10)], space)
    wave_field.set_elements_names(['u'])
    return wave_field

def get_randomly_spaced_wave_field():
    x = np.concatenate((np.linspace(-2*np.pi, -1.8*np.pi, 50), np.linspace(-1.8*np.pi + 0.01, -1.6*np.pi, 10), np.linspace(-1.6*np.pi + 0.01, 1.8*np.pi, 50), np.linspace(1.8*np.pi + 0.01, 2*np.pi, 50)))
    y = np.concatenate((np.linspace(-2*np.pi, -1.8*np.pi, 50), np.linspace(-1.8*np.pi + 0.01, -1.6*np.pi, 10), np.linspace(-1.6*np.pi + 0.01, 1.8*np.pi, 50), np.linspace(1.8*np.pi + 0.01, 2*np.pi, 50)))
    X, Y = np.meshgrid(x, y, indexing='ij')
    space = Space([x, y])
    space.set_elements_names(['x', 'y'])
    wave_field = Field([np.sin(X) * np.exp(Y / 10)], space)
    wave_field.set_elements_names(['u'])
    return wave_field

def get_time_dependent_wave_fields():
    x = np.linspace(-2*np.pi, 2*np.pi, 100)
    y = np.linspace(-2*np.pi, 2*np.pi, 100)
    X, Y = np.meshgrid(x, y, indexing='ij')
    space = Space([x, y])
    space.set_elements_names(['x', 'y'])

    y_coeffs = np.linspace(1, 10, 100)
    fields = []
    for y_coeff in y_coeffs:
        u = np.sin(X) * np.exp(Y / y_coeff)
        u = u / np.amax(u)
        wave_field = Field([u], space)
        wave_field.set_elements_names(['u'])
        fields.append(wave_field)
    return fields

def get_time_dependent_circular_flow_fields():
    x = np.linspace(-5, 5, 100)
    y = np.linspace(-2, 2, 100)
    a = 1
    U_inf = 10
    K = 0
    X, Y = np.meshgrid(x, y, indexing='ij')
    R_sq = X**2 + Y**2
    space = Space([x, y])
    space.set_elements_names(['x', 'y'])

    K_coeffs = np.linspace(0, 2 * U_inf * a, 100)
    fields = []
    for K in K_coeffs:
        u = U_inf * (1 - (a**2 * R_sq - 2 * a**2 * Y**2) / R_sq**2) - K * a * Y / R_sq
        v = - 2 * U_inf * a**2 * X * Y / R_sq**2 + K * a * X / R_sq
        for xi in range(len(x)):
            for yi in range(len(y)):
                if x[xi]**2 + y[yi]**2 < a**2:
                    u[xi, yi] = 0.
                    v[xi, yi] = 0.

        circ_field = Field([u, v], space)
        circ_field.set_elements_names(['u', 'v'])
        fields.append(circ_field)
    return fields

def get_simple_1D_field():
    x = np.linspace(0, 5, 100)
    space = Space([x])
    space.set_elements_names(['x'])
    field = Field([x**2], space)
    field.set_elements_names(['u'])

    return field

def get_simple_2D_field():
    x = np.linspace(0, 2, 100)
    y = np.linspace(0, 2, 100)
    X, Y = np.meshgrid(x, y, indexing='ij')
    space = Space([x, y])
    space.set_elements_names(['x', 'y'])
    field = Field([X**2 + Y**3], space)
    field.set_elements_names(['u'])
    return field

def get_simple_3D_field():
    x = np.linspace(0, 2, 80)
    y = np.linspace(0, 2, 100)
    z = np.linspace(0, 2, 120)
    X, Y, Z = np.meshgrid(x, y, z, indexing='ij')
    space = Space([x, y, z])
    space.set_elements_names(['x', 'y', 'z'])
    field = Field([X**2 + Y**3 + Z**4], space)
    field.set_elements_names(['u'])
    return field


import sympy
from transfer_func import PolyTransferFunc

s, gamma = sympy.symbols('s gamma')

tf_1dof = (s - sympy.I * gamma) / (s + sympy.I * gamma)
tf_2dof = (s**2 / gamma + s - sympy.I * gamma) / (-s**2 / gamma + s + sympy.I * gamma)

def test_expr_gives_expected_result():
    poly_fraction = PolyTransferFunc.from_transfer_function(tf_1dof, s)
    assert poly_fraction.expr == tf_1dof

def test_poly_fraction_from_transfer_func_gives_expected_result():
    poly_fraction = PolyTransferFunc.from_transfer_function(tf_1dof, s)
    assert poly_fraction.numer.equals(s - sympy.I * gamma)
    assert poly_fraction.denom.equals(s + sympy.I * gamma)
    poly_fraction = PolyTransferFunc.from_transfer_function(tf_2dof, s)
    assert poly_fraction.numer.equals(s**2 / gamma + s - sympy.I * gamma)

def test_getting_coefficients_gives_expected_result():
    poly_fraction = PolyTransferFunc.from_transfer_function(tf_2dof, s)
    assert poly_fraction.numer_coeffs == [1 / gamma, 1, -sympy.I * gamma]
    assert poly_fraction.denom_coeffs == [-1 / gamma, 1, sympy.I * gamma]

def test_controllable_canonical_form_gives_expected_state_space():
    poly_tf = PolyTransferFunc.from_transfer_function(tf_2dof, s)
    state_space = poly_tf.as_ccf_state_space

    assert state_space.num_inputs == state_space.num_outputs == 1
    assert state_space.num_dof == 2

    a_mat = sympy.Matrix([[0, 1], [sympy.I * gamma**2, gamma]])
    b_mat = sympy.Matrix([[0], [1]])
    c_mat = sympy.Matrix([[0, -2*gamma]])
    d_mat = sympy.Matrix([[-1]])

    assert state_space.a == a_mat
    assert state_space.b == b_mat
    assert state_space.c == c_mat
    assert state_space.d == d_mat

    assert state_space.siso_transfer_function.equals(tf_2dof)

def test_ccf_for_the_coupled_cavity_transfer_function(run_slow):
    """ This is to test using the work being done locally in coupled-cavity.nb """

    s = sympy.symbols("s")
    omega_s, Omega, tau_1, gamma_1, gamma_1_prime =\
        sympy.symbols("omega_s Omega tau_1 gamma_1 gamma_1'", real=True, positive=True)
    I = sympy.I

    prefactor = I * tau_1 * (gamma_1 - gamma_1_prime)

    tf = (-prefactor * Omega**2 + 2 * gamma_1 * Omega + prefactor * omega_s**2) /\
         (+prefactor * Omega**2 + 2 * gamma_1 * Omega - prefactor * omega_s**2)

    tf_normalized_freq = tf.subs(Omega, -I*omega_s*s)  # do we need to do this?

    prefactor = 2 * gamma_1 / (tau_1 * (gamma_1 - gamma_1_prime) * omega_s)

    # testing my re-arranging skills
    assert sympy.simplify(tf_normalized_freq - ((s**2 - prefactor * s + 1)/(-s**2 - prefactor*s - 1))) == 0

    poly_tf = PolyTransferFunc.from_transfer_function(tf_normalized_freq, s)

    ss = poly_tf.as_ccf_state_space

    assert ss.a == sympy.Matrix([[0, 1], [-1, -prefactor]])
    assert ss.b == sympy.Matrix([[0], [1]])
    assert ss.c == sympy.Matrix([[0, 2 * prefactor]])
    assert ss.d == sympy.Matrix([[-1]])

    # the simplifications make these tasks pretty slow
    if run_slow:
        assert sympy.simplify(ss.siso_transfer_function.subs(s, I * Omega / omega_s) - tf) == 0
        assert sympy.simplify(ss.siso_transfer_function - tf_normalized_freq) == 0
        assert PolyTransferFunc.from_transfer_function(ss.siso_transfer_function, s) == poly_tf