# -*- coding: utf-8 -*-
"""
Created on Thu Apr 23 15:21:15 2020
@author: Wei-shan
Solving Poisson Equation
    del^2 V = -rho
in the electric potential problem
with Finite difference of Gauss-Seidel Method and overrelaxation.
Reference: Mark Newman, Computational Physics, CH9.
"""
from pylab import imshow,gray,show
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import AutoMinorLocator
import pandas as pd

# Constants
M = 100         # Grid squares on a side
V = 30.0         # Voltage at top wall
rho = 1.0       # charge density
target = 1e-6   # Target accuracy
omega = 0.9
delta = 1.0
xMin = 0.0
xMax = 100.0
yMin = 0.0
yMax = 100.0

# Create arrays to hold potential values
phi = np.zeros([M+1,M+1],float) # phi[y,x]

# Main loop
while delta>target:
    delta = 0.0
    # Calculate new values of the potential
    for i in range(M+1):
        for j in range(M+1):
            ## Setting up boundary conditions (Simulation 1)
            if i==0:
                phi[i,j] = V
            elif j==0:
                phi[i,j] = V
            elif i==M:
                phi[i,j] = -V
            elif j==M:
                #or j==M: # something is wrong for setting phi[i,j]=V at i==M or j==M
                phi[i,j] = -V
            ## End of Setting up boundary conditions (Simulation 1No)
            ## Setting up other boundary values inside the digram (Simulation 3)
            #if i==0 or i==M or j==0 or j==M:
            #    phi[i,j] = 0.0
            #elif (i>=20 and i<=80) and j==20:
            #    phi[i,j]=V
            #elif (i>=20 and i<=80) and j==80:
            #    phi[i,j]=-V
            ## End of Setting up other boundary values inside the digram (Simulation 3)
            ## Charge densit
            ## Setting up rho value (Simulation 2)
            elif ( ( i>=20 and i<=40 ) and ( j>=60 and j<=80 ) ):
                temp = (phi[i+1,j] + phi[i-1,j] + phi[i,j+1] + phi[i,j-1])*(1+omega)/4 - omega * phi[i,j] + 1/4*rho
                if ( abs( phi[i,j] - temp ) > delta ): delta = abs( phi[i,j] - temp )
                phi[i,j] = temp
            #elif ( ( i>=60 and i<=80 ) and  ( j>=20 and j<=40 ) ):
            #    temp = (phi[i+1,j] + phi[i-1,j] + phi[i,j+1] + phi[i,j-1])*(1+omega)/4 - omega * phi[i,j] - 1/4*rho
            #    if ( abs( phi[i,j] - temp ) > delta ): delta = abs( phi[i,j] - temp )
            #    phi[i,j] = temp
            ## End of Setting up rho value (Simulation 2)
            else:
                temp = (phi[i+1,j] + phi[i-1,j] + phi[i,j+1] + phi[i,j-1])*(1+omega)/4 - omega * phi[i,j]
                if ( abs( phi[i,j] - temp ) > delta ): delta = abs( phi[i,j] - temp )
                phi[i,j] = temp
# End of main loop

# Make a plot
ax = plt.gca()
imshow(phi,extent=[xMin,xMax,yMin,yMax])#,origin="lower")

plt.minorticks_on()
minorLocatorX = AutoMinorLocator(4) # number of minor intervals per major
                                    # inteval
minorLocatorY = AutoMinorLocator(4)
ax.xaxis.set_minor_locator(minorLocatorX) # add minor ticks on x axis
ax.yaxis.set_minor_locator(minorLocatorY) # add minor ticks on y axis
ax.set_xticklabels(ax.get_xticks(),family='monospace',fontsize=10)
ax.set_yticklabels(ax.get_yticks(),family='monospace',fontsize=10)
gray()
show()

# Save location vs voltage into csv file.
phiData = pd.DataFrame(columns = ['X','Y','Voltage'])
phiData_file = open(r'E:\github\Solving-Poisson-Equation-with-finite-difference-Gauss-Seidel-Method\poissonGS.csv','w',newline='')

X = []
Y = []
Voltage = []

for i in range(M+1):
    for j in range(M+1):
        X += [j * (xMax-xMin)/M]
        Y += [i * (yMax-yMin)/M]
        Voltage += [ phi[i,j] ]

phiData['X'] = X
phiData['Y'] = Y
phiData['Voltage'] = Voltage

phiData.to_csv(phiData_file, sep=',', encoding='utf-8', index=False)
phiData_file.close()


import numpy as np

# helper functions
def cart2sph(x, y, z):
    """
    cart2sph(x, y, z) -> theta, phi, r

    Computes the corresponding spherical coordinate of the given input parameters :attr:`x`, :attr:`y` and :attr:`x`.

    Args:
        x (Number): x position
        y (Number): y position
        z (Number): z position

    Example::

        >>> cart2sph(1, 1, 1)
        (0.78539816339744828, 0.95531661812450919, 1.7320508075688772)
    """
    azimuthal_angle = np.arctan2(y, x)
    radial_distance = np.sqrt(x**2 + y**2 + z**2)
    polar_angle = np.arccos(z/radial_distance)
    return azimuthal_angle, polar_angle, radial_distance

def sph2cart(azimuthal_angle, polar_angle, radial_distance):
    """
    sph2cart(polar_angle, azimuthal_angle, radial_distance) -> x, y, z

    Computes the corresponding cartesian coordinate of the given input parameters :attr:`polar_angle`,
    :attr:`azimuthal_angle` and :attr:`radial_distance`.

    Args:
        polar_angle (Number): polar_angle
        azimuthal_angle (Number): azimuthal_angle
        radial_distance (Number): radial_distance

    Example::

        >>> cart2sph(0.78539816339744828, 0.95531661812450919, 1.7320508075688772)
        (0.99999999999999978, 0.99999999999999967, 1.0)
    """
    x = radial_distance * np.sin(polar_angle) * np.cos(azimuthal_angle)
    y = radial_distance * np.sin(polar_angle) * np.sin(azimuthal_angle)
    z = radial_distance * np.cos(polar_angle)
    return x, y, z


##############################################################################
### To use the functions in this lib simply import this python module using
### import myStats
### Then you'll able able to call functions with the proper arguments using
### returnVal=myStats.func1(arg1,arg2)
##############################################################################
##############################################################################
import numpy as np

################### FUNC benjamini_hochberg_correction  #####################
#### Given an array of p-values (not necessarily sorted) and the number of total
### tests that were performed to gather these p-values, this function performs
###  the multiple hypothesis testing correction described by Benjamini-Hochberg.
###
###
### If the number of tests are much more compared to p-value array and
### the omitted p-values are all supposed to be zero you should use it like:
### q_array=benjamini_hochberg_correction([0.03,0.4,0.7,0.01],10)
###
### If the number of tests are equal to the ones in p-values array then:
### p_array=[0.03,0.4,0.7,0.01]
### q_array=benjamini_hochberg_correction(p_array,len(p_array))
##############################################################################
def benjamini_hochberg_correction(p_values, num_total_tests):
	# assumes that p_values vector might not be sorted
	pvalsArray=np.array(p_values)
	order=pvalsArray.argsort()
	sorted_pvals=np.take(p_values,order)
	q_values=[1.0 for i in range(len(p_values))]
	prev_bh_value = 0
	for i, p_value in enumerate(sorted_pvals):
		bh_value = p_value * num_total_tests / (i + 1)
		# Sometimes this correction can give values greater than 1,
		# so we set those values at 1
		bh_value = min(bh_value, 1)

		# To preserve monotonicity in the values, we take the
		# maximum of the previous value or this one, so that we
		# don't yield a value less than the previous.
		bh_value = max(bh_value, prev_bh_value)
		prev_bh_value = bh_value
		qIndex=order[i]
		q_values[qIndex] =bh_value
	#END for
	return q_values

################### FUNC meanAndVariance  ##################################
#### Given an array this function calculates the mean and variance
##############################################################################
def meanAndVariance(a):
	#calculates variance using E(x^2) - (Ex)^2
	sumxsquared=0
	sumx=0
	for x in a:
		sumxsquared += (x*x)
		sumx += x
	mean=sumx/float(len(a))
	squaremean=sumxsquared/float(len(a))
	variance=squaremean - (mean*mean)
	return (mean, variance)


# How to Do Linear Regression using Gradient Descent - Live session from 3/29/17
# https://www.youtube.com/watch?v=XdM6ER7zTLk
# https://github.com/llSourcell/linear_regression_live

# My modification, that uses Numpy to the full extent, which can be faster.

import numpy as np

def computeErrorForGivenPoints(m, b, points):
    x, y = points[:, 0], points[:, 1]
    squareDiff = np.square(y - (m*x + b))
    totalError = squareDiff.mean()
    return totalError

def step_gradient(mCurrent, bCurrent, points, learningRate):
    """ gradient descent """
    x, y = points[:, 0], points[:, 1]
    bGradient = (mCurrent*x + bCurrent) - y
    mGradient = x*bGradient
    mGradient = 2.*mGradient.mean()
    bGradient = 2.*bGradient.mean()
    newM = mCurrent - learningRate*mGradient
    newB = bCurrent - learningRate*bGradient
    return newM, newB

def gradient_descent_runner(points, startingM, startingB, learningRate, numIterations):
    m = startingM
    b = startingB
    for i in range(numIterations):
        m, b = step_gradient(m, b, points, learningRate)
    return m, b

def run():
    points = np.genfromtxt('data.csv', delimiter=',')
    # hyperparameter(s)
    learningRate = .0001
    # y = mx + b (slope formula)
    initialM = 0.
    initialB = 0.
    numIterations = 1000
    print('Starting gradient descent at m = {}, b = {}, error = {}'.format(initialM, initialB, computeErrorForGivenPoints(initialM, initialB, points)))     # error = 5565.1078
    print('Running...')
    m, b = gradient_descent_runner(points, initialM, initialB, learningRate, numIterations)
    print('After {} iterations:'.format(numIterations))
    print('m =', m)     # 1.4777
    print('b =', b)     # 0.0889
    print('error = ', computeErrorForGivenPoints(m, b, points))     # 112.6148

if __name__ == "__main__":
    run()


# -*- coding: utf-8 -*-
"""
Created on Mon Dec 07 13:43:24 2015

@author: hehu
"""

import matplotlib.pyplot as plt
import numpy as np

def gaussian(x, mu, sig):
    multiplier = (1/np.sqrt(2*np.pi*sig**2.))
    return multiplier * np.exp(-np.power(x - mu, 2.) / (2 * np.power(sig, 2.)))

def gaussian_log(x, mu, sig):
    multiplier = (1/np.sqrt(2*np.pi*sig**2.))
    return np.log(multiplier) + (-np.power(x - mu, 2.) / (2 * np.power(sig, 2.)))

if __name__ == "__main__":

    x = np.linspace(-3, 9, 100)
    y1 = gaussian(x, 3, 1)

    ax1 = plt.subplot(211)
    p1 = plt.plot(x, y1, linewidth = 2, label = "Likelihood")
    ax1.set_xlabel('A')
    ax1.set_title('PDF of A assuming x[0] = 3')

    plt.savefig("../images/PDF_A.pdf", bbox_inches = "tight")

    for tl in ax1.get_yticklabels():
        tl.set_color('b')

    ax2 = ax1.twinx()
    p2 = plt.plot(x, gaussian_log(x, 3, 1), 'r', linewidth = 2, label = "Log-likelihood")

    for tl in ax2.get_yticklabels():
        tl.set_color('r')

    lns = p1 + p2
    labs = [l.get_label() for l in lns]
    ax2.legend(lns, labs, loc=1)

    plt.savefig("../images/PDF_A_LL.pdf", bbox_inches = "tight")

    ##########################
    # Second picture: log likelihood for a sample of 50 points

    np.random.seed(1665)

    numSamples = 50

    x0 = 5 + np.random.randn(numSamples)

    x = np.linspace(5-3, 5+3, 200)
    likelihood = []
    log_likelihood = []

    for A in x:
        likelihood.append(gaussian(x0, A, 1).prod())
        log_likelihood.append(gaussian_log(x0, A, 1).sum())

    plt.figure()

    ax1 = plt.subplot(211)
    p1 = ax1.plot(x, likelihood, linewidth = 2, label = "Likelihood")
    ax1.set_xlabel('A')

    maxIdx = x[np.argmax(log_likelihood)]

    ax1.set_title('Likelihood of A (max at %.2f)' % maxIdx)

    p2 = ax1.plot(x0, 0.5*np.mean(likelihood) * np.ones_like(x0), 'go', label = "Samples")

    for tl in ax1.get_yticklabels():
        tl.set_color('b')

    ax2 = ax1.twinx()
    p3 = plt.plot(x, log_likelihood, 'r', linewidth = 2, label = "Log-likelihood")

    for tl in ax2.get_yticklabels():
        tl.set_color('r')

    lns = p2 + p1 + p3
    labs = [l.get_label() for l in lns]
    ax2.legend(lns, labs, loc=1)

    plt.savefig("../images/PDF_A_LL_full.pdf", bbox_inches = "tight")

    print(x0.mean())


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

# # Newton interpolation polynomial

# ## Import library

import numpy as np
import matplotlib.pyplot as plt
from sympy import *
from sympy import init_printing
init_printing()

# Nhap input
def inputData():
    x = []
    y = []
    with open('Newton.txt','r+') as f:
            for line in f.readlines():
                xt = float(line.split(' ')[0])
                yt = float(line.split(' ')[1])
                check = True
                for x_check in x:
                    if x_check == xt:
                        check = False
                        break
                if check:
                    x.append(xt)
                    y.append(yt)
    return x, y, len(x)-1

# Dung bang ty hieu
def buildBTH(x, y, n):
    ## Khoi tao
    BTH = np.zeros([n+1, n+1])
    ## Gan cot dau
    for i in range(n+1):
        BTH[i, 0] = y[i]
    ## Xay dung ty hieu
    for j in range(1,n+1):
        for i in range(n+1-j):
            BTH[i, j] = (BTH[i+1, j-1] - BTH[i, j-1]) / (x[i+j] - x[i])
    return BTH

# Noi suy Newton tien
def nsNewtonTien(x, y, n):
    BTH = buildBTH(x, y, n)
    t = Symbol('t')
    f = BTH[0, 0]
    var = (t - x[0])
    for i in range(1,n+1):
        f += var * BTH[0, i]
        var = var * (t - x[i])
    return f

# Noi suy Newton lui
def nsNewtonLui(x, y, n):
##    f = Symbol('f')
    BTH = buildBTH(x, y, n)
    t = Symbol('t')
    f = BTH[n, 0]
    var = (t - x[n])
    for i in range(1,n+1):
        f += var * BTH[n-i, i]
        var = var * (t - x[n-i])
    return f

# Xap xi gia tri
def pickPoints(x, x0, num):
    if num > len(x):
        raise Exception('Moi nhap lai')
    else:
        hieu = [abs(x[i] - x0) for i in range(len(x))]
        index = [i[0] for i in sorted(enumerate(hieu), key=lambda t:t[1])]
        return index[:num]

def estimate(x, y, x0, deg):
    index = pickPoints(x, x0, deg+1)
    x1 = [x[i] for i in index]
    y1 = [y[i] for i in index]
    ## buildBTH
    BTH = buildBTH(x1, y1, deg)
    f = nsNewtonTien(x1, y1, deg)
    value = f.subs(Symbol('t'), x0)
    return f, value

def main():
    x, y, n = inputData()
    x0 = float(input("Moi nhap gia tri can tinh: "))
    deg = int(input("Moi nhap bac da thuc (< bac lon nhat): "))
    f, v = estimate(x, y, x0, deg)
    print("Da thuc noi suy la: ", simplify(f))
    print("Gia tri can tinh tai ", x0, " la: ", v)
    ## plot
    xx = np.linspace(x[0], x[-1], 100)
    fx = [f.subs(Symbol('t'), xxx) for xxx in xx]

    plt.figure()
    plt.scatter(x, y, marker='*')
    plt.plot(xx, fx)
    plt.xlabel('Points')
    plt.ylabel('Values')
    plt.savefig("mygraph.png")

if __name__=='__main__':
    main()

Topic 3 - Function Approximation/17.Newton_Interpolation/nsNewton.py


import numpy as np

ar1 = np.array([1, 2, 3])

# ar2 = np.array([[4, 6, 1], [2, 3, 5, 6], [5, 3, 4, 1]])  # VisibleDeprecationWarning: Creating an ndarray from ragged
# nested sequences

ar3 = np.array([[4, 6, 1, 3], [2, 3, 5, 6], [5, 3, 4, 1]], dtype='int64')
print(ar3)

# Get Dimension
print(ar3.ndim)

# Get Shape - Gives Vector
print(ar3.shape)

# Get Type
print(ar3.dtype)

# Get Size
print(ar3.itemsize)

# Get Total Size
print(ar3.nbytes)

# Access Rows,Columns

# Get Specific element - [r,c]
print(ar3[1, 3])

# Get Specific row
print(ar3[1, :])

# Get Specific column
print(ar3[:, 3])

# Initialize all different types of arrays

# All 0's Matrix
print(np.zeros((2, 3, 2, 5)))

# All 1's Matrix
print(np.ones((2, 3, 2, 5), dtype='int16'))

# Any Other Number
print(np.full((2, 3), 77, dtype='int16'))

# Any Other Number with full_like
print(np.full_like(ar3, 77, dtype='int16'))

# Random Decimals
print(np.random.rand(4, 3))

# Random Decimals with Shape
print(np.random.random_sample(ar3.shape))

# Random Integers
print(np.random.randint(7, 10, size=ar3.size))

# identity Matrix
print(np.identity(5))

# Repeat Array
myArr = np.array([[1, 2, 3]])
r1 = np.repeat(myArr, 3, axis=0)
print(r1)

# Problem:
res = np.ones((5, 5))
z = np.zeros((3, 3))
z[1, 1] = 9
res[1:4, 1:4] = z
print(res)

# Careful in Copying
sample = np.array([1, 2, 3])
b = sample.copy()
b[1] = 200
print(b)
print(sample)

# Maths
# https://numpy.org/doc/stable/reference/routines.linalg.html
print(np.sin(sample))

a = np.ones((3, 2))
b = np.full((2, 3), 3)
res = np.matmul(a, b)
print(res)

# Find the Determinant
id = np.identity(3)
print(np.linalg.det(id))

# Statistics
print(np.max(ar3, axis=1))
print(np.sum(ar3))

# Reorganizing
before = np.array([[4, 6, 1, 3], [2, 3, 5, 6]])
after = before.reshape((8, 1))
print(after)

# Vertical Stacking
v1 = np.array([4, 6, 1, 3])
v2 = np.array([2, 3, 5, 6])
print(np.vstack([v1, v2, v2]))

# # Misc
f1 = np.genfromtxt("data.txt", delimiter=",")
f1 = f1.astype("int32")

# Boolean Masking and Advanced Indexing
print([f1 > 50])
np.any(f1 > 50, axis=0)  # Column Indexing
np.all(f1 > 50, axis=0)

# Examples:
a = ar3[2:4, 0:2]
b = ar3[[0, 1, 2, 3], [1, 2, 3, 4]]
c = ar3[[1, 3, 4], 3:]


import numpy as np
# X = 2*np.random.rand(100,1)
# y = 4 + 3*X + np.random.randn(100,1)
# X_ = np.c_[np.ones((100,1)),X]
# theta_best = np.linalg.inv(X_.T.dot(X_)).dot(X_.T).dot(y)
#
#
# X_new = np.array([[2],[0]])
# X_new_ = np.c_[np.ones((2,1)),X_new]
# y_pred = X_new_.dot(theta_best)
#
import matplotlib.pyplot as plt
#
# # plt.plot(X_new,y_pred,"r-")
# # plt.plot(X,y, "g.")
# # plt.show()
#
from sklearn.linear_model import LinearRegression
# lin_reg = LinearRegression()
# lin_reg.fit(X,y)
# ### least square
# theta_best_lstsq, residuals, rank, s = np.linalg.lstsq(X_,y,rcond=1e-6)
# ###pseudoinverse
# print(np.linalg.pinv(X_).dot(y))

# n_epochs = 50
# t0, t1 = 5, 50
# m = 100
# def learning_schedule(t):
#     return t0/(t+t1)
#
# theta = np.random.rand(2,1)
# for epoch in range(n_epochs):
#     for i in range(m):
#        random_index = np.random.randint(m)
#        xi = X_[random_index:random_index+1]
#        yi = y[random_index:random_index+1]
#        gradients = 2*xi.T.dot(xi.dot(theta)-yi)
#        eta = learning_schedule(epoch*m+i)
#        theta = theta - eta*gradients
#
from sklearn.linear_model import SGDRegressor
# sgd_reg = SGDRegressor(max_iter=1000, tol=1e-3, penalty=None, eta0=0.1)
# sgd_reg.fit(X,y.ravel()) # .ravel makes column to array
# print(sgd_reg.intercept_, sgd_reg.coef_)

m = 100
X = 6*np.random.rand(m,1)-3
y = 0.5*X**2 + X + 2 + np.random.rand(m,1)

from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
poly_features = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly_features.fit_transform(X)
lin_reg = SGDRegressor(max_iter=1000, tol=1e-5, penalty=None)
lin_reg.fit(X_poly,y.ravel())
print(lin_reg.intercept_,lin_reg.coef_)

from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2)
def plot_learning_curve(model, X, y):
    X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2)
    train_errors, val_errors = [], []
    for m in range(1, len(X_train)):
        model.fit(X_train[:m], y_train[:m])
        y_train_predict = model.predict(X_train[:m])
        y_val_predict = model.predict(X_val)
        train_errors.append(mean_squared_error(y_train[:m], y_train_predict))
        val_errors.append(mean_squared_error(y_val, y_val_predict))
    plt.plot(np.sqrt(train_errors), "r-", linewidth=2, label="train")
    plt.plot(np.sqrt(val_errors), "b-", linewidth=3, label="val")
    plt.ylim(0,3)
    plt.show()

# lin_reg = LinearRegression()
# plot_learning_curve(lin_reg,X,y)

from sklearn.pipeline import Pipeline
# polynomial_regression = Pipeline([
#     ("poly_features", PolynomialFeatures(degree=10,include_bias=False)),
#      ("lin_reg", LinearRegression())
# ])
# plot_learning_curve(polynomial_regression, X,y)

from sklearn.linear_model import Ridge
ridge_reg = Ridge(alpha=1, solver="cholesky")
ridge_reg.fit(X,y)
print(ridge_reg.predict([[1.5]]))

sgd_reg = SGDRegressor(penalty="l2")
sgd_reg.fit(X,y.ravel())
print(sgd_reg.predict([[1.5]]))

from sklearn.linear_model import ElasticNet
ela_net = ElasticNet(alpha=0.1, l1_ratio=0.5)
ela_net.fit(X, y)
print(ela_net.predict([[1.5]]))

poly_scaler = Pipeline([
    ("poly_features", PolynomialFeatures(degree=100, include_bias=False)),
    ("std_sca", StandardScaler())
])
X_train_poly_scaled = poly_scaler.fit_transform(X_train)
X_val_poly_scaled = poly_scaler.transform(X_val)

from sklearn.base import clone
sgd_reg = SGDRegressor(max_iter=1, tol=-np.infty, warm_start=True, penalty=None, learning_rate="constant", eta0=0.0005)
# warm start is used to train continously
minimum_val_error = float("inf")
best_epoch = None
best_model = None
# for epoch in range(1000):
#     sgd_reg.fit(X_train_poly_scaled, y_train.ravel())
#     y_val_predict = sgd_reg.predict(X_val_poly_scaled)
#     val_error = mean_squared_error(y_val, y_val_predict)
#     if val_error < minimum_val_error:
#         minimum_val_error = val_error
#         best_epoch = epoch
#         best_model = clone(sgd_reg)
#         print(best_epoch)

from sklearn import datasets
iris = datasets.load_iris()
X = iris["data"][:,3:]
y = (iris["target"]==2).astype(np.int)

from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression()
log_reg.fit(X,y)

X_new = np.linspace(0,3,1000).reshape(-1,1) # creae 1000 points between 0 and 3
y_prob = log_reg.predict_proba(X_new)
plt.plot(X_new,y_prob[:,1],"g-")
plt.plot(X_new,y_prob[:,0],"b--")
plt.show()


from __future__ import division, print_function

import numpy as np
from scipy.signal import freqz
import matplotlib.pyplot as plt

plt.figure(figsize=(4.0, 3.0))

for n in [3, 7, 21]:
    taps = np.full(n, fill_value=1.0/n)
    w, h = freqz(taps, worN=2000)
    plt.plot(w, abs(h), label="n = %d" % n)

plt.xlim(0, np.pi)
plt.xlabel('Frequency (radians/sample)')
plt.ylabel('Gain')
xaxis = plt.gca().xaxis
xaxis.set_ticks([0, 0.25*np.pi, 0.5*np.pi, 0.75*np.pi, np.pi])
xaxis.set_ticklabels(['0', r'$\frac{\pi}{4}$', r'$\frac{\pi}{2}$',
                      r'$\frac{3\pi}{4}$', r'$\pi$'])
plt.grid(alpha=0.5)
plt.legend(framealpha=1, shadow=True, loc='best')
plt.title("Amplitude Response for\nMoving Average Filter", fontsize=10)
plt.tight_layout()
# plt.savefig("moving_avg_freq_response.pdf")
plt.show()


import os
import matplotlib.pyplot as plt
import numpy as np
import sympy as sp
import sympy
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
from mpl_toolkits.mplot3d import axes3d, Axes3D
from sympy.utilities.lambdify import lambdastr

if __name__ == '__main__':
    x, y = sp.symbols("x, y")

    G = 9 * x ** 2 + 3 * x + 1
    g = sp.diff(G, x)
    X = np.linspace(-10, 10, 1_000)
    plt.plot(X, [G.evalf(subs={"x": i}) for i in X], label=f"G = {G}")
    plt.plot(X, [g.evalf(subs={"x": i}) for i in X], label=f"g := G' = {g}")
    plt.grid()
    plt.legend()
    plt.xlabel("x")
    plt.ylabel("y")
    plt.savefig(os.getcwd() + "/diff_exemple_G_and_g.png", dpi=300)
    plt.show()

    F = x**2 - y**2
    grad_F = [sp.diff(F, x_i) for x_i in (x, y)]
    print(f"grad_F = {grad_F}")

    X = np.linspace(-5, 5, 50)
    Y = np.linspace(-5, 5, 50)
    X, Y = np.meshgrid(X, Y)
    F_lambdify = sp.lambdify((x, y), F, modules="numpy")
    print(f"Grad_F = {lambdastr((x, y), grad_F)}")
    Z = F_lambdify(X, Y)
    grad_F_lambdify = sp.lambdify((x, y), grad_F, modules="numpy")

    fig = plt.figure()
    ax = Axes3D(fig)

    # Plot the surface.
    surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, linewidth=0, antialiased=False)
    # add gradient
    grad_Z = grad_F_lambdify(X, Y)
    ax.quiver(X, Y, Z, grad_Z[0], grad_Z[1], F_lambdify(*grad_Z), length=0.2, normalize=True,
              label=f"Vecteur directionnel du gradient")

    # Customize the z axis.
    ax.zaxis.set_major_locator(LinearLocator(10))
    ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

    # Add a color bar which maps values to colors.
    fig.colorbar(surf, shrink=0.5, aspect=5)
    plt.legend()
    plt.savefig(os.getcwd() + "/diff_exemple_F.png", dpi=300)
    plt.show()


# exercise 2.3.1

from matplotlib.pyplot import figure, plot, xlabel, ylabel, show
from scipy.io import loadmat
from sklearn.neighbors import KNeighborsClassifier
import scipy.linalg as linalg
import numpy as np

# Number of principal components to use for classification,
# i.e. the reduced dimensionality
K = [8,10,15,20,30,40,50,60,100,150]

# Load Matlab data file and extract training set and test set
mat_data = loadmat('../Data/zipdata.mat')
X = mat_data['traindata'][:,1:]
y = mat_data['traindata'][:,0]
Xtest = mat_data['testdata'][:,1:]
ytest = mat_data['testdata'][:,0]
N,M = X.shape
Ntest = Xtest.shape[0] # or Xtest[:,0].shape

# Subtract the mean from the data
Y = X - np.ones((N,1))*X.mean(0)
Ytest = Xtest - np.ones((Ntest,1))*X.mean(0)

# Obtain the PCA solution  by calculate the SVD of Y
U,S,V = linalg.svd(Y,full_matrices=False)
V = V.T

# Repeat classification for different values of K
error_rates = []
for k in K:
    # Project data onto principal component space,
    Z = Y @ V[:,:k]
    Ztest = Ytest @ V[:,:k]

    # Classify data with knn classifier
    knn_classifier = KNeighborsClassifier(n_neighbors=1)
    knn_classifier.fit(Z,y.ravel())
    y_estimated = knn_classifier.predict(Ztest)

    # Compute classification error rates
    y_estimated = y_estimated.T
    er = (sum(ytest!=y_estimated)/float(len(ytest)))*100
    error_rates.append(er)
    print('K={0}: Error rate: {1:.1f}%'.format(k, er))

# Visualize error rates vs. number of principal components considered
figure()
plot(K,error_rates,'o-')
xlabel('Number of principal components K')
ylabel('Error rate [%]')
show()

print('Ran Exercise 2.3.1')


# Problem: https://projecteuler.net/problem=329

"""
    . Use Markov process to calculate the probability of the frog to cloak the mentioned sequence.
    . Let T_P be the transition matrix where,
        T_P[i][j] is the probability of the frog to cloak "P" at position i before jumping to position j.
    . Let T_N be the transition matrix where,
        T_N[i][j] is the probability of the frog to cloak "N" at position i before jumping to position j.
    . So,
        Case 1: i is prime
            T_P[i][j] = 2/3 * n_neighbors(i)
            T_N[i][j] = 1/3 * n_neighbors(i)
        Case 2: i is not a prime
            T_P[i][j] = 1/3 * n_neighbors(i)
            T_N[i][j] = 2/3 * n_neighbors(i)
    . So, the transition matrix of the sequence "PPPPNNPPPNPPNPN" is:
        T_seq = product(i \in "PPPPNNPPPNPPNPN") T_{i}
    . Consider starting at an integer K,
        Let S[i] be the probability of the frog to be at position i.
        So, at iteration 0, S[K] = 1 and S[i] = 0 for i != K.
        After cloaking the sequence "PPPPNNPPPNPPNPN", the probability distribution of the position of the frog is:
            S' = S * T_seq
        So, the probability of the frog to cloaking the sequence "PPPPNNPPPNPPNPN" after starting at position K is,
            Pr("PPPPNNPPPNPPNPN") = sum(S')
    . Since the starting position is uniformly distributed,
        answer = 1/500 * sum_{i \in [1, 500]} (sum(S' of starting at i))
"""

from sage.all import *

if __name__ == "__main__":
    ans = 0

    N = 500
    seq = "PPPPNNPPPNPPNPN"

    T_P = matrix(QQ, N+1, N+1)
    T_N = matrix(QQ, N+1, N+1)
    T = {"P": T_P, "N": T_N}

    for i in range(1, N+1):
        neighbors = []
        if i-1 > 0:
            neighbors.append(i-1) # left neighbor
        if i+1 <= N:
            neighbors.append(i+1) # right neighbor
        n_neighbors = len(neighbors)
        for neighbor in neighbors:
            if is_prime(i):
                T_P[i,neighbor] = Rational("{}/{}".format(2, 3)) * Rational("{}/{}".format(1, n_neighbors))
                T_N[i,neighbor] = Rational("{}/{}".format(1, 3)) * Rational("{}/{}".format(1, n_neighbors))
            else:
                T_P[i,neighbor] = Rational("{}/{}".format(1, 3)) * Rational("{}/{}".format(1, n_neighbors))
                T_N[i,neighbor] = Rational("{}/{}".format(2, 3)) * Rational("{}/{}".format(1, n_neighbors))

    Tseq = copy(T[seq[0]])
    for letter in seq[1:]:
        Tseq = Tseq * T[letter]

#    for i in range(1, N+1):
#        S = matrix(QQ, 1, N+1)
#        S[0, i] = Rational("1/1")
#        S = S * Tseq
#        ans = ans + Rational("1/500") * sum(S[0])

    S = matrix(QQ, 1, N+1)
    for i in range(1, N+1):
        S[0, i] = Rational("1/500")
    S = S * Tseq
    ans = sum(S[0])
    print(ans)


import numpy as np

#Kalman filtering code

def gaussian_linear_transform(mean,cov,A,b):
    """Given a prior x~N(mean,cov), returns the
    mean and covariance of the variate y=A*x+b.
    """
    ymean = np.dot(A,mean)+b
    ycov = np.dot(A,np.dot(cov,A.T))
    return (ymean,ycov)

def kalman_filter_predict(prior_mean,prior_cov,F,g,SigmaX):
    """For the Kalman filter model with transition model:
      x[t] = F*x[t-1] + g + eps_x
    with eps_x ~ N(0,SigmaX)
    and given prior estimate x[t-1]~N(prior_mean,prior_cov),
    computes the predicted mean and covariance matrix at x[t]

    Output:
    - A pair (mu,cov) with mu the updated mean and cov the updated covariance
      matrix.

    Note: all elements are numpy arrays.
    """
    if isinstance(SigmaX,(int,float)):
        SigmaX = np.eye(len(prior_mean))*SigmaX
    muprime = np.dot(F,prior_mean)+g
    covprime = np.dot(F,np.dot(prior_cov,F.T))+SigmaX
    return (muprime,covprime)

def kalman_filter_update(prior_mean,prior_cov,F,g,SigmaX,H,j,SigmaZ,z):
    """For the Kalman filter model with transition model:
      x[t] = F*x[t-1] + g + eps_x
    and observation model
      z[t] = H*x[t] + j + eps_z
    with eps_x ~ N(0,SigmaX) and eps_z ~ N(0,SigmaZ),
    and given prior estimate x[t-1]~N(prior_mean,prior_cov),
    computes the updated mean and covariance matrix after observing z[t]=z.

    Output:
    - A pair (mu,cov) with mu the updated mean and cov the updated covariance
      matrix.

    Note: all elements are numpy arrays.

    Note: can be applied as an approximate extended Kalman filter by setting
    F*x+g and H*x+j to be the linearized models about the current estimate
    prior_mean.  (The true EKF would propagate the mean update and linearize
    the observation term around the mean update)
    """
    if isinstance(SigmaX,(int,float)):
        SigmaX = np.eye(len(prior_mean))*SigmaX
    if isinstance(SigmaZ,(int,float)):
        SigmaZ = np.eye(len(z))*SigmaZ
    muprime = np.dot(F,prior_mean)+g
    covprime = np.dot(F,np.dot(prior_cov,F.T))+SigmaX
    C = np.dot(H,np.dot(covprime,H.T))+SigmaZ
    zpred = np.dot(H,muprime)+j
    K = np.dot(covprime,np.dot(H.T,np.linalg.pinv(C)))
    mu = muprime + np.dot(K,z-zpred)
    cov = np.dot(covprime,np.eye(covprime.shape[0])-np.dot(K,H))
    return (mu,cov)


import numpy as np

m_train = train_set_x_orig.shape[0]
m_test = test_set_x_orig.shape[0]
num_px = train_set_x_orig.shape[1]

#reshape data
train_set_x = train_set_x_orig.reshape(train_set_x_orig.shape[0],-1).T
test_set_x = test_set_x_orig.reshape(test_set_x_orig.shape[0],-1).T

def sigmoid(z):

	sig = 1 / (1 + np.exp(-z))

	return sig

def initialize(dim):

	w = np.zeros(shape=(dim,1))
	b = 0

	return w,b

def propagate(w,b,X,Y):

	m = X.shape[1]
	# forward propagate
	z = np.dot(w.T,X) + b
	A = sigmoid(z)
	#cost = (-1/m) * np.sum(Y * np.log(A) + (1 - Y) * np.log(1 - A))

	# backward propagate
	dw = 1/m * np.dot(X,(A - Y).T)
	db = 1/m * np.sum(A - Y)

	return dw,db

def optimize(X,Y,w,b,num_iter,learning_rate):

	for i in range(num_iter):
		dw,db = propagate(w,b,X,Y)

		w = w - learning_rate * dw
		b = b - learning_rate * db

	return w,b

def predict(w,b,X):

	z = np.dot(w.T,X) + b
	A = sigmoid(z)

	for i in range(A.shape[1]):
		Y_predict = 1 if A[0,i] > 0.5 else 0

	return Y_predict

def model(X_train,Y_train,X_test,Y_test,num_iter,learning_rate):

	w,b = initialize(train_set_x.shape[0])

	w,b = optimize(X_train,Y_train,w,b,num_iter,learning_rate)

	Y_predict = predict(w,b,X_test)

	Y_predict_train = predict(w,b,X_train)

	print("test_accuracy: {} %".format(np.mean(np.abs(Y_test - Y_predict)) * 100))
	print("train_accuracy: {} %".format(np.mean(np.abs(Y_train - Y_predict_train)) * 100))


import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
import seaborn as sns

# Sigmoid Function
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# Implementation of the stochastic gradient descent
def gradient_descent(X, y, params, learning_rate, iterations):
    m = len(y)
    cost_history = np.zeros((iterations, 1))

    for i in range(iterations):
        params = params - (learning_rate/m) * (X.T @ (sigmoid(X @ params) - y))
        cost_history[i] = compute_cost(X, y, params)

    return (cost_history, params)

# Computing the cost via the negative log loss
def compute_cost(X, y, theta):
    m = len(y)
    h = sigmoid(X @ theta)
    epsilon = 1e-5
    cost = (1/m)*(((-y).T @ np.log(h + epsilon))-((1-y).T @ np.log(1-h + epsilon)))
    return cost

def predict(X, params):
    return np.round(sigmoid(X @ params))

# Driver Code

# Used scikit-learn to make a random binary classification dataset
X, y = make_classification(n_samples=500, n_features=2, n_redundant=0, n_informative=1,
                             n_clusters_per_class=1, random_state=14)

y = y[:, np.newaxis]

sns.set_style('white')
sns.scatterplot(X[:, 0], X[:, 1], hue=y.reshape(-1))

m = len(y)

X = np.hstack((np.ones((m, 1)), X))
n = np.size(X, 1)
params = np.zeros((n, 1))

iterations = 1000  # Number of iterations
learning_rate = 0.01  # Learning rate of stochastic gradient descent

initial_cost = compute_cost(X, y, params)

print("Initial Cost is: {} \n".format(initial_cost))

(cost_history, params_optimal) = gradient_descent(X, y, params, learning_rate, iterations)

print("Optimal Parameters are: \n", params_optimal, "\n")

plt.figure()
sns.set_style('white')
plt.plot(range(len(cost_history)), cost_history, 'r')
plt.title("Convergence Graph of Cost Function")
plt.xlabel("Number of Iterations")
plt.ylabel("Cost")
plt.show()

y_pred = predict(X, params_optimal)
score = float(sum(y_pred == y)) / float(len(y))

print("Score is : ", score)

slope = -(params_optimal[1] / params_optimal[2])
intercept = -(params_optimal[0] / params_optimal[2])

sns.set_style('white')
sns.scatterplot(X[:, 1], X[:, 2], hue=y.reshape(-1))

ax = plt.gca()
ax.autoscale(False)
x_vals = np.array(ax.get_xlim())
y_vals = intercept + (slope * x_vals)
plt.plot(x_vals, y_vals, c="k")


import numpy as np
from numpy.linalg import norm

def vec2unit_vec(vec):
    return vec / norm(vec)

# thresholds values based on percentiles
#  so values above get set to pos_val, values below get set to neg_val, and in between get set to middle_val
def threshold_vector_by_pct(vector, pct_cutoff=90, pos_val=1, neg_val=-1, middle_val=0):
    assert pct_cutoff >= 50
    neg_pct_cutoff = 100-pct_cutoff

    pos_threshold = np.percentile(vector, pct_cutoff)
    neg_threshold = np.percentile(vector, neg_pct_cutoff)

    mod_vec = vector
    mod_vec = np.where(  mod_vec >= pos_threshold,  pos_val,
                np.where(mod_vec <  neg_threshold,  neg_val,
                    middle_val))
    return mod_vec

def sparsify_vector_by_pct(vector, pct_cutoff=90):
    assert pct_cutoff >= 50
    neg_pct_cutoff = 100-pct_cutoff

    pos_threshold = np.percentile(vector, pct_cutoff)
    neg_threshold = np.percentile(vector, neg_pct_cutoff)

    mod_vec = vector.copy()
    mod_vec[(mod_vec <= pos_threshold) & (mod_vec >= neg_threshold)] = 0
    return mod_vec

# thresholds values based on pct's computed from a population of values
def threshold_vector_by_popn_pct(vector, pct2val, pct_cutoff=90, pos_val=1, neg_val=-1, middle_val=0):
    assert pct_cutoff >= 50
    neg_pct_cutoff = 100-pct_cutoff
    mod_vec = vector
    mod_vec = np.where(  mod_vec >= pct2val[pct_cutoff],      pos_val,
                np.where(mod_vec <  pct2val[neg_pct_cutoff],  neg_val,
                    middle_val))
    return mod_vec

# thresholds values to above (inc.) and below a threshold
def threshold_vector_by_val(vector, cutoff=0, pos_val=1, neg_val=-1):
    mod_vec = vector
    mod_vec = np.where(  mod_vec >= cutoff,  pos_val, neg_val)
    return mod_vec


"""

    This module finds the inverse of a matrix using Newton's method.
    Marina von Steinkirch spring 2013.

"""

import numpy as npy

def inverseNewton(AInput):

    CONST_TOLERANCE = 10**-11
    A = AInput.copy()
    Asize = len(A[:,:])

    # verifies if A is square
    if not (A.shape[0] == A.shape[1]):
        print "ERROR: A should be square"
        return None

    # calculates initial guess and tolerance
    I = npy.identity(Asize)

    """ based on  Victor Pan and Robert Schreiber """
    X = npy.transpose(A)/(npy.linalg.norm(A, ord=1)*npy.linalg.norm(A, ord=npy.inf))

    # iteration
    dx = 1.0
    i = 0
    while (abs(dx) > abs(CONST_TOLERANCE)):
        X = npy.dot(X,2*I)-npy.dot(X,npy.dot(A,X))
        A_dx = npy.linalg.inv(A)
        dx = npy.linalg.norm(X-A_dx)
        i += 1

    return X, dx,i


import numpy as np
import sympy
from sympy import cos, sin, sqrt, pi

sympy.var('A, An, T, rho')
t = sympy.Symbol('t')
n = sympy.Symbol('n', integer=True, positive=True)
x = sympy.Symbol('x', positive=True)
L = 7
a = 3*L/4
y0 = sympy.Piecewise((A*x/a, ((x>=0) & (x<=a))),
        (A*(L-x)/(L-a), ((x>a) & (x<=L))))
Yn = An*sympy.sin(n*pi*x/L)
exp = sympy.integrate(rho*Yn**2, (x, 0, L)) - 1
An = sympy.solve(exp, An)[1].simplify()
Yn = An*sin(n*pi*x/L)

# Finding Modal Force
F0 = 1.
Omega = 0.99*1*pi*sqrt(T/(rho*L**2))
Fx = F0
Fn = sympy.integrate(Fx*Yn, (x, 0, L))

# Finding modal initial conditions
eta0 = sympy.integrate(rho*Yn*y0, (x, 0, L)).simplify()
omegan = n*pi*sqrt(T/(rho*L**2))
k1 = eta0 - Fn/(omegan**2 - Omega**2)
etan = Fn/(omegan**2 - Omega**2)*cos(Omega*t) + k1*cos(omegan*t)

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

plt.cla()
nmaxs = [1, 2, 3, 4, 5, 10, 40]
for nmax in nmaxs:
    yxt = 0
    for ni in range(1, nmax+1):
        yxt += (Yn*etan).subs(n, ni)
    subs = dict(
            rho=7e3,
            T=100e2,
            A=0.01,
            )
    yxt = yxt.subs(subs)
    fyxt = sympy.lambdify('x, t', yxt, modules='numpy')
    ts = np.linspace(0, 10, 100)
    plt.plot(ts, fyxt(L/2, ts), label='$n_{max}=%d$' % nmax)
plt.legend()
plt.savefig('string_harmonic_excitation_convergence.png', bbox_inches='tight')

plt.cla()
nmax = 40
yxt = 0
for ni in range(1, nmax+1):
    yxt += (Yn*etan).subs(n, ni)
subs = dict(
        rho=7e3,
        T=100e2,
        A=0.01,
        )
yxt = yxt.subs(subs)
fyxt = sympy.lambdify('x, t', yxt, modules='numpy')
ts = np.linspace(0, 1200, 10000)
plt.plot(ts, fyxt(L/2, ts), label='$n_{max}=%d$' % nmax)
plt.legend()
plt.savefig('string_harmonic_excitation.png', bbox_inches='tight')

if True:
    fig = plt.gcf()
    ax = plt.gca()
    plt.cla()
    x = np.linspace(0, L, 500)
    ax.plot(x, x*0, '-k')
    ax.plot(x, x*0, '--k')
    lines = ax.get_lines()
    ts = np.linspace(0, 1200, 2000)
    fps = 25

    def animate(i):
        global lines
        y = fyxt(x, ts[i])
        lines[1].set_data(*[x, y])
        return lines

    ani = FuncAnimation(fig, animate, range(len(ts)))
    ani.save('string_harmonic_excitation.gif', fps=fps)


import math
import numpy as np

#https://www.hackerrank.com/challenges/diagonal-difference/problem
def diagonalDifference(arr):
    i = 0
    j = len(arr[0]) - 1
    sum1 = 0
    sum2 = 0
    for _, row in enumerate(arr):
        sum1 += row[i]
        sum2 += row[j]
        i += 1
        j -= 1
    return abs(sum1 - sum2)

#https://www.hackerrank.com/challenges/plus-minus/problem
def plusMinus(arr):
    num_of_values = len(arr)
    pos = 0
    neg = 0
    zero = 0
    for val in arr:
        if val > 0:
            pos += 1
        elif val < 0:
            neg += 1
        else:
            zero += 1

    frac_pos = pos / num_of_values
    frac_neg = neg / num_of_values
    frac_zero = zero / num_of_values

    print("{0:.6f}\n{1:.6f}\n{2:.6f}".format(frac_pos, frac_neg, frac_zero))

#https://www.hackerrank.com/challenges/staircase/problem
def staircase(n):
    for i in range(1, n+1):
        print(' ' * (n - i) + '#' * i)

#https://www.hackerrank.com/challenges/mini-max-sum/problem
def miniMaxSum(arr):
    arr_len = len(arr)
    min_sum = sum(arr)
    max_sum = 0
    for i in range(arr_len):
        cur_sum = sum(arr) - arr[i]
        if min_sum > cur_sum:
            min_sum = cur_sum
        if max_sum < cur_sum:
            max_sum = cur_sum
        else:
            continue

    print("{0} {1}".format(min_sum, max_sum))

#https://www.hackerrank.com/challenges/birthday-cake-candles/problem
def birthdayCakeCandles(ar):
    max_candle_hight = max(ar)
    counter = 0

    for _, val in enumerate(ar):
        if val == max_candle_hight:
            counter += 1

    return counter

#https://www.hackerrank.com/challenges/time-conversion/problem
def timeConversion(s):
    splitted_time = s.split(':')
    new_time = ""
    hours = ''
    if splitted_time[2][2] == 'A':
        if splitted_time[0] == '12':
            hours = '00'
        else:
            hours = splitted_time[0]
        new_time = "{0}:{1}:{2}".format(hours, splitted_time[1], splitted_time[2].replace('AM', ''))
    else:
        if splitted_time[0] == '12':
            hours = '12'
        else:
            hours = int(splitted_time[0])+12
        new_time = "{0}:{1}:{2}".format(hours, splitted_time[1], splitted_time[2].replace('PM', ''))

    return new_time

#https://www.hackerrank.com/challenges/grading/problem
def gradingStudents(grades):
    new_grades = []

    for _, val in enumerate(grades):
        if val < 38:
            cur_grade = val
        elif val % 5 >= 3:
            cur_grade = 5 * round(val / 5)
        else:
            cur_grade = val

        new_grades.append(cur_grade)

    return new_grades

#https://www.hackerrank.com/challenges/apple-and-orange/problem
def countApplesAndOranges(s, t, a, b, apples, oranges):
    apples_counter = 0
    oranges_counter = 0

    for _, val in enumerate(apples):
        g = a + val
        if g >= s and g <= t:
            apples_counter += 1

    for _, val in enumerate(oranges):
        g = b + val
        if g >= s and g <= t:
            oranges_counter += 1

    print("{0}\n{1}".format(apples_counter, oranges_counter))

#https://www.hackerrank.com/challenges/kangaroo/problem
def kangaroo(x1, v1, x2, v2):
    if v2 > v1 or v1 == v2:
        return "NO";

    return "YES" if (x2 - x1) % (v1 - v2) == 0 else "NO"

#https://www.hackerrank.com/challenges/between-two-sets/problem
def getTotalX(a, b):
    max_a = max(a)
    min_b = min(b)
    a_factor = list()
    result = list()

    for i in range(max_a, min_b + 1):
        if all(i % x == 0 for x in a):
            a_factor.append(i)

    for x in a_factor:
        if all(elem % x == 0 for elem in b):
            result.append(x)

    return len(result)

#https://www.hackerrank.com/challenges/breaking-best-and-worst-records/problem
def breakingRecords(scores):
    game_num = len(scores)
    min_score = scores[0]
    max_score = scores[0]
    highest_score = 0
    lowest_score = 0

    for i in range(game_num):
        if scores[i] > min_score:
            highest_score += 1
            min_score = scores[i]
        elif scores[i] < max_score:
            lowest_score += 1
            max_score = scores[i]

    return highest_score, lowest_score

#https://www.hackerrank.com/challenges/magic-square-forming/problem
def formingMagicSquare(s):
    costs = [[], [], []]
    stack = []
    missing_values = []
    s_list = [item for row in s for item in row]

    for i in range(1, 10):
        if i not in s_list:
            missing_values.append(i)

    for m in missing_values:
        for i in range(len(s)):
            for j in range(len(s[i])):
                costs[i].append(abs(m - s[i][j]))

    return costs

#https://www.hackerrank.com/challenges/the-birthday-bar/problem
def birthday(s, d, m):
    counter = 0
    temp_sum = 0

    for i in range(0, len(s)):
        for j in range(0, m):
            if i + j < len(s):
                temp_sum += s[i + j]
        if temp_sum == d:
            counter += 1
        temp_sum = 0

    return counter

#https://www.hackerrank.com/challenges/divisible-sum-pairs/problem
def divisibleSumPairs(n, k, ar):
    counter = 0

    for i in range(0, n):
        for j in range(0, n):
            if (ar[i] + ar[j]) % k == 0 and i < j:
                counter += 1

    return counter

#https://www.hackerrank.com/challenges/migratory-birds/problem
def migratoryBirds(arr):
    freq = 0
    temp = 0
    arr_set = set(arr)

    for _, val2 in enumerate(arr_set):
        for _, val1 in enumerate(arr):
            if val2 == val1:
                temp += 1
        if temp > freq:
            index = val2
            freq = temp
            temp = 0

    return index

if __name__ == '__main__':
    arr = [1, 2, 3, 4, 5, 4, 3, 2, 1, 3, 4]

    a = migratoryBirds(arr)

    print(a)


# -*- coding: utf-8 -*-
import numpy as np

# Cálculo do máximo divisor comum
def gcdxy(a, b):
    """
    Esta função calcula o máximo divisor comum entre a e b
    de forma a resolver a equação ax + by = mdc(a,b).
    Visto em: https://www.geeksforgeeks.org/python-program-
    for-basic-and-extended-euclidean-algorithms-2/
    Argumentos:
        - a,b - int
    Devolve:
        - gcd, x, y - int
    Exemplo:
        gcdxy(15,8)
            >> (1, -1, 2)
    """
    if a == 0 :
        return b,0,1
    gcd,x_i,y_i = gcdxy(b%a, a)
    x,y = y_i - (b//a) * x_i, x_i
    return gcd,x,y

# Cálculo do inverso multiplicativo modular
def modinv(b,n):
    """
    Esta função calcula o inverso multiplicativo de b módulo n
    Argumentos:
        b, n - int
    Devolve
        x%n - int
    Exemplo:
        modinv(3,5)
            >> 2
    """
    if 0 <= n < 2:
        raise ValueError("Não podemos usar o módulo 1, ou 0")
    gcd, x, y = gcdxy(b,n)
    if gcd == 1:
        return x%n
    else:
        raise ValueError("Não existe inverso, o mdc é {}".format(gcd))

# =============================================================================
# OPERAÇÕES INTERNAS À CHAKRAVALA
# =============================================================================

def compose(lst0,lst1,n):
    """
    Este é um método auxiliar que toma dois ternos e usa a regra de composição
    necessária para usar o método da Chakravala.
    (a,b,k)*(c,d,k') = (ac - nbd, ad + bc, kk')
    Argumentos:
        a,b,k - int
    Devolve:
        composition - int
    Exemplo:
        compose([3,2,1],[3,2,1],2)
            >> (17,12,1)
    """
    composition = (
            lst0[0]*lst1[0] + lst0[1]*lst1[1]*n,
            lst0[0]*lst1[1] + lst0[1]*lst1[0],
            lst0[2]*lst1[2])
    return composition

def m_method(a,b,k,n):
    """
    Este é um método auxiliar que procura o melhor valor para um parâmetro do
    método Chakravala
    Argumentos:
        a,b,k,n - int
    Devolve:
        vect[mins] - int
    Exemplo:
        m_method(2,1,2,2)
            >> 2
    """
    first_m = (-a*modinv(b,k)) % abs(k)
    while abs(first_m) < np.sqrt(n):
        first_m = first_m + abs(k)
    vect = [first_m, first_m - abs(k)]
    quadrated_m_possible = [abs(i**2 - n) for i in vect]
    mins = np.argmin(quadrated_m_possible)
    return vect[mins]


from typing import Any, Tuple, Union

import numpy as np
import pandas as pd

def named_aggregate_summary(series: pd.Series, key: str):
    summary = {
        f"max_{key}": np.max(series),
        f"mean_{key}": np.mean(series),
        f"median_{key}": np.median(series),
        f"min_{key}": np.min(series),
    }

    return summary

def mad(arr, m=None):
    """ Median Absolute Deviation: a "Robust" version of standard deviation.
        Indices variability of the sample.
        https://en.wikipedia.org/wiki/Median_absolute_deviation
    """
    if m is None:
        m = np.median(arr)
    return np.median(np.abs(arr - m))

def numerical_summary(
    series: pd.Series,
    quantiles=(0.05, 0.25, 0.5, 0.75, 0.95),
    count=None,
    is_unique=None,
    return_values=False,
) -> Union[dict, Tuple[dict, Any]]:
    """

    Args:
        series: series to summarize

    Returns:

    """

    if count is None:
        count = series.count()

    values = series.values
    present_values = values[~np.isnan(values)]
    finite_mask = np.isfinite(present_values)
    finite_values = present_values[finite_mask]

    summary = {
        "mean": np.mean(present_values),
        "std": np.std(present_values, ddof=1),
        "min": np.min(present_values),
        "max": np.max(present_values),
        # Unbiased kurtosis obtained using Fisher's definition (kurtosis of normal == 0.0). Normalized by N-1.
        "kurt": series.kurt(),
        # Unbiased skew normalized by N-1
        "skew": series.skew(),
        "sum": np.sum(present_values),
        "n_infinite": (~finite_mask).sum(),
        "n_zeros": (count - np.count_nonzero(present_values)),
    }

    for percentile, value in series.quantile(quantiles).to_dict().items():
        summary["quantile_{:d}".format(int(percentile * 100))] = value
    summary["median"] = summary["quantile_50"]
    summary["iqr"] = summary["quantile_75"] - summary["quantile_25"]

    summary["mad"] = mad(present_values, summary["quantile_50"])
    summary["variance"] = summary["std"] ** 2
    summary["cv"] = summary["std"] / summary["mean"] if summary["mean"] else np.NaN
    summary["range"] = summary["max"] - summary["min"]

    summary["monotonic_increase"] = series.is_monotonic_increasing
    summary["monotonic_decrease"] = series.is_monotonic_decreasing

    summary["monotonic_increase_strict"] = (
        summary["monotonic_increase"] and series.is_unique
    )
    summary["monotonic_decrease_strict"] = (
        summary["monotonic_decrease"] and series.is_unique
    )

    if return_values:
        return summary, finite_values

    return summary


'''
DTMF detection based on FFT.
This is a pedagogical tool. The implemented algorithm here is not as efficient,
as an implementation based on Goertzel algorithm [1,2].

Inspired on Ali Jamali Zavare's code: https://github.com/alijamaliz/DTMF-detector
I removed the dependency on PyAudio, which may require a C compiler.
And changed the algorithm to use peak picking.

[1] https://en.wikipedia.org/wiki/Goertzel_algorithm
[2] https://github.com/EliasOenal/multimon-ng/ and https://github.com/EliasOenal/multimon-ng/blob/master/demod_dtmf.c

October 10, 2020 - Aldebaro Klautau - www.lasse.ufpa.br/aldebaro
'''
from scipy.io import wavfile as wav
from scipy.fftpack import fft
from scipy.io import wavfile
#import wave
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks

audio_file_name = 'dial2.wav' #input file in WAV format
should_plot = False #use True if want to see auxiliary plots or False otherwise
silence_duration = 80e-3 #in seconds, interval between two DTMF tones. It depends on the DTMF standard
window_duration =  50e-3 # in seconds, analysis windows. Suggestion: use as half of the DTMF duration
shift_duration = 10e-3 # in seconds, window shift
window_power_threshold = 6 # in dB, below this threshold from the maximum the window is considered silence
frequencies_power_threshold = 10 # in dB, below this threshold from the maximum the FFT value is considered zero
spectrum_resolution = 4 #in Hz, spectrum (FFT) resolution. The smaller this number, the larger the FFT size will be
frequency_error_tolerance = 5 #in Hz, tolerance to error when comparing estimated DTMF frequencies with nominal values

def nextpow2(x):
    return int(np.ceil(np.log2(np.abs(x))))

def extract_block(x, num_block, window_length, window_shift):
    first_sample = num_block * window_shift
    last_sample = first_sample + window_length
    return x[first_sample:last_sample]

def isNumberInArray(array, number, tolerance=5):
    for i in range(number - frequency_error_tolerance, number + frequency_error_tolerance):
        if i in array:
            return True
    return False

DTMF_TABLE = {
    '1': [1209, 697],
    '2': [1336, 697],
    '3': [1477, 697],
    'A': [1633, 697],

    '4': [1209, 770],
    '5': [1336, 770],
    '6': [1477, 770],
    'B': [1633, 770],

    '7': [1209, 852],
    '8': [1336, 852],
    '9': [1477, 852],
    'C': [1633, 852],

    '*': [1209, 941],
    '0': [1336, 941],
    '#': [1477, 941],
    'D': [1633, 941],
}

# reading audio
Fs, signal = wav.read(audio_file_name) #change for your file name
Ts = 1.0/Fs #sampling interval = 1 / (sampling frequency)

window_length = round(window_duration / Ts)
window_shift = round(shift_duration / Ts)
silence_length = round(silence_duration / Ts)

print('Some information about file: ', audio_file_name)
print('Sampling frequency = ', Fs, 'Hz')
print('Sampling interval = ', Ts, 's')
print('Window length = ', window_length, 'samples')
print('Window shift = ', window_shift, 'samples')
print('Silence length = ', silence_length, 'samples')
print('')

#choose a strategy to determine the frequency (FFT) resolution
if False:
    num_fft = 2 ** nextpow2(window_length) #use FFT with size power of 2 for speed
    spectrum_resolution = Fs / num_fft #in Hz
else:
    num_fft = np.ceil(Fs/spectrum_resolution)
    num_fft = 2 ** nextpow2(num_fft) #use FFT with size power of 2 for speed
    spectrum_resolution = Fs / num_fft #in Hz

signal_length = len(signal)
#number of windows to analyze
num_windows = int( (signal_length - window_length) / (window_shift)) + 1

#detect the power in dB of each analysis window. The goal is to detect silence between DTMF tones
window_power = np.zeros((num_windows,), np.float)
for i in range(num_windows):
    signal_window = extract_block(signal, i, window_length, window_shift) #get one window for analysis
    energy = np.linalg.norm(signal_window) ** 2 #squared norm is the energy
    average_power = energy / window_length #average power is normalized energy
    if average_power > 0: #avoid log of zero
        window_power[i] = 10.0 * np.log10(average_power) #convert from Watts to dB

if should_plot:
    #plot the signal and the power per window
    plt.subplot(311)
    plt.plot(signal)
    plt.ylabel('Signal amplitude')
    plt.subplot(312)
    plt.plot(window_power)
    plt.ylabel('Power per window')

max_power = np.max(window_power) #get maximum power over all windows
min_power = max_power - window_power_threshold #required minimum power in dB

#use binary array to distinguish DTMF (element = 1) or silence (element = 0)
#when finding consecutive runs of ones, choose a single representative: the one
#with maximum power. For instance, transform:
#0 1 1 1 0 0 0
#into:
#0 0 0 1 0 0 0    <= a single 1 represents the sequence of 3 1's above
#assuming the fourth window has more power than the second and third.
window_represents_DTMF = np.zeros((num_windows,), np.int) #initialize
interval_best_index = -1 #initialize, best index for the current "run" of ones
interval_max_power = -np.inf #initialize
for window_index in range(num_windows):
    if window_power[window_index] < min_power:
        #it is a "silence", reset:
        interval_best_index = -1
        interval_max_power = -np.inf
    else: #it is a window with enough power to be a potential DTMF
        if window_power[window_index] > interval_max_power:
            #current power is larger than the best up to this moment
            if interval_best_index != -1:
                window_represents_DTMF[interval_best_index] = 0 #erase previous decision
            #update who is the "best":
            interval_max_power = window_power[window_index]
            interval_best_index = window_index
            window_represents_DTMF[interval_best_index] = 1

#filter very short silence segments such as 0 0 1 0 0, to turn it
#into 0 0 0 0 0 based on silence_duration in seconds, specified by the user,
#which was alredy converted to silence_length in samples
last_found_DTMF = -100000 #initialize with negative number
#each element of window_represents_DTMF represents a window, not
#a sample. Therefore, we need to define how many windows corresponds to the duration of silence:
silence_interval_in_windows = int(silence_length / window_shift)
if silence_interval_in_windows < 1:
    silence_interval_in_windows = 1 #should be at least 1
for window_index in range(num_windows):
    if window_represents_DTMF[window_index] == 1:
        #check how far is the current index 1 from previous index 1
        difference_in_indices = window_index - last_found_DTMF
        if difference_in_indices  <= silence_interval_in_windows:
            window_represents_DTMF[window_index] = 0 #flip the current 1, to indicate silence now
        else:
            last_found_DTMF = window_index #update for next iteration

if should_plot:
    #plot the signal and the power per window
    plt.subplot(313)
    plt.plot(window_represents_DTMF)
    plt.ylabel('DTMF candidates')
    plt.show()

#At this stage we have a single window representing each DTMF tone.
#That is, if a tone of duration 200 ms was mapped to 4 windows of 50 ms each,
#we chose one among these four windows to represent the tone.
#
#The next stage is to recognize the frequencies using peak picking of the
#spectrum calculated for each window
for window_index in range(num_windows):
    if window_represents_DTMF[window_index] == 0:
        continue #skip the windows that are not representing a DTMF tone

    #get a single window of the signal to analyze
    signal_window = extract_block(signal, window_index, window_length, window_shift)

    #Calculate fourier trasform of this frame of the signal
    fourier_transform = np.fft.fft(signal_window, num_fft)
    spectrum_magnitude = np.abs(fourier_transform) / num_fft #normalize by the FFT length
    spectrum_magnitude_dB = 20 * np.log10(spectrum_magnitude) #convert to dB
    spectrum_magnitude_dB = spectrum_magnitude_dB[0:int(num_fft / 2)] #discard "negative" frequencies

    #Discard (make zero) all magnitudes above specified threshold
    max_frequency_amplitude = np.max(spectrum_magnitude_dB)
    zeroed_indices = spectrum_magnitude_dB < max_frequency_amplitude - frequencies_power_threshold
    spectrum_magnitude_dB[zeroed_indices] = 0

    #find the two strongest peaks
    peaks, _ = find_peaks(spectrum_magnitude_dB, height=0)  #only positive frequencies
    sortead_peak_index = np.argsort(spectrum_magnitude_dB[peaks])
    first_frequency_index = peaks[sortead_peak_index[-1]] #sort worked in ascending order, get last
    second_frequency_index = peaks[sortead_peak_index[-2]]

    #make sure first_frequency < second_frequency (this is not really necessary)
    if first_frequency_index > second_frequency_index:
        temp = first_frequency_index
        first_frequency_index = second_frequency_index
        second_frequency_index = temp

    #convert from index to frequency in Hertz
    first_frequency = first_frequency_index * spectrum_resolution
    second_frequency = second_frequency_index * spectrum_resolution

    if should_plot:
        plt.subplot(311)
        plt.plot(signal_window)
        plt.subplot(312)
        #generate frequency axis for plots
        f_axis = np.arange(0,len(spectrum_magnitude_dB))*spectrum_resolution
        plt.plot(f_axis, spectrum_magnitude_dB)
        #indicate the location of the 2 peaks
        plt.plot(first_frequency, spectrum_magnitude_dB[first_frequency_index], "x")
        plt.plot(second_frequency, spectrum_magnitude_dB[second_frequency_index], "x")
        plt.show()

    #pack the two frequencies in a list
    detectedFrequencies = list()
    detectedFrequencies.append(int(round(second_frequency)))
    detectedFrequencies.append(int(round(first_frequency)))
    print('Detected frequencies:', detectedFrequencies)

    #check if the 2 detected frequencies compose a DTMF tone, and print it if the test is positive
    for char, frequency_pair in DTMF_TABLE.items():
        if (isNumberInArray(detectedFrequencies, frequency_pair[0],tolerance=frequency_error_tolerance) and
            isNumberInArray(detectedFrequencies, frequency_pair[1],tolerance=frequency_error_tolerance)):
            print ('Decoded as ', char, '(nominal frequencies: ', frequency_pair,')')
            print('')
            break


from typing import Callable
import numpy as np

def bisectionSolver(f: Callable, a: float, b: float,
                    tol: float=10e-6) -> float:
    """Bisection method solver, implemented using recursion.

    Arguments:
        f {Callable} -- Function to be optimized.
        a {float} -- Lower bound.
        b {float} -- Upper bound.

    Keyword Arguments:
        tol {float} -- Solution tolerance (default: {10e-6}).

    Raises:
        Exception -- Raised if no solution is found.

    Returns:
        float -- Solution to the function s.t. f(x) = 0.
    """

    # Compute midpoint
    mid = (a + b) / 2

    # Check if estimate is within tolerance
    if (b - a) < tol:
        return mid

    # Evaluate function at midpoint
    f_mid = f(mid)

    # Check position of estimate, move point and re-evaluate
    if (f(a) * f_mid) < 0:
        return bisectionSolver(f=f, a=a, b=mid)
    elif (f(b) * f_mid) < 0:
        return bisectionSolver(f=f, a=mid, b=b)
    else:
        raise Exception("No solution found.")


# normal distribution fits the probability distribution of many events, eg. IQ Scores, Heartbeat etc.
# it has three parameters
# loc - (mean) where peak of bell exists.
# scale - (standard deviation) how flat graph distribution should be.
# size - shape of returned array.

from numpy import random
import matplotlib.pyplot as plt                    # to show the graph
import seaborn as sns

arr1 = random.normal(size=(2, 3))                # gives 2 arrays with 3 values in each
print(arr1)

arr2 = random.normal(loc=5, scale=2, size=(1, 4))   # with mean 2 and standard deviation 2
print(arr2)                                         # 68% of returned values are between (loc - scale) 5-2=3 and
# (loc+scale) 5+2=7 that means between 3 to 7

sns.distplot(random.normal(size=3), hist=False)    # 3 values in a array and kde is true
plt.show()

omkar = random.normal(loc=2, scale=2, size=(2, 20))
print(omkar)
sns.distplot(omkar, hist=False)               # graph create with given values
plt.show()                                    # shows graph on screen

Python/Numpy/numpy 20 - normal (gaussian) distribution.py


"""Get triangle number with more than a certain number of divisors."""
# What is the value of the first triangle number to have over five
# hundred divisors?
# (Link: https://projecteuler.net/problem=12)

from math import sqrt, prod
from functools import lru_cache
from typing import Iterable
import numpy as np

FIRST_TRIANGLE_NUMBER = 1

def _generate_triangle_number() -> Iterable[int]:
    curr = FIRST_TRIANGLE_NUMBER
    while True:
        # The n-th triangular number is the sum of all integers until n,
        # so it is basically an arithmetic projection of ratio 1
        yield curr * (curr + 1) // 2
        curr += 1

def _sieve_of_erastothenes(limit: int) -> np.ndarray:
    # Inspired by https://stackoverflow.com/a/3035188/12058106
    if limit < 2:
        return np.array([], dtype=int)
    limit += 1 # Including "limit" itself in the range
    # Initialize half sieve
    is_index_prime = np.ones(limit // 2, dtype=np.bool)
    # Iterate on sieve
    for i in range(3, int(sqrt(limit)) + 1, 2):
        if is_index_prime[i // 2]:
            # Cut off non-primes
            is_index_prime[i * i // 2 :: i] = False
    return np.insert(
        arr=2 * np.nonzero(is_index_prime)[0][1:] + 1,
        obj=0,
        values=2
    )

@lru_cache
def _divisor_function(num: int) -> int:
    # Inspired by https://www.geeksforgeeks.org/count-divisors-n-on13/
    divisors = 1 # All numbers have at least 1 divisor (1)
    for prime in _sieve_of_erastothenes(limit=num):
        if prime > num:
            break
        # Is divisor?
        if num % prime == 0:
            # If divisor, what is the highest power to get to num?
            power = 0
            while num % prime == 0:
                num = num // prime
                power += 1
            # If n = 1**u_1 * 2**u_2 * 3**u_3 ... p**u_r,
            # The number of divisors is
            # (1 + u_1)(1 + u_2)(1 + u_3)...(1 + u_r)
            divisors *= power + 1
    return divisors

def _get_triangle_number_divisors(nth_triangle: int) -> int:
    """The triangle number is given by (n * (n + 1) // 2)
    As n and (n + 1) are co-primes, the total number of divisors
    of a triangle number (D(t)) will be either
    (D(n) * D((n + 1) // 2)) or (D(n // 2) * D(n + 1))
    """
    if nth_triangle % 2 == 0:
        first_factor = nth_triangle // 2
        second_factor = nth_triangle + 1
    else:
        first_factor = nth_triangle
        second_factor = (nth_triangle + 1) // 2
    return prod(_divisor_function(factor) for factor in (first_factor, second_factor))

def get_triangle_number(more_than_many_divisors: int) -> int:
    for i, triangle_num in enumerate(_generate_triangle_number(), start=FIRST_TRIANGLE_NUMBER):
        if _get_triangle_number_divisors(i) > more_than_many_divisors:
            return triangle_num
    assert False, "Unreachable"

if __name__ == '__main__':
    print(get_triangle_number(500))


import numpy as np

def accuracy(
        real_y: np.ndarray,
        predicted_y: np.ndarray
) -> np.float64:
    return np.mean(real_y == predicted_y)

def precision(
        real_y: np.ndarray,
        predicted_y: np.ndarray
) -> np.float64:
    true_positive = np.sum((real_y == 1) & (predicted_y == 1))
    false_positive = np.sum((real_y == 0) & (predicted_y == 1))

    return true_positive / (true_positive + false_positive)

def recall(
        real_y: np.ndarray,
        predicted_y: np.ndarray
) -> np.float64:
    true_positive = np.sum((real_y == 1) & (predicted_y == 1))
    false_negative = np.sum((real_y == 1) & (predicted_y == 0))

    return true_positive / (true_positive + false_negative)

def contingency_table(
        real_y: np.ndarray,
        predicted_y: np.ndarray
) -> np.ndarray:
    """

    :param real_y: real labels
    :param predicted_y: predicted labels
    :return: contingency table with structure as given:

             True positive  |  False negative
             ---------------|----------------
             False positive |  True negative

    Label 1 is regarded as positive and 0 as negative.
    """

    true_positive = np.sum((real_y == 1) & (predicted_y == 1))
    true_negative = np.sum((real_y == 0) & (predicted_y == 0))
    false_positive = np.sum((real_y == 0) & (predicted_y == 1))
    false_negative = np.sum((real_y == 1) & (predicted_y == 0))

    return np.array([
        [true_positive, false_negative],
        [false_positive, true_negative]
    ])


# -*- coding: utf-8 -*-
"""Aula_python_7.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1yEW5lTKSQg02vDReC_phFVqU1UYIGWUc

# Histogramas
Histogramas são ferramentas fundamentais de análise em várias áreas do conhecimento. Na Física, são usados para investigar variáveis ditas aleatórias.
Estas variáveis são associadas a problemas onde a abordagem mais adequada é a estatística. Os histogramas representam as distribuições destas variáveis.

A Mecânica Quântica, que estuda a natureza em nível microscópico, lida com distribuições de variáveis aleatórias em sua formulação de base.

Na Física Clássica, várias problemas são mais facilmente tratados usando-se ferramentas estatísticas.
Por exemplo, para um número suficientemente grande de jogadas de um dado ideal, o número de vezes que se esperam os números 1,2,3,4,5 e 6 deve ser semelhante. O gráfico do número de vezes que cada um desses números ocorreu é o histograma da distribuição de números desse dado.

Qual o resultado esperado? Como fazer esse gráfico?
"""

#Iniciamos "jogando" nosso dado
# Para isso vamos usar o pacote random que contém o gerador randint
import random as rand
N = 1800
z = list([rand.randint(1,6) for i in range(N)]) #a função randint(1,6) gera os números no intervalo de interesse.
#print(z) # a lista z contém os valores obtidos após N "jogadas"

#Para contar a ocorrência de cada número da lista z, vamos criar um array de numpy com 6 posições
import numpy as np
hist = np.zeros(6)
print(hist)

#Um algoritmo simples para contar o número de ocorrências de cada valor consiste
# em usar os próprios números da lista z como índices do array hist. A cada ocorrência de
# um número em z, o valor de hist correspondente àquele índice-1 (lembre que os índices começam em zero) é incrementado de 1.
hist = np.zeros(6)

for i in z:
    hist[i-1]+=1

print(z)
print(hist)
print(np.sum(hist))

#fazendo o histograma com barras verticais
import matplotlib.pyplot as plt

x = np.arange(1,7) #colocando os valores que irão no eixo x no gráfico do histograma

plt.bar(x,hist)
plt.show()

#usando diretamente a função do python
plt.hist(z,bins=6,range=(1,7), align='left')

plt.show()

"""Indo além: como poderíamos adaptar o algoritmo 'manual' acima para determinar o histograma com uma divisão de bins diferente (por exemplo, 3 bins em vez de 6 no caso dos dados)?

Indo mais além: como seria o histograma da soma dos números produzidos por dois dados? Esse é o objetivo da TAREFA no Moodle (para entregar até dia 23/09)
"""


from __future__ import print_function

import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
import math

mpl.rcParams['mathtext.fontset'] = 'cm'
mpl.rcParams['mathtext.rm'] = 'serif'

# see: http://glowingpython.blogspot.com/2011/08/how-to-plot-frequency-spectrum-with.html
# and
# http://docs.scipy.org/doc/numpy/reference/routines.fft.html

# Since our input data is real, the negative frequency components
# don't include any new information, and are not interesting to us.
# The rfft routines understand this, and rfft takes n real points and
# returns n/2+1 complex output points.  The corresponding inverse
# knows this, and acts accordingly.
#
# these are the routines we want for real valued data
#
# note that the scipy version of rfft returns that data differently
#
# M. Zingale (2013-03-03)

def single_freq_sine(npts, xmax, f_0):

    # a pure sine with no phase shift will result in pure imaginary
    # signal

    xx = np.linspace(0.0, xmax, npts, endpoint=False)
    return xx, np.sin(2.0*math.pi*f_0*xx)

def single_freq_sine_plus_shift(npts, xmax, f_0):

    # a pure sine with no phase shift will result in pure imaginary
    # signal
    xx = np.linspace(0.0, xmax, npts, endpoint=False)
    return xx, np.sin(2.0*math.pi*f_0*xx + math.pi/4)

def two_freq_sine(npts, xmax, f_0, f_1):

    # a pure sine with no phase shift will result in pure imaginary
    # signal
    xx = np.linspace(0.0, xmax, npts, endpoint=False)
    f = 0.5*(np.sin(2.0*math.pi*f_0*xx) + np.sin(2.0*math.pi*f_1*xx))
    return xx, f

def single_freq_cosine(npts, xmax, f_0):

    # a pure cosine with no phase shift will result in pure real
    # signal
    xx = np.linspace(0.0, xmax, npts, endpoint=False)
    f = np.cos(2.0*math.pi*f_0*xx)
    return xx, f

def plot_FFT(xx, xmax, f, outfile):

    plt.clf()

    plt.rc("font", size=10)

    npts = len(xx)

    # Forward transform: f(x) -> F(k)
    fk = np.fft.rfft(f)

    # Normalization -- the '2' here comes from the fact that we are
    # neglecting the negative portion of the frequency space, since
    # the FFT of a real function contains redundant information, so
    # we are only dealing with 1/2 of the frequency space.
    #
    # technically, we should only scale the 0 bin by N, since k=0 is
    # not duplicated -- we won't worry about that for these plots
    norm = 2.0/npts

    fk = fk*norm

    fk_r = fk.real
    fk_i = fk.imag

    # the fftfreq returns the postive and negative (and 0) frequencies
    # the newer versions of numpy (>=1.8) have an rfftfreq() function
    # that really does what we want -- we'll use that here.
    k = np.fft.rfftfreq(npts)

    # to make these dimensional, we need to divide by dx.  Note that
    # max(xx) is not the true length, since we didn't have a point
    # at the endpoint of the domain.
    kfreq = k*npts/(max(xx) + xx[1])

    # Inverse transform: F(k) -> f(x) -- without the normalization
    fkinv = np.fft.irfft(fk/norm)

    plt.subplot(411)

    plt.plot(xx, f)
    plt.xlabel("x")
    plt.ylabel("$f(x)$")

    plt.xlim(0, xmax)

    plt.subplot(412)

    plt.plot(kfreq, fk_r, label=r"Re($\mathcal{F}$)")
    plt.plot(kfreq, fk_i, ls=":", label=r"Im($\mathcal{F}$)")
    plt.xlabel(r"$k$")
    plt.ylabel("$\mathcal{F}_k$")

    plt.legend(fontsize="small", frameon=False, ncol=2, loc="upper right")

    plt.subplot(413)

    plt.plot(kfreq, np.abs(fk))
    plt.xlabel(r"$k$")
    plt.ylabel(r"$|\mathcal{F}_k|$")

    plt.subplot(414)

    plt.plot(xx, fkinv.real)
    plt.xlabel(r"$x$")
    plt.ylabel(r"$\mathcal{F}^{-1}(\mathcal{F}_k)$")

    plt.xlim(0, xmax)

    plt.tight_layout()

    plt.savefig(outfile)

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

npts = 256  #64  #256

f_0 = 0.2

xmax = 10.0/f_0

# FFT of sine
xx, f = single_freq_sine(npts, xmax, f_0)
plot_FFT(xx, xmax, f, "fft-sine.pdf")

# FFT of cosine
xx, f = single_freq_cosine(npts, xmax, f_0)
plot_FFT(xx, xmax, f, "fft-cosine.pdf")

# FFT of sine with pi/4 phase
xx, f = single_freq_sine_plus_shift(npts, xmax, f_0)
plot_FFT(xx, xmax, f, "fft-sine-phase.pdf")

# FFT of two sines
f_1 = 0.5
xx, f = two_freq_sine(npts, xmax, f_0, f_1)
plot_FFT(xx, xmax, f, "fft-two-sines.pdf")


# Author: Xinshuo Weng
# email: xinshuo.weng@gmail.com
import numpy as np

import init_paths
from math_geometry import get_2dline_from_pts_slope
from numpy.testing import assert_almost_equal

def test_get_2dline_from_pts_slope():
	print('check normal line')
	pts1 = [0, 1, 1]
	slope = 45
	line = get_2dline_from_pts_slope(pts1, slope)
	assert_almost_equal(line, np.array([-0.70710678, 0.70710678, -0.70710678]).reshape((3, 1)))

	print('check vertical line')
	pts1 = [0, 1, 1]
	slope = -90
	line = get_2dline_from_pts_slope(pts1, slope)
	assert_almost_equal(line, np.array([1, 0, 0]).reshape((3, 1)))

	print('check vertical line')
	pts1 = [0, 1, 1]
	slope = 90
	line = get_2dline_from_pts_slope(pts1, slope)
	assert_almost_equal(line, np.array([-1, 0, 0]).reshape((3, 1)))

	print('check horizontal line')
	pts1 = [0, 1, 1]
	slope = 0
	line = get_2dline_from_pts_slope(pts1, slope)
	assert_almost_equal(line, np.array([0, 1, -1]).reshape((3, 1)))

	print('check a point at infinity')
	pts1 = [0, 2, 0]
	slope = 45
	line = get_2dline_from_pts_slope(pts1, slope)
	assert_almost_equal(line, np.array([0, 0, -1.41421356]).reshape((3, 1)))

	print('\n\nDONE! SUCCESSFUL!!\n')

if __name__ == '__main__':
	test_get_2dline_from_pts_slope()


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

def eqn(X, t):
    x, y = X
    dotx = y + x - x**3
    doty = -x
    return np.array([dotx, doty])
def RK4(func, X0, t):
    dt = t[1] - t[0]
    nt = len(t)
    X  = np.zeros([nt, len(X0)])
    X[0] = X0
    for i in range(nt-1):
        k1 = func(X[i], t[i])
        k2 = func(X[i] + dt/2. * k1, t[i] + dt/2.)
        k3 = func(X[i] + dt/2. * k2, t[i] + dt/2.)
        k4 = func(X[i] + dt    * k3, t[i] + dt)
        X[i+1] = X[i] + dt / 6. * (k1 + 2. * k2 + 2. * k3 + k4)
    return X

def graph(t,x,y,x1,y1,x2,y2,x3,y3,title):
    fig,axs=plt.subplots(2,2,figsize=(7,7))
    fig.suptitle(title, fontsize=30)
    ax11,ax12,ax21,ax22=axs[0][0],axs[0][1],axs[1][0],axs[1][1]

    ax11.scatter(t,x,color='black',label="x"),ax11.scatter(t,y,color='brown',label="y")
    ax11.set_title("x(0)=0 & y(0)=-1")
    ax12.scatter(t,x1,color='black',label="x"),ax12.scatter(t,y1,color='brown',label="y")
    ax12.set_title("x(0)=0 & y(0)=-2")
    ax21.scatter(t,x2,color='black',label="x"),ax21.scatter(t,y2,color='brown',label="y")
    ax21.set_title("x(0)=0 & y(0)=-3"),ax21.set_xlabel("Time")
    ax22.scatter(t,x3,color='black',label="x"),ax22.scatter(t,y3,color='brown',label="y")
    ax22.set_title("x(0)=0 & y(0)=-4"),ax22.set_xlabel("Time")

    ax11.legend(),ax11.grid(True),ax12.legend(),ax12.grid(True),ax21.legend(),ax21.grid(True),ax22.legend(),ax22.grid(True)
    plt.show()
def graph1(x,y,x1,y1,x2,y2,x3,y3,title):
    fig,axs=plt.subplots(2,2,figsize=(7,7))
    fig.suptitle(title, fontsize=30)
    ax11,ax12,ax21,ax22=axs[0][0],axs[0][1],axs[1][0],axs[1][1]
    ax11.scatter(x,y,color='black')
    ax11.set_title("1st condition");ax11.set_ylabel("y")
    ax12.scatter(x1,y1,color='black')
    ax12.set_title("2nd condition");
    ax21.scatter(x2,y2,color='black')
    ax21.set_title("3rd condition");ax21.set_xlabel("x");ax21.set_ylabel("y")
    ax22.scatter(x3,y3,color='black')
    ax22.set_title("4th condition");ax22.set_xlabel("x")
    ax11.legend(),ax11.grid(True),ax12.legend(),ax12.grid(True),ax21.legend(),ax21.grid(True),ax22.legend(),ax22.grid(True)
    plt.show()

if __name__ == "__main__":
    x0 = [0,0,0,0];y0 = [-1,-2,-3,-4];Nt = 100;tmax = 15
    t = np.linspace(0.,tmax, Nt)
    X0 = [x0[0], y0[0]]
    X1 = [x0[1], y0[1]]
    X2 = [x0[2], y0[2]]
    X3 = [x0[3], y0[3]]
    res = RK4(eqn, X0, t)
    res1 = RK4(eqn, X1, t)
    res2 = RK4(eqn, X2, t)
    res3 = RK4(eqn, X3, t)
    x, y = res.T;
    x1, y1 = res1.T
    x2, y2 = res2.T
    x3, y3 = res3.T
    graph(t,x,y,x1,y1,x2,y2,x3,y3,"RK4 Method")
    graph1(x,y,x1,y1,x2,y2,x3,y3,"x vs y")
    data = {"Time":t,"x_rk4":x2,"y_rk4":y2}
    print(pd.DataFrame(data))


# -*- coding: utf-8 -*-
"""Hermite Interpolation.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1JMBfCJ8LsyglSeJMPOkd5koarA839LHQ

Before you turn this problem in, make sure everything runs as expected. First, **restart the kernel** (in the menubar, select Kernel → Restart) and then **run all cells** (in the menubar, select Cell → Run All).

Make sure you fill in any place that says YOUR CODE HERE or "YOUR ANSWER HERE", as well as your name and collaborators below:
"""

NAME = "Prabal Chowdhury"
COLLABORATORS = ""

"""# **CSE330 Lab: Hermite Interpolation**

Hermite Interpolation is an example of a variant of the interpolation problem, where the interpolant matches one or more derivatives of  f  at each of the nodes, in addition to the function values.

## **Importing the necessary libraries**
"""

import numpy as np
import matplotlib.pyplot as plt
from itertools import combinations
from numpy.polynomial import Polynomial

"""## **Creating the components for Hermite interpolation**

For the case of Hermite Interpolation, we look for a polynomial that matches both  $f'(x_i)$  and  $f(x_i)$  at the nodes  $x_i = x_0,\dots,x_n$ . Say you have  $n+1$  data points, $(x_0,y_0),(x_1,y_1),x_2,y_2),…,(x_n,y_n)$  and you happen to know the first-order derivative at all of these points, namely,  $(x_0, y_0 ^\prime ), (x_1, y_1 ^\prime ), x_2, y_2 ^\prime ), \dots ,(x_n, y_n ^\prime )$ . According to hermite interpolation, since there are  $2n+2$  conditions;  $n+1$  for  $f(x_i)$  plus  $n+1$  for  $f′(x_i)$ ; you can fit a polynomial of order  $2n+1$ .

General form of a  $2n+1$  degree Hermite polynomial:

$$p_{2n+1} = \sum_{k=0}^{n} \left(f(x_k)h_k(x) + f'(x_k)\hat{h}_k(x)\right), \tag{1}$$

where  $h_k$  and  $\hat{h}_k$  are defined using Lagrange basis functions by the following equations:

$$h_k(x) = (1-2(x-x_k)l^\prime_k(x_k))l^2_k(x_k), \tag{2}$$

and
$$\hat{h}_k(x) = (x-x_k)l^2_k(x_k), \tag{3}$$

where the Lagrange basis function being:
$$l_k(x) = \prod_{j=0, j\neq k}^{n} \frac{x-x_j}{x_k-x_j}. \tag{4}$$

**Note** that, we can rewrite Equation  $(2)$  in this way,
\begin{align}
h_k(x) &= \left(1-2(x-x_k)l^\prime_k(x_k) \right)l^2_k(x_k) \\
&= \left(1 - 2xl^\prime_k(x_k) + 2x_kl^\prime_k(x_k) \right)l^2_k(x_k) \\
&= \left(1 + 2x_kl^\prime_k(x_k) - 2l'_k(x_k)x \right) l^2_k(x_k) \tag{5}
\end{align}

Replacing  $l′_k(x_k)$  with  m , we get:
$$h_k(x) = (1 - 2xm + 2x_km)l^2_k(x_k). \tag{6}$$
## **Tasks:**
* The functions: l(k, x), `h(k, x)` and `h_hat(k, x)` calculate the corresponding
$l_k$,  $h_k$, and  $\hat{h}_k$, respectively.

* Function `l(k, x)` has already been defined for you.
* Your task is to complete the `h(k, x)`, `h_hat(k, x)`, and `hermit(x, y, y_prime)` functions.

Later we will draw some plots to check if the code is working.

### **Part 1: Calculate $l_k$**

This function uses the following equation to calculate $l_k(x)$ and returns a polynomial:
$$l_k(x) = \prod_{j=0, j\neq k}^{n} \frac{x-x_j}{x_k-x_j}$$
"""

def l(k, x):
    n = len(x)
    assert (k < len(x))

    x_k = x[k]
    x_copy = np.delete(x, k)

    denominator = np.prod(x_copy - x_k)

    coeff = []

    for i in range(n):
        coeff.append(sum([np.prod(x) for x in combinations(x_copy, i)]) * (-1)**(i) / denominator)

    coeff.reverse()

    return Polynomial(coeff)

"""### **Part 2: Calculate  $h_k$**

This function calculates  $h_k(x)$  using the following equation:
$$h_k(x) = \left(1 + 2x_kl^\prime_k(x_k) - 2l'_k(x_k)x \right) l^2_k(x_k).$$

This equation is basically a multiplication of two polynomials.

First polynomial:  $1 + 2x_kl^\prime_k(x_k) - 2l'_k(x_k)x$

Second polynomial:  $l^2_k(x_k)$ .

The `coeff` variable should contain a python list of coefficient values for the **first** polynomial of the equation. These coefficient values are used to create a polynomial `p`.
"""

def h(k, x):
    # initialize with None. Replace with appropriate values/function calls
    # initialize with None. Replace with appropriate values/function calls
    l_k = l(k, x)
    l_k_sqr = l_k * l_k
    l_k_prime = l_k.deriv(1)
    coeff = [1 + 2 * x[k] * l_k_prime(x[k]), -2 * l_k_prime(x[k])]
    p = Polynomial(coeff)

    # --------------------------------------------
    # YOUR CODE HERE

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

    return p * l_k_sqr

# Test case for the h(k, x) function

x = [3, 5, 7, 9]
k = 2
h_test = h(k, [3, 5, 7, 9])
h_result = Polynomial([-2.5, 0.5]) * (l(k, x) ** 2)

assert Polynomial.has_samecoef(h_result, h_test)
assert h_result == h_test

"""### **Part 3: Calculate  $\hat{h}_k$**
This function calculates  $\hat{h}_k(x)$  using the following equation:

$$\hat{h}_k(x) = (x-x_k)l^2_k(x_k).$$

This equation is also a multiplication of two polynomials.

First polynomial:  $x-x_k$ .

Second polynomial:  $l^2_k(x_k)$ .

The `coeff` variable should contain a python list of coefficient values for the **first** polynomial of the equation. These coefficient values are used to create a polynomial `p`.
"""

def h_hat(k, x):
    # Initialize with none
    l_k = l(k, x)
    l_k_sqr = l_k * l_k
    coeff = [-x[k], 1]
    p = Polynomial(coeff)

    # --------------------------------------------
    # YOUR CODE HERE

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

    return p * l_k_sqr

# Test case for the h(k, x) function

x = [3, 5, 7, 9]
k = 2
h_test = h_hat(k, [3, 5, 7, 9])
h_result = Polynomial([-7, 1]) * (l(k, x) ** 2)

assert Polynomial.has_samecoef(h_result, h_test)
assert h_result == h_test

"""### **Part 4: The Hermite Polynomial**
This function uses the following equation:

$$p_{2n+1} = \sum_{k=0}^{n} \left(f(x_k)h_k(x) + f'(x_k)\hat{h}_k(x)\right).$$

The polynomial denoted by the equation is calculated by the variable `f`.
"""

def hermit(x, y, y_prime):
    assert len(x) == len(y)
    assert len(y) == len(y_prime)

    f = Polynomial([0.0])
    # --------------------------------------------
    # YOUR CODE HERE
    for i in range(len(x)):
        f += y[i] * h(i, x) + y_prime[i] * h_hat(i, x)
    # --------------------------------------------
    return f

"""### **Testing our methods by plotting graphs.**
**Note:**

* For each of the 5 plots, there will be 2 curves plotted: one being the original function, and the other being the interpolated curve.
* The original functions are displayed in orange color, while the hermite interpolated curves are in blue.
* `x`, `y`, and `y_prime` contain  $x_i$, $f(x_i)$, and  $f'(x_i)$  of the given nodes of the original function  $f$ .

Upon calling the `hermit()` function, it returns a polynomial `f`. For example, for plot 1, it is called `f3`.

In general, a polynomial may look like the following:  $f = 1 + 2x + 3x^2$. Next, we pass in a number of  $x$  values to the polynomial by calling the `.linspace()` function on the polynomial object using `f.linspace()`. This function outputs a tuple, which is stored in a variable called data. First element of data contains a 1D numpy array of  $x_i$  values generated by `linspace()`, and the second element of data contains a 1D numpy array of the corresponding  $y_i$  values outputted by our example polynomial:  $f = 1 + 2x + 3x^2$.

Using `test_x`, we generate a range of  $x_i$  values to plot the original function, and `test_y` contains the corresponding  $y_i$  values of the original function. For the first plot, our original function is the sine curve.

For all the plots:

`plt.plot(test_x, test_y)` plots the original function.

`plt.plot(data[0], data[1])` plots the interpolated polynomial.
"""

pi      = np.pi
x       = np.array([0.0, pi/2.0,  pi, 3.0*pi/2.0])
y       = np.array([0.0,    1.0, 0.0,       -1.0])
y_prime = np.array([1.0,    0.0, 1.0,        0.0])

"""**Plot 1**: trying to interpolate a sine curve `(np.sin())` using first 2 nodes in `x` and `y`, and their corresponding derivative in `y_prime`."""

n      = 1
f3     = hermit(x[:(n+1)], y[:(n+1)], y_prime[:(n+1)])
data   = f3.linspace(n=50, domain=[-3, 3])
test_x = np.linspace(-3, 3, 50, endpoint=True)
test_y = np.sin(test_x)

plt.plot(data[0], data[1])
plt.plot(test_x, test_y)
plt.show()
np.testing.assert_allclose(data[1][20:32], test_y[20:32], atol=0.7, rtol=1.4)

"""**Plot 2**: trying to interpolate a sine curve `(np.sin())` using first 3 nodes in `x` and `y` and their corresponding derivative in `y_prime`."""

n      = 2
f5     = hermit(x[:(n+1)], y[:(n+1)], y_prime[:(n+1)])
data   = f5.linspace(n=50, domain=[-0.7, 3])
test_x = np.linspace(-2*pi, 2*pi, 50, endpoint=True)
test_y = np.sin(test_x)

plt.plot(test_x, test_y) # 25-
plt.plot(data[0], data[1]) # 10-33
plt.show()

data = f5.linspace(n=50, domain=[0, 3])
test_x = np.linspace(0, 3, 50, endpoint=True)
test_y = np.sin(test_x)
np.testing.assert_allclose(data[1], test_y, atol=0.5, rtol=1.7)

"""**Plot 3**: trying to interpolate a sine curve `(np.sin())` using first 4 nodes in `x` and `y` and their corresponding derivative in `y_prime`."""

n      = 3
f7     = hermit(x[:(n+1)], y[:(n+1)], y_prime[:(n+1)])
data   = f7.linspace(n=50, domain=[-0.3, 3])
test_x = np.linspace(-2*pi, 2*pi, 50, endpoint=True)
test_y = np.sin(test_x)

plt.plot(data[0], data[1])
plt.plot(test_x, test_y)
plt.show()

data = f7.linspace(n=50, domain=[0, 3])
test_x = np.linspace(0, 3, 50, endpoint=True)
test_y = np.sin(test_x)
np.testing.assert_allclose(data[1], test_y, atol=0.8, rtol=1.9)

"""**Plot 4**: trying to interpolate an exponential curve `(np.exp())` using all nodes in `x` and `y` and their corresponding derivatives in `y_prime`."""

#defining new set of given node information: x, y and y'
x       = np.array([0.0, 1.0,          2.0       ])
y       = np.array([1.0, 2.71828183,  54.59815003])
y_prime = np.array([0.0, 5.43656366, 218.39260013])

f7      = hermit( x, y, y_prime)
data    = f7.linspace(n=50, domain=[-0.5, 2.2])
test_x  = np.linspace(-0.5, 2.2, 50, endpoint=True)
test_y  = np.exp(test_x**2)

plt.plot(data[0], data[1])
plt.plot(test_x, test_y)
plt.show()

np.testing.assert_allclose(test_y[27:47], data[1][27:47], atol=3, rtol=0.4)

"""**Plot 5:** trying to interpolate  $y = (x-3)^2 + 1$  using all nodes in `x` and `y` and their corresponding derivatives in `y_prime`.

For this plot you might be able to see only one curve due to the two curves overlapping. This means that our polynomial is accurately interpolating the original function.
"""

#defining new set of given node information: x, y and y'
x       = np.array([1.0, 3.0, 5.0])
y       = np.array([5.0, 1.0, 5.0])
y_prime = np.array([-4.0, 0.0, 4.0])

f7      = hermit( x, y, y_prime)
data    = f7.linspace(n=50, domain=[-10, 10])
test_x  = np.linspace(-10, 10, 50, endpoint=True)
test_y  = (test_x-3)**2 + 1

plt.plot(data[0], data[1])
plt.plot(test_x, test_y)
plt.show()

np.testing.assert_allclose(test_y, data[1], atol=0.1, rtol=0.1)


from numpy.polynomial import Polynomial

def legendres(n: int):
    if n < 0:
        raise Exception("n must be >= 0")

    X = Polynomial([0, 1])
    P = [Polynomial([1]), X]
    # P_n = (2n - 1)/n * P_{n-1} * X - (n-1)/n * P_{n-2}
    for i in range(2, n + 1):
        P_i = (2 * i - 1) / i * P[i - 1] * X - (i - 1) / i * P[i - 2]
        P.append(P_i)
    return P[:n + 1]


import numpy as np

from abc import abstractmethod

class Loss:
    @abstractmethod
    def loss(self, y_true, y_pred):
        pass

    @abstractmethod
    def gradient(self , y_true, y_pred):
        pass

class MSE:
    def loss(self, y_true, y_pred):
       return 0.5*(np.power((y_true-y_pred),2))

    def gradient(self , y_true, y_pred):
        return -1*(y_true -y_pred)


import numpy as np

# Setting the random seed, can be tweaked
np.random.seed(42)

def stepFunction(t):
    if t >= 0:
        return 1
    return 0

def prediction(X, W, b):
    return stepFunction((np.matmul(X,W)+b)[0])

# The function receives as inputs the data X, the labels y,
# the weights W (as an array), and the bias b,
#  It updates the weights W and bias b, according to the perceptron algorithm,
# and returns W and b.
def perceptronStep(X, y, W, b, learn_rate = 0.01):
    for i in range(len(X)):
        y_hat = prediction(X[i],W,b)
        addOrSubFactor = y[i] - y_hat
        for j in range(2):
            W[j] += addOrSubFactor * X[i][j] * learn_rate
        b += addOrSubFactor * learn_rate
    return W, b

# This function runs the perceptron algorithm repeatedly on the dataset,
# and returns a few of the boundary lines obtained in the iterations,
# for plotting purposes.
# The learning rate and the num_epochs can be tweaked
def trainPerceptronAlgorithm(X, y, learn_rate = 0.01, num_epochs = 1000):
    x_min, x_max = min(X.T[0]), max(X.T[0])
    y_min, y_max = min(X.T[1]), max(X.T[1])
    W = np.array(np.random.rand(2,1))
    b = np.random.rand(1)[0] + x_max
    # These are the solution lines that get plotted below.
    boundary_lines = []
    for i in range(num_epochs):
        # In each epoch, we apply the perceptron step.
        W, b = perceptronStep(X, y, W, b, learn_rate)
        boundary_lines.append((-W[0]/W[1], -b/W[1]))

    return boundary_lines


import numpy as np
import random
from time import process_time

#circle x polar coordinate
def x_circle(r1,r2):
    x= np.sqrt(r1)*np.cos(2*np.pi*r2)
    return x

#circle y polar coordinate
def y_circle(r1,r2):
    x= np.sqrt(r1)*np.sin(2*np.pi*r2)
    return x

#circunference definition, condition for random sampling inside the circle: x^2+y^2<=1
def circ(x,y):
    c= (x)**2+(y)**2
    return c

#square x coordinate for sampling with rejection method
def x_square(r1):
    x=-1+2*r1
    return x

#square y coordinate for sampling with rejection method
def y_square(r2):
    y=-1+2*r2
    return y

N=10**6             #number of sampled couples

#sampling with inversion/analytical method, computing the CPU time
x1, y1 = [],[]               #coordinates of the points inside the circle
t1_start=process_time()
while len(x1) < N:
    r1=random.random()
    r2=random.random()
    x1.append(x_circle(r1,r2))
    y1.append(y_circle(r1,r2))
t1_stop=process_time()
print('time to sample the circle with inversion method: %g s' %(t1_stop-t1_start))

#sampling with rejection method, computing the CPU time
x2, y2 = [],[]                   #coordinates of the points inside the circle
t2_start=process_time()
while len(x2) < N:
    r1=random.random()
    r2=random.random()
    if circ(x_square(r1),y_square(r2))<=1:
        x2.append(x_square(r1))
        y2.append(y_square(r2))
t2_stop=process_time()
print('time to sample the circle with rejection method: %g s' %(t2_stop-t2_start))


import numpy as np
from .ForwardPropagate import ForwardPropagate
from .RollTheta import RollTheta

def CostFunction(Theta,X,y,s,Lambda):
	#now to populate a, including adding the ones for the bias unit
	a = []
	z = []
	m = np.size(y)
	L = np.size(s)
	a.append(X)
	for j in range(1,L):
		if j == L-1:
			at = np.zeros((m,s[j]),dtype='float32')
		else:
			at = np.zeros((m,s[j]+1),dtype='float32')
		zt = np.copy(at)
		a.append(at)
		z.append(zt)
	ForwardPropagate(a,z,L,Theta)

	#calculate J first (I will replace this with the vectorized version once I find my code)
	#simple way is to sum of K outputs (s[-1])
	J = 0.0
	h = a[-1]
	m = X.shape[0]
	for k in range(0,s[-1]):
		#select the training
		yk = np.float32(y == k+1)
		hk = h[:,k]
		J +=  (1.0/m)*np.sum(-yk*np.log(hk.clip(min=1e-40)) - (1.0 - yk)*np.log((1.0 - hk).clip(min=1e-40)))

	#Regularization
	Reg = 0.0
	for i in range(0,L-1):
		T = Theta[i]
		Reg += Lambda/(2.0*m) * np.sum(T[:,1:]**2.0)
	J += Reg

	return J

def CostFunction_y2d(Theta,X,y,s,Lambda):
	#now to populate a, including adding the ones for the bias unit
	a = []
	z = []
	shape = y.shape
	m = shape[0]
	L = np.size(s)
	a.append(X)
	for j in range(1,L):
		if j == L-1:
			at = np.zeros((m,s[j]),dtype='float32')
		else:
			at = np.zeros((m,s[j]+1),dtype='float32')
		zt = np.copy(at)
		a.append(at)
		z.append(zt)
	ForwardPropagate(a,z,L,Theta)

	#calculate J first (I will replace this with the vectorized version once I find my code)
	#simple way is to sum of K outputs (s[-1])
	J = 0.0
	h = a[-1]
	m = X.shape[0]
	for k in range(0,s[-1]):
		#select the training
		yk = np.float32(y[:,k])
		hk = h[:,k]
		J +=  (1.0/m)*np.sum(-yk*np.log(hk.clip(min=1e-40)) - (1.0 - yk)*np.log((1.0 - hk).clip(min=1e-40)))

	#Regularization
	Reg = 0.0
	for i in range(0,L-1):
		T = Theta[i]
		Reg += Lambda/(2.0*m) * np.sum(T[:,1:]**2.0)
	J += Reg

	return J

def ReturnUnrolledCostFunction(X,y,s,Lambda,y2d=False):

	def UnrolledCostFunction(Theta):

		RolledTheta = RollTheta(Theta,s)
		if y2d:
			J = CostFunction_y2d(RolledTheta,X,y,s,Lambda)
		else:
			J = CostFunction(RolledTheta,X,y,s,Lambda)
		return J

	return UnrolledCostFunction

def ReturnCostPrinter(X,y,s,Lambda,y2d=False):

	def PrintCost(Theta):
		RolledTheta = RollTheta(Theta,s)
		if y2d:
			J = CostFunction_y2d(RolledTheta,X,y,s,Lambda)
		else:
			J = CostFunction(RolledTheta,X,y,s,Lambda)
		print('Cost: {0}'.format(J))

	return PrintCost


import numpy as np

"""Utility functions for conversions between various coordinate systems."""

def pol_to_cart(rho, phi):
    """Converts Polar Coordinates to Cartesian Coordinates.

    See:
        http://stackoverflow.com/questions/20924085/python-conversion-between-coordinates

    Arguments:
        rho -- displacement component of the polar coordinate.
        phi -- angle component of the polar coordinate.
    """
    x = rho * np.cos(phi)
    y = rho * np.sin(phi)
    return x, y

def complex_to_real_2d(z):
    """Converts a complex number to a position in 2d Cartesian space.

    Arguments:
        z -- a complex number
    """
    if not isinstance(z, complex):
        return
    x = np.real(z)
    y = np.imag(z)
    return x, y

def real_to_complex_2d(x, y):
    """Converts a position in 2d Cartesian space to a complex number.

    Arguments:
        x -- the x component (maps to the real axis)
        y -- the y component (maps to the imaginary axis)
    """
    return np.complex(x, y)


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

# Load the dataframe
df = pd.read_csv(path)

#Code starts here
#task 1 - calculating joint probability

p_a = len(df[(df['fico']>700)])/len(df['fico'])
# print(p_a)
p_b = len(df[df['purpose']=='debt_consolidation'])/len(df['purpose'])
# print(p_b)
df1 = df[df['purpose']=='debt_consolidation']
p_a_b = len(df1[df1['purpose']=='debt_consolidation'])*len(df1[df1['fico']>700])/len(df1[df1['fico']>700])
# print(p_a_b)
result = p_a_b == p_a
# print(f'This is result {result}')

#task 2  - calculating conditional probability
prob_lp = len(df[df['paid.back.loan'] == 'Yes'])/len(df['paid.back.loan'])
# print(prob_lp)
prob_cs = len(df[df['credit.policy']=='Yes'])/len(df['credit.policy'])
# print(prob_cs)

new_df = df[df['paid.back.loan'] == 'Yes']

prob_pd_cs = prob_pd_cs = new_df[new_df['credit.policy'] == 'Yes'].shape[0] / new_df.shape[0]

bayes = round((prob_pd_cs*prob_lp)/prob_cs,4)
print(bayes)

#step-3
df['purpose'].value_counts(normalize=True).plot(kind='bar')
plt.show()

df1 = df[df['paid.back.loan']=='No']
df1['purpose'].value_counts(normalize=True).plot(kind='bar')
plt.show()

#step-4
inst_median = df['installment'].median()

inst_mean = df['installment'].mean()

df['installment'].hist(normed=True,bins=50)
plt.show()

df['log.annual.inc'].hist(normed=True,bins=50)
plt.show()


import math
from typing import cast

import numpy

from overloads.typedefs import ndarray

def norm_inf(x: ndarray) -> float:
    return float(numpy.abs(x).max())

def norm_l2(x: ndarray) -> float:
    infnorm = norm_inf(x)
    if infnorm == 0:
        return 0
    x = cast(ndarray, x / infnorm)
    return infnorm * math.sqrt(float(x @ x))

def safe_normalize(x: ndarray) -> ndarray:
    l2norm = norm_l2(x)
    if l2norm == 0:
        return x
    return x / l2norm  # type: ignore


import numpy as np

def distance(point1, point2):
    """
    Calculate distance between two points.
    Parameters
    ----------
    point1: array_like
        The first point
    point2 : array_like
        The second point

    Returns
    ----------
    float
        The distance between point1 and point2.
    """
    point1 = np.asarray(point1)
    point2 = np.asarray(point2)
    return np.linalg.norm(point1-point2)


# -*- coding: utf-8 -*-
"""
Created on 2020/12/31 13:33

@author: Irvinfaith

@email: Irvinfaith@hotmail.com
"""
import numpy as np

def mse(true_y, prediction_y, derive=False):
    if derive:
        return 2 / true_y.shape[0] * (prediction_y - true_y)
    else:
        return np.mean((true_y - prediction_y) ** 2)

def mae(true_y, prediction_y, derive=False):
    if derive:
        return 1 / true_y.shape[0] * (prediction_y - true_y)
    else:
        return np.mean(np.abs(true_y - prediction_y))

def cross_entropy_loss(true_y, prediction_y, derive=False, epsilon=1e-9):
    if derive:
        return prediction_y - true_y
    return -np.multiply(true_y, np.log(np.where(prediction_y < epsilon, epsilon, prediction_y))).sum() / \
           prediction_y.shape[0]