# coding: utf-8

# In[ ]:

import numpy as np
import matplotlib.pyplot as plt

# In[ ]:

# Logistic function implementation
def logistic_eq(r,x):
    return r*x*(1-x)

# In[ ]:

# Show the logistic function
x = np.linspace(0, 1)
plt.plot(x, logistic_eq(2, x), 'k')
plt.show()

# logistic_eq(4.0009, 0.75)

# In[ ]:

# Iterate the function for a given r
def logistic_equation_orbit(seed, r, n_iter, n_skip=0):
    print('Orbit for seed {0}, growth rate of {1}, plotting {2} iterations after skipping {3}'.format(seed, r, n_iter, n_skip))
    X_t=[]
    T=[]
    t=0
    x = seed;
    # Iterate the logistic equation, printing only if n_skip steps have been skipped
    for i in range(n_iter + n_skip):
        if i >= n_skip:
            X_t.append(x)
            T.append(t)
            t+=1
        x = logistic_eq(r,x);
    # Configure and decorate the plot
    plt.plot(T, X_t)
    plt.ylim(0, 1)
    plt.xlim(0, T[-1])
    plt.xlabel('Time t')
    plt.ylabel('X_t')
    plt.show()

# In[ ]:

logistic_equation_orbit(0.1, 3.05, 100)
logistic_equation_orbit(0.1, 3.9, 100)
logistic_equation_orbit(0.1, 3.9, 100, 1000)

# In[ ]:

# Create the bifurcation diagram
def bifurcation_diagram(seed, n_skip, n_iter, step=0.0001, r_min=0):
    print("Starting with x0 seed {0}, skip plotting first {1} iterations, then plot next {2} iterations.".format(seed, n_skip, n_iter));
    # Array of r values, the x axis of the bifurcation plot
    R = []
    # Array of x_t values, the y axis of the bifurcation plot
    X = []

    # Create the r values to loop. For each r value we will plot n_iter points
    r_range = np.linspace(r_min, 4, int(1/step))

    for r in r_range:
        x = seed;
        # For each r, iterate the logistic function and collect datapoint if n_skip iterations have occurred
        for i in range(n_iter+n_skip+1):
            if i >= n_skip:
                R.append(r)
                X.append(x)

            x = logistic_eq(r,x);
    # Plot the data
    plt.plot(R, X, ls='', marker=',')
    plt.ylim(0, 1)
    plt.xlim(r_min, 4)
    plt.xlabel('r')
    plt.ylabel('X')
    plt.show()

# In[ ]:

bifurcation_diagram(0.2, 100, 5)
bifurcation_diagram(0.2, 100, 10)
bifurcation_diagram(0.2, 100, 10, r_min=2.8)


import numpy as np

# ndarray with shape 3x4 with zeros

x = np.zeros((3,4))
print(x)

x = np.zeros((3,4), dtype = int)
print(x)

# ndarray full of ones

x = np.ones((3,4))
print(x)

x = np.ones((3,4),dtype = int)
print(x)

# ndarray full of any numbers

x = np.full((3,4), 5)
print(x)

# Identity matrix ,  An Identity matrix is a square matrix that has only 1s in its main diagonal and zeros everywhere else

x = np.eye(5, dtype=int)
print(x)

# Diagonal Matrix, square matrix that only has values in its main diagonal

x = np.diag([10,20,30,50])
print(x)

# ndarrays that have evenly spaced values within a given interval

x = np.arange(10)
print(x)

x = np.arange(1, 11, 3)
print(x)

# arange when used for non integer result can be mallicious

# In the cases where non-integer steps are required, it is usually better to use the function np.linspace()

x = np.linspace(0,25, 10)
print(x)

x = np.linspace(0,25, 10, endpoint = False)
print(x)

# Using arange and linespace for > 1 rank array

# Use reshape() to comine to create rank 2 ndarrays

x = np.arange(20)
print(x)

x = np.reshape(x, (4,5))

print(x)

# Can call as a method
x = np.arange(20).reshape((4,5))

print(x)

x = np.linspace(0,50,10, endpoint=False).reshape(5,2)
print(x)

# Random ndarray float type

x = np.random.random((3,3))
print(x)

# Random ndarray int type
x = np.random.randint(4,15, size=(3,2))
print(x)

# For example, you may want the random numbers in the ndarray to have an average of 0.
# NumPy allows you create random ndarrays with numbers drawn from various probability
# distributions. The function np.random.normal(mean, standard deviation, size=shape),
# for example, creates an ndarray with the given shape that contains random numbers
# picked from a normal (Gaussian) distribution with the given mean and standard deviation.

x = np.random.normal(0, 0.1, size=(1000, 1000))
print(x)

x = np.arange(2, 34, 2, dtype = int).reshape((4,4))
print(x)


'''
shape

The shape tool gives a tuple of array dimensions and can be used to change the dimensions of an array.

(a). Using shape to get array dimensions

import numpy

my__1D_array = numpy.array([1, 2, 3, 4, 5])
print my_1D_array.shape     #(5,) -> 5 rows and 0 columns

my__2D_array = numpy.array([[1, 2],[3, 4],[6,5]])
print my_2D_array.shape     #(3, 2) -> 3 rows and 2 columns
(b). Using shape to change array dimensions

import numpy

change_array = numpy.array([1,2,3,4,5,6])
change_array.shape = (3, 2)
print change_array

#Output
[[1 2]
[3 4]
[5 6]]
reshape

The reshape tool gives a new shape to an array without changing its data. It creates a new array and does not modify the original array itself.

import numpy

my_array = numpy.array([1,2,3,4,5,6])
print numpy.reshape(my_array,(3,2))

#Output
[[1 2]
[3 4]
[5 6]]
Task

You are given a space separated list of nine integers. Your task is to convert this list into a X NumPy array.

Input Format

A single line of input containing  space separated integers.

Output Format

Print the X NumPy array.

Sample Input

1 2 3 4 5 6 7 8 9
Sample Output

[[1 2 3]
 [4 5 6]
 [7 8 9]]
'''

import numpy as np

ip = input().strip().split(' ')
x = np.array(ip)
x = x.astype(np.int32)
x = x.reshape(3,3)
print(x)

#print(ip)

Hackerrank Practice/Shape and Reshape.py


import numpy as np
import matplotlib.pyplot as plt
import scipy as sp
from scipy import stats
import pandas as pd

###############################################################################################################
###############################################################################################################
def reg_corr_plot():
    class LinearRegression:
        def __init__(self, beta1, beta2, error_scale, data_size):
            self.beta1 = beta1
            self.beta2 = beta2
            self.error_scale = error_scale
            self.x = np.random.randint(1, data_size, data_size)
            self.y = self.beta1 + self.beta2*self.x + self.error_scale*np.random.randn(data_size)

        def x_y_cor(self):
            return np.corrcoef(self.x, self.y)[0, 1]

    fig, ax = plt.subplots(nrows = 2, ncols = 4,figsize=(24, 12))

    beta1, beta2, error_scale,data_size =  2, .05, 1, 100
    lrg1 = LinearRegression(beta1, beta2, error_scale, data_size)
    ax[0, 0].scatter(lrg1.x, lrg1.y)
    ax[0, 0].plot(lrg1.x, beta1 + beta2*lrg1.x, color = '#FA954D', alpha = .7)
    ax[0, 0].set_title(r'$Y={}+{}X+{}u$'.format(beta1, beta2, error_scale))
    ax[0, 0].annotate(r'$\rho={:.4}$'.format(lrg1.x_y_cor()), xy=(0.1, 0.9), xycoords='axes fraction')

    beta1, beta2, error_scale,data_size =  2, -.6, 1, 100
    lrg2 = LinearRegression(beta1, beta2, error_scale, data_size)
    ax[0, 1].scatter(lrg2.x, lrg2.y)
    ax[0, 1].plot(lrg2.x, 2 - .6*lrg2.x, color = '#FA954D', alpha = .7)
    ax[0, 1].set_title(r'$Y={}+{}X+{}u$'.format(beta1, beta2, error_scale))
    ax[0, 1].annotate(r'$\rho={:.4}$'.format(lrg2.x_y_cor()), xy=(0.1, 0.9), xycoords='axes fraction')

    beta1, beta2, error_scale,data_size =  2, 1, 1, 100
    lrg3 = LinearRegression(beta1, beta2, error_scale, data_size)
    ax[0, 2].scatter(lrg3.x, lrg3.y)
    ax[0, 2].plot(lrg3.x, beta1 + beta2 * lrg3.x, color = '#FA954D', alpha = .7)
    ax[0, 2].set_title(r'$Y={}+{}X+{}u$'.format(beta1, beta2, error_scale))
    ax[0, 2].annotate(r'$\rho={:.4}$'.format(lrg3.x_y_cor()), xy=(0.1, 0.9), xycoords='axes fraction')

    beta1, beta2, error_scale,data_size =  2, 3, 1, 100
    lrg4 = LinearRegression(beta1, beta2, error_scale, data_size)
    ax[0, 3].scatter(lrg4.x, lrg4.y)
    ax[0, 3].plot(lrg4.x, beta1 + beta2 * lrg4.x, color = '#FA954D', alpha = .7)
    ax[0, 3].set_title(r'$Y={}+{}X+{}u$'.format(beta1, beta2, error_scale))
    ax[0, 3].annotate(r'$\rho={:.4}$'.format(lrg4.x_y_cor()), xy=(0.1, 0.9), xycoords='axes fraction')

    beta1, beta2, error_scale,data_size =  2, 3, 3, 100
    lrg5 = LinearRegression(beta1, beta2, error_scale, data_size)
    ax[1, 0].scatter(lrg5.x, lrg5.y)
    ax[1, 0].plot(lrg5.x, beta1 + beta2 * lrg5.x, color = '#FA954D', alpha = .7)
    ax[1, 0].set_title(r'$Y={}+{}X+{}u$'.format(beta1, beta2, error_scale))
    ax[1, 0].annotate(r'$\rho={:.4}$'.format(lrg5.x_y_cor()), xy=(0.1, 0.9), xycoords='axes fraction')

    beta1, beta2, error_scale,data_size =  2, 3, 10, 100
    lrg6 = LinearRegression(beta1, beta2, error_scale, data_size)
    ax[1, 1].scatter(lrg6.x, lrg6.y)
    ax[1, 1].plot(lrg6.x, beta1 + beta2 * lrg6.x, color = '#FA954D', alpha = .7)
    ax[1, 1].set_title(r'$Y={}+{}X+{}u$'.format(beta1, beta2, error_scale))
    ax[1, 1].annotate(r'$\rho={:.4}$'.format(lrg6.x_y_cor()), xy=(0.1, 0.9), xycoords='axes fraction')

    beta1, beta2, error_scale,data_size =  2, 3, 20, 100
    lrg7 = LinearRegression(beta1, beta2, error_scale, data_size)
    ax[1, 2].scatter(lrg7.x, lrg7.y)
    ax[1, 2].plot(lrg7.x, beta1 + beta2 * lrg7.x, color = '#FA954D', alpha = .7)
    ax[1, 2].set_title(r'$Y={}+{}X+{}u$'.format(beta1, beta2, error_scale))
    ax[1, 2].annotate(r'$\rho={:.4}$'.format(lrg7.x_y_cor()), xy=(0.1, 0.9), xycoords='axes fraction')

    beta1, beta2, error_scale,data_size =  2, 3, 50, 100
    lrg8 = LinearRegression(beta1, beta2, error_scale, data_size)
    ax[1, 3].scatter(lrg8.x, lrg8.y)
    ax[1, 3].plot(lrg3.x, beta1 + beta2 * lrg3.x, color = '#FA954D', alpha = .7)
    ax[1, 3].set_title(r'$Y={}+{}X+{}u$'.format(beta1, beta2, error_scale))
    ax[1, 3].annotate(r'$\rho={:.4}$'.format(lrg8.x_y_cor()), xy=(0.1, 0.9), xycoords='axes fraction')

###############################################################################################################
###############################################################################################################

def central_limit_theorem_plot():
    fig, ax = plt.subplots(4, 3, figsize = (20, 20))

    ########################################################################################
    x = np.linspace(2, 8, 100)
    a = 2 # range of uniform distribution
    b = 8
    unif_pdf = np.ones(len(x)) * 1/(b-a)

    ax[0, 0].plot(x, unif_pdf, lw = 3, color = 'r')
    ax[0, 0].plot([x[0],x[0]],[0, 1/(b-a)], lw = 3, color = 'r', alpha = .9) # vertical line
    ax[0, 0].plot([x[-1],x[-1]],[0, 1/(b-a)], lw = 3, color = 'r', alpha = .9)
    ax[0, 0].fill_between(x, 1/(b-a), 0, alpha = .5, color = 'r')

    ax[0, 0].set_xlim([1, 9])
    ax[0, 0].set_ylim([0, .4])
    ax[0, 0].set_title('Uniform Distribution', size = 18)
    ax[0, 0].set_ylabel('Population Distribution', size = 12)

    ########################################################################################
    ss = 2 #sample size
    unif_sample_mean = np.zeros(1000)
    for i in range(1000):
        unif_sample = np.random.rand(ss)
        unif_sample_mean[i] = np.mean(unif_sample)
    ax[1, 0].hist(unif_sample_mean, bins = 20, color = 'r', alpha = .5)
    ax[1, 0].set_ylabel('Sample Distribution， $n = 2$', size = 12)
    ########################################################################################
    ss = 10 #sample size
    unif_sample_mean = np.zeros(1000)
    for i in range(1000):
        unif_sample = np.random.rand(ss)
        unif_sample_mean[i] = np.mean(unif_sample)
    ax[2, 0].hist(unif_sample_mean, bins = 30, color = 'r', alpha = .5)
    ax[2, 0].set_ylabel('Sample Distribution, $n = 10$', size = 12)

    ########################################################################################
    ss = 1000 #sample size
    unif_sample_mean = np.zeros(1000)
    for i in range(1000):
        unif_sample = np.random.rand(ss)
        unif_sample_mean[i] = np.mean(unif_sample)
    ax[3, 0].hist(unif_sample_mean, bins = 40, color = 'r', alpha = .5)
    ax[3, 0].set_ylabel('Sample Distribution, $n = 1000$', size = 12)

    ########################################################################################
    a = 6
    b = 2
    x = np.linspace(0, 1, 100)
    beta_pdf = sp.stats.beta.pdf(x, a, b)
    ax[0, 1].plot(x, beta_pdf, lw = 3, color = 'g')
    ax[0, 1].set_ylim([0, 6])
    ax[0, 1].fill_between(x, beta_pdf, 0, alpha = .5, color = 'g')
    ax[0, 1].set_title('Beta Distribution', size = 18)
    ########################################################################################

    ss = 2 #sample size
    beta_sample_mean = np.zeros(1000)
    for i in range(1000):
        beta_sample = sp.stats.beta.rvs(a, b, size = ss)
        beta_sample_mean[i] = np.mean(beta_sample)
    ax[1, 1].hist(beta_sample_mean, color = 'g', alpha = .5)

    ########################################################################################

    ss = 10 #sample size
    beta_sample_mean = np.zeros(1000)
    for i in range(1000):
        beta_sample = sp.stats.beta.rvs(a, b, size = ss)
        beta_sample_mean[i] = np.mean(beta_sample)
    ax[2, 1].hist(beta_sample_mean, color = 'g', bins = 20, alpha = .5)

    ########################################################################################

    ss = 100000 #sample size
    beta_sample_mean = np.zeros(1000)
    for i in range(1000):
        beta_sample = sp.stats.beta.rvs(a, b, size = ss)
        beta_sample_mean[i] = np.mean(beta_sample)
    ax[3, 1].hist(beta_sample_mean, color = 'g', bins = 30, alpha = .5)

    ########################################################################################
    a = 6
    x = np.linspace(0, 25, 100)

    gamma_pdf = sp.stats.gamma.pdf(x, a)
    ax[0, 2].plot(x, gamma_pdf, lw = 3, color = 'b')
    ax[0, 2].set_ylim([0, 0.34])
    ax[0, 2].fill_between(x, gamma_pdf, 0, alpha = .5, color = 'b')
    ax[0, 2].set_title('Gamma Distribution', size = 18)

    ########################################################################################
    ss = 2 #sample size
    gamma_sample_mean = np.zeros(1000)
    for i in range(1000):
        gamma_sample = sp.stats.gamma.rvs(a, size = ss)
        gamma_sample_mean[i] = np.mean(gamma_sample)
    ax[1, 2].hist(gamma_sample_mean, color = 'b', alpha = .5)

    ########################################################################################
    ss = 10 #sample size
    gamma_sample_mean = np.zeros(1000)
    for i in range(1000):
        gamma_sample = sp.stats.gamma.rvs(a, size = ss)
        gamma_sample_mean[i] = np.mean(gamma_sample)
    ax[2, 2].hist(gamma_sample_mean, bins = 20, color = 'b', alpha = .5)
    ########################################################################################
    ss = 1000 #sample size
    gamma_sample_mean = np.zeros(1000)
    for i in range(1000):
        gamma_sample = sp.stats.gamma.rvs(a, size = ss)
        gamma_sample_mean[i] = np.mean(gamma_sample)
    ax[3, 2].hist(gamma_sample_mean, bins = 30, color = 'b', alpha = .5)
    ########################################################################################
    plt.show()

##########################################################################################################
##########################################################################################################
def type12_error():
    x = np.linspace(-6, 9, 200)
    null_loc, alter_loc = 0, 3
    y_null = sp.stats.norm.pdf(x, loc = null_loc)
    y_alter =  sp.stats.norm.pdf(x, loc = alter_loc)
    fig, ax = plt.subplots(figsize = (18, 6))
    ax.plot(x, y_null, x, y_alter)
    ax.annotate('Null', (null_loc-.2, max(y_null)/2), size = 15)
    ax.annotate('Alternative', (alter_loc-.6, max(y_alter)/2), size = 15)
    ax.annotate('Type I Error', (2, max(y_alter)/30), size = 15)
    ax.annotate('Type II Error', (0, max(y_alter)/30), size = 15)
    ax.fill_between(x[-98:], y_null[-98:])
    ax.fill_between(x[:103], y_alter[:103])
    ax.set_ylim([0, .5])
    plt.show()

##########################################################################################################
##########################################################################################################
# def reject_region():
#     data = pd.read_csv('500_Person_Gender_Height_Weight_Index.csv')

#     male_mean = data[data['Gender']=='Male']['Height'].mean()
#     male_std = data[data['Gender']=='Male']['Height'].std(ddof=1)
#     male_std_error = male_std/np.sqrt(len(data[data['Gender']=='Male']))
#     male_null = 172

#     df = len(data[data['Gender']=='Male'])-1
#     t_975 = sp.stats.t.ppf(.975, df=df)
#     t_025 = sp.stats.t.ppf(.025, df=df)

#     x = np.linspace(male_null-5, male_null+5, 200)
#     df = len(data[data['Gender']=='Male'])-1
#     y_t = sp.stats.t.pdf(x, df = df, loc = male_null)

#     fig, ax = plt.subplots(2, 1, figsize = (18,8))

#     ax[0].plot(x, y_t, color = 'tomato', lw = 3)

#     rejection_lower = male_null - t_975*male_std_error
#     x_rej_lower = np.linspace(rejection_lower-3, rejection_lower, 30)
#     y_rej_lower = sp.stats.t.pdf(x_rej_lower, df = df, loc = male_null)
#     ax[0].fill_between(x_rej_lower, y_rej_lower, color = 'tomato', alpha = .7)

#     rejection_upper = male_null + t_975*male_std_error
#     x_rej_upper = np.linspace(rejection_upper, rejection_upper+3, 30)
#     y_rej_upper = sp.stats.t.pdf(x_rej_upper, df = df, loc = male_null)
#     ax[0].fill_between(x_rej_upper, y_rej_upper, color = 'tomato', alpha = .7)

#     ax[0].set_ylim([0, .45])

#     x = np.linspace(-5, 5, 200)
#     y_t = sp.stats.t.pdf(x, df = df, loc = 0)

#     ax[1].plot(x, y_t, color = 'tomato', lw = 3)

#     x_rej_lower = np.linspace(t_025-3, t_025, 30)
#     y_rej_lower = sp.stats.t.pdf(x_rej_lower, df = df)
#     ax[1].fill_between(x_rej_lower, y_rej_lower, color = 'tomato', alpha = .7)

#     x_rej_lower = np.linspace(t_975+3, t_975, 30)
#     y_rej_lower = sp.stats.t.pdf(x_rej_lower, df = df)
#     ax[1].fill_between(x_rej_lower, y_rej_lower, color = 'tomato', alpha = .7)

#     ax[1].set_ylim([0, .45])

#     plt.show()

##########################################################################################################
# ##########################################################################################################
# def draw_something():
#     x = np.linspace(0, 10, 100)
#     y = np.sin(x)
#     plt.plot(x, y)

##########################################################################################################
##########################################################################################################
def anova_plot():
    def gen_3samples(loc1, loc2, loc3, scale1, scale2, scale3, size1, size2, size3):
        F_statistic, p_value = [], []
        for i in range(1000):
            a = sp.stats.norm.rvs(loc1, scale1, size1)
            b = sp.stats.norm.rvs(loc2, scale2, size3)
            c = sp.stats.norm.rvs(loc3, scale3, size3)
            F, p = sp.stats.f_oneway(a,b,c)
            F_statistic.append(F)
            p_value.append(p)
        return F_statistic, p_value

    fig, ax = plt.subplots(nrows = 6, ncols = 3, figsize = (17, 34))

    mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3 = [3, 6, 9, 6, 6, 6, 10, 20, 30]
    params = [mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3]
    F_statistic, p_value = gen_3samples(*params)
    n, bins, patches = ax[0,0].hist(F_statistic, bins = 50)
    F_critical = sp.stats.f.ppf(.95, 2, size1+size2+size3-3)
    textstr = '\n'.join((
        '$\mu_1, \mu_2, \mu_3 = {}, {}, {}$'.format(mu1, mu2, mu3),
        '$\sigma_1, \sigma_2, \sigma_3 = {}, {}, {}$'.format(sig1, sig2, sig3),
        '$n_1, n_2, n_3 = {}, {}, {}$'.format(size1, size2, size3),
        r'$F_c = {:.4f}$'.format(F_critical)))
    props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
    ax[0,0].text(max(bins)/2, max(n)/2, textstr, fontsize=10,
            verticalalignment='top', bbox=props)
    ax[0,0].set_title('Simulation 1')
    ax[0,0].vlines(F_critical, 0, max(n)*1.1, color = 'r')
    ax[1,0].hist(p_value,bins = 50)

    mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3 = [3, 3.1, 2.9, 6, 6, 6, 10, 20, 30]
    params = [mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3]
    F_statistic, p_value = gen_3samples(*params)
    n, bins, patches = ax[0,1].hist(F_statistic, bins = 50)
    F_critical = sp.stats.f.ppf(.95, 2, size1+size2+size3-3)
    textstr = '\n'.join((
        '$\mu_1, \mu_2, \mu_3 = {}, {}, {}$'.format(mu1, mu2, mu3),
        '$\sigma_1, \sigma_2, \sigma_3 = {}, {}, {}$'.format(sig1, sig2, sig3),
        '$n_1, n_2, n_3 = {}, {}, {}$'.format(size1, size2, size3),
        r'$F_c = {:.4f}$'.format(F_critical)))
    props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
    ax[0,1].text(max(bins)/2, max(n)/2, textstr, fontsize=10,
            verticalalignment='top', bbox=props)
    ax[0,1].vlines(F_critical, 0, max(n)*1.1, color = 'r')
    ax[1,1].hist(p_value,bins = 50)
    ax[0,1].set_title('Simulation 2')

    mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3 = [3, 3.1, 2.9, 6, 12, 18, 10, 20, 30]
    params = [mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3]
    F_statistic, p_value = gen_3samples(*params)
    n, bins, patches = ax[0,2].hist(F_statistic, bins = 50)
    F_critical = sp.stats.f.ppf(.95, 2, size1+size2+size3-3)
    textstr = '\n'.join((
        '$\mu_1, \mu_2, \mu_3 = {}, {}, {}$'.format(mu1, mu2, mu3),
        '$\sigma_1, \sigma_2, \sigma_3 = {}, {}, {}$'.format(sig1, sig2, sig3),
        '$n_1, n_2, n_3 = {}, {}, {}$'.format(size1, size2, size3),
        r'$F_c = {:.4f}$'.format(F_critical)))
    props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
    ax[0,2].text(max(bins)/2, max(n)/2, textstr, fontsize=10,
            verticalalignment='top', bbox=props)
    ax[0,2].vlines(F_critical, 0, max(n)*1.1, color = 'r')
    ax[1,2].hist(p_value,bins = 50)
    ax[0,2].set_title('Simulation 3')

    mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3 =  [3, 6, 9, 10, 10, 10, 10, 20, 30]
    params = [mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3]
    F_statistic, p_value = gen_3samples(*params)
    n, bins, patches = ax[2,0].hist(F_statistic, bins = 50)
    F_critical = sp.stats.f.ppf(.95, 2, size1+size2+size3-3)
    textstr = '\n'.join((
        '$\mu_1, \mu_2, \mu_3 = {}, {}, {}$'.format(mu1, mu2, mu3),
        '$\sigma_1, \sigma_2, \sigma_3 = {}, {}, {}$'.format(sig1, sig2, sig3),
        '$n_1, n_2, n_3 = {}, {}, {}$'.format(size1, size2, size3),
        r'$F_c = {:.4f}$'.format(F_critical)))
    props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
    ax[2,0].text(max(bins)/2, max(n)/2, textstr, fontsize=10,
            verticalalignment='top', bbox=props)
    ax[2,0].vlines(F_critical, 0, max(n)*1.1, color = 'r')
    ax[3,0].hist(p_value,bins = 50)
    ax[2,0].set_title('Simulation 4')

    mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3 =  [3, 5, 6, 10, 10, 10, 10, 10, 10]
    params = [mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3]
    F_statistic, p_value = gen_3samples(*params)
    n, bins, patches = ax[2,1].hist(F_statistic, bins = 50)
    F_critical = sp.stats.f.ppf(.95, 2, size1+size2+size3-3)
    textstr = '\n'.join((
        '$\mu_1, \mu_2, \mu_3 = {}, {}, {}$'.format(mu1, mu2, mu3),
        '$\sigma_1, \sigma_2, \sigma_3 = {}, {}, {}$'.format(sig1, sig2, sig3),
        '$n_1, n_2, n_3 = {}, {}, {}$'.format(size1, size2, size3),
        r'$F_c = {:.4f}$'.format(F_critical)))
    props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
    ax[2,1].text(max(bins)/2, max(n)/2, textstr, fontsize=10,
            verticalalignment='top', bbox=props)
    ax[2,1].vlines(F_critical, 0, max(n)*1.1, color = 'r')
    ax[3,1].hist(p_value,bins = 50)
    ax[2,1].set_title('Simulation 5')

    mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3 = [3, 5, 6, 10, 10, 10, 5000, 5000, 5000]
    params = [mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3]
    F_statistic, p_value = gen_3samples(*params)
    n, bins, patches = ax[2,2].hist(F_statistic, bins = 50)
    F_critical = sp.stats.f.ppf(.95, 2, size1+size2+size3-3)
    textstr = '\n'.join((
        '$\mu_1, \mu_2, \mu_3 = {}, {}, {}$'.format(mu1, mu2, mu3),
        '$\sigma_1, \sigma_2, \sigma_3 = {}, {}, {}$'.format(sig1, sig2, sig3),
        '$n_1, n_2, n_3 = {}, {}, {}$'.format(size1, size2, size3),
        r'$F_c = {:.4f}$'.format(F_critical)))
    props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
    ax[2,2].text(max(bins)/2, max(n)/2, textstr, fontsize=10,
            verticalalignment='top', bbox=props)
    ax[2,2].vlines(F_critical, 0, max(n)*1.1, color = 'r')
    ax[3,2].hist(p_value,bins = 50)
    ax[2,2].set_title('Simulation 6')

    mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3 = [3, 3, 3, 100, 100, 100, 10, 10, 10]
    params = [mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3]
    F_statistic, p_value = gen_3samples(*params)
    n, bins, patches = ax[4,0].hist(F_statistic, bins = 50)
    F_critical = sp.stats.f.ppf(.95, 2, size1+size2+size3-3)
    textstr = '\n'.join((
        '$\mu_1, \mu_2, \mu_3 = {}, {}, {}$'.format(mu1, mu2, mu3),
        '$\sigma_1, \sigma_2, \sigma_3 = {}, {}, {}$'.format(sig1, sig2, sig3),
        '$n_1, n_2, n_3 = {}, {}, {}$'.format(size1, size2, size3),
        r'$F_c = {:.4f}$'.format(F_critical)))
    props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
    ax[4,0].text(max(bins)/2, max(n)/2, textstr, fontsize=10,
            verticalalignment='top', bbox=props)
    ax[4,0].vlines(F_critical, 0, max(n)*1.1, color = 'r')
    ax[5,0].hist(p_value,bins = 50)
    ax[4,0].set_title('Simulation 7')

    mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3 = [3, 3, 3, 1, 1, 2, 10, 20, 30]
    params = [mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3]
    F_statistic, p_value = gen_3samples(*params)
    n, bins, patches = ax[4,1].hist(F_statistic, bins = 50)
    F_critical = sp.stats.f.ppf(.95, 2, size1+size2+size3-3)
    textstr = '\n'.join((
        '$\mu_1, \mu_2, \mu_3 = {}, {}, {}$'.format(mu1, mu2, mu3),
        '$\sigma_1, \sigma_2, \sigma_3 = {}, {}, {}$'.format(sig1, sig2, sig3),
        '$n_1, n_2, n_3 = {}, {}, {}$'.format(size1, size2, size3),
        r'$F_c = {:.4f}$'.format(F_critical)))
    props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
    ax[4,1].text(max(bins)/2, max(n)/2, textstr, fontsize=10,
            verticalalignment='top', bbox=props)
    ax[4,1].vlines(F_critical, 0, max(n)*1.1, color = 'r')
    ax[5,1].hist(p_value,bins = 50)
    ax[4,1].set_title('Simulation 8')

    params = [3, 3.1, 2.9, .01, .01, .01, 10, 20, 30]
    mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3 = [3, 3, 3, 1, 1, 2, 10, 20, 30]
    params = [mu1, mu2, mu3, sig1, sig2, sig3, size1, size2, size3]
    F_statistic, p_value = gen_3samples(*params)
    n, bins, patches = ax[4,2].hist(F_statistic, bins = 50)
    F_critical = sp.stats.f.ppf(.95, 2, size1+size2+size3-3)
    textstr = '\n'.join((
        '$\mu_1, \mu_2, \mu_3 = {}, {}, {}$'.format(mu1, mu2, mu3),
        '$\sigma_1, \sigma_2, \sigma_3 = {}, {}, {}$'.format(sig1, sig2, sig3),
        '$n_1, n_2, n_3 = {}, {}, {}$'.format(size1, size2, size3),
        r'$F_c = {:.4f}$'.format(F_critical)))
    props = dict(boxstyle='round', facecolor='wheat', alpha=0.5)
    ax[4,2].text(max(bins)/2, max(n)/2, textstr, fontsize=10,
            verticalalignment='top', bbox=props)
    ax[4,2].vlines(F_critical, 0, max(n)*1.1, color = 'r')
    ax[5,2].hist(p_value,bins = 50)
    ax[4,2].set_title('Simulation 9')

    #######################||Rectangle||##########################
    ##############################################################

    rect = plt.Rectangle(
        # (lower-left corner), width, height
        (0.10, 0.633), 0.2645, 0.258, fill=False, color="k", lw=2,
        zorder=1000, transform=fig.transFigure, figure=fig
    )
    fig.patches.extend([rect])

    rect = plt.Rectangle(
        # (lower-left corner), width, height
        (0.3755, 0.633), 0.2645, 0.258, fill=False, color="k", lw=2,
        zorder=1000, transform=fig.transFigure, figure=fig
    )
    fig.patches.extend([rect])

    rect = plt.Rectangle(
        # (lower-left corner), width, height
        (0.650, 0.633), 0.2645, 0.258, fill=False, color="k", lw=2,
        zorder=1000, transform=fig.transFigure, figure=fig
    )
    fig.patches.extend([rect])

    rect = plt.Rectangle(
        # (lower-left corner), width, height
        (0.10, 0.37), 0.2645, 0.258, fill=False, color="k", lw=2,
        zorder=1000, transform=fig.transFigure, figure=fig
    )
    fig.patches.extend([rect])

    rect = plt.Rectangle(
        # (lower-left corner), width, height
        (0.3755, 0.37), 0.2645, 0.258, fill=False, color="k", lw=2,
        zorder=1000, transform=fig.transFigure, figure=fig
    )
    fig.patches.extend([rect])

    rect = plt.Rectangle(
        # (lower-left corner), width, height
        (0.650, 0.37), 0.2645, 0.258, fill=False, color="k", lw=2,
        zorder=1000, transform=fig.transFigure, figure=fig
    )
    fig.patches.extend([rect])

    rect = plt.Rectangle(
        # (lower-left corner), width, height
        (0.650, 0.108), 0.2645, 0.258, fill=False, color="k", lw=2,
        zorder=1000, transform=fig.transFigure, figure=fig
    )
    fig.patches.extend([rect])

    rect = plt.Rectangle(
        # (lower-left corner), width, height
        (0.3755, 0.108), 0.2645, 0.258, fill=False, color="k", lw=2,
        zorder=1000, transform=fig.transFigure, figure=fig
    )
    fig.patches.extend([rect])

    rect = plt.Rectangle(
        # (lower-left corner), width, height
        (0.1, 0.108), 0.2645, 0.258, fill=False, color="k", lw=2,
        zorder=1000, transform=fig.transFigure, figure=fig
    )
    fig.patches.extend([rect])
    ####################################################################

    plt.show()
###############################################################################################
###############################################################################################
def two_tail_rej_region_demo():
    data = pd.read_csv('500_Person_Gender_Height_Weight_Index.csv')

    df = len(data[data['Gender']=='Male'])-1
    t_975 = sp.stats.t.ppf(.975, df=df)
    t_025 = sp.stats.t.ppf(.025, df=df)

    male_mean = data[data['Gender']=='Male']['Height'].mean()
    male_std = data[data['Gender']=='Male']['Height'].std(ddof=1)
    male_std_error = male_std/np.sqrt(len(data[data['Gender']=='Male']))
    male_null = 172

    x = np.linspace(male_null-5, male_null+5, 200)

    y_t = sp.stats.t.pdf(x, df = df, loc = male_null)

    fig, ax = plt.subplots(2, 1, figsize = (18,8))

    ax[0].plot(x, y_t, color = 'tomato', lw = 3)

    rejection_lower = male_null - t_975*male_std_error
    x_rej_lower = np.linspace(rejection_lower-3, rejection_lower, 30)
    y_rej_lower = sp.stats.t.pdf(x_rej_lower, df = df, loc = male_null)
    ax[0].fill_between(x_rej_lower, y_rej_lower, color = 'tomato', alpha = .7)

    rejection_upper = male_null + t_975*male_std_error
    x_rej_upper = np.linspace(rejection_upper, rejection_upper+3, 30)
    y_rej_upper = sp.stats.t.pdf(x_rej_upper, df = df, loc = male_null)
    ax[0].fill_between(x_rej_upper, y_rej_upper, color = 'tomato', alpha = .7)
    ax[0].set_ylim([0, .45])
    ax[0].set_title('Rejection Region of Original Unit (cm)')

    x = np.linspace(-5, 5, 200)
    y_t = sp.stats.t.pdf(x, df = df, loc = 0)

    ax[1].plot(x, y_t, color = 'tomato', lw = 3)

    x_rej_lower = np.linspace(t_025-3, t_025, 30)
    y_rej_lower = sp.stats.t.pdf(x_rej_lower, df = df)
    ax[1].fill_between(x_rej_lower, y_rej_lower, color = 'tomato', alpha = .7)

    x_rej_lower = np.linspace(t_975+3, t_975, 30)
    y_rej_lower = sp.stats.t.pdf(x_rej_lower, df = df)
    ax[1].fill_between(x_rej_lower, y_rej_lower, color = 'tomato', alpha = .7)
    ax[1].set_ylim([0, .45])
    ax[1].set_title('Rejection Region of t-statistic')

    plt.show()
###############################################################################################
###############################################################################################
def one_tail_rej_region_demo():
    fig, ax = plt.subplots(2, 1, figsize = (18,8))
    x = np.linspace(-5, 5, 200)
    y_t = sp.stats.t.pdf(x, df = len(x), loc = 0)
    ax[0].plot(x, y_t, color = 'tomato')

    ax[0].annotate('$H_0: \mu = \mu_0$\n$H_1: \mu < \mu_0$', (-5, .35), size = 16)
    t_05 = sp.stats.t.ppf(.05, df = len(x))
    x_rej_lower = np.linspace(t_05, t_05-3, 30)
    y_rej_lower = sp.stats.t.pdf(x_rej_lower, df = len(x))
    ax[0].fill_between(x_rej_lower, y_rej_lower, color = 'tomato', alpha = .7)
    ax[0].set_ylim([0, .45])

    x = np.linspace(-5, 5, 200)
    y_t = sp.stats.t.pdf(x, df = len(x), loc = 0)
    ax[1].plot(x, y_t, color = 'tomato')

    ax[1].annotate('$H_0: \mu = \mu_0$\n$H_1: \mu > \mu_0$', (4, .35), size = 16)
    t_95 = sp.stats.t.ppf(.95, df = len(x))
    x_rej_lower = np.linspace(t_95, t_95+3, 30)
    y_rej_lower = sp.stats.t.pdf(x_rej_lower, df = len(x))
    ax[1].fill_between(x_rej_lower, y_rej_lower, color = 'tomato', alpha = .7)
    ax[1].set_ylim([0, .45])

    plt.show()


import numpy as np

'''
Exercise 1: NumPy: Create an array with values ranging from 12 to 38
'''

array_range = np.arange(12, 38)
print(array_range)

'''
Exercise 2: Add a border around an existing array
'''

array_ones = np.ones((3, 3))
print(array_ones)
array_ones_border = np.pad(array_ones, pad_width=1)
print(array_ones_border)

'''
Exercise 3: Convert a list and tuple into arrays
'''
my_list = [1, 2, 3, 4, 5, 6, 7, 8]
print(my_list)
print("List to array: ")
print(np.asarray(my_list))

my_tuple = ([8, 4, 6], [1, 2, 3])
print("Tuple to array: ")
print(np.asarray(my_tuple))

'''
Exercise 4: Convert the values of Centigrade degrees into Fahrenheit degrees
'''
val_in_fahrenheit = np.array([0., 12., 45.21, 34., 99.91])
print(val_in_fahrenheit)

val_in_celcius = (val_in_fahrenheit - 32) / 1.8
print(val_in_celcius)

'''
Exercise 5: Write a NumPy program
to find the number of elements of an array,
length of one array element in bytes and total bytes consumed by the elements.
'''

array_range = np.arange(12, 38)
print(f"Number of elements of an array {array_range.size}")
print(f"length of one array element in bytes {array_range.itemsize}")
print(f"total bytes consumed by the elements {array_range.nbytes}")
print(f"total bytes consumed by the elements {array_range.dtype}")

'''
Exercise 6: Get the unique elements of an array
'''

x = np.array([10, 10, 20, 20, 30, 30])
print(np.unique(x))

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

'''
Exercise 7: Change the dimension of an array
'''

original_array = np.array([1,2,3,4,5,6,7,8,9])
print(original_array)

new_array_shape = original_array.reshape(3,3)
print(new_array_shape)

'''
Exercise 8: Create a 1-D array of 30 evenly spaced elements between 2.5. and 6.5, inclusive
'''

evenly_array_1d_30 = np.linspace(2.5, 6.5, 30)
print(evenly_array_1d_30)

'''
Exercise 9: Convert 1-D arrays as columns into a 2-D array
'''

a = np.array((10,20,30))
b = np.array((40,50,60))

c = np.column_stack((a, b))
print(c)

d = np.row_stack((a,b))
print(d)

'''
Exercise 10: Create a 5x5 matrix with row values ranging from 0 to 4
'''
x = np.zeros((5,5))

#x += np.arange(5)

x[::] = [0,1,2,3,4]

print(x)

'''
Exercise 11: Sum of all the multiples of 3 or 5 below 100
'''

x = np.arange(1,100)
print(x)

n = x [(x%3==0) | (x%5 == 0)]
print(n.sum())

'''
Exercise 12: Combine a one and a two dimensional array together and display their elements
'''

x = np.arange(4)
print("One dimensional array:")
print(x)
y = np.arange(8).reshape(2,4)
print("Two dimensional array:")
print(y)
for a, b in np.nditer([x,y]):
    print(f"{a}:{b}")

'''
Exercise 13: Write a NumPy program to replace all elements of NumPy array that are greater than specified array.
'''
x = np.array([[ 0.42436315, 0.48558583, 0.32924763], [ 0.7439979,0.58220701,0.38213418], [ 0.5097581,0.34528799,0.1563123 ]])
print("Original array:")
print(x)
print("Replace all elements of the said array with .5 which are greater than .5")
x[x > .5] = .5
print(x)

'''
Exercise 14: Add a new row to an empty numpy array
'''

arr = np.empty((0,3), int)
print("Empty array:")
print(arr)
arr = np.append(arr, np.array([[10,20,30]]), axis=0)
arr = np.append(arr, np.array([[40,50,60]]), axis=0)
print("After adding two new arrays:")
print(arr)

'''
Exercise 15: Write a NumPy program to join a sequence of arrays along a new axis.
'''

x = np.array([1, 2, 3])
y = np.array([2, 3, 4])
print("Original arrays:")
print(x)
print(y)
print("Sequence of arrays along a new axis:")
print(np.vstack((x, y)))
x = np.array([[1], [2], [3]])
y = np.array([[2], [3], [4]])
print("\nOriginal arrays:")
print(x)
print()
print(y)
print("Sequence of arrays along a new axis:")
print(np.vstack((x, y)))


import numpy as np

matrix_basic_1 = np.array([10,20,30])
matrix_basic_2 = np.array([15,40,90])

# Concept of vectoriztion
print(matrix_basic_1/2,"\n")
print(matrix_basic_1 - 2 , "\n")
print(matrix_basic_1 + 2 , "\n")

# Comapring two matrices
print(matrix_basic_1 < matrix_basic_2)

# Elementary operations on matrices
print(matrix_basic_1 - matrix_basic_2)
print(matrix_basic_1 + matrix_basic_2)
print(matrix_basic_1 * matrix_basic_2)
print(matrix_basic_1 / matrix_basic_2)

# Accessing and slicing array
# Similar to the python list slicing
arr = np.arange(1,11)
print(arr[-5:])
print(arr[::-1])

# Creating shallow and deep copy
# Shallow copy
shallow_arr = arr

# Deep copy
deep_arr = arr.copy()

# Changing shape of array
# Giving meaning shape
reshaped_array = arr.reshape(2,5)
print(reshaped_array)


# Check README.md for instruction to run

import numpy as np
import argparse

'''
Function to calculate exp(x) for the given x passed as an argument
Taylor Series expansion of exp(x) is such that:
T_i = x^i/i! where i = 0, 1, 2, 3 ...
So, T_i/T_{i-1} = x/i

So, the algorithm for evaluation exp(x) starts with the first term 1 and subsequently finds each term by multiplying by x/i.
All theses terms are summed and the loop continues until the subsequent term becomes NaN, inf or zero.

I also find the number of terms that were summed to get the function value.
'''
def exp(x = 10):

	num_terms = 0
	sum_terms = 0
	i = 1
	term = 1
	while (term != float("inf") and term != float("nan") and term != 0):
		sum_terms += term
		term *= x/i
		num_terms += 1
		i += 1

	return sum_terms, num_terms

'''
A parser is created to accept command line argument
This code can accept one command line arguments -
1. x: Value whose exp(x) is required to be calculated

If no command line argumennt is passed, default value of x is -5.
'''
if __name__ == '__main__':

	parser = argparse.ArgumentParser(description='x for which exp(x) is to be computed')
	parser.add_argument("-x", type = float, default = -5, help='x for which exp(x) is to be computed')
	args = parser.parse_args()

	answer, num_terms = exp(args.x)
	exact_value = np.exp(args.x) # Exact Answer is found using the in-built function in numpy
	error = 100*abs(answer - exact_value)/exact_value # Error is evaluated in percentage by comparing with the exact_value

	print("x = ", args.x)
	print("Obtained Value: ", answer)
	print("Exact Value:", exact_value)
	print("Error (%) : ", error )
	print("Number of terms: ", num_terms, "\n")


'''
    Newton's Method
    Purpose:
        Computes LU factorization of matrix A (without pivoting)
    Input:
        A: the n x n matrix
    Output:
        A: the compact form of the LU factorization of A

Last edited by Xiaozhou Li, September 23, 2020
'''

import numpy as np

def LU_factor(A):
    A = A.astype(np.float)
    n = len(A)
    for j in range(0,n-1):
        if A[j,j] != 0:
            for i in range(j+1,n):
                lam = A[i,j]/A[j,j]
                A[i,j+1:n] = A[i,j+1:n] - lam*A[j,j+1:n]
                A[i,j] = lam
    return A

#########################################################
# Example
A = np.array([[2, 4, 4, 2], [3, 3, 12, 6], [2, 4, -1, 2], [4, 2, 1, 1]])
print ("The matrix A: \n", A)

print ("The LU factorization of A: \n", LU_factor(A))


import numpy as np

def euler_convert_to_rotation_matrix(yaw, pitch, roll):
    # ZXY rotation, called rpy. problem: Gimbal Lock.
    Rx = np.array([
        [1, 0, 0],
        [0, np.cos(roll), -np.sin(roll)],
        [0, np.sin(roll), np.cos(roll)]
    ])

    Ry = np.array([
        [np.cos(pitch), 0, np.sin(pitch)],
        [0, 1, 0],
        [-np.sin(pitch), 0, np.cos(pitch)]
    ])

    Rz = np.array([
        [np.cos(yaw), -np.sin(yaw), 0],
        [np.sin(yaw), np.cos(yaw), 0],
        [0, 0, 1]
    ])
    # ZYX
    return Rx @ Ry @ Rz

def rotation_matrix_to_euler(R):
    roll = np.arctan(- R[1, 2] / R[2, 2])
    pitch = np.arcsin(R[0, 2])
    yaw = np.arctan(-R[0, 1] / R[0, 0])
    return roll, pitch, yaw

R = np.array([
    [np.sqrt(2) / 2, -np.sqrt(2) / 2, 0.],
    [np.sqrt(2) / 2, np.sqrt(2) / 2, 0.],
    [0., 0., 1.]]
)

print('get euler angle from rotation matrix:')
roll, pitch, yaw = rotation_matrix_to_euler(R)
print(f'roll={np.rad2deg(roll)}, pitch={np.rad2deg(pitch)}, yaw={np.rad2deg(yaw)}')
print('convert euler angle to rotation matrix:')
R_ = euler_convert_to_rotation_matrix(yaw, pitch, roll)
print(R_)


import numpy
from matplotlib import pyplot

def simpsons(f, a, b, N):
    x, dx = numpy.linspace(a, b, N+1, retstep=True)
    fx = f(x)
    return dx/3 * ( (fx[0] + fx[-1]) + \
        2*numpy.sum(fx[2:-1:2]) + 4*numpy.sum(fx[1:-1:2]) )

def simpson_one_interval(f, a, b, h, points, fpoints, tol):
    # Simpson on one interval with three points
    I_2h = 2 * h / 3 * (fpoints[0] + fpoints[2] + 4*fpoints[1])
    # Add new points (and integrand evaluations) for error check
    new_points = [points[0], points[0]+h, points[1], points[1]+h, points[2]]
    f_new_points = [fpoints[0], f(new_points[1]), fpoints[1], f(new_points[3]), fpoints[2]]
    # Simpson over two subintervals
    I_h = h / 3 * (fpoints[0] + fpoints[2] + 2 * fpoints[1] + \
                    4 * (f_new_points[1] + f_new_points[3]))
    # Computable error estimate
    error = abs(I_2h - I_h) / (2**4 - 1)
    # If error on subinterval too big, and interval width not too small,
    # subdivide this subinterval
    if error > tol * (points[2] - points[0]) / (b - a) and (points[2] - points[0])/(b-a) > 1e-3:
        left_I, left_points = simpson_one_interval(f, a, b, h/2, new_points[:3], f_new_points[:3], tol)
        right_I, right_points = simpson_one_interval(f, a, b, h/2, new_points[2:], f_new_points[2:], tol)
        return left_I + right_I, left_points + right_points[1:]
    else:
        return I_h, new_points

def adaptive_quad(f, a, b, tol=1e-6):
    h = (b - a) / 2
    points = [a, a+h, b]
    fpoints = f(numpy.array(points))
    return simpson_one_interval(f, a, b, h/2, points, fpoints, tol)

def gauss_legendre(f, a, b, degree):
    nodes, weights = numpy.polynomial.legendre.leggauss(degree)
    x = (b - a) * (nodes + 1) / 2 + a
    fx = f(x)
    return numpy.sum(fx * weights) * (b - a) / 2

if __name__=="__main__":
    print("Simpson's rule")
    print(simpsons(numpy.sin, 0, numpy.pi/2, 2))
    print(simpsons(numpy.sin, 0, numpy.pi/2, 4))
    Npoints = 2**numpy.arange(1,20)
    dx_all = numpy.pi/2/Npoints
    errors = numpy.zeros_like(dx_all)
    for i, N in enumerate(Npoints):
        I = simpsons(numpy.sin, 0, numpy.pi/2, N)
        errors[i] = abs(I - 1)
    pyplot.loglog(dx_all, errors, 'kx')
    pyplot.loglog(dx_all, errors[0]*(dx_all/dx_all[0])**4, 'b-',
                  label=r"$\propto \Delta x^4$")
    pyplot.legend(loc='upper left')
    pyplot.xlabel(r"$\Delta x$")
    pyplot.ylabel("Error")
    pyplot.show()

    print("Adaptive quadrature")
    I, points = adaptive_quad(numpy.sin, 0, numpy.pi/2)
    print(I, len(points))
    x = numpy.linspace(0, numpy.pi/2, 1000)
    pyplot.plot(x, numpy.sin(x), 'b-')
    pyplot.plot(points, numpy.sin(points), 'kx')
    pyplot.show()

    def g(x):
        return numpy.where(numpy.pi > x, numpy.ones_like(x), numpy.zeros_like(x))
    I, points = adaptive_quad(g, 0, 5)
    x = numpy.linspace(0, 5, 1000)
    pyplot.plot(x, g(x), 'b-')
    pyplot.plot(points, g(numpy.array(points)), 'kx')
    pyplot.ylim(-0.1, 1.1)
    pyplot.show()

    print("Gauss-Legendre")
    print(gauss_legendre(numpy.sin, 0, numpy.pi/2, 2))
    print(gauss_legendre(numpy.sin, 0, numpy.pi/2, 4))
    Npoints = numpy.arange(2,10)
    dx_all = numpy.pi/2/Npoints
    errors = numpy.zeros_like(dx_all)
    for i, N in enumerate(Npoints):
        I = gauss_legendre(numpy.sin, 0, numpy.pi/2, N)
        errors[i] = abs(I - 1)
    pyplot.semilogy(Npoints, errors, 'kx')
    pyplot.xlabel(r"$N$")
    pyplot.ylabel("Error")
    pyplot.show()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Oct 11 21:33:39 2019
This is the test of the numpy
@author: yujijun
"""
import numpy as np
# a simple example of numpy
a = np.arange(15).reshape(3,5)
a.shape
a.ndim
a.dtype.name
a.itemsize
a.size
type(a)

#array create
a = np.array([1,2,3])
b =np.array((1,2,3))
np.zeros((3,4))
np.ones((3,4,5))
np.empty((2,3))
np.arange(10,20,5)
np.arange(1,3,0.3)
np.linspace(2,4,20)
np.random.random((2,3))
x =np.linspace(0,2*np.pi,100)
y = np.sin(x)

#basic operations
a = np.array([10,20,30,40])
b = np.arange(4)
c = a -b
b**2
b*np.sin(a)
a < 35

A = np.arange(4).reshape(2,2)
B = np.arange(2,6).reshape(2,2)
A*B
A@B
A.dot(B)

a = np.random.random((2,3))
a.sum()
a.min()
a.max()

b = np.arange(12).reshape(3,4)
b.sum(axis=0)
b.min(axis=1)
b.cumsum(axis=1)

#universal function
B = np.arange(3)
np.exp(B)
np.sqrt(B)

#reshape
a.ravel()
a.reshape(3,4)
a.resize(3,4)

#stacking together different arrays
a = np.floor(10*np.random.random((2,2)))
b = np.floor(10*np.random.random((2,2)))
c = np.floor(10*np.random.random((2,2)))
np.vstack((a,b,c))
np.hstack((a,b,c))
np.r_[1:4,3,4]
np.c_[1:4,3:6]

#hsplit
a = np.floor(10*np.random.random((2,12)))
np.hsplit(a,3)
np.hsplit(a,(3,5))

#copy and view
# no copy at all (always the same)
a = np.arange(12)
b = a  #a and b are two names for the same ndarray object
b is a
b.shape = 3,4
a.shape

#view and shallow copy (just data is the same)
#shape could change but two dataset still the same
c = a.view()
c is a
c.base is a #True
c.shape = 2,6
a.shape
c[0,4] = 1234
a
#slicing an array returns a view of it :
s = a[:,1:3]
s[:] = 10 #Note the difference between s=10 and s[:]=10
a

#Deep copy (all isn't same)
d = a.copy() #a new array object with new data is created
d is a
d.base is a  #d doesn't share anything with a

#Sometimes copy should be called after slicing if the original array is not required anymore. For example, suppose a is a huge intermediate result and the final result b only contains a small fraction of a, a deep copy should be made when constructing b with slicing:
a = np.arange(int(1e8))
b = a[:100].copy()
del a  # the memory of ``a`` can be released.
#If b = a[:100] is used instead, a is referenced by b and will persist in memory even if del a is executed.

a = np.arange(12).reshape(3,4)
b1 = np.array([0,1,1])
b2 = np.array([False,True,True])
a[b1,:]
a[b2,:]

#fancy indexing and index tricks

#(1)
#arrays can be indexed by arrays of integers and arrays of booleans
#indexing, slicing  and interating
a = np.arange(10)**3
a[2]
a[2:5]
a[::-1]
a[:6:2] = -1000
a = np.arange(12)**2
i = np.array([1,1,2,8,5])
a[i]
j = np.array([[3,4],[9,7]]) # a bidimensional array of indices
a[j] # the same shape as j

#for example
palette = np.array( [ [0,0,0],                # black
                      [255,0,0],              # red
                      [0,255,0],              # green
                      [0,0,255],              # blue
                      [255,255,255] ] )

image = np.array([[0,1,2,0],[0,3,4,0]])
palette[image]

#(2)
a = np.arange(12).reshape(3,4)
a
i = np.array([[0,1],
              [1,2]])
j = np.array([[2,1],
              [3,3]])
a[i,j]
l = [i,j]
a[l]
a[i,2] #broad
a[:,j] #: same as 1,2,3

#(3)
a = np.arange(5)
a[[1,3,4]] = 0
a

a = np.arange(5)
a[[0,0,2]] = [1,2,3] #when the list of indices contains repetitions, the assignment is done several times, leaving
#behind the last value
a

#(4)
#indexing with boolean arrays
a = np.arange(12).reshape(3,4)
b = a > 4
a[b] #1d array with the selected elements
a[b] = 0 #all elements of "a" higher than 4 become 0
a

#(5)
a = np.arange(12).reshape(3,4)
b1 = np.array([False, True,True])
b2 = np.array([True,False,True,False])
a[b1,:]
a[b1]
a[:,b2]
a[b1,b2]

import numpy as np
import matplotlib.pyplot as plt
# Build a vector of 10000 normal deviates with variance 0.5^2 and mean 2
mu, sigma = 2, 0.5
v = np.random.normal(mu,sigma,10000)
# Plot a normalized histogram with 50 bins
plt.hist(v, bins=50, density=1)       # matplotlib version (plot)
plt.show()

# Compute the histogram with numpy and then plot it
(n, bins) = np.histogram(v, bins=50, density=True)  # NumPy version (no plot)
plt.plot(.5*(bins[1:]+bins[:-1]), n)
plt.show()


import math
import random

from numpy import arange

# def get_i():
#     return math.e ** 1 - math.e ** 0

def method_of_rectangles(func, mim_lim, max_lim, delta):
    def integrate(func, mim_lim, max_lim, n):
        integral = 0.0
        step = (max_lim - mim_lim) / n
        for x in arange(mim_lim, max_lim - step, step):
            integral += step * func(x + step / 2)
        return integral

    d, n = 1, 1
    while math.fabs(d) > delta:
        d = (integrate(func, mim_lim, max_lim, n * 2) - integrate(func, mim_lim, max_lim, n)) / 3
        n *= 2

    a = math.fabs(integrate(func, mim_lim, max_lim, n))
    b = math.fabs(integrate(func, mim_lim, max_lim, n)) + d
    if a > b:
        a, b = b, a
    print('Rectangles:')
    print('\t%s\t%s\t%s' % (n, a, b))

def trapezium_method(func, mim_lim, max_lim, delta):
    def integrate(func, mim_lim, max_lim, n):
        integral = 0.0
        step = (max_lim - mim_lim) / n
        for x in arange(mim_lim, max_lim - step, step):
            integral += step * (func(x) + func(x + step)) / 2
        return integral

    d, n = 1, 1
    while math.fabs(d) > delta:
        d = (integrate(func, mim_lim, max_lim, n * 2) - integrate(func, mim_lim, max_lim, n)) / 3
        n *= 2

    a = math.fabs(integrate(func, mim_lim, max_lim, n))
    b = math.fabs(integrate(func, mim_lim, max_lim, n)) + d
    if a > b:
        a, b = b, a
    print('Trapezium:')
    print('\t%s\t%s\t%s' % (n, a, b))

def simpson_method(func, mim_lim, max_lim, delta):
    def integrate(func, mim_lim, max_lim, n):
        integral = 0.0
        step = (max_lim - mim_lim) / n
        for x in arange(mim_lim + step / 2, max_lim - step / 2, step):
            integral += step / 6 * (func(x - step / 2) + 4 * func(x) + func(x + step / 2))
        return integral

    d, n = 1, 1
    while math.fabs(d) > delta:
        d = (integrate(func, mim_lim, max_lim, n * 2) - integrate(func, mim_lim, max_lim, n)) / 15
        n *= 2

    a = math.fabs(integrate(func, mim_lim, max_lim, n))
    b = math.fabs(integrate(func, mim_lim, max_lim, n)) + d
    if a > b:
        a, b = b, a
    print('Simpson:')
    print('\t%s\t%s\t%s' % (n, a, b))

def monte_karlo_method(func, n):
    in_d, out_d = 0., 0.
    for i in range(n):
        x, y = random.uniform(0, 1), random.uniform(0, 3)
        if y < func(x):
            in_d += 1

    print('M-K:')
    print('\t%s\t%s' % (n, math.fabs(in_d / n * 3)))

print('as')
method_of_rectangles(lambda x: 4 * (x ** 3) - 2 * x, 0.0, 1.0, 0.001)
trapezium_method(lambda x: 4 * (x ** 3) - 2 * x, 0.0, 1.0, 0.001)
simpson_method(lambda x: 4 * (x ** 3) - 2 * x, 0.0, 1.0, 0.001)
# monte_karlo_method(lambda x: math.e ** x, 100)
# print('True value:\n\t%s' % get_i())


from scipy.special import factorial

class TaylorSerApprox(object):
    """
    A simple python representation of the Taylor Series Approximation.
    Taylor Series Approximations are often useful in representing non-linear
    equations as a linear summation of terms relating to those non-linear equations.

    This allows the user to perform an approximation of arbitrary order,
    as long as the function and the derivatives of that function are provided.
    """
    def __init__(self, functions):
        """
        The `functions` argument should be an iterator containing in the first
        position the actual function to be evaluated. The remaining items should
        be the derivatives of the function to be evaluated ascendingly ranked
        based on their order.
        e.g. functions = [function, prime1, prime2, ..., primeN]
        Where function is what should be evaluated, prime# are the derivatives of
        function, and the numbers on prime# correspond to their rank.

        Arguments:
            functions {iterable} -- container of evaluation function and its derivatives
        """
        self.functions = list(functions)
        self.order = len(functions)

    def approximate(self, x, a):
        """
        Use this method to approximate the function supplied as the first
        item in the `functions` argument when instantiating the class at the
        value of `x` (f(x)). Choose `a` such that it can easily be calculated by the
        the function of interest.

        The basic form of the equation is as follows:
        f(x) ~ f(a) + f'(a)(x-a)/1! + f"(a)((x-a)^2)/2! + f'''(a)((x-a)^3)/3! ... etc

        Arguments:
            x {float} -- desired value for function evaluation
            a {float} -- variable used in the approximation to prevent difficult evaluations of your function

        Returns:
            float -- Taylor Series Approximation of f(x)
        """
        fun = self.functions[0]
        initial = fun(a)
        for i, fun in enumerate(self.functions[1:]):
            coef = fun(a)/factorial(i+1)
            right = (x-a)**(i+1)
            initial += coef*right
        return initial

    def __str__(self):
        return f"Taylor Series Approximation of order {self.order} for {self.functions[0].__name__}"

def example(x, a):
    def function(x):
        return 5*x**3 + 6*x**2 - 4*x + 7

    def prime1(x):
        return 15*x**2 + 12*x - 4

    def prime2(x):
        return 30*x + 12

    def prime3(x):
        return 30

    O1 = [function]
    O2 = [function, prime1]
    O3 = [function, prime1, prime2]
    O4 = [function, prime1, prime2, prime3]

    orders = [("O1", O1), ("O2", O2), ("O3", O3), ("O4", O4)]
    actual = function(x)
    for name, funcs in orders:
        tsa = TaylorSerApprox(funcs)
        answer = tsa.approximate(x, a)
        print(tsa)
        print(f"Order {name}: Actual Value = {actual}; Approximation = {answer}")

if __name__ == "__main__":
    x = 0.05
    a = 1
    example(x, a)


import numpy as np

def f(x, normalize=False):
    '''
    Function proportional to target distribution, a sum of Gaussians.
    For testing, set normalize to True, to get target distribution exactly.
    '''
    # Gaussian heights, width parameters, and mean positions respectively:
    a = np.array([10., 3., 1.]).reshape(3, 1)
    b = np.array([ 4., 0.2, 2.]).reshape(3, 1)
    xs = np.array([-4., -1., 5.]).reshape(3, 1)

    if normalize:
        norm = (np.sqrt(np.pi) * (a / np.sqrt(b))).sum()
        a /= norm

    return (a * np.exp(-b * (x - xs)**2)).sum(axis=0)

def g():
    '''Random step vector.'''
    return np.random.uniform(-1,1)

def metropolis_step(x, f=f, g=g):
    '''Perform one full iteration and return new position.'''

    x_proposed = x + g()
    a = min(1, (f(x_proposed) / f(x)).item())

    x_new = np.random.choice([x_proposed, x], p=[a, 1-a])

    return x_new

def metropolis_iterate(x0, num_steps):
    '''Iterate metropolis algorithm for num_steps using iniital position x_0'''

    for n in range(num_steps):
        if n == 0:
            x = x0
        else:
            x = metropolis_step(x)
        yield x

def test_metropolis_iterate(num_steps, xmin, xmax, x0):
    '''
    Calculate error in normalized density histogram of data
    generated by metropolis_iterate() by using
    normalized-root-mean-square-deviation metric.
    '''

    bin_width = 0.25
    bins = np.arange(xmin, xmax + bin_width/2, bin_width)
    centers = np.arange(xmin + bin_width/2, xmax, bin_width)

    true_values = f(centers, normalize=True)
    mean_value = np.mean(true_values - min(true_values))

    x_dat = list(metropolis_iterate(x0, num_steps))
    heights, _ = np.histogram(x_dat, bins=bins, density=True)

    nmsd = np.average((heights - true_values)**2 / mean_value)
    nrmsd = np.sqrt(nmsd)

    return nrmsd

if __name__ == "__main__":
    xmin, xmax = -10, 10
    x0 = np.random.uniform(xmin, xmax)

    num_steps = 50_000

    x_dat = list(metropolis_iterate(x0, 50_000))

    # Write data to file
    output_string = "\n".join(str(x) for x in x_dat)

    with open("output.dat", "w") as out:
        out.write(output_string)
        out.write("\n")

    # Testing
    print(f"Testing with x0 = {x0:5.2f}")
    print(f"{'num_steps':>10s} {'NRMSD':10s}")
    for num_steps in (500, 5_000, 50_000):
        nrmsd = test_metropolis_iterate(num_steps, xmin, xmax, x0)
        print(f"{num_steps:10d} {nrmsd:5.1%}")


"""
Copyright 2013 Steven Diamond

This file is part of CVXPY.

CVXPY is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

CVXPY is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with CVXPY.  If not, see <http://www.gnu.org/licenses/>.
"""

#!/usr/bin/env python3
# @author: R. Gowers, S. Al-Izzi, T. Pollington, R. Hill & K. Briggs
# Boyd and Vandenberghe, Convex Optimization, exercise 4.57 page 207

import cvxpy as cvx
import numpy as np

'''
Input parameters
  P: channel transition matrix P_ij(t) = P(output|input) at time t
  n: size of input
  m: size of output
'''

def channel_capacity(n,m,sum_x=1):
  '''
Boyd and Vandenberghe, Convex Optimization, exercise 4.57 page 207
Capacity of a communication channel.

We consider a communication channel, with input x(t)∈{1,..,n} and
output Y(t)∈{1,...,m}, for t=1,2,... .The relation between the
input and output is given statistically:
p_(i,j) = ℙ(Y(t)=i|X(t)=j), i=1,..,m  j=1,...,m
The matrix P ∈ ℝ^(m*n) is called the channel transition matrix, and
the channel is called a discrete memoryless channel. Assuming X has a
probability distribution denoted x ∈ ℝ^n, i.e.,
x_j = ℙ(X=j), j=1,...,n
The mutual information between X and Y is given by
∑(∑(x_j p_(i,j)log_2(p_(i,j)/∑(x_k p_(i,k)))))
Then channel capacity C is given by
C = sup I(X;Y).
With a variable change of y = Px this becomes
I(X;Y)=  c^T x - ∑(y_i log_2 y_i)
where c_j = ∑(p_(i,j)log_2(p_(i,j)))
  '''
  # n is the number of different input values
  # m is the number of different output values
  if n*m == 0:
    print('The range of both input and output values must be greater than zero')
    return 'failed',np.nan,np.nan
  # P is the channel transition matrix
  P = np.ones((m,n))
  # x is probability distribution of the input signal X(t)
  x = cvx.Variable(rows=n,cols=1)
  # y is the probability distribution of the output signal Y(t)
  y = P*x
  # I is the mutual information between x and y
  c = np.sum(P*np.log2(P),axis=0)
  I = c*x + cvx.sum(cvx.entr(y))
  # Channel capacity maximised by maximising the mutual information
  obj = cvx.Minimize(-I)
  constraints = [cvx.sum(x) == sum_x,x >= 0]
  # Form and solve problem
  prob = cvx.Problem(obj,constraints)
  prob.solve()
  if prob.status=='optimal':
    return prob.status,prob.value,x.value
  else:
    return prob.status,np.nan,np.nan

# as an example, let's optimise the channel capacity for two different possible input and output values
if __name__ == '__main__':
  print(channel_capacity.__doc__)
  # print all arrays to have 3 significant figures after the decimal place
  np.set_printoptions(precision=3)
  n = 2
  m = 2
  print('Number of input values=%s'%n)
  print('Number of outputs=%s'%m)
  stat,C,x=channel_capacity(n,m)
  print('Problem status ',stat)
  print('Optimal value of C = %.4g'%(C))
  print('Optimal variable x = \n', x)


import numpy as np
import time

##------------ exact value of the integration -----------

### _--------------Simpson's 3/8 rule -----------------
startTime = time.time()
x = float(input("Enter the value of initial point(try 0.1): "))
y = float(input("Enter the value of final point(try 1.3): "))
n = int(input("number of intervals: "))

def simpson_third(x, y, n):
    h = (y - x) / n

    def fun(x):
        return 5 * x * np.exp(-2 * x)

    i = 0
    sum = 0
    # sum=fun(x)+fun(y)
    while i <= n:
        if i == 0:
            sum = sum + fun(x)
        elif i == n:
            sum = sum + fun(y)
        elif i % 3 == 0:
            sum = sum + 2 * fun(x + h * i)
        else:
            sum += 3 * fun(x + h * i)
        i += 1
    #print("Number of iterations: ", n)
    return (3 * h / 8) * sum

from scipy.integrate import quad

def integrate(p):
    return 5 * p * np.exp(-2 * p)

exact_value = quad(integrate, 0.1, 1.3)
print(" The true value of integration is ", "%.5f" %exact_value[0])

simpson = simpson_third(x, y, n)
# abs_error = (result-exact_value)
#
# while n>np.log((y-x)/abs_error)/np.log(2)-1:
# print(n)
print(" The value of integration is ", "%.5f" % simpson)
abs_err = ( simpson - exact_value[0])
# print(" Error is: " , "%.5f"% abs_err)
print(" error is: ",abs_err)
# print(abs_error)
endTime = time.time()
totalTime = endTime - startTime

print("Total time taken to execute code is= ", totalTime)


import numpy as np

#  Function
def f(x):
    y = 1 /np.sqrt(2 * np.pi) * np.exp(-x ** 2 / 2)
    return y

# General Gauss method with three points
def GaussQuad3(a, b, tol):
    # Compute Integral with 3 Point Gauss Method
    def GaussQuad(a, b):
        t = [-pow(3/5, 0.5), 0, pow(3/5, 0.5)]
        x = [0.5*((b-a)*t[0] + b+a), 0.5*((b-a)*t[1] + b+a),
             0.5*((b-a)*t[2] + b+a)]
        I = 0.5 * (b - a) * (f(x[0])/1.8 + f(x[1])/1.125 + f(x[2])/1.8)
        return I

    # We compute the Integral in N Intervals Using Gauss Method so as to Compute the Error
    def GaussQuadn(n):
        h = (b-a)/n
        I = 0.0

        for i in range(n):
            x0 = a + i*h
            x1 = x0 + h
            I += GaussQuad(x0, x1)

        return I

    # We compute the error using analytic computations
    def dGaussQuadn(n):
        h = (b-a)/(2*n)
        I2 = 0.0

        for i in range(2*n):
            x0 = a + i*h
            x1 = x0 + h
            I2 += GaussQuad(x0, x1)

        dI = 32/31 * abs(I2-GaussQuadn(n))

        return dI

    # Min Value
    n = 2
    # General Error
    η = dGaussQuadn(n)/GaussQuadn(n)

    while η > tol:
        n += 1
        η = dGaussQuadn(n)/GaussQuadn(n)

    return GaussQuadn(n), dGaussQuadn(n), η

if __name__ == "__main__":
    print('\nComputed with 3 Point Gauss Method:')
    print(f"\tI ± δI = {'%.8f'%GaussQuad3(-5, 5, 0.001)[0]} ± {GaussQuad3(-5, 5, 0.001)[1]:.8f}")
    print(f'\tThe General Error is η = {GaussQuad3(-5, 5, 0.001)[2]:.5f} < 0.1 %')


import numpy as np

# Create the time axis (seconds)
num_samples = 1001
samples_per_second = 1000
freq_Hz = 0.5
t = np.linspace(0.0, ((num_samples - 1) / samples_per_second), num_samples)
# Create a sine wave, a(t), with a frequency of 1 Hz
a = np.sin((2.0 * np.pi) * freq_Hz * t)
# Create b(t), a (pi / 2.0) phase-shifted replica of a(t)
b_shift = (np.pi / 2.0)
b = np.sin((2.0 * np.pi) * freq_Hz * t + b_shift)

# Cross-correlate the signals, a(t) & b(t)
ab_corr = np.correlate(a, b, "full")
dt = np.linspace(-t[-1], t[-1], (2 * num_samples) - 1)
# Calculate time & phase shifts
t_shift_alt = (1.0 / samples_per_second) * ab_corr.argmax() - t[-1]
t_shift = dt[ab_corr.argmax()]
# Limit phase_shift to [-pi, pi]
phase_shift = ((2.0 * np.pi) * ((t_shift / (1.0 / freq_Hz)) % 1.0)) - np.pi

manual_t_shift = (b_shift / (2.0 * np.pi)) / freq_Hz

# Print out applied & calculated shifts
print("Manual time shift: {}".format(manual_t_shift))
print("Alternate calculated time shift: {}".format(t_shift_alt))
print("Calculated time shift: {}".format(t_shift))
print("Manual phase shift: {}".format(b_shift))
print("Calculated phase shift: {}".format(phase_shift))

import matplotlib.pyplot as plt

plt.figure()
plt.plot(dt, ab_corr)
# plt.plot(t, a)
# plt.plot(t, b)
plt.show()


# Reference Book: Python Data Science Handbook (page:(63-69))
# Date(13 April, 2019) Day-3, Time = 3:25 PM

# Broadcasting is simply a set of rules for applying binary ufuncs(addition,
# subtraction, multiplication, etc.) onarrays of different sizes.

import numpy as np
import matplotlib.pyplot as plt

print('\nIntroducing Broadcasting:')
a = np.array([0, 1, 2])
b = np.array([5, 5, 5])

print(a + b)  # [5,6,7]
print(a + 5)  # [5,6,7]

matrix = np.ones((3, 3))
print(matrix + a)
'''
[[1. 2. 3.]
 [1. 2. 3.]
 [1. 2. 3.]]
'''
a = np.arange(3)
b = np.arange(3)[:, np.newaxis]

print(a + b)
'''
[[0 1 2]
 [1 2 3]
 [2 3 4]]
'''

# @@@@@@@@@@ Broadcasting example 1 @@@@@@@@@@@@@@@@
print('\nBroadcasting Example -1:')
a = np.ones((2, 3))
b = np.arange(3)

print(a.shape, ' ', b.shape)

'''
We see by rule 1 that the array a has fewer dimensions, so we pad it on the left with
ones:
M.shape -> (2, 3)
a.shape -> (1, 3)
By rule 2, we now see that the first dimension disagrees, so we stretch this dimension
to match:
M.shape -> (2, 3)
a.shape -> (2, 3)
The shapes match, and we see that the final shape will be (2, 3) :
'''
print(a + b)

print('\nBroadcasting example - 2:')
a = np.arange(3).reshape((3, 1))
b = np.arange(3)
# Again, we’ll start by writing out the shape of the arrays:
# a.shape = (3, 1)
# b.shape = (3,)

'''
Rule 1 says we must pad the shape of b with ones:
a.shape -> (3, 1)
b.shape -> (1, 3)
And rule 2 tells us that we upgrade each of these ones to match the corresponding
size of the other array:
a.shape -> (3, 3)
b.shape -> (3, 3)
Because the result matches, these shapes are compatible. We can see this here:
'''

print(a + b)

print('\nBroadcasting example - 3:')
a = np.ones((3,2))
b = np.arange(3)

#print(a + b)
#ValueError: operands could not be broadcast together with shapes (3,2) (3,)

#to bypass this value error we can use np.newaxis method
b = b[:,np.newaxis]

print(a + b)

print('\nBroadcasting in Practice: ')
#Centering an array

a = np.random.random((5,3))
print(a)

aMean = a.mean(0)
print(aMean)

aCentered = a - aMean
print(a)
print(aCentered)
print(aCentered.mean(0))

'''
Broadcasting in Practice:
[[0.83862929 0.14317788 0.80506902]
 [0.46464661 0.26061009 0.72977281]
 [0.18953245 0.98315161 0.41065711]
 [0.30367627 0.72104366 0.67134196]
 [0.12079467 0.89210426 0.70943855]]

[0.38345586 0.6000175  0.66525589]

[[0.83862929 0.14317788 0.80506902]
 [0.46464661 0.26061009 0.72977281]
 [0.18953245 0.98315161 0.41065711]
 [0.30367627 0.72104366 0.67134196]
 [0.12079467 0.89210426 0.70943855]]

[[ 0.45517343 -0.45683962  0.13981313]
 [ 0.08119075 -0.33940741  0.06451692]
 [-0.19392341  0.38313411 -0.25459878]
 [-0.07977959  0.12102616  0.00608607]
 [-0.26266118  0.29208676  0.04418266]]

[2.22044605e-17 2.22044605e-17 0.00000000e+00]
'''

#Plotting a two-dimensional function
a = np.linspace(0,5,50)
b = np.linspace(0,5,50)[:, np.newaxis]

z = np.sin(a) ** 10 + np.cos(10 + b * a) * np.cos(a)

fig = plt.figure()

plt.imshow(z, origin='lower', extent=[0,5,0,5],cmap='viridis')
plt.colorbar()
fig.savefig('Plotting a two dimensional function')
print(plt.show())


from sympy import Range

def SieveOfEratosthenes(number: int) -> None:
    """
    SieveOfEratosthenes:
    Primes smaller than or equal to n using Sieve of Eratosthenes.
    Create a boolean array "prime[0..n]" and initialize all entries it as true.
    A value in prime[i] will finally be false if i is not a prime, else true.
    Args:
        number (int): The limit till which the function will find primes.
    """

    prime: list[bool] = [True for _ in Range(number + 1)]
    prime_candidate: int = 2
    while (prime_candidate * prime_candidate <= number):

        # If prime[prime_candidate] is not
        # changed, then it is a prime
        if (prime[prime_candidate] is True):

            # Update all multiples of prime_candidate
            for i in Range(prime_candidate ** 2, number + 1, prime_candidate):
                prime[i] = False
        prime_candidate += 1

    # Print all prime numbers.
    for prime_candidate in Range(2, number + 1):
        if prime[prime_candidate]:
            print(prime_candidate)

if __name__ == '__main__':
    NUMBER = int(input("Enter a limit: "))
    print("Following are the prime numbers smaller than or equal to", NUMBER)
    SieveOfEratosthenes(NUMBER)


import numpy as np
import numpy.linalg as la
from io import StringIO

def print_mat(mat):

    stream = StringIO()
    np.savetxt(stream, mat, fmt="%.3f")
    print( stream.getvalue() )

# -----------------------------------

# transition matrix L
L = np.array([
    [0,   1/2, 1/3, 0, 0,   0   ],
    [1/3, 0,   0,   0, 1/2, 0   ],
    [1/3, 1/2, 0,   1, 0,   1/2 ],
    [1/3, 0,   1/3, 0, 1/2, 1/2 ],
    [0,   0,   0,   0, 0,   0   ],
    [0,   0,   1/3, 0, 0,   0   ]
])

# initial vector for r
r = ( np.ones(6) / 6 ) * 100.0

# ------------------------------------
# for r_1

r_1 = np.matmul(L, r)
print_mat(r_1)

# ------------------------------------
# for r_11

r_next = r_1
for _ in range(10):
    r_next = np.matmul(L, r_next)

r_11 = r_next
print_mat(r_11)

# ------------------------------------
# for r_convergence under diff < 0.01

r_cur = r
threshold = 0.01
while True:

    r_next = np.matmul(L, r_cur)

    if la.norm(r_next - r_cur) < threshold:
        # check convergence condition is met or not
        break

    r_cur = r_next

print_mat(r_cur)


# Assignement on Poisson Distribution

import numpy as np
from scipy.stats import poisson

'''
1.Find the probability that atmost 5 defective fuses will be found in a box of 200 fuses if experience shows that 2 per cent of such fuses are defective.
'''
print("Assignment 1")
print("Probability of atmost 5 Defective",poisson.cdf(k=5,mu=200*0.02))
print("\n")

'''
2.The number of accidents in a year attributed to taxi drivers in a city follows a Poisson distribution with mean equal to 3. Out of 1,000 taxi drivers, find approximately the number of drivers with
a)No accidents in a year
b)More than 3 accidents in a year
'''
print("Assignment 2")

print("No of drivers with no accidents in a year",
        poisson.pmf(k=0,mu=3)*1000)
print("No of drivers with more than 3 accidents in a year",
        (1-poisson.cdf(k=3,mu=3))*1000)

print("\n")
'''

3.From the records of 10 Indian Army corps kept over 20 years the following data were obtained showing the number of deaths caused by the horse. Calculate the theoretical Poisson frequencies
No of Deaths:		0	1	2	3	4	Total
Frequency:		109	65	22	3	1	200
'''
print("Assignment 3")
mean_value=(0*109 + 1*65 + 2*22 + 3*3 + 4*1)/200
print("Frequencies of Deaths")
for k in np.arange(4+1):
    print("No of Deaths={}, Frequency={}"\
            .format(k,poisson.pmf(k=k,mu=mean_value)*200))

print("\n")


import numpy as np                     # Import numpy for array manipulation
import matplotlib.pyplot as plt        # Import matplotlib for charts
from utils_nb import plot_vectors      # Function to plot vectors (arrows)
# Create a 2 x 2 matrix
R = np.array([[2, 0],
              [0, -2]])
x = np.array([[1, 1]]) # Create a 1 x 2 matrix
y = np.dot(x, R) # Apply the dot product between x and R
y
plot_vectors([x], axes=[4, 4], fname='transform_x.svg')
plot_vectors([x, y], axes=[4, 4], fname='transformx_and_y.svg')

angle = 100 * (np.pi / 180) #convert degrees to radians

Ro = np.array([[np.cos(angle), -np.sin(angle)],
              [np.sin(angle), np.cos(angle)]])

x2 = np.array([2, 2]).reshape(1, -1) # make it a row vector
y2 = np.dot(x2, Ro)

print('Rotation matrix')
print(Ro)
print('\nRotated vector')
print(y2)

print('\n x2 norm', np.linalg.norm(x2))
print('\n y2 norm', np.linalg.norm(y2))
print('\n Rotation matrix norm', np.linalg.norm(Ro))

plot_vectors([x2, y2], fname='transform_02.svg')

A = np.array([[2, 2],
              [2, 2]])
A_squared = np.square(A)
A_squared

A_Frobenius = np.sqrt(np.sum(A_squared))
A_Frobenius

print('Frobenius norm of the Rotation matrix')
print(np.sqrt(np.sum(Ro * Ro)), '== ', np.linalg.norm(Ro))


#!/usr/bin/env python
# coding: utf-8

# # Diffie–Hellman Key Exchange Algorithm

# ## About
# Diffie–Hellman key exchange is a method of securely exchanging cryptographic keys over a public channel and was one of the first public-key protocols as conceived by Ralph Merkle and named after Whitfield Diffie and Martin Hellman. Diffie–Hellman is one of the earliest practical examples of public key exchange implemented within the field of cryptography.
#
# Diffie-Hellman, uses Asymetric Key cryptography to communicate the Key securely through the media.

# ## Algorithm
#
# 1. Select a random prime number, **q**
# 2. Calculate $\alpha$, such that, $\alpha$ is the **Primitive Root of q** and $\alpha$ > q
# 3. **For User A:**
#     1. Select **Private Key** , **pvtKeya**, such that pvtKeya < q
#     2. Calculate **Public Key**, **pubKeya = $\alpha$pvtKeya mod q**
# 4. **For User B:**
#     1. Select **Private Key** , **pvtKeyb**, such that pvtKeyb < q
#     2. Calculate **Public Key**, **pubKeyb = $\alpha$pvtKeyb mod q**
#
# After the above steps we get a **pair of Private and Public Keys** for each User. These are to be **used** for generating the final **Key**.
#
#
# **User A :** { Private Key of A , Public Key of A } = { **pvtKeya** , **pubKeya**  }
#
# **User B :** { Private Key of B , Public Key of B } = { **pvtKeyb** , **pubKeyb**  }
#
# Generate **Key**, **Ka & Kb**  at both users' end. ***If keys generated***, **match**, the Key Exchange process is **Successful**.
#
# ***Note:*** The Private Key of a user is known only to that user and no other user has the access to it. While the Public Key of all the users are known to all the users in the network.
#
# ![total.jpg](attachment:total.jpg)

# ## Key Generation
#
# For User A, **Ka = pubKeyb pvtKey a  mod q**
#
#
# For User B, **Kb = pubKeya pvtKey b  mod q**
#
#
# If **Ka = Kb** then the **Key Exchange** is **Successful**. And The final secret key is ***K = Ka = Kb***
#
# ![keyGen.jpg](attachment:keyGen.jpg)

# In[13]:

from sympy import *
from termcolor import colored
import random

# ------ Generate q ------ #

q = randprime(0, 250)

# ------ Funtion to Generate ------ #

def generateKey(pubKey, pvtKey):
    return (pubKey**pvtKey)%q

# ------ Funtion to Generate Public Key ------ #

def publicKey(key, pr):
    return (pr**key)%q

# ------ Funtion to Determine primitive roots ------ #

def primitiveRoot(q):
    setOfPR = []
    a = 1
    while a<q:
        rootSet= set()
        reqSet = set()
        for i in range(1, q):
            rootSet.add(int((a**i)%q))
        #print(rootSet)
        for j in range(1, q):
            reqSet.add(j)
        if rootSet == reqSet:
            setOfPR.append(a)
            a += 1
            #break
        else:
            a += 1
    print("Primitive Roots of q = ", setOfPR, end="\n\n")
    return random.choice(setOfPR)

print("q = ", q, end="\n\n")

# -------------- Primitive root of q -------------- #

primRoot = primitiveRoot(q)

print("Selected (at random) Primitive Root of q = ", primRoot, end="\n\n")

# -------------- Name of user A and B -------------- #

a , b = input("Enter the Names of the two users communicating: ").split(" ")

# ------------------ User A Operations ------------------ #

# Private Key of user A
privateKeyOfA = int(input("\nSelect {}'s Private Key (less than q): ".format(a)))

# Public Key of user A
publicKeyOfA = publicKey(privateKeyOfA, primRoot)

# Print Public Key of A
print("Keys of User {}".format(a))
print("--- Private Key : ", privateKeyOfA)
print("--- Public  Key : ", publicKeyOfA)

# ------------------ User B Operations ------------------ #

# Private Key of user B
privateKeyOfB = int(input("\nSelect {}'s Private Key (less than q): ".format(b)))

# Public Key of user B
publicKeyOfB = publicKey(privateKeyOfB, primRoot)

# Print Public Key of B
print("Keys of User {}".format(b))
print("--- Private Key : ", privateKeyOfB)
print("--- Public  Key : ", publicKeyOfB)

# ------------------ Key Generation ------------------ #

print("\nKey Generation")

# Key Generation for A
print("\nGenerate Key for {}".format(a))
keyA = generateKey(publicKeyOfB, int(input("--- Enter {}'s Private Key: ".format(a))))
print("--- Key generated for {} is {}".format(a, keyA))

# Key Generation for B
print("\nGenerate Key for {}".format(b))
keyB = generateKey(publicKeyOfA, int(input("--- Enter {}'s Private Key: ".format(b))))
print("--- Key generated for {} is {}".format(b, keyB))

# ------------------- Key Exchange Verification ------------------- #

if keyA == keyB :
    print(colored("\nKey Exchange Successful!", 'green'))
    print(colored("--- Your Key is {}".format(keyA) , 'green'))
else:
    print(colored("\nKey Exchange Failed!", 'red'))

# #### Tanmoy Sen Gupta
# [tanmoysg.com](http://tanmoysg.com) | +91 9864809029 | tanmoysps@gmail.com

Diffie-Hellman Key Exchange/Diffie-Hellman Key Exchange.py


import numpy as np

def inverse_power_method(A, tol=1e-9, Max_iter=100):
    """ Calculate the minimum eigenvalue and the corresponding eigenvector by inverse power method.

    Args:
        A: ndarray, the matrix to be solved
        tol: double, iteration accuracy
        Max_iter: int, maximum iteration number

    Retruns:
        k: int, interation number
        eig: double. minimum eigenvalue of the matrix A
        eigv: ndarray, corresponding eigenvector
    """
    # initialization
    # iteration number
    k = 0
    # initial eigenvalue
    eig = 0
    # initial eigenvector
    eigv = np.ones(A.shape[0])

    # iteration
    while k < Max_iter and np.linalg.norm(A @ eigv - eig * eigv) >= tol:
        k += 1
        x = np.linalg.solve(A, eigv)
        eig = 1 / x[np.argmax(x)]
        eigv = x * eig

    return k, eig, eigv

def acceleration_inverse_power(A, alpha, tol=1e-9, Max_iter=100):
    """ Calculate the eigenvalue around alpha and corresponding eigenvector by inverse power method.

    Args:
        A: ndarray, the matrix to be solved
        alpha: double, acceleration number
        tol: double, iteration accuracy
        Max_iter: int, maximum iteration number

    Returns:
        k: int, iteration number
        eig: double, eigenvalue around alpha of the matrix A
        eigv: ndarray, corresponding eigenvector
    """
    # initialization
    B = A - alpha * np.eye(A.shape[0])

    # inverse power method
    k, eig, eigv = inverse_power_method(B, tol, Max_iter)

    eig += alpha

    return k, eig, eigv

if __name__ == '__main__':
    A = np.array([[4, -1, 1], [-1, 3, -2], [1, -2, 3]])
    n, eig, eigv = inverse_power_method(A, 1e-6)
    print(f"The eigenvalue is {eig:.7f}, and corresponding eigenvector is {eigv}.")
    print(f"Iteration number is {n}.")
    n, eig, eigv = acceleration_inverse_power(A, 2.5, 1e-6)
    print(f"The eigenvalue around 2.5 is {eig:.7f}, and corresponding eigenvector is {eigv}.")
    print(f"Iteration number is {n}.")


import numpy as np

# Basic demo of
# 1. Given a secuence, compute and apply a Hann Window
# 2. Compute DFT using the decimation in time algorithm => FFT

x = np.array([1, 1, 2, 0, 0, 2, 1, 1])
L = len(x)
N = L - 1

# Hanning window
w = 0.5 * (1 - np.cos(2*np.pi*np.arange(L)/N))

# Windowed signal
xw = x * w

# Wkn
Wkn = np.exp(-1j * 2*np.pi * np.arange(4)/L)
# Patch: Wkn[2] is super ugly!
Wkn[2] = -1j

# Step 1: combine first with second half of the sequence
X1 = np.zeros(L)
X1[0:4] = xw[0:4] + xw[4:]
X1[4:8] = xw[0:4] - xw[4:]

print('Pass 1a', X1)
# Multiply second half by Wkn
X1 = X1 * np.hstack((np.ones_like(Wkn), Wkn))
print('Pass 1b', X1)

# Step 2: 4 elements combos
X2 = np.zeros(L)
X2 = X2 + 1j * 0  # Trick to convert X2 to complex
X2[0:2] = X1[0:2] + X1[2:4]
X2[2:4] = X1[0:2] - X1[2:4]
X2[4:6] = X1[4:6] + X1[6:8]
X2[6:8] = X1[4:6] - X1[6:8]

print('Pass 2a', X2)
# Multiply by Wkn factors
X2 = X2 * np.array([1, 1, Wkn[0], Wkn[2], 1, 1, Wkn[0], Wkn[2]])
print('Pass 2b', X2)

# Step 3: 2 elements combos
X3 = np.zeros_like(X2)  # This directly creates a complex array
X3[0] = X2[0] + X2[1]
X3[1] = X2[0] - X2[1]
X3[2] = X2[2] + X2[3]
X3[3] = X2[2] - X2[3]
X3[4] = X2[4] + X2[5]
X3[5] = X2[4] - X2[5]
X3[6] = X2[6] + X2[7]
X3[7] = X2[6] - X2[7]

# Bit reverse
# binary_repr(...)[::-1] returns the binary number reversed
# int(..., base=2) converts back to decimal
br = [int(np.binary_repr(x, width=3)[::-1], base=2) for x in range(8)]
X3 = X3[br]

# Check result
print('FFT      ', X3)
print('FFT numpy', np.fft.fft(xw))


import scipy as sp

def hilbert(n):
    """Calculate an nxn Hilbert matrix"""

    H = sp.zeros((n,n))

    for i in range(n):
        for j in range(n):
            H[i][j] = 1.0/(i+j+1)

    return H

def cond(matrix):
    """Calculate the condition number of matrix"""

    return sp.linalg.norm(matrix)*sp.linalg.norm(sp.linalg.pinv(matrix))


import sympy as smp
from sympy import *

def prgrm_iter():
    x, k, n, h = smp.symbols ('x k n h')
    f = smp.sin(x)

    print (" ")
    print ("This program comes from the GitHub repository")
    print ("AndreiMurashev/pos.int_diff_formula")
    print (" ")
    print ("The purpose of this program is to check if the formula")
    print ("for the derivative of a certain positive integer order holds")
    print (" ")

    print ("For which positive integer case would you like to check")
    n = int(input("if the formula works?: "))

    d = diff(f, x, n)
    D = smp.limit((smp.Sum(((-1)**k)*(smp.binomial(n,k))*(f.subs(x,x+(n-k)*h)), (k, 0, n)).doit())/(h**n), h, 0)
    print(d," ?=? ", D)
    print (" ")

    if d == D:
        print (d," = ", D)
        print ("[VALID]: The formula holds for the derivative of order", n)

    if d != D:
        print (d," =/= ", D)
        print ("[INVALID]: The formula fails for the derivative of order", n)
        print ("Please screenshot this and email the creator of the GitHub repository")

def prgrm():
    while True:
        prgrm_iter()
        ans = input("Repeat? (y/n): ")
        if ans != "y":
            break

if __name__ == '__main__':
    try:
        prgrm()
    finally:
        input("Done. Press any key to exit: ")


# This script uses the Montecarlo method to find the
# [approximated] area under a curve (definite integral)

import math
import random
import time

import numpy as np
import scipy.integrate as integrate
import matplotlib.pyplot as plt

def montecarlo_iterative_integration(fun, a, b, num_puntos=1000):
    # To keep track of time
    tic = time.time()

    #HALLAMOS M
    M = 0
    for i in np.arange(a, b, (b-a)/num_puntos):
        aux = fun(i)
        if aux > M :
            M = aux
    print("\n__Integral (iterative)__")
    print("Máximum: ", M)

    #QUEDA DEFINIDO EL CUADRADO ENTRE A-B Y 0-M
    #LANZAMOS PUNTOS ALEATORIOS DENTRO DEL CUADRADO

    nDebajo = 0

    for i in range(num_puntos):
        x = random.uniform(a, b)
        y = random.uniform(0, M)

        if fun(x)>y :
            nDebajo+=1

    print("Points under curve: ", nDebajo)
    print("Total points: ", num_puntos)

    I = (nDebajo/num_puntos)*(b-a)*M
    print ("Montecarlo integral: ", I)

    toc = time.time()
    print("time: ", 1000*(toc - tic))

    return 1000*(toc - tic)

def montecarlo_vectorized_integration(fun, a, b, num_puntos=1000):
    # To keep track of time
    tic = time.time()

    # Vectors with uniformly distributed points
    vectorX = np.random.uniform(low = a, high = b, size =(num_puntos))

    vectorizedFun = np.vectorize(fun)
    funResults = vectorizedFun(vectorX)
    M = funResults.max()
    vectorY = np.random.uniform(low = 0, high = M, size =(num_puntos))

    print("\n__Integral (vectorized)__")
    print("Máximum: ", M)

    # Points under the curve
    nDebajo = np.greater(funResults, vectorY).sum()

    print("Points under curve: ", nDebajo)
    print("Total points: ", num_puntos)

    # Value of the integral (Montecarlo approximation)
    I = (nDebajo/num_puntos)*(b-a)*M
    print ("Montecarlo integral: ", I)

    toc = time.time()
    print("Time: ", 1000*(toc - tic))

    return 1000*(toc - tic)

iterativeArray = []
vectorizedArray = []
iValues = []

# Compare both methods (iterative and vectorized) performance when using
# increasingly larger number of points
for i in range(1, 1000000, 100000):
    iterativeArray.append(montecarlo_iterative_integration(math.sin, 0, math.pi, i))
    vectorizedArray.append(montecarlo_vectorized_integration(math.sin, 0, math.pi, i))
    iValues.append(i)

# Show and save the results
plt.figure()
plt.scatter(iValues, iterativeArray, color='red', label="Iterative")
plt.scatter(iValues, vectorizedArray, color='blue', label="Vectorized")
plt.ylabel('Time comparison')
plt.legend()
plt.savefig("time_comparison.png")
plt.show()

print("\nReal integral value: ", integrate.quad(math.sin, 0, math.pi)[0], "\n")


#!python
# -*- coding: utf-8 -*-#
"""
:Title: Univariate Linear Regression.

@author: Bhishan Poudel

@date: Sep 22, 2017

@email: bhishanpdl@gmail.com

The cost function is given by

.. math::

  J(w) = \\frac{1}{2N} \sum_{n=1}^N (h(x_n,w) - t_n)^2

Minimizing the cost function w.r.t. w gives two system of liner equations:

.. math::

    w_0N + w_1 \sum_{n=1}^N x_n = \sum_{n=1}^N t_n \\\\\\\\
    w_0 \sum_{n=1}^N x_n + w_1 \sum_{n=1}^N x_n^2 = \sum_{n=1}^N t_nx_n

We solve these normal equations and find the values w0 and w1.
"""
# Imports
import argparse
import sys
import numpy as np
from matplotlib import pyplot as plt
import numpy.polynomial.polynomial as poly

# checking
# import statsmodels.api as sm # sm 0.8.0 gives FutureWarning

def read_data(infile):
    X,t = np.loadtxt(infile,unpack=True)
    return X,t

#
def train(X, t):
    """Implement univariate linear regression to compute w = [w0, w1].

    I solve system of linear equations from lecture 01

    w0 N      + w1 sum_x  = sum_t

    w0 sum_x  + w1 sum_xx = sum_tx

    """

    # Use system of equations
    N = len(t)
    sum_x = sum(X)
    sum_t = sum(t)

    sum_xsp = sum(X*X)
    sum_tx = sum(X*t)

    w1 = (sum_t * sum_x - N * sum_tx) / (sum_x * sum_x - N * sum_xsp)
    w0 = (sum_t - w1 * sum_x) / N

    w = np.array([w0, w1])

    # checking values using statsmodel library
    # w = sm.OLS(t,sm.add_constant(X)).fit().params
    # [-15682.27021631    115.41845202]

    # params w
    # print('y-intercept bias term w0 = {:.2f}'.format(w[0][0]))
    # print('weight term           w1 = {:.2f}'.format(w[1][0]))

    # plt.scatter(X,t)
    # plt.plot(X, X*w[1] + w[0])
    # plt.show()

    return w

def compute_rmse(X,t,w):
    """Compute RMSE on dataset (X, t).

    Note: cost function J is 1/2 of mean squared error.
    RMSE is square root of mean squared error.

    """
    h = X*w[1] + w[0]
    rmse = np.sqrt(np.mean(( h - t )**2) )

    # debug
    # print('w[0] =', w[0])
    # print('w[1] =', w[1])

    # rmse = np.sqrt(((np.dot(X,w.T)- t)**2).mean())

    return rmse

#
def compute_cost(X, t, w):
    """Compute objective function on dataset (X, t)."""
    h = X*w[1] + w[0]
    J = 1/2 *  np.mean(( h - t )**2)
    return J

def univariate_reg(fh_train, fh_test):
    # Read the training and test data.
    Xtrain, ttrain = read_data(fh_train)
    Xtest, ttest = read_data(fh_test)

    # Train model on training examples.
    w = train(Xtrain, ttrain)

    # train
    E_rms_train_uni = compute_rmse(Xtrain, ttrain, w)
    J_train_uni = compute_cost(Xtrain, ttrain, w)

    # test
    E_rms_test_uni = compute_rmse(Xtest, ttest, w)
    J_test_uni = compute_cost(Xtest, ttest, w)

    return E_rms_train_uni, J_train_uni, E_rms_test_uni, J_test_uni

def myplot(fh_train,fh_test,w):
    # matplotlib customization
    plt.style.use('ggplot')
    fig, ax = plt.subplots()

    # data
    Xtrain, ttrain = read_data(fh_train)
    Xtest, ttest = read_data(fh_test)
    Xhyptest = Xtest * w[1] + w[0]

    # plot with label, title
    ax.scatter(Xtrain,ttrain,color='b',marker='o', label='Univariate Train')
    ax.scatter(Xtest,ttest,c='limegreen', marker='^', label='Univariate Test')
    ax.plot(Xtest,Xhyptest,'r--',label='Best Fit')

    # set xlabel and ylabel to AxisObject
    ax.set_xlabel('Floor Size (Square Feet)')
    ax.set_ylabel('House Price (Dollar)')
    ax.set_title('Univariate Regression')
    ax.legend()
    ax.grid(True)
    plt.tight_layout()
    plt.savefig('images/Univariate.png')
    plt.show()

##=======================================================================
## Main Program
##=======================================================================
def main():
    """Run main function."""
    parser = argparse.ArgumentParser('Univariate Exercise.')
    parser.add_argument('-i', '--input_data_dir',
                        type=str,
                        default='../data/univariate',
                        help='Directory for the univariate houses dataset.')
    FLAGS, unparsed = parser.parse_known_args()

    # Data file paths
    fh_train = FLAGS.input_data_dir + "/train.txt"
    fh_test  = FLAGS.input_data_dir + "/test.txt"

    # Print weight vector
    Xtrain, ttrain = read_data(fh_train)
    w = train(Xtrain, ttrain)
    print('Params Univariate: ', w, '\n')

    # Print RMSE and Cost
    E_rms_train_uni, J_train_uni, E_rms_test_uni, J_test_uni = univariate_reg(fh_train, fh_test)

    print("#"*50)
    print("Univariate Regression")

    # Print cost and RMSE on training data.
    print('E_rms_train Univariate: %0.2e' % E_rms_train_uni)
    print('J_train Univariate: %0.2e' % J_train_uni)

    # Print cost and RMSE on test data.
    print("\n")
    print('E_rms_test Univariate: %0.2e' % E_rms_test_uni)
    print('J_test Univariate: %0.2e' % J_test_uni)

    # Plotting
    myplot(fh_train, fh_test,w)

if __name__ == "__main__":
   import time

   # Beginning time
   program_begin_time = time.time()
   begin_ctime        = time.ctime()

   #  Run the main program
   main()

   # Print the time taken
   program_end_time = time.time()
   end_ctime        = time.ctime()
   seconds          = program_end_time - program_begin_time
   m, s             = divmod(seconds, 60)
   h, m             = divmod(m, 60)
   d, h             = divmod(h, 24)
   print("\n\nBegin time: ", begin_ctime)
   print("End   time: ", end_ctime, "\n")
   print("Time taken: {0: .0f} days, {1: .0f} hours, \
     {2: .0f} minutes, {3: f} seconds.".format(d, h, m, s))


import numpy as np

print("")
print("array0")
print("____")
array0 = np.array(5)
print(array0.shape) # ()
print(array0.ndim) # 0

print("")
print("array1")
print("____")
array1 = np.array([1,2,3,4])
print(array1.shape) # (4, )
print(array1.ndim) # 1

print("")
print("array2")
print("____")
array2 = np.array([[1,2,3,4],[5, 6, 7, 8]])
print(array2.shape) # (2,4)
print(array2.ndim) # 2

print(array2[1,3]) # 8

print("")
print("array5")
print("____")
array5 = np.array([5, 6, 7, 8], ndmin = 5)
print(array5) # [[[[[5 6 7 8]]]]]
print(array5.shape) # (1,1,1,1,4)
print(array5.ndim) # 5
print(array5[0,0,0,0,2]) # 7

print("________________")
print("________________")
print("________________")
print("________________")
print("________________")
print("---RESHAPING----")
print("________________")
print("________________")
print("________________")
print("________________")
print("________________")

array = np.array([1,2,3,4,5,6,7,8,9,10,11,12])

newarr1 = array.reshape(4,3)

print(array)
# [ 1  2  3  4  5  6  7  8  9 10 11 12]
print(newarr1)
"""[[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]

"""
print(newarr1.base) # It is a view
# [ 1  2  3  4  5  6  7  8  9 10 11 12]

newarr2 = array.reshape(3,2,2)

print(newarr2)
"""
[[[ 1  2]
  [ 3  4]]

 [[ 5  6]
  [ 7  8]]

 [[ 9 10]
  [11 12]]]
"""

try:
	array.reshape(8)
except Exception as e:
	print("Can not reshape it to 8 dim")

print("________________")
print("________________")
print("Falttening Arrays")
print("________________")
print("________________")

array = np.array([[1,2,3,4],[5,6,7,8]])

newarr1 = array.reshape(-1)

print(newarr1)
# [1 2 3 4 5 6 7 8]


import numpy as np

def f(x):
    return np.exp(-1*x**2)

def g(x):
    return np.sin(x) / x

def romberg_algorithm(inte, func, tol, Max_iter=10):
    """ Calculate the integral by Romberg Algorithm

    Args:
        inte: ndarray, the integrand interval
        func: function boject, the integrand function
        tol: double, the interation accurancy
        Max_iter: int, the maximum number of iterations

    Returns:
        (T[-1], m):
            T[-1]: double, the integral value by Romberg algorithm
            m: the number of iterations
    """
    # initial values
    m = 0
    T = [(inte[1] - inte[0]) * np.sum(func(inte)) / 2]
    for i in range(1, Max_iter+1):
        x_list = np.linspace(inte[0], inte[1], 2**i+1)
        T.append(T[i-1]/2 + (x_list[1] - x_list[0]) * np.sum(func(x_list[1::2])))
    T = np.array(T)

    # iteration
    m += 1
    S = (4 * T[1:] - T[:-1]) / (4 - 1)

    # mark whether getting the given iteration accurancy
    flag = 1
    while np.fabs(S[-1] - T[-1] >= tol):
        if m == Max_iter:
            flag = 0
            break
        else:
            m += 1
            T = S
            S = (4**m * T[1:] - T[:-1]) / (4**m - 1)

    if flag:
        return (T[-1], m)
    else:
        reutnr (nan, Max_iter)

if __name__ == '__main__':
    # interval
    inte = np.array([1e-32, 1])
    # the first integral
    value, n = romberg_algorithm(inte, f, 1e-6)
    print(f"The first integral's value is {value:.6f} by Romberg algorithm after {n} iterations")
    # the second integral
    value, n = romberg_algorithm(inte, g, 1e-6)
    print(f"The second integral's value is {value:.6f} by Romberg algorithm after {n} iterations")


import numpy as np

#-------------------------------------------------------------------------
'''
    Problem 2: getting familiar with numpy package.
    In this problem, please install the following python package:
        * numpy
    Numpy is the library for scientific computing in Python. It provides a high-performance multidimensional array object, and tools for working with these arrays.
    To install numpy using pip, you could type `pip install numpy` in the terminal.
    Then start implementing function matrix_vector_multiplication()
    You could test the correctness of your code by typing `nosetests -v test2.py` in the terminal.

'''

#--------------------------
def matrix_vector_multiplication(X, y):
    '''
        Given a matrix X and a vector y, compute the product X*y = z
        Input:
                X: a numpy matrix of float values, such as np.mat([1., 2.],[3., 4.],[5. ,6. ]), which is a (3 by 2) matrix;
                y: a numpy vector of float values, such as np.mat([[1.], [2.]]), which is a (2 by 1) vector.
        Output:
                z: the numpy vector of float values, such as np.mat([[5.], [11.], [17.]]), which is a (3 by 1) vector.
    '''
    #########################################
    ## INSERT YOUR CODE HERE

    z = np.dot(X, y)

    #########################################
    return z


import numpy as np

def tanh(value, derivative=False):
    """
    Tanh(x) function / derivative
    :param value: ndarray -> value to activate
    :param derivative: bool -> compute derivative
    :return: ndarray -> activated ndarray
    """
    if derivative:
        return 1.0 - (value ** 2.0)
    return np.tanh(value)

def sigmoid(value, derivative=False):
    """
    Sigmoid(x) function / derivative
    :param value: ndarray -> value to activate
    :param derivative: bool -> compute derivative
    :return: ndarray -> activated ndarray
    """
    if derivative:
        return value * (1.0 - value)
    return 1.0 / (1.0 + np.exp(-value))

def softplus(value, derivative=False):
    """
    Softplus(x) function / derivative
    :param value: ndarray -> value to activate
    :param derivative: bool -> compute derivative
    :return: ndarray -> activated ndarray
    """
    if derivative:
        return 1.0 / (1.0 + np.exp(-value))
    return np.log(1.0 + np.exp(value))

def softmax(value, derivative=False):
    """
    Softmax(x) function / derivative
    :param value: ndarray -> value to activate
    :param derivative: bool -> compute derivative
    :return: ndarray -> activated ndarray
    """
    if derivative:
        s = value.reshape(-1, 1)
        return np.diagflat(s) - np.dot(s, s.T)
    return np.exp(value) / np.sum(np.exp(value))

def stable_softmax(value, derivative=False):
    """
    Softmax(x) function / derivative (softmax - except compute value in a numerically stable way)
    :param value: ndarray -> value to activate
    :param derivative: bool -> compute derivative
    :return: ndarray -> activated ndarray
    """
    if derivative:
        s = value.reshape(-1, 1)
        return np.diagflat(s) - np.dot(s, s.T)
    shift_x = value - np.max(value)
    return np.exp(shift_x)/np.sum(np.exp(shift_x))


'''
    This script tries to use a random number generator
    that samples a value from a uniform distribution
    between (0,1) to estimate the value of pi.

    The intuition behind the function created is that the
    ratio of the areas of a circle and a square having a
    length equal to the circles diameter is pi/4.

    So if we are able to estimate the number of times a point in
    2D space falls within a circle versus outside the circle bounded
    by a square out of a number of trials, we will be able to estimate pi
'''

import numpy as np

def estimate_pi(n_trials):
    #counter variable to estimate the probability
    ctr = 0
    for i in range(n_trials):
        #sample a 2d coordinate
        x = np.random.random()
        y = np.random.random()
        #count the number of times the coordinate falls within the circle radius
        if (x**2+y**2) < 1:
           ctr+=1
    #multiply by 4 to get pi since the probability is equal to pi/4
    return 4*(ctr/n_trials)


import numpy as np

# Write a function that takes as input two lists Y, P,
# and returns the float corresponding to their cross-entropy.

def cross_entropy(Y, P):
    Y = np.float_(Y)
    P = np.float_(P)
    return -1 * np.sum(Y * np.log(P) + (1 - Y) * np.log(1 - P))

Y = [1, 1, 0]
P = [0.8, 0.7, 0.1]
result = cross_entropy(Y, P)

print(
    "The result of the above Y[1,1,0] and P[0.8, 0.7, 0.1] should be 0.69, and the calculated was "+str(result))

Y = [0, 0, 1]
P = [0.8, 0.7, 0.1]
result = cross_entropy(Y, P)

print(
    "The result of the above Y[0, 0, 1] and P[0.8, 0.7, 0.1] should be 5.12, and the calculated was "+str(result))