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


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


"""

    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)


# -*- 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 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.")


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


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


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

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


# -*- 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]


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

def error(b,m,x,y):
    finalError=0
    for i in range(len(x)):
        finalError +=(y [i]-(m*x[i]+b))**2
    return finalError/len(x)

def gradient_descent(init_m,init_b,x,y):
    learning_rate=0.001
    num_iterations=1000
    b=init_b
    m=init_m
    for i in range(num_iterations):
        b,m=step(init_b,init_m,x,y)
        init_b=init_b-(learning_rate*b)
        init_m=init_m-(learning_rate*m)
    return [init_b, init_m]

def step(b,m,x,y):
    m_gradient=0
    b_gradient=0
    for i in range(len(x)):
        b_gradient += -(2/len(x))*(y[i]-((m*x[i])+b))
        m_gradient += -x[i]*(2/len(x))*(y[i]-((m*x[i])+b))

    return [b_gradient,m_gradient]

def linearRegression():
#collecting the data
    dataset = pd.read_csv('lactic.csv')
    X = dataset.iloc[:,1].values
    Y = dataset.iloc[:,-1].values
    print(X)

    in_b=0
    in_m=0
    print('Starting at b={0},m={1},error = {2} '.format(in_b,in_m,error(in_b,in_m,X,Y)))
    [b,m]=gradient_descent(in_m,in_b,X,Y)
    print('Finally at b={0},m={1},error = {2} '.format(b,m,error(b,m,X,Y)))

    #plotting the graph
    y_vals=[m*x+b for x in range(20)]
    x_vals = range(20)

    plt.scatter(X,Y)
    plt.plot(x_vals,y_vals,linewidth=3)
    plt.show()

if __name__=='__main__':
    linearRegression()


import numpy as np

def mean_square_error(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate MSE loss

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    MSE of given predictions
    """
    return (1/y_true.size) * sum(np.subtract(y_true, y_pred) ** 2)

def misclassification_error(y_true: np.ndarray, y_pred: np.ndarray, normalize: bool = True) -> float:
    """
    Calculate misclassification loss

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values
    normalize: bool, default = True
        Normalize by number of samples or not

    Returns
    -------
    Misclassification of given predictions
    """
    misclassification_amount = 0
    for i in range(y_true.size):
        if y_true[i] != y_pred[i]:
            misclassification_amount += 1
    if normalize:
        misclassification_amount /= y_true.size
    return misclassification_amount

def accuracy(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate accuracy of given predictions

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    Accuracy of given predictions
    """
    return 1 - misclassification_error(y_true, y_pred, True)

def cross_entropy(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate the cross entropy of given predictions

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    Cross entropy of given predictions
    """
    raise NotImplementedError()

if __name__ == '__main__':
    y_true = np.array([279000, 432000, 326000, 333000, 437400, 555950])
    y_pred = np.array(
        [199000.37562541, 452589.25533196, 345267.48129011, 345856.57131275, 563867.1347574, 395102.94362135])
    print(mean_square_error(y_true, y_pred))


import numpy as np
import math

# gradient_descent_logistic_regresion
# Teta :
#   - is features vector : teta_0,teta_1,....,teta_n .
#   - Teta is column vector (n+1)x1 (n+1 is the number of features)
# X :
#   - a matrix [X0,X1,X2,....,Xn].
#   - each X0,X1,X2,....,Xn is a column vector mx1
#   - m is number of data set points.
#   - X is mx(n+1).
#   - Notice that X0 is always 1
# X*Teta :
#   - is : teta0*X0 + teta1*X1 + ….. +teta_n*Xn
#   - X*Teta is a column vector mx1
def gradient_descent_logistic_regresion (Teta,X,Y,alfa):
  m = Y.size
  H_linear_regression =  np.dot(X,Teta)
  H = sigmoid(H_linear_regression)
  E = H - Y
  dJ_to_dTeta = np.dot(E, X)
  Teta = Teta - alfa * dJ_to_dTeta
  j_vec = Y * np.log(H) + (1-Y)*np.log(1-H)
  J = (-1/m)*np.sum(j_vec)
  return {"Teta" : Teta , "J" : J}

# gradient_descent_linear_regresion
# Teta :
#   - is features vector : teta_0,teta_1,....,teta_n .
#   - Teta is column vector (n+1)x1 (n+1 is the number of features)
# X :
#   - a matrix [X0,X1,X2,....,Xn].
#   - each X0,X1,X2,....,Xn is a column vector mx1
#   - m is number of data set points.
#   - X is mx(n+1).
#   - Notice that X0 is always 1
# X*Teta :
#   - is : teta0*X0 + teta1*X1 + ….. +teta_n*Xn
#   - X*Teta is a column vector mx1
def gradient_descent_linear_regresion (Teta,X,Y,alfa):
  m = Y.size
  H_linear_regression =  np.dot(X,Teta)
  E = H_linear_regression - Y
  dJ_to_dTeta = (1/m)*np.dot(E, X)
  Teta = Teta - alfa * dJ_to_dTeta
  J = np.dot(E,E)/(2*m)
  return {"Teta" :  Teta , "J" : J}

# cost_function_logistic_regression_J
# Teta :
#   - is features vector : teta_0,teta_1,....,teta_n .
#   - Teta is column vector (n+1)x1 (n+1 is the number of features)
# X :
#   - a matrix [X0,X1,X2,....,Xn].
#   - each X0,X1,X2,....,Xn is a column vector mx1
#   - m is number of data set points.
#   - X is mx(n+1).
#   - Notice that X0 is always 1
# X*Teta :
#   - is : teta0*X0 + teta1*X1 + ….. +teta_n*Xn
#   - X*Teta is a column vector mx1
def cost_function_logistic_regression_J(Teta,X,Y):
    m = Y.size
    H_linear_regression =  np.dot(X,Teta)
    H = sigmoid(H_linear_regression)
    j_vec = Y * np.log(H) + (1-Y)*np.log(1-H)
    J = (-1/m)*np.sum(j_vec)
    return J

# cost_function_linear_regression_J
# Teta :
#   - is features vector : teta_0,teta_1,....,teta_n .
#   - Teta is column vector (n+1)x1 (n+1 is the number of features)
# X :
#   - a matrix [X0,X1,X2,....,Xn].
#   - each X0,X1,X2,....,Xn is a column vector mx1
#   - m is number of data set points.
#   - X is mx(n+1).
#   - Notice that X0 is always 1
# X*Teta :
#   - is : teta0*X0 + teta1*X1 + ….. +teta_n*Xn
#   - X*Teta is a column vector mx1
# lamda :
#   - is a scalar which is regularization parameter used for over fitting
#   - by default there is no regularization thus lambda is zero
def cost_function_linear_regression_J(Teta,X,Y,lamda=0):
    m = Y.size
    H_linear_regression =  np.dot(X,Teta)
    E = Y - H_linear_regression
    J = np.dot(E,E)/(2*m)
    if (lamda > 0):
      # regulrization does not affect Teta[0]
      J += lamda*np.dot(Teta[1:],Teta[1:])/(2*m)

    return J

def sum_square_residuals(y,h):
    """compute sum of square residuals

    Args:
        y ([number]): actual , m x 1
        h ([number]): hypothesis , m x 1

    Returns:
        number: sum over all m points (y[i] - h[i])^2
    """
    residual = y - h
    # this sum (y[i]-h[i])^2 over all items or using vector notation (y-h)^2
    ssr = np.dot(residual,residual)
    return ssr

def softplus(val):
    return np.log(1+np.exp(val))

# it turns out that the derivative to softplus is exactly sigmoid
# check here(https://medium.com/@abhinavr8/activation-functions-neural-networks-66220238e1ff#:~:text=Softplus%20function%3A%20f(x),also%20called%20the%20logistic%20function.)
def dsoftplus_to_dval(val):
    return sigmoid(val)

def sigmoid(val):
    return 1/(1+np.exp(-val))

def dsigmoid_to_dval(val):
    sig = sigmoid(val)
    return sig * (1 - sig)

# return 0 or 1
def sigmoid_binari(val):
    sig = 1/(1+np.exp(-val))
    return 1 if sig >= 0.5 else 0

# return 0 or 1
def neuron(Teta,X):
  val = np.dot(Teta,X)
  return sigmoid_binari(val)

# a, b : 0,1
def logical_and(a,b):
  Teta = np.array([-30 , 20 , 20 ])
  X = np.array([1 , a , b ])
  return neuron(Teta,X)

NUMERICAL_DERIVATIVE_EPS = 0.001

def compute_numerical_derivative(func_value_plus_eps,func_value_minus_eps,eps = NUMERICAL_DERIVATIVE_EPS):
  return (func_value_plus_eps - func_value_minus_eps) / (2*eps)

# compute_X_with_normalization_for_polynom
# e.g. for order 2 X before normalization is [X0,X1,np.power(X1,2)]
# normalization is done for all Xi (i != 0)
#
# X1    :
#   - column vector mx1
# order :
#   - order of the polynom
#   - order must be > 1
# X     :
#   - a matrix [X0,X1,X2,....,Xn]
#   - each X0,X1,X2,....,Xn is a column vector mx1
#   - m is number of data set points.
#   - X is mx(n+1)
#   - Notice that X0 is always 1
def compute_X_with_normalization_for_polynom(X1,order):
  if(order < 1):
    raise Exception("order must be > 1")

  m = X1.size
  X0 = np.ones(m)
  X= np.vstack((X0,normalize(X1)))

  temp_pow = 2
  while (temp_pow <= order):
    Xi = np.power(X1,temp_pow)
    Xi = normalize(Xi)
    X= np.vstack((X,Xi))
    temp_pow += 1

  return X.T

# normalize a 1d array in general to -0.5 : 0.5
def normalize(v1d):
  v1d_range = np.amax(v1d) - np.amin(v1d)
  v1d_mean = np.mean(v1d)
  return (v1d-v1d_mean)/v1d_range if v1d_range > 0 else v1d

def normal_dist(sample_x,x):
    mean_x = np.mean(x)
    variance_x = np.var(x)
    return normal_dist_short(sample_x,mean_x,variance_x)

def normal_dist_short(sample_x,mean_x,variance_x):
    delta = sample_x - mean_x
    p = (1/math.sqrt(2*math.pi*variance_x))*math.exp(-math.pow(delta,2)/(2*variance_x))
    return p

# actual and estimated are 1
def true_positive(actual,estimated):
  mul = actual * estimated
  return np.sum(mul) # sum 1

# actual is 0 but estimated is 1
def false_positive(actual,estimated):
  ar_index_estimated_1 = np.where(estimated == 1)[0]
  actual_slice = actual[ar_index_estimated_1]
  actual_slice_0 = np.where(actual_slice == 0)[0]
  num_actual_slice_0 = len(actual_slice_0)
  return num_actual_slice_0

# actual is 1 but estimated is 0
def false_negative(actual,estimated):
  ar_index_actual_1 = np.where(actual == 1)[0]
  estimated_slice = estimated[ar_index_actual_1]
  estimated_slice_0 = np.where(estimated_slice == 0)[0]
  num_estimated_slice_0 = len(estimated_slice_0)
  return num_estimated_slice_0

def precision(actual,estimated):
    tp = true_positive(actual,estimated)
    fp = false_positive(actual,estimated)
    return tp/(tp+fp)

def recall(actual,estimated):
    tp = true_positive(actual,estimated)
    fn = false_negative(actual,estimated)
    return tp /(tp + fn)

def F1score(actual,estimated):
    prec = precision(actual,estimated)
    rec = recall(actual,estimated)
    return 2*prec*rec/(prec+rec)

def symetric_random(val_max):
  """[summary]
  get a random number [-val_max , val_max]

  Args:
      val_max (number): [description]

  Returns:
      [type]: [description]
  """
  return np.random.rand()*2*val_max - val_max

def random_normal_distribution():
    return np.random.normal()

def linear_line(x,w,b):
    return w * x + b


"""

https://apmonitor.com/pdc/index.php/Main/TransferFunctions

"""

import sympy as sym
from sympy.abc import s,t,x,y,z
import numpy as np
from sympy.integrals import inverse_laplace_transform
import matplotlib.pyplot as plt

# Define inputs
# First step (up) starts at 1 sec
U1 = 2/s*sym.exp(-s)
# Ramp (down) starts at 3 sec
U2 = -1/s**2*sym.exp(-3*s)
# Ramp completes at 5 sec
U3 = 1/s**2*sym.exp(-5*s)

# Transfer function
G = 5*(s+1)/(s+3)**2

# Calculate responses
Y1 = G * U1
Y2 = G * U2
Y3 = G * U3

# Inverse Laplace Transform
u1 = inverse_laplace_transform(U1,s,t)
u2 = inverse_laplace_transform(U2,s,t)
u3 = inverse_laplace_transform(U3,s,t)
y1 = inverse_laplace_transform(Y1,s,t)
y2 = inverse_laplace_transform(Y2,s,t)
y3 = inverse_laplace_transform(Y3,s,t)
print(u1)
print(u2)
print(u3)
print(y1)
print(y2)
print(y3)

# generate data for plot
tm = np.linspace(0,8,100)
us = np.zeros(len(tm))
ys = np.zeros(len(tm))

# substitute numeric values for u and y
for u in [u1,u2,u3]:
    for i in range(len(tm)):
        us[i] += u.subs(t,tm[i])
for y in [y1,y2,y3]:
    for i in range(len(tm)):
        ys[i] += y.subs(t,tm[i])

# plot results
plt.figure()
plt.plot(tm,us,label='u(t)')
plt.plot(tm,ys,label='y(t)')
plt.legend()
plt.xlabel('Time')
plt.show()


from __future__ import division
from builtins import range
from past.utils import old_div
import numpy as np

def solver(I, V, m, b, s, F, t, damping='linear'):
    """
    Solve m*u'' + f(u') + s(u) = F for time points in t.
    u(0)=I and u'(0)=V,
    by a central finite difference method with time step dt.
    If damping is 'linear', f(u')=b*u, while if damping is
    'quadratic', we have f(u')=b*u'*abs(u').
    s(u) is a Python function, while F may be a function
    or an array (then F[i] corresponds to F at t[i]).
    """
    N = t.size - 1              # No of time intervals
    dt = t[1] - t[0]            # Time step
    u = np.zeros(N+1)           # Result array
    b = float(b)                # Avoid integer division
    m = float(m)                # Avoid integer division

    # Convert F to array
    if callable(F):
        F = F(t)
    elif isinstance(F, (list, tuple, np.ndarray)):
        F = np.asarray(F)
    else:
        raise TypeError(
            'F must be function or array, not %s' % type(F))

    u[0] = I
    if damping == 'linear':
        u[1] = u[0] + dt*V + dt**2/(2*m)*(-b*V - s(u[0]) + F[0])
    elif damping == 'quadratic':
        u[1] = u[0] + dt*V + \
               dt**2/(2*m)*(-b*V*abs(V) - s(u[0]) + F[0])
    else:
        raise ValueError('Wrong value: damping="%s"' % damping)

    for n in range(1, N):
        if damping == 'linear':
            u[n+1] = old_div((2*m*u[n] + (b*dt/2 - m)*u[n-1] +
                              dt**2*(F[n] - s(u[n]))), (m + b*dt/2))
        elif damping == 'quadratic':
            u[n+1] = old_div((2*m*u[n] - m*u[n-1] + b*u[n]*abs(u[n] - u[n-1])
                              - dt**2*(s(u[n]) - F[n])),
                             (m + b*abs(u[n] - u[n-1])))
    return u, t

# Simplified implementation
from numpy import *

def solver_linear_damping(I, V, m, b, s, F, t):
    N = t.size - 1              # No of time intervals
    dt = t[1] - t[0]            # Time step
    u = zeros(N+1)              # Result array
    u[0] = I
    u[1] = u[0] + dt*V + dt**2/(2*m)*(-b*V - s(u[0]) + F[0])

    for n in range(1, N):
        u[n+1] = 1./(m + b*dt/2)*(2*m*u[n] +
                                  (b*dt/2 - m)*u[n-1] + dt**2*(F[n] - s(u[n])))
    return u


'''
Implementation of the nDCG metric for ranking evaluation.

Balazs Kovacs, 2017
'''

import numpy as np

def dcg(rel_scores, k=None, use_exp=False):
    '''
    Computes the DCG metric as defined in https://en.wikipedia.org/wiki/Discounted_cumulative_gain

    :param rel_scores: List of relevance scores.
    :param k: We will compute DCG@k. If k is None, we will set it to
    len(rel_scores).
    :param use_exp: If True, we use 2 ** (relevance score) - 1 in the numerator
    instead of (relevance score).

    :returns: The DCG score of the input
    '''

    if k is None:
        k = len(rel_scores)

    rel_scores = np.array(rel_scores, dtype=float)[:k]
    if use_exp:
        num = 2 ** rel_scores - 1
    else:
        num = rel_scores

    den = np.log2(np.arange(k) + 2)
    return np.sum(num / den)

def ndcg(rel_scores, k=None, use_exp=False):
    '''
    Computes the nDCG metric as defined in https://en.wikipedia.org/wiki/Discounted_cumulative_gain#Normalized_DCG

    :param rel_scores: List of relevance scores.
    :param k: We will compute nDCG@k. If k is None, we will set it to
    len(rel_scores).
    :param use_exp: If True, we use 2 ** (relevance score) - 1 in the numerator
    instead of (relevance score).

    :returns: The nDCG score of the input
    '''

    if k is None:
        k = len(rel_scores)

    dcg_val = dcg(rel_scores=rel_scores, k=k, use_exp=use_exp)
    idcg_val = dcg(rel_scores=sorted(rel_scores, reverse=True), k=k, use_exp=use_exp)

    return dcg_val / idcg_val

#if __name__ == '__main__':
    #r = [3, 2, 3, 0, 1, 2]
    #for use_exp in [False, True]:
        #print dcg(rel_scores=r, use_exp=use_exp)
        #print ndcg(rel_scores=r, use_exp=use_exp)


import numpy as np

def solve(A):
	u = np.random.random(A.shape[0])
	lmd, lmd_old = 1e10, 0
	cnt = 0
	while abs(lmd - lmd_old) >= 1e-5:
		lmd_old = lmd
		v = A.dot(u)
		lmd = abs(v).max()
		u = v / lmd
		cnt += 1
	x = u
	return x, lmd, cnt

def gen51():
	print('t51 result'.center(30, '-'))
	A = np.array([
		[5, -4, 1],
		[-4, 6, -4],
		[1, -4, 7]
		])
	B = np.array([
		[25, -41, 10, -6],
		[-41, 68, -17, 10],
		[10, -17, 5, -3],
		[-6, 10, -3, 2]
		])
	xa, la, ca = solve(A)
	print('x_A:', xa, '\nlambda_A:', la, ', cnt_A:', ca)
	xb, lb, cb = solve(B)
	print('x_B:', xb, '\nlambda_B:', lb, ', cnt_B:', cb)
	print('end t51'.center(30, '-')+'\n')

if __name__ == '__main__':
	gen51()


# -*- coding: utf-8 -*-
"""
Created on Mon Dec 18 08:31:26 2017

@author: ASUS
"""

import tensorflow as tf;
import numpy as np;

# In[]
a = np.array([[1.0, 2.0], [3.0, 4.0]])

with tf.Session() as sess:
    print('total mean:',  sess.run(tf.reduce_mean(a)) ) #  (1+2+3+4)/4 = 2.5
    print('mean by column:', sess.run(tf.reduce_mean(a, axis=0))  ) # [(1+3)/2, (2+4)/2] = [2, 3]
    print('mean by row:', sess.run(tf.reduce_mean(a, axis=1))  ) # [(1+2)/2, (3+4)/2] = [1.5, 3.5]

    print('total sum:',  sess.run(tf.reduce_sum(a)) ) #  (1+2+3+4) = 10
    print('sum by column:', sess.run(tf.reduce_sum(a, axis=0))  ) # [1+3, 2+4] = [4, 6]
    print('sum by row:', sess.run(tf.reduce_sum(a, axis=1))  ) # [1+2, 3+4)] = [3, 7]

# In[]
# tf.equal(x, y, name=None) - Returns the truth value of (x == y) element-wise.
a = tf.constant([1, 2], tf.int32)
b = tf.constant([2, 2], tf.int32)
with tf.Session() as sess:
    print(sess.run(tf.equal(a, b))) # [False  True]

# In[]

x = tf.constant(["hehe", "haha", "hoho", "kaka"], tf.string)
y = tf.constant("hoho", tf.string)
with tf.Session() as sess:
    print(sess.run(tf.equal(x, y))) # [False False  True False]

# In[]
#  tf.argmax(input, axis=None, name=None, dimension=None): find index of the max value in input by axis
a = [[1,3,4,5,6]]
b = [[1,3,4], [2,4,1]]

with tf.Session() as sess:
    print(sess.run(tf.argmax(a, 1))) # 4
    print(sess.run(tf.argmax(b, 1))) # [2,1]

# In[]
#  tf.cast(x, dtype, name=None): transfer x to dtype
a = tf.convert_to_tensor(np.array([[1, 1, 2, 4], [3, 4, 5, 6]]))

with tf.Session() as sess:
    print(a.dtype)
    b = tf.cast(a, tf.float32)
    print(b.dtype)

# In[]
   # tf.truncated_normal(shape, mean, stddev): mean - 2*std <= normal(mean, std) <= mean + 2*std
shape = ([2, 2, 3, 1]) #
a = tf.truncated_normal(shape=shape, mean=0,  stddev=0.1)

with tf.Session() as sess:
    print (sess.run(a))


'''
softmax
'''

import sys
import numpy as np

def softmax(a):
    '''
    softmax function
    '''
    c = np.max(a)
    exp_a = np.exp(a - c)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y

def main():
    '''
    main function
    '''
    a = np.array([0.3, 2.9, 4.0])
    print(softmax(a))
    return

if __name__ == '__main__':
    sys.exit(main())


# Simulate a Poisson point process on the surface of a n-dimensional
# ball (that is, a (n-1)-dimensional sphere).
# Author: H. Paul Keeler, 2020.
# Website: hpaulkeeler.com
# Repository: github.com/hpaulkeeler/posts
# For more details, see the post:
# hpaulkeeler.com/simulating-a-poisson-point-process-on-a-n-dimensional-sphere/

import numpy as np;  # NumPy package for arrays, random number generation, etc
from scipy.special import gamma, factorial #gamma function
from numpy import linalg as la #linear algebra pack
import matplotlib.pyplot as plt  # for plotting
from mpl_toolkits import mplot3d

plt.close('all');  # close all figures

numbDim=2; #number of dimensions of embedding (regular sphere numbDim=3)

r=1.7; #radius of sphere

#Point process parameters
lambda0=5; #intensity (ie mean density) of the Poisson process

#surface area of d-dimensional ball
areaTotal=2*np.pi**(numbDim/2)*r**(numbDim-1)/gamma(numbDim/2);

measureTotal=areaTotal*lambda0; #total measure

#Simulate Poisson point process
numbPoints=np.random.poisson(measureTotal);#Poisson number of points

xxRand=np.random.normal(0,1,size=(numbPoints,numbDim));
normRand=la.norm(xxRand,2,1); #Euclidean norms
xxRandBall=xxRand/normRand[:,None]; #rescale by Euclidean norms
xxRandBall=r*xxRandBall; #rescale for non-unit sphere

##Plotting
if numbDim==2:
    #disk
    xx= xxRandBall[:,0];
    yy= xxRandBall[:,1];
    plt.scatter(xx, yy, edgecolor='b', facecolor='b');
    plt.xlabel('x');
    plt.ylabel('y');
    plt.axis('equal');

if numbDim==3:
    #sphere
    xx= xxRandBall[:,0];
    yy= xxRandBall[:,1];
    zz= xxRandBall[:,2];
    fig = plt.figure()
    ax = plt.axes(projection='3d')
    ax.scatter3D(xx, yy,zz,color='b');
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')

    #control ticks on x,y,z axes
    plt.locator_params(axis='x', nbins=5);
    plt.locator_params(axis='y', nbins=5);
    plt.locator_params(axis='z', nbins=5);

    #create mesh to plot the outline of a sphere
    numbMesh=20;
    thetaMesh, phiMesh = np.meshgrid(np.linspace(0,np.pi,numbMesh), np.linspace(0,2*np.pi,numbMesh))
    #convert to Cartesian coordinates
    xMesh = r * np.cos(thetaMesh)*np.sin(phiMesh)
    yMesh  = r * np.sin(thetaMesh)*np.sin(phiMesh)
    zMesh  = r * np.cos(phiMesh)

    #do a surface plot with a clear faces (ie alpha=0)
    ax.plot_surface(xMesh, yMesh, zMesh, edgecolor='k',alpha=0)


'''
Resilience
Problem 243
'''

from fractions import Fraction
from itertools import combinations
from time import time

import numpy as np
from numba import jit

f0 = Fraction(15499, 94744)

@jit
def get_primes(n):
    arr = np.ones(n + 1, "?")
    arr[0], arr[1] = False, False
    for i in range(2, n + 1):
        if arr[i] == 1:
            arr[i * i:n + 1:i] = False
    return arr.nonzero()[0]

@jit
def get_prime_factors(d):
    factors = []
    a = d
    for p in primes:
        if (p * p) > a:
            if a > 1:
                factors.append(a)
            break
        elif a % p == 0:
            factors.append(p)
            while (a % p == 0):
                a = a // p

    return factors

def non_coprime_cnt(d, factors):
    '''
        Using Euler's Totient Function
    '''
    cnt = d
    for p in factors:
        cnt = (cnt // p) * (p - 1)

    return cnt

def non_coprime_cnt_1(d, factors):
    '''
        Using set inclusion exclusion principle
    '''
    cnt = 0
    nf = len(factors)
    action = -1
    for size in range(1, nf + 1):
        action = action * (-1)
        for f_set in combinations(factors, size):
            mul = 1
            for f in f_set:
                mul *= f
            s_cnt = (d // mul) - 1

            cnt += action * s_cnt

    return cnt

def compute_resilance(d):
    factors = get_prime_factors(d)

    if factors[0] == d:
        return Fraction(1)

    return Fraction(non_coprime_cnt(d, factors), d - 1)

if __name__ == "__main__":

    primes = get_primes(10**4)
    print("Primes computed")

    # Test
    # print(compute_resilance(10))
    # print(compute_resilance(11))
    # print(compute_resilance(12))
    # print(compute_resilance(20))

    x = 2 * 3 * 5 * 7 * 11 * 13 * 17
    print("x {:,}".format(x))
    step = 10 ** 8
    next_stop = step
    min_i, min_f = 0, Fraction(1, 1)

    for i in range(x, 10**10, x):
        f = compute_resilance(i)

        if f < min_f:
            min_f = f
            min_i = i

        if f < f0:
            print("\n" + "=" * 80)
            print("solution found !!! ", i)
            print("Found : {:,} !!!. Ressilance factor {:.15f}".format(
                i, float(f)))
            print("=" * 80 + "\n")
            break

        if i >= next_stop:
            print("Current i: {:,} ,required factor: {:.15f} min_i: {:,} min_f : {:.15f} ".format(
                i, float(f0), min_i, float(min_f)))
            next_stop = i + step

    print("Done")


from sympy.solvers import solve
from sympy.abc import x
from sympy import *

def getDeepDotQuality(func, arg, val, n = 3):
  dy = func.diff(arg)
  dyn = dy.subs(arg, val).evalf()
  if (dyn == 0):
    return getDeepDotQuality(dy, arg, val, n+1)
  elif (n % 2 == 1):
    return 'has an inflection point'
  elif (dyn > 0):
    return 'is min'
  else:
    return 'is max'
  return 'aaaaaa'

def getDotQuality(func, arg, val):
  dy = func.subs(arg, val).evalf()
  if (dy > 0):
    return 'is min'
  elif (dy < 0):
    return 'is max'
  else:
    return getDeepDotQuality(func, arg, val)

def findExtremums(func, arg):
  dy = func.diff(arg)
  ddy = dy.diff(arg)
  extremums = solve(dy, arg)

  maxValues = []
  minValues = []
  wat = []

  for val in extremums:
    if getDotQuality(ddy, arg, val) == "is max":
      val = float(simplify(sympify(val)).evalf())
      maxValues.append(val)
    elif getDotQuality(ddy, arg, val) == "is min":
      val = float(simplify(sympify(val)).evalf())
      minValues.append(val)
    elif getDotQuality(ddy, arg, val) == "has an inflection point":
      val = float(simplify(sympify(val)).evalf())
      wat.append(val)

  return maxValues, minValues, wat

if __name__ == "__main__":
  # findExtremums(x**2, x)
  # findExtremums(x**3 - 2*x**2 + x + 1, x)
  # findExtremums(2*x**4, x)
  # findExtremums(2*x**3, x)
  max1, min1 = findExtremums(E**x**2-4*x,x)
  print(max1)
  #print(type(max1[0]))
  print(min1)
  print(type(min1[0]))


#codes are seperated by """ as multiline comments

"""
import numpy as np
defsample_z_score(mean_old_sample, mean_sample,std, size):
tmp = (mean_old_sample-mean_sample)/(std/np.sqrt(size))
    return tmp
answer = sample_z_score(120,110,20,25)
"""

"""
import numpy as np
defstandard_error(std, size):
tmp = std/np.sqrt(size)
    return tmp
answer = standard_error(0.284,10)
"""

"""
import numpy as np
import scipy.stats as stats
import random

#Generating Sample Population Ages have to mean like35 and 150000 data points. Package scipy is used for dummy data generation. We have passed the mean, the size, and the shift provided to the distribution.
population_ages1 = stats.poisson.rvs(loc=18, mu=35, size=150000)

#Generating Sample Population Ages having mean as 10 and 100000 data points
population_ages2 = stats.poisson.rvs(loc=18, mu=10, size=100000)

# Concatenating the two samples to generate one combined sample
population_ages = np.concatenate((population_ages1, population_ages2))

#Let’s take 500 sample ages from the above population decided
sample_ages = np.random.choice(a= population_ages, size=500)

print("The Sample Mean is", sample_ages.mean())
print("The Population Mean is", population_ages.mean())
print("The Difference between both the means is: ", population_ages.mean() - sample_ages.mean())

std = np.std(sample_ages)
se = standard_error(std, len(sample_ages))
print("Standard Error for the Sample is", se)
print("************************")
print("%f percentage of the mean is the Standard Error, therefore it is quite precise" %((se)/sample_ages.mean()))
"""