### Calculate Integrals ###
import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate

#_______________________________ QUAD INT ____________________________________#
from scipy.integrate import quad # También podemos usar trapz, simps

## Define function ##
def fun(x):
    return x * np.sin(x)

## Plot graph ##
x = np.linspace(0,10,100)
y = fun(x)
with plt.style.context('seaborn-notebook'):
    # título
    plt.title('$y = x sin(x)$', fontsize = 25)

    # pintando la línea
    plt.plot(x,y, linewidth = 2)

    # pintando el relleno
    x_fill = np.linspace(2,9,100)
    y_fill = fun(x_fill)
    plt.fill_between(x_fill, y_fill, color='gray', alpha=0.5)

    # poniendo la cuadrícula
    plt.grid()

## Integrate with quad ##
# Integremos la función en el intervalo [2,9]. Recuerda que esto te calcula la integral, no el area:

value, err = quad(fun, 2, 9)
print("El resultado es: ", value, "con un error de: ", err)

#___________________________SIMPSONS & TRAPEZOID______________________________#
x = np.linspace(2,9,100)

value = integrate.trapz(fun(x), x)

print("El resultado es: ", value)

x = np.linspace(2,9,100)

value = integrate.simps(fun(x), x)

print("El resultado es: ", value)


#Basic Libraries Import
import numpy as np
import scipy as sc
import matplotlib.pyplot as plt

from sklearn.datasets import make_circles

#Dataset
print("Original Dataset")

n = 500
p = 2

X, Y = make_circles(n_samples=n, factor=0.5, noise=0.05)

Y = Y[:, np.newaxis]

plt.scatter(X[Y[:, 0] == 0, 0], X[Y[:, 0] == 0, 1], c="blue")
plt.scatter(X[Y[:, 0] == 1, 0], X[Y[:, 0] == 1, 1], c="red")
plt.axis("equal")
plt.show()

#Neural Network
  #Neural Layers
  class neural_layer():
  def __init__(self, n_conn, n_neur, act_f):
    self.act_f = act_f
    self.b = np.random.rand(1, n_neur) * 2 - 1
    self.W = np.random.rand(n_conn, n_neur) * 2 - 1

  #Activation Function
    #Sigmoid Function
      #Function
      sigm = (
        lambda x: 1 / (1 + np.e ** (-x)),
        lambda x: x * (1 - x)
        )

      #Variables
      rang = np.linspace(-5, 5, 100)
      sigm_func = sigm[0](rang)
      sigm_derv = sigm[1](rang)

      #Graph Plotting
      fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(15,5))
      axes[0].plot(rang, sigm_func)
      axes[1].plot(rang, sigm_derv)
      fig.tight_layout()

    #ReLu Function
      #Function
      def relu_derivate(x):
        x[x<=0] = 0
        x[x>0] = 1
        return x

      relu = (
        lambda x: x * (x > 0),
        lambda x: relu_derivate(x)
        )

      #Variables
      rang = np.linspace(-5, 5, 100)
      relu_func = relu[0](rang)
      relu_derv = relu[1](rang)

      # Graph Plotting
      fig, axes = plt.subplots(nrows=1, ncols=2, figsize =(15,5))
      axes[0].plot(rang, relu_func)
      axes[1].plot(rang, relu_derv)
      plt.show()

  #Neural Network
    #Creation
    def create_nn(topology, act_f):

      nn = []

      for l, layer in enumerate(topology[:-1]):
        nn.append(neural_layer(topology[l], topology[l+1], act_f))

      return nn

    topology = [p, 4, 8, 4, 1]

    neural_network = create_nn(topology, sigm)

    print(neural_network)

    #Training
      #Cost Function
      l2_cost = (
        lambda Yp, Yr: np.mean((Yp - Yr) ** 2),
        lambda Yp, Yr: (Yp - Yr)
      )

      #Training Process
      def train(neural_network, X, Y, l2_cost, lr=0.5, train=True):

        out = [(None, X)]

        #Forward Pass
        for l, layer in enumerate(neural_network):
          z = out[-1][1] @ neural_network[l].W + neural_network[l].b
          a = neural_network[l].act_f[0](z)

          out.append((z, a))

        if train:

          #Backward Pass
          deltas = []

          for l in reversed(range(0, len(neural_network))):

            z = out[l+1][0]
            a = out[l+1][1]

            if l == len (neural_network) -1:
              deltas.insert(0, l2_cost[1](a, Y) * neural_network[l].act_f[1](a))

            else:
              deltas.insert(0, deltas[0] @ _W.T * neural_network[l].act_f[1](a))

            _W = neural_network[l].W

            #Gradient Descent
            neural_network[l].b = neural_network[l].b - np.mean(deltas[0], axis=0, keepdims=True) * lr
            neural_network[l].W = neural_network[l].W - out[l][1].T @ deltas[0] * lr

        return out[-1][1]

      train(neural_network, X, Y, l2_cost, 0.5)

#Runing The Neuronal Network
import time
from IPython.display import clear_output

neural_n = create_nn(topology, sigm)

loss = []

for i in range (2500):

  #Training
  pY = train(neural_n, X, Y, l2_cost, lr=0.051)

  if i % 25 == 0:

    print (pY)

    loss.append (l2_cost[0](pY, Y))

    res = 50

    _x0 = np.linspace(-1.5, 1.5, res)
    _x1 = np.linspace(-1.5, 1.5, res)

    _Y = np.zeros((res, res))

    for i0, x0 in enumerate(_x0):
      for i1, x1 in enumerate(_x1):
        _Y[i0, i1] = train(neural_n, np.array([[x0, x1]]), Y, l2_cost, train=False)[0][0]

    plt.pcolormesh(_x0, _x1, _Y, cmap="coolwarm")
    plt.axis("equal")

    plt.scatter(X[Y[:, 0] == 0, 0], X[Y[:, 0] == 0, 1], c="blue")
    plt.scatter(X[Y[:, 0] == 1, 0], X[Y[:, 0] == 1, 1], c="red")

    clear_output(wait=True)
    plt.show()
    plt.plot(range(len(loss)), loss)
    plt.show()
    time.sleep(0.5)


# heights and positions are available as lists
positions = ['GK', 'M', 'A', 'D', 'M', 'D', 'M', 'M', 'M', 'GK']
heights = [191, 184, 185, 180, 181, 187, 170, 179, 183, 186]

# Import numpy
import numpy as np

# Convert positions and heights to numpy arrays: np_positions, np_heights
np_positions = np.array(positions)
np_heights = np.array(heights)

# Heights of the goalkeepers: gk_heights
gk_heights = np_heights[np_positions == 'GK']

# Heights of the other players: other_heights
other_heights = np_heights[np_positions != 'GK']

# Print out the median height of goalkeepers. Replace 'None'
print("Median height of goalkeepers: " + str(np.median(gk_heights)))

# Print out the median height of other players. Replace 'None'
print("Median height of other players: " + str(np.median(other_heights)))


import numpy as np
import matplotlib.pyplot as plt

def _lchirp(N, tmin=0, tmax=1, fmin=0, fmax=None):
    fmax = fmax if fmax is not None else N / 2
    t = np.linspace(tmin, tmax, N, endpoint=True)

    a = (fmin - fmax) / (tmin - tmax)
    b = (fmin*tmax - fmax*tmin) / (tmax - tmin)

    phi = (a/2)*(t**2 - tmin**2) + b*(t - tmin)
    phi *= (2*np.pi)
    return phi

def lchirp(N, tmin=0, tmax=1, fmin=0, fmax=None, zero_phase_tmin=True, cos=True):
    phi = _lchirp(N, tmin, tmax, fmin, fmax)
    if zero_phase_tmin:
        phi *= ( (phi[-1] - phi[-1] % (2*np.pi)) / phi[-1] )
    else:
        phi -= (phi[-1] % (2*np.pi))
    fn = np.cos if cos else np.sin
    return fn(phi)

f0 = 7000
f1 = 17000
samplerate = 192000
T = .004

N = int(samplerate * T)
tmin = 0
tmax = T

t = np.linspace(tmin, tmax, N, endpoint=True)
for zero_phase_min in (True, False):
    for cos in (True, False):
        x = lchirp(N=int(samplerate * T), tmin=tmin, tmax=tmax, fmin=f0, fmax=f1,
                   zero_phase_tmin=zero_phase_min, cos=cos)
        plt.plot(t, x)
        plt.title("cos={}, zero_phase_tmin={}".format(cos, zero_phase_min),
                  weight='bold', fontsize=17, loc='left')
        plt.show()


import numpy as np

def lambdas(i):
    import sympy as sm

    # Parâmetros para o sistema
    a = 1
    b = 3
    c = 1
    d = 5
    r = 0.006
    s = 4
    xr = - 1.56

    x, y, z = sm.symbols('x, y, z')

    # O sistema dinâmico a ser simulado
    fx = y - a * x ** 3 + b * x ** 2 - z + i
    fy = c - d * x ** 2 - y
    fz = r * (s * (x - xr) - z)

    # Igualar as equações do sistema a zero
    eqx = sm.Eq(fx, 0)
    eqy = sm.Eq(fy, 0)
    eqz = sm.Eq(fz, 0)

    # Resolver o sistema
    pf1, pf2, pf3 = sm.solve([eqx, eqy, eqz])

    sistema = sm.Matrix([fx, fy, fz])                # Sistema de matrizes
    jacobiano_sistema = sistema.jacobian((x, y, z))  # Jacobiano das matrizes   |A*I - lambda| = 0

    # Substituir os pontos de equilibrio no sistema das matrizes jacobianas
    jacobiano_pf1 = jacobiano_sistema.subs([(x, pf1.get(x)), (y, pf1.get(y)), (z, pf1.get(z))])
    jacobiano_pf2 = jacobiano_sistema.subs([(x, pf2.get(x)), (y, pf2.get(y)), (z, pf2.get(z))])
    jacobiano_pf3 = jacobiano_sistema.subs([(x, pf3.get(x)), (y, pf3.get(y)), (z, pf3.get(z))])

    # Printar as soluções para os lambdas de cada função em cada intensidade I
    print(f'\n', f'*'*25, f'Lambdas para I = {i}', f'*'*25)
    print(f'Lambdas para o ponto fixo 1:')
    for x in jacobiano_pf1.eigenvals():
        print(f'{x}')
    print(f'\nLambdas para o ponto fixo 2:')
    for y in jacobiano_pf2.eigenvals():
        print(f'{y}')
    print(f'\nLambdas para o ponto fixo 3:')
    for z in jacobiano_pf3.eigenvals():
        print(f'{z}')

def sist_EDO(edo, t, i):
    # Função para nos retornar a matriz do sistema a ser resolvida pela função odeint

    # Parâmetros para o sistema
    a = 1
    b = 3
    c = 1
    d = 5
    r = 0.006
    s = 4
    xr = - 1.56

    # Retorna a matriz que representa o sistema de equações
    return np.array([edo[1] - a * edo[0] ** 3 + b * edo[0] ** 2 - edo[2] + i,  # x' = y - a*x^3 + b*x^2 - z + I
                     c - d * edo[0] ** 2 - edo[1],                             # y' = c - d*x^2 - y
                     r * (s * (edo[0] - xr) - edo[2])])                        # z' = r*[s*(x - xr) - z]

def sol_EDO(i):
    # Função para resolver o sistema dinâmico que é retornado pela função sist_EDO

    from scipy.integrate import odeint
    import matplotlib.pyplot as plt
    from matplotlib.pyplot import figure

    plt.style.use('seaborn-poster')     # Estilo do plot
    tempo = np.arange(0, 1500, 0.01)    # Matriz para a iteração de tempo
    cond_inicial = np.array([0, 0, 0])  # Condições iniciais para o sistema

    # Usamos a função odeint para resolver o sistema de equações retornado pela função
    # sist_EDO utilizando o tempo e as condições iniciais e diferentes intensidades I
    solucao_edo = odeint(sist_EDO, cond_inicial, tempo, args=(i,))
    x = solucao_edo[:, 0]
    y = solucao_edo[:, 1]
    z = solucao_edo[:, 2]

    # Plot para as funções x, y e z em função do tempo
    figure(figsize=(15, 8), dpi=80)
    plt.title(f'I = {i:.2f}')
    plt.xlabel('Tempo [s]')
    plt.ylabel('Variável')
    plt.xlim(0, 1000)
    plt.ylim(-12, 4)
    plt.plot(tempo, x, label='x', linewidth=0.75)
    plt.plot(tempo, y, label='y', linewidth=0.75)
    plt.plot(tempo, z, label='z', linewidth=0.75)
    plt.legend(loc=4)
    plt.savefig(f'graficos-var-tempo/var_tempo-{i:.2f}.png')

    # # Plot para o plano de fase de y vs. x
    # figure(figsize=(15, 8), dpi=80)
    # plt.xlabel('x')
    # plt.ylabel('y')
    # plt.plot(x[36000:], y[36000:], linewidth=0.75)
    # plt.show()
    #
    # # Plot para o plano de fase de z vs. x
    # figure(figsize=(15, 8), dpi=80)
    # plt.xlabel('x')
    # plt.ylabel('z')
    # plt.plot(x[36000:], z[36000:], linewidth=0.75)
    # plt.show()
    #
    # # Plot para o plano de fase de z vs. y
    # figure(figsize=(15, 8), dpi=80)
    # plt.xlabel('z')
    # plt.ylabel('y')
    # plt.plot(y[36000:], z[36000:], linewidth=0.75)
    # plt.show()
    #
    # # Plot para o plano de fase 3D
    # figure(figsize=(15, 8), dpi=80)
    # fig = plt.figure()
    # ax = fig.gca(projection='3d')
    # ax.plot(x[36000:], y[36000:], z[36000:])
    # ax.set_xlabel("Eixo x")
    # ax.set_ylabel("Eixo y")
    # ax.set_zlabel("Eixo z")
    # ax.set_title("Atrator de Lorenz")
    # plt.show()

if __name__ == '__main__':
    # Encontrar os autovalores lambdas para diferentes intensidades I
    # lambdas(1.1)
    # lambdas(1.2)
    # lambdas(3.0)

    # Simular o sistema dinâmico para diferentes intensidades I
    # sol_EDO(1.1)
    # sol_EDO(1.2)
    # sol_EDO(3.0)

    i_range = np.arange(0, 3.1, 0.025)

    for intensidade in i_range:
        sol_EDO(intensidade)


#%%
#Importing packages
import matplotlib.pyplot as plt
import matplotlib.patches as ptch
import numpy as np
import math
from scipy.spatial.distance import euclidean
from scipy.optimize import minimize

#%%
#test dataget to make diagrams
#p,r,0 = passer, reciever, opponent
p,r,o = (2.8747200000000035, -6.010519999999998), (0.5851199999999968, -10.46928), (35.43791999999999, -2.485399999999998)
#p = (1, 1)
#r = (4, 1)
#o = (3, 0)
all_points = [p,r,o]
labels = ['p', 'r', 'o']

#%%
#function to calculate points of intersection of two circles
#source of function
#https://stackoverflow.com/questions/55816902/finding-the-intersection-of-two-circles
def get_intersections(x0, y0, r0, x1, y1, r1):
    """
    circle 1: center (x0, y0), radius r0
    circle 2: center (x1, y1), radius r1
    """
    d = math.sqrt((x1-x0)**2 + (y1-y0)**2)

    # non intersecting circles
    if d > r0 + r1 :
        raise Exception('non intersecting')
    # One circle within other
    if d < abs(r0-r1):
        raise Exception('one inside another')
    # coincident circles
    if d == 0 and r0 == r1:
        raise Exception('coincident')
    else:
        a=(r0**2-r1**2+d**2)/(2*d)
        h=math.sqrt(r0**2-a**2)
        x2=x0+a*(x1-x0)/d
        y2=y0+a*(y1-y0)/d
        x3=x2+h*(y1-y0)/d
        y3=y2-h*(x1-x0)/d

        x4=x2-h*(y1-y0)/d
        y4=y2+h*(x1-x0)/d

        return (x3, y3, x4, y4)

#%%
#Function to evaluate accuracy of gamma calculation
def obj_func(gamma, p, r, o):
    """
    gamma: value of ɣ
    p, r, o: (x,y) coordinates of pas, rec, opp
    """
    t = 0.25
    c = 4
    d = euclidean(p,r)

    R_p = gamma*d*t
    R_r = gamma*d*(1-t)
    R_a = c*d/gamma

    #get the center of the circles that form the arcs
    inters = get_intersections(p[0],p[1],(R_a-R_p),
                                r[0],r[1],(R_a-R_r))
    C_a1x, C_a1y, C_a2x, C_a2y = inters

    dist_Ca1_o = euclidean((C_a1x, C_a1y), o)
    dist_Ca2_o = euclidean((C_a2x, C_a2y), o)
    return abs(max(dist_Ca1_o, dist_Ca2_o) - R_a)

#%%
#using scipy.optimize to calculate gamma
def calc(p, r, o):
    return minimize(obj_func, args=(p,r,o), x0 = 0.5).x[0]

#%%
#Drawing diagrams
#testing gamma
t = 0.25 #scaling factor
d = euclidean(p,r) #dist btw p,r
c = 4 #other scaling factor

R_a_store = []
plot = True

#Loop to make plots for different values of gamma
for ind, gamma in enumerate(np.linspace(0.0001, 3, 5)):
    print(gamma)

    R_p = gamma*d*t
    R_r = gamma*d*(1-t)
    R_a = c*d/gamma
    R_a_store.append(R_a)

    C_a1x, C_a1y, C_a2x, C_a2y = get_intersections(p[0],p[1],(R_a-R_p), r[0],r[1],(R_a-R_r))

    dist_Ca1_o = euclidean((C_a1x, C_a1y), o)
    dist_Ca2_o = euclidean((C_a2x, C_a2y), o)

    print(abs(max(dist_Ca1_o, dist_Ca2_o) - R_a))

    if plot:
        fig, ax = plt.subplots()
        ax.set_aspect('equal')
        x = [x[0] for x in all_points]
        y = [y[1] for y in all_points]

        ax.scatter(x,y)
        C_p = plt.Circle((x[0], y[0]), R_p, fill = False)
        C_r = plt.Circle((x[1], y[1]), R_r, fill = False)
        C_a1 = plt.Circle((C_a1x, C_a1y), R_a, fill = False, color = 'red')
        C_a2 = plt.Circle((C_a2x, C_a2y), R_a, fill = False, color = 'orange')
        print(dist_Ca1_o, dist_Ca2_o, R_a)

        ax.add_patch(C_p)
        ax.add_patch(C_r)
        ax.add_patch(C_a1)
        ax.add_patch(C_a2)
        ax.text(-1,4,f'ɣ = {gamma:.2f}')
        plt.ylim(-35,35)
        plt.xlim(-20,20)

        #plt.savefig(f'C:/Users/Ayoola_PC/Documents/cap2/LaurieOnTracking/gifims/img{ind}.png')
        plt.show()

# %%


from scipy.fftpack import fft, ifft
import numpy as np
import matplotlib.pyplot as plt

t = np.linspace(0, 100, 1000, endpoint=False)
sig=[]
for t1 in t:
    if t1<20:
        sig1 = np.cos(2 * np.pi * 0.5 * t1)
        print("5",t1)
    elif t1<40:
        sig1 = np.cos(2 * np.pi * 1 * t1)
        print("10",t1)
    elif t1<60:
        sig1 = np.cos(2 * np.pi * 1.5 * t1)
        print("20",t1)
    elif t1<80:
        sig1 = np.cos(2 * np.pi * 2 * t1)
        print("30",t1)
    else:
        sig1 = np.cos(2 * np.pi * 2.5 * t1)
        print(t1)
    sig.append(sig1)

plt.plot(t, sig)
plt.axis([0, 100, -2, 2])
plt.show()

freq =fft(sig,1024)
Pyy = np.sqrt(freq*freq.conj())/1025 #np.abs(freq)/1025    #freq*freq.conj(freq)/1025
f = np.arange(1024)
plt.plot(f,Pyy)
plt.axis([0, 512, 0,0.2])
plt.show()

t1=np.linspace(0, 100, 1024, endpoint=False)
sig1=ifft(freq)
plt.plot(t1, sig1)
plt.axis([0, 100, -2, 2])
plt.show()


'''
Benchmarks for testing / comparisons
'''

import numpy as np
from freelunch.util import ZeroLengthSolutionError

# %%

class benchmark:
    '''
    base class for benchmarking functions
    '''
    default_bounds = lambda n:None
    rtm_optimum = lambda n:None

    def __init__(self, n=None):
        if n is None:
            self.n = 2
        else:
            self.n = n
        self.bounds = self.default_bounds()
        self.optimum = self.rtn_optimum()

    def __call__(self, dna):
        if len(dna) == 0:
            raise ZeroLengthSolutionError('An empty trial solution was passed')
        return self.obj(dna)

# %%

class ackley(benchmark):
    '''
    ackely function in n dimensions
    '''

    default_bounds = lambda self:np.array([[-10, 10]]*self.n)
    rtn_optimum = lambda self:np.array([0]*self.n)
    f0 = 0
    tol = 10**-2

    a,b,c = 20, 0.2, 2*np.pi
    def obj(self, dna):
        t1 = -self.a * np.exp(-self.b * (1/len(dna)) * np.sum(dna**2))
        t2 = - np.exp(1/len(dna) * np.sum(np.cos(self.c * dna)))
        t3 = self.a + np.exp(1)
        return t1 + t2 + t3

class exponential(benchmark):
    '''
    exponential function in n dimensions
    '''

    default_bounds = lambda self:np.array([[-10, 10]]*self.n)
    rtn_optimum = lambda self:np.array([0]*self.n)
    f0 = -1
    tol = 10**-3

    a = -0.5
    def obj(self, dna):
        t1 = - np.exp(self.a * np.sum(dna**2))
        return t1

class happycat(benchmark):
    '''
    happycat function in n dimensions
    '''

    default_bounds = lambda self:np.array([[-2, 2]]*self.n)
    rtn_optimum = lambda self:np.array([-1]*self.n)
    f0 = 0
    tol = None

    a = 1/8
    def obj(self, dna):
        norm = np.sum(dna**2)
        t1 = ((norm - self.n)**2)**(self.a)
        t2 = (1/self.n)*(0.5*norm + np.sum(dna)) + 0.5
        return t1 + t2

class periodic(benchmark):
    '''
    periodic function in n dimensions
    '''

    default_bounds = lambda self:np.array([[-10, 10]]*self.n)
    rtn_optimum = lambda self:np.array([0]*self.n)
    f0 = 0.9
    tol = None

    def obj(self, dna):
        t1 = np.sum(np.sin(dna)**2) +1
        t2 = - 0.1 * np.exp(-np.sum(dna**2))
        return t1 + t2


import numpy as np
import math
from scipy.special import gamma,factorial,beta
from scipy import integrate
from distributions import *

def derivative(f,x,h=0.0001): #one parameter fuction derivative
    return (f(x+h)-f(x))/h

def derivative2(f,x,h=0.0001): #Second Derivative
    return (derivative(f,x+h,h) - derivative(f,x,h))/h

def normalDistribution(x):
    return 1/np.sqrt(2*np.pi) * np.exp(-0.5*x**2)

def softmaxFuc(x):
    softmax = np.exp(x)/np.sum(np.exp(x))
    #print(softmax)
    #print(np.sum(softmax))
    return softmax

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

def log(x):
    return np.log(x)

def entropy(x):
    return -1*x*np.log(x)

def exp(x):
    return np.exp(x)

def circle(x):
    return np.sqrt(1-x**2)*randomSymbol(len(x))

def heart(x): #heart equation: x**2+ (5*y/4 - sqrt(abs(x)))**2 = 1
    a = np.sqrt(1-x**2)*randomSymbol(len(x)) + np.sqrt(abs(x))
    return a*4/5

def sawtoothWave(x): # y = t-floor(t) or y = t%1
    #return x%1
    #return x%1 + x
    #return x%1 + np.sin(x)*x
    a = 10 #perid
    return 2*(x/a - np.floor(0.5+x/a))

def powerX(x):
    #return np.power(x,x)
    return powerAX(x,x)

def powerAX(a,x):
    return np.power(a,x)

def logisticMap2(r=1.5,x0=0.8,N=10): #x:= r*x(1-x)
    maps=[]
    a = x0
    while N>0:
        #print(a,' ',end='')
        maps.append(a)
        a = r*a*(1-a)**3
        N -= 1

    return maps

def logisticMap(r=1.5,x0=0.8,N=10): #x:= r*x(1-x)
    maps=[]
    a = x0
    while N>0:
        #print(a,' ',end='')
        maps.append(a)
        a = r*a*(1-a)
        N -= 1

    return maps

def randomSymbol(length): #-1,1,1,-1,1,-1...
    f = np.zeros(length)+np.where(np.random.random(length)>0.5,1.0,-1.0)
    return f

def Divisorfunction(param): #https://en.wikipedia.org/wiki/Divisor_function#Definition
    def getDivsorList(N):
        for i in range(1,N+1):
            #print('i=',i)
            if N%i == 0:
                yield i

    N = param[0]
    p = param[1]
    def powerF(x):
        #print('x=',x,np.power(x,p))
        return np.power(x,p)

    l = list(map(powerF, list(getDivsorList(N))))
    return np.sum(l)

def EulerTotients(N=10):#https://en.wikipedia.org/wiki/Euler%27s_totient_function
    def gcd(p,q): # Create the gcd of two positive integers.
        while q != 0:
            p, q = q, p%q
        return p

    def is_coprime(x, y):
        return gcd(x, y) == 1

    def Totients(x):
        if x == 1:
            return 1
        n = [y for y in range(1,x) if is_coprime(x,y)]
        #print('n=',n)
        return len(n)

    return Totients(N)

def PrimeNumbers(N=10): #https://en.wikipedia.org/wiki/Prime-counting_function
    def isPrime(num):
        if num>1:
            for n in range(2, num):
                if (num % n) == 0:
                    return False
            return True
        return False

    def getPrime():
        for i in range(2,N+1):
            if isPrime(i):
                yield i

    l = list(getPrime())
    print('l=', len(l), l)
    return len(l)

def Mobiusfunction(N=10): #https://en.wikipedia.org/wiki/M%C3%B6bius_function
    def IsSquareFreeIntegers(x):
        for n in range(2, int(np.sqrt(x)+1)):
            if (x % n**2) == 0:
                return False
        return True

    def SquareFreeIntegers2():
        squareFreeNumbers=[]
        for val in range(1, N + 1):
            if IsSquareFreeIntegers(val):
                squareFreeNumbers.append(val)
        return squareFreeNumbers

    def SquareFreeIntegers():
        bSqure=False
        for val in range(1, N + 1):
            for n in range(2, int(np.sqrt(N)+1)):
                bSqure=False
                if (val % n**2) == 0:
                    bSqure=True
                    break
            if not bSqure:
                yield val

    def Mobius(x):
        if IsSquareFreeIntegers(x):
            nPrime = PrimeNumbers(x)
            print('x,nPrime=',x,nPrime)
            if nPrime % 2 ==0:
                return 1
            return -1
        return 0

    #squareFreeNumbers = SquareFreeIntegers2() #[i for i in SquareFreeIntegers()]
    #print('squareFreeNumbers=',len(squareFreeNumbers),squareFreeNumbers)
    #l = list(map(Mobius, [i for i in range(N)]))
    #print('l=',len(l),l)
    return Mobius(N)

def LegendreFunction(x,n=0): #https://en.wikipedia.org/wiki/Legendre_function
    if n == 0:
        return 0.5*np.log((1+x)/(1-x))
    elif n == 1:
        return x*LegendreFunction(x,0) -1 #P1(x) = x
    return ((2*n-1)/n)*x*LegendreFunction(x,n-1) - ((n-1)/n)*LegendreFunction(x,n-2)

def ScorersFunctionGi(x): #https://en.wikipedia.org/wiki/Scorer%27s_function
    def gi(t):
        return (1/np.pi)*np.sin((1/3)*t**3 + x*t)
    # return integrate.quad(gi, 0, 1)[0]
    def hi(t):
        return (1/np.pi)*np.exp((-1/3)*t**3 + x*t)

    # rGi = integrate.quad(gi, 0, np.inf,epsabs=1.49e-8,
    #                epsrel=1.49e-8, maxp1=50, limit=50)[0]
    # rHi = integrate.quad(hi, 0, np.inf,epsabs=1.49e-8,
    #                epsrel=1.49e-8, maxp1=50, limit=50)[0]
    # return rGi,rHi
    return integrate.quad(gi, 0, np.inf)[0], integrate.quad(hi, 0, np.inf)[0]

def Logarithmic_integral(x): #https://en.wikipedia.org/wiki/Logarithmic_integral_function
    def Li(t):
        return 1/np.log(t)

    return integrate.quad(Li, 0, x)[0]

def Exponential_integral(x): #https://en.wikipedia.org/wiki/Exponential_integral
    def exp_in(t):
        return -1*np.exp(-1*t)/t

    return integrate.quad(exp_in, -1*x, np.inf)[0]

def Trigonometric_integral(x): #https://en.wikipedia.org/wiki/Trigonometric_integral
    def Si(t):
        return np.sin(t)/t
    def Ci(t):
        return -1*np.cos(t)/t

    si = integrate.quad(Si, 0, x)[0]
    ci = integrate.quad(Ci, x, np.inf)[0]
    return si,ci

def KL_divergence(x):#https://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence
    p = NormalDistribution(x)
    q = NormalDistribution(x,u=1)

    def KL_integratePQ(t):
        return p*np.log(p/q)

    def KL_integrateQP(t):
        return q*np.log(q/p)

    return KL_integratePQ(x),KL_integrateQP(x)
    #return integrate.quad(KL_integrate, -100, x)[0]
    #return integrate.quad(KL_integrate, -1*np.inf, np.inf)[0]
    #return integrate.quad(KL_integrate, -3, 4)[0]


# python 3 version 1/16 - frt
import numpy as np
import matplotlib.pyplot as plt
"""
interp - Program to interpolate data using Lagrange
polynomial to fit quadratic to three data points
clear all; help interp;  % Clear memory and print header
Initialize the data points to be fit by quadratic
"""
def intrpf(xi,x,y):
    """
    Function to interpolate between data points
    using Lagrange polynomial (quadratic)
    Inputs
       x    Vector of x coordinates of data points (3 values)
       y    Vector of y coordinates of data points (3 values)
       xi   The x value where interpolation is computed
    Output
      yi   The interpolation polynomial evaluated at xi
    """

# Calculate yi = p(xi) using Lagrange polynomial
    yi = (xi-x[1])*(xi-x[2])/((x[0]-x[1])*(x[0]-x[2]))*y[0]\
    + (xi-x[0])*(xi-x[2])/((x[1]-x[0])*(x[1]-x[2]))*y[1] \
    + (xi-x[0])*(xi-x[1])/((x[2]-x[0])*(x[2]-x[1]))*y[2];
    return (yi);

x = [0.,0.,0.];
y = [0.,0.,0.]
print ('Enter data points as x,y pairs (e.g., 1,2)');
for i in range(0,3):
  temp1,temp2 =  input("Enter data points: ").split(',');
  x[i] = float(temp1);
  y[i] = float(temp2);

# Establish the range of interpolation (from x_min, x_max)
temp1,temp2 = input("Enter range of x values as x_min, x_max: ").split(',');

xr=np.array([float(temp1),float(temp2)]);
# Find yi for the desired interpolation values xi using
# the function intrpf
nplot = 100;     #% Number of points for interpolation curve
xi= np.linspace(xr[0], xr[1], nplot,endpoint=True)
yi= np.linspace(0, 0, nplot,endpoint=True)
for i in range(0,nplot):
  xi[i] = xr[0] + (xr[1]-xr[0])*(i-1)/(nplot-1);
  yi[i] = intrpf(xi[i],x,y);  #% Use intrpf function to interpolate

# Plot the curve given by (xi,yi) and mark original data points
plt.figure(1);plt.clf() # open a window and clear it
plt.plot(x,y,'*',label="Data points")
plt.plot(xi,yi,'-',label="Interpolation");
plt.xlabel('x');
plt.ylabel('y');
plt.title('Three point interpolation');
plt.legend()
plt.show()


import numpy as np

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

def sigmoid_derivative(x):
    return x * (1 - x)

training_inputs = np.array([[0, 0, 1],
                           [1, 1, 1],
                           [1, 0, 1],
                           [0, 1, 1]])

training_outputs = np.array([[0,1,1,0]]).T

np.random.seed(1)

synaptic_weights = 2 * np.random.random((3,1)) - 1

print("Random synaptic weights: ")
print(synaptic_weights)

for iteration in range(100000):
    input_layer = training_inputs
    output = sigmoid(np.dot(input_layer, synaptic_weights))
    error = training_outputs - output
    adjustments = error * sigmoid_derivative(output)
    synaptic_weights += np.dot(input_layer.T, adjustments)

print("Synaptic weights after training: ")
print(synaptic_weights)
print("Outputs after training: ")
print(output)


import numpy as np

def sphere(d):
    return np.sum([x**2 for x in d])

def sphereFn(d):
    def fn(*args):
        return sum([args[i]**2 for i in range(len(args))])
    return fn

def ackley(d, *, a=20, b=0.2, c=2 * np.pi):
    sum_part1 = np.sum([x**2 for x in d])
    part1 = -1.0 * a * np.exp(-1.0 * b * np.sqrt((1.0 / len(d)) * sum_part1))

    sum_part2 = np.sum([np.cos(c * x) for x in d])
    part2 = -1.0 * np.exp((1.0 / len(d)) * sum_part2)

    return a + np.exp(1) + part1 + part2

def ackleyFn(d, *, a=20, b=0.2, c=2 * np.pi):
    def fn(*args):
        sum_part1 = sum([args[i]**2 for i in range(len(args))])
        part1 = -1.0 * a * np.exp(-1.0 * b * np.sqrt((1.0 / d) * sum_part1))

        sum_part2 = sum([np.cos(c * args[i]) for i in range(len(args))])
        part2 = -1.0 * np.exp((1.0 / d) * sum_part2)

        return a + np.exp(1) + part1 + part2
    return fn

def rastrigin(d):
    sum_i = np.sum([x**2 - 10 * np.cos(2 * np.pi * x) for x in d])
    return 10 * len(d) + sum_i

def rastriginFn(d):
    def fn(*args):
        sum_i = sum([args[i]**2 - 10 * np.cos(2 * np.pi * args[i])
                     for i in range(len(args))])
        return 10 * d + sum_i

    return fn


#plot Bayesian updates to beta function with prior 1.4, 2.3
from scipy.stats import beta
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 1, num = 100)
plt.plot(x, beta(1.4, 2.3).pdf(x), label = "Prior = beta(1.4,2.3)")
for i in range(1,11,2):
    plt.plot(x, beta(1.4+i,2.3).pdf(x), label = "After {} heads".format(i))
for i in range(1,6,2):
    plt.plot(x, beta(1.4+i*5+10,2.3).pdf(x), label = "After {} heads".format(i*5+10))
plt.legend()
plt.title("Updates to prior distribution")
plt.show()


import silence_tensorflow.auto
import numpy as np
import tensorflow as tf
import tensorflow_probability as tfp
from scipy.special import logsumexp
import matplotlib.pyplot as plt

from tqdm import tqdm # progress-meter

# def em(dataset, n_classes, n_iterations, random_seed):
#     n_samples = dataset.shape[0]

#     np.random.seed(random_seed)

#     # Initial guesses for the parameters
#     mus = np.random.rand(n_classes)
#     sigmas = np.random.rand(n_classes)
#     class_probs = np.random.dirichlet(np.ones(n_classes))

#     for em_iter in tqdm(range(n_iterations)):
#         # E-Step
#         responsibilities = tfp.distributions.Normal(loc=mus, scale=sigmas).prob(
#             dataset.reshape(-1, 1)
#         ).numpy() * class_probs

#         responsibilities /= np.linalg.norm(responsibilities, axis=1, ord=1, keepdims=True)

#         class_responsibilities = np.sum(responsibilities, axis=0)

#         # M-Step
#         for c in range(n_classes):
#             class_probs[c] = class_responsibilities[c] / n_samples
#             mus[c] = np.sum(responsibilities[:, c] * dataset) / class_responsibilities[c]
#             sigmas[c] = np.sqrt(
#                 np.sum(responsibilities[:, c] * (dataset - mus[c])**2) / class_responsibilities[c]
#             )

#         # Calculate the marginal log likelihood
#         log_likelihood = np.sum(
#             logsumexp(
#                 np.log(class_probs)
#                 +
#                 tfp.distributions.Normal(loc=mus, scale=sigmas).log_prob(
#                     dataset.reshape(-1, 1)
#                 ).numpy()
#                 ,
#                 axis=1
#             )
#             ,
#             axis=0
#         )
#         print(log_likelihood)

#     return class_probs, mus, sigmas

def em_with_guesses(
    dataset,
    n_iterations,
    class_probs_initial,
    mus_initial,
    sigmas_initial,
):
    n_classes = class_probs_initial.shape[0]
    n_samples = dataset.shape[0]

    class_probs = class_probs_initial.copy()
    mus = mus_initial.copy()
    sigmas = sigmas_initial.copy()

    log_likelihood_history = []

    for em_iter in tqdm(range(n_iterations)):
        # E-Step
        responsibilities = tfp.distributions.Normal(loc=mus, scale=sigmas).prob(
            dataset.reshape(-1, 1)
        ).numpy() * class_probs

        responsibilities /= np.linalg.norm(responsibilities, axis=1, ord=1, keepdims=True)

        class_responsibilities = np.sum(responsibilities, axis=0)

        # M-Step
        for c in range(n_classes):
            class_probs[c] = class_responsibilities[c] / n_samples
            mus[c] = np.sum(responsibilities[:, c] * dataset) / class_responsibilities[c]
            sigmas[c] = np.sqrt(
                np.sum(responsibilities[:, c] * (dataset - mus[c])**2) / class_responsibilities[c]
            )

        # Calculate the marginal log likelihood
        log_likelihood = np.sum(
            logsumexp(
                np.log(class_probs)
                +
                tfp.distributions.Normal(loc=mus, scale=sigmas).log_prob(
                    dataset.reshape(-1, 1)
                ).numpy()
                ,
                axis=1
            )
            ,
            axis=0
        )
        log_likelihood_history.append(log_likelihood)

    return class_probs, mus, sigmas, log_likelihood_history

def em_sieved(
    dataset,
    n_classes,
    n_iterations_pre_sieving,
    n_candidates,
    n_iterations_post_sieving,
    n_chosen_ones,
    random_seed,
):

    # (1) Pre-Sieving

    mus_list = []
    sigmas_list = []
    class_probs_list = []
    log_likelihood_history_list = []

    for candidate_id in range(n_candidates):
        np.random.seed(random_seed + candidate_id)

        mus = np.random.rand(n_classes)
        sigmas = np.random.rand(n_classes)
        class_probs = np.random.dirichlet(np.ones(n_classes))

        class_probs, mus, sigmas, log_likelihood_history = em_with_guesses(
            dataset,
            n_iterations_pre_sieving,
            class_probs,
            mus,
            sigmas,
        )
        mus_list.append(mus)
        sigmas_list.append(sigmas)
        class_probs_list.append(class_probs)
        log_likelihood_history_list.append(log_likelihood_history)

    # (2) Sieving, select the best candidates
    log_likelihood_history_array = np.array(log_likelihood_history_list)

    # Sort in descending order
    ordered_candidate_ids = np.argsort( - log_likelihood_history_array[:, -1])
    chosen_ones_ids = ordered_candidate_ids[:n_chosen_ones]

    # (3) Post-Sieving
    mus_chosen_ones_list = []
    sigmas_chosen_ones_list = []
    class_probs_chosen_ones_list = []
    log_likelihood_history_chosen_ones_list = []
    for chosen_one_id in chosen_ones_ids:
        class_probs, mus, sigmas, log_likelihood_history = em_with_guesses(
            dataset,
            n_iterations_post_sieving,
            class_probs_list[chosen_one_id],
            mus_list[chosen_one_id],
            sigmas_list[chosen_one_id],
        )

        mus_chosen_ones_list.append(mus)
        sigmas_chosen_ones_list.append(sigmas)
        class_probs_chosen_ones_list.append(class_probs)
        log_likelihood_history_chosen_ones_list.append(log_likelihood_history)

    # (4) Select the very best candidate
    log_likelihood_history_chosen_ones_array = np.array(log_likelihood_history_chosen_ones_list)

    # Sort in descending order
    ordered_chosen_ones_ids = np.argsort( - log_likelihood_history_chosen_ones_array[:, -1])

    best_chosen_one_id = ordered_chosen_ones_ids[0]
    best_mus = mus_chosen_ones_list[best_chosen_one_id]
    best_sigmas = sigmas_chosen_ones_list[best_chosen_one_id]
    best_class_probs = class_probs_chosen_ones_list[best_chosen_one_id]

    return best_class_probs, best_mus, best_sigmas, log_likelihood_history_chosen_ones_array

def main():
    class_probs_true = [0.6, 0.4]
    mus_true = [2.5, 4.8]
    sigmas_true = [0.6, 0.3]
    random_seed = 42 # for reproducability
    n_samples = 1000
    n_iterations_pre_sieving = 5
    n_candidates = 100
    n_iterations_post_sieving = 100
    n_chosen_ones = 5
    n_classes = 2

    # generate the data
    univariate_gmm = tfp.distributions.MixtureSameFamily(
        mixture_distribution=tfp.distributions.Categorical(probs=class_probs_true),
        components_distribution=tfp.distributions.Normal(
            loc=mus_true,
            scale=sigmas_true,
        )
    )

    dataset = univariate_gmm.sample(n_samples, seed=random_seed).numpy()

    class_probs, mus, sigmas, log_likelihood_histories = em_sieved(
        dataset,
        n_classes,
        n_iterations_pre_sieving,
        n_candidates,
        n_iterations_post_sieving,
        n_chosen_ones,
        random_seed,
    )

    print(class_probs)
    print(mus)
    print(sigmas)

    plt.figure()
    for log_likelihood_history in log_likelihood_histories:
        plt.plot(log_likelihood_history)
    plt.xlabel("Iteration")
    plt.ylabel("Log Likelihood")
    plt.show()

if __name__ == "__main__":
    main()


import scipy.optimize as opt
import numpy as np
import pylab as plt

#define model function and pass independant variables x and y as a list
def twoD_Gaussian(xy, amplitude, xo, yo, sigma_x, sigma_y, theta, offset):
    x = xy[0]
    y = xy[1]
    xo = float(xo)
    yo = float(yo)
    a = (np.cos(theta)**2)/(2*sigma_x**2) + (np.sin(theta)**2)/(2*sigma_y**2)
    b = -(np.sin(2*theta))/(4*sigma_x**2) + (np.sin(2*theta))/(4*sigma_y**2)
    c = (np.sin(theta)**2)/(2*sigma_x**2) + (np.cos(theta)**2)/(2*sigma_y**2)
    g = offset + amplitude*np.exp( - (a*((x-xo)**2) + 2*b*(x-xo)*(y-yo) + c*((y-yo)**2)))
    return g.ravel()

# Create x and y indices
x = np.linspace(0, 200, 201)
y = np.linspace(0, 200, 201)
x, y = np.meshgrid(x, y)

#create data
data = twoD_Gaussian((x, y), amplitude=3, xo=100, yo=100, sigma_x=20, sigma_y=40, theta=0, offset=10)

# plot twoD_Gaussian data generated above
plt.figure()
plt.imshow(np.reshape(data, (201, 201)))
plt.colorbar()
plt.show()

# add some noise to the data and try to fit the data generated beforehand
initial_guess = (3,100,100,20,40,0,10)

data_noisy = data + 0.2*np.random.normal(size=data.shape)

popt, pcov = opt.curve_fit(twoD_Gaussian, (x, y), data_noisy, p0=initial_guess)

data_fitted = twoD_Gaussian((x, y), *popt)

fig, ax = plt.subplots(1, 1)
ax.hold(True)
ax.imshow(data_noisy.reshape(201, 201), cmap=plt.cm.jet, origin='bottom',
    extent=(x.min(), x.max(), y.min(), y.max()))
ax.contour(x, y, data_fitted.reshape(201, 201), 8, colors='w')
plt.show()


## Storing Kernels :
import numpy as np

def lin(x, y):
    print "Computing linear Kernel"
    return np.dot(x,y.T)
# Defining Gaussian Kernel
def rbf(x, y, sigma= 0.2):
    print "Computing RBF Kernel"
    z = d(x, y)
    return np.exp(-z**2/(2*(sigma**2)))

def d(x, y):
    ## Compute the matrix distance between two matrices of features
    gram_matrix = np.dot(x, y.T)

    x_norm = np.sum( np.abs(x) ** 2 , axis=1, keepdims=True)
    y_norm = np.sum( np.abs(y) ** 2 , axis=1, keepdims=True)

    d_mat = x_norm + y_norm.T - 2 * gram_matrix

    d_mat= np.sqrt(np.maximum(d_mat,0))

    return d_mat


#!/usr/bin/python3.4

import numpy as np
from numpy import *
import matplotlib.pyplot as plt
import math as m
import os
from partie1 import *

from matplotlib.pyplot import figure, show

M = np.matrix([[11,21,5,12],[48,548,16,887],[47,88,91,45],[17,32,68,17]])

def extraireVect_Col(M,n,m,i):
    #Function that extract the column vector with index i from the matrix M
    Y = np.zeros(shape=(n,1))
    for j in range(i,n): #i
        Y[j] = M[j,i]
    return Y

def extraireVect_Lig(M,n,m,i):
    #Function that extract the line vector with index i from the matrix M
    Y = np.zeros(shape=(m,1))
    for j in range(i+1,m): #i+1
        Y[j] = M[i,j]
    return Y

def genererVect(X):
    Y = np.zeros(shape=np.shape(X))
    i = 0
    while (i < np.shape(X)[0] and X[i] == 0):
        i += 1
    if (i < np.shape(X)[0]):
        Y[i] = np.linalg.norm(X)
    return Y

def BD(A):
    #Function that transforms the matrix A to a bidiagonal matrix BD and two others Qleft and Qright
    #The matrix provide A = Qleft x BD x Qright
    n,m = np.shape(A)
    Qleft = np.eye(n)
    Qright = np.eye(m)
    BD = A
    for i in range(n-1):
        X = extraireVect_Col(BD,n,m,i)
        Y = genererVect(X)
        if (np.linalg.norm(X) == 0 and np.linalg.norm(Y) == 0):
            Q1 = np.eye(X.size)
        else:
            Q1 = householder(X,Y)
        Qleft = np.dot(Qleft, Q1)
        BD = np.dot(Q1, BD)
        if (i < (m-2)):
            X2 = extraireVect_Lig(BD,n,m,i)
            Y2 = genererVect(X2)
            if (np.linalg.norm(X2) == 0 and np.linalg.norm(Y2) == 0):
                Q2 = np.eye(X2.size)
            else:
                Q2 = householder(X2,Y2)
            Qright = np.dot(Q2, Qright)
            BD = np.dot(BD, Q2)
    return (Qleft, BD, Qright)
'''
Qleft, BD2, Qright = BD(M)

A = np.dot(np.dot(Qleft,BD2), Qright)

ec_rel = np.linalg.norm(A-M)/np.linalg.norm(M)

print(A)

print(ec_rel)
'''


"""
Objective
In this challenge, we go further with Poisson distributions.

Task
The manager of a industrial plant is planning to buy a machine of either type A or type B. For each day’s operation:

The number of repairs, X, that machine A needs is a Poisson random variable with mean 0.88.
The daily cost of operating A is C_A = 160+40X^2.
The number of repairs, Y, that machine B needs is a Poisson random variable with mean 1.55.
The daily cost of operating B is C_B = 128+40Y^2.
Assume that the repairs take a negligible amount of time and the machines are maintained nightly to ensure that
they operate like new at the start of each day.
Find and print the expected daily cost for each machine.
"""

import numpy as np

def daily_cost(lam=0.88, intercept=160):
    """
    Return the expected daily cost for machine with lam and intercept
    """
    # for a poisson distribution, E(X) = lam, Var(X) = lam,
    # since E(X-E(X))^2 = E(X^2) - (EX)^2,
    # then E(X^2) = Var(X) + (EX)^2
    return intercept + 40*(lam + lam**2)

# print the expected daily cost for machine A
print(np.round(daily_cost(), 3))
# print the expected daily cost for machine B
print(np.round(daily_cost(lam=1.55, intercept=128), 3))


import numpy as np
import matplotlib.pyplot as plt
from numpy.core.multiarray import ndarray
from typing import Optional, Union, Tuple

"""
1	Topic Introduction
--------------------------
Find the depth of the water tank to be filled so it holds 30 m^3

2	Topic Theory/Approach
--------------------------
Manipulate the given function based off of the given variables and solve for the roots
when V = 30 using false position and midpoint root functions with the lower limit of 0
and upper limit as R.

3	Problems
--------------------------
    (a)	Problem Statement
You are designing a spherical tank to hold water for a small village in a developing country. The
volume of liquid it can hold can be computed as
V =          3R - h
    pi*h^2*___________
                3
Where V =volume (m3), h=depth of water in tank(m), and R=the tank radius(m). If R=3 m, to
what depth must the tank be lled so that it holds 30 m3? Calculate the answer using both the
false position and midpoint approaches. Employ a lower limit of xl = 0 and xu = R.

    (b)	Problem Approach
Enter the given variables in the function, rearrange the function to set equal to 0 and V = 30.
Graph the function to visually see how many roots there are.
Determine the solution through false position and midpoint approaches.

    (c)	Problem Results
False Position Root Estimate:	-1.64081, -0.0
False Position Root Estimate:	2.02691, 0.0
False Position Root Estimate:	8.61391, 0.0

Midpoint Root Estimate:	-1.64081, 0.0
Midpoint Root Estimate:	2.02691, 0.0
Midpoint Root Estimate:	8.61391, -0.0

    (d)	Problem Discussion of Results
I set the ranges to check:
    [-2.5, 0]
    [0, 3]
    [7.5, 10]

These results returned the roots between the lower and upper limits.
These roots demonstrate where the depth can maintain 30 m^2

"""

def false_position(f, xa, xb):
    x_lp = xa
    x_up = xb

    for i in range(1, 21, 1):
        x_rp = x_up - ((f(x_up) * (x_lp - x_up)) / (f(x_lp) - f(x_up)))
        if f(x_lp) * f(x_rp) < 0:
            x_up = x_rp
        else:
            x_lp = x_rp
    plt.plot(x_rp, f(x_rp), 'y*')
    print('False Position Root Estimate:\t' + str(round(x_rp, 5)) + ', ' + str(round(f(x_rp), 5)))

def midpoint(f, xa, xb):
    x_lower = xa
    x_upper = xb
    x_r = x_lower
    for i in range(1, 100, 1):
        x_r = ((x_upper + x_lower) / 2)
        if (f(x_lower) * f(x_r) < 0):
            x_upper = x_r
        else:
            x_lower = x_r
    plt.plot(x_r, f(x_r), 'b*')
    print('Midpoint Root Estimate:\t' + str(round(x_r, 5)) + ', ' + str(round(f(x_r), 5)))

if __name__ == "__main__":
    h: Union[ndarray, Tuple[ndarray, Optional[float]]] = np.linspace(-10, 10)

    V = lambda R, h: np.pi * h ** 2 * ((3 * R - h) / 3.0)
    V_new = lambda h: 9 * np.pi * h ** 2 - np.pi * h ** 3 - 90

    line, = plt.plot(h, V_new(h), 'r')

    false_position(V_new, -2.5, 0)
    false_position(V_new, 0, 3)
    false_position(V_new, 7.5, 10)

    midpoint(V_new, -2.5, 0)
    midpoint(V_new, 0, 3)
    midpoint(V_new, 7.5, 10)

    line.set_antialiased(False)  # turn off antialising

    plt.setp(line, 'linewidth', 2.0)
    plt.legend((line, ), ('V = pi * h ^ 2 * (3R-h/3)',))
    plt.grid(True)
    plt.show()


import numpy
from scipy.integrate import solve_ivp

def fhn(t,y, c1, c2):
    a = -0.12
    b = 0.011
    c3 = 0.55

    v = y[0]
    w = y[1]

    f0 = c1*v*(v-a)*(1-v) - c2*w
    f1 =  b*(v-c3*w)

    return [f0, f1]

# Initial parameter at the Hopf point
c1 = 0.050417
c2 = 0.05

# Initial parameter far from the Hopf point
c1 = 0.15
c2 = 0.05

# Final parameter at the Hopf point
c1 = 0.050417
c2 = 0.025736

# Final parameter far from the Hopf point
c1 = 0.15
c2 = 0.025736

# initial condition for FHN
y0 = [0.01, 0.0]  # Off into orbit
T = 2000
t = numpy.linspace(0, T, T+1)

sol = solve_ivp(fhn, [0,T], y0, args=(c1,c2), t_eval=t)
print("min_t v = ", min(sol.y[0]))
print("max_t v = ", max(sol.y[0]))

S = numpy.array([[sol.t[i], sol.y[0,i], sol.y[1,i]] for i in range(len(sol.t))])
numpy.savetxt("sol_%.3f_%.3f.csv" %(c1,c2), S, delimiter=',')

# # Plot solutions
import pylab
pylab.figure()
pylab.plot(sol.t, sol.y[0])

pylab.ylabel("v (mV)")
pylab.xlabel("t (s)")
pylab.savefig("fhn_v.png")


import numpy as np

def get_haversine(lon1, lat1, lon2, lat2, d2r):

    dlat = d2r * (lat2 - lat1)
    dlon = d2r * (lon2 - lon1)
    lt1 = d2r * lat1
    lt2 = d2r * lat2

#    a = np.sin(0.5 * dlon) * np.sin(0.5 * dlon)
#    a = a * np.cos(lt1) * np.cos(lt2)
#    a = a + (np.sin(0.5 * dlat) * np.sin(0.5 * dlat))
#    thedist = 2.0 * np.arctan2(np.sqrt(a), np.sqrt(1.0 - a))

    a = np.sin(0.5 * dlon) * np.sin(0.5 * dlon) * \
            np.cos(lt1) * np.cos(lt2) + \
            (np.sin(0.5 * dlat) * np.sin(0.5 * dlat))
    thedist = 2.0 * np.arctan2(np.sqrt(a), np.sqrt(1.0 - a))

    return thedist

def distance_vector(lon1, lat1, lon2, lat2):

    erad = 6371315.0
    d2r = np.arctan2(0.,-1.)/ 180. # atan2(0.,-1.) == pi

    m = np.shape(lon1)[0]

    dist = np.zeros((m))
    for i in range(m):
        dist[i] = get_haversine(lon1[i], lat1[i], lon2[i], lat2[i], d2r)

    dist = dist * erad

    return dist

def distance_matrix(xa, xb):

    erad = 6371315.0
    d2r = np.arctan2(0.,-1.)/ 180. # atan2(0.,-1.) == pi

    m = np.shape(xa)[1] #changed by Ben, used to be 0
    n = np.shape(xb)[1] #changed by Ben, used to be 0

    dist = np.zeros((m,n))

    for j in range(m):
        #for i in range(n):
            #dist[j,i] = get_haversine(xa[j,0], xa[j,1], xb[i,0], xb[i,1],d2r)  #fiona probably had xa and xb zipped
            #dist[j,i] = get_haversine(xa[0,j], xa[1,j], xb[0,i], xb[1,i], d2r)  #first edit by Ben
        dist[j,:] = get_haversine(xa[0,j], xa[1,j], xb[0,:], xb[1,:], d2r)  #Ben's attempt to do entire row at once

    dist = dist * erad

    return dist

def distance(lon1, lat1, lon2, lat2):

    erad = 6371315.0
    d2r = np.arctan2(0.,-1.)/ 180. # atan2(0.,-1.) == pi

    thedist = get_haversine(lon1, lat1, lon2, lat2, d2r)
    thedist = thedist * erad

    return thedist


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

train_X = np.linspace(-1, 1, 100);

train_Y = 2 * train_X + np.random.randn(*train_X.shape) * 0.3

plt.plot(train_X, train_Y, 'ro', label='Original data')
plt.legend()
plt.show()

X = tf.placeholder("float")
Y = tf.placeholder("float")

W = tf.Variable(tf.random_normal([1]), name='weight')
b = tf.Variable(tf.zeros([1]), name='bias')

z = tf.multiply(X, W) + b

cost = tf.reduce_mean(tf.square(Y - z))
learning_rate = 0.01
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)

init = tf.global_variables_initializer()

training_epochs = 20
display_step = 2

with tf.Session() as sess:
	sess.run(init)
	plotdata={"batchsize":[],"loss":[]}

	for epoch in range(training_epochs):
		for (x, y) in zip(train_X, train_Y):
			sess.run(optimizer, feed_dict={X:x, Y:y})

		if epoch % display_step == 0:
			loss = sess.run(cost, feed_dict={X:train_X, Y:train_Y})
			print ("Epoch:", epoch+1, "cost=", loss, "W=", sess.run(W), "b=", sess.run(b))

			if not (loss == 'NA'):
				plotdata['batchsize'].append(epoch)
				plotdata['loss'].append(loss)

	print ("Finished!")
	print ("cost=", sess.run(cost, feed_dict={X:train_X, Y:train_Y}),
	"W=", sess.run(W), "b=", sess.run(b))


# -*- coding:UTF8 -*-
import numpy as np
import sys,os
import math

from tools.loadData import load_array
from tools import ulti

path = os.getcwd()

# Housholder reduction
def Housholder_reduction(mat, m, n):
    p_factor = 1.
    P = np.identity(m)
    mat_A = mat.copy()
    for diag_idx in range(min(m,n)):
        A = mat_A[diag_idx:, diag_idx:].copy()
        if A.shape==(1,1):
            break
        # ulti.print_array(A,m-diag_idx,n-diag_idx)
        # 计算 u,R,和R的系数
        x = A[0:,0].copy()
        a1_norm =round(math.sqrt(np.sum(np.square(x))),4)
        e1 = np.zeros(m-diag_idx)
        e1[0] = 1
        I = np.identity(m-diag_idx)
        u = np.matrix(x - a1_norm * e1)
        r1_factor = 2/ np.matmul(u, u.T)[0,0]
        r1 = np.matmul(u,u.T)[0,0] * I / 2 - np.matmul(u.T, u)
        # ulti.print_array(r1, m-diag_idx,m-diag_idx)

        # 当前P矩阵，p_factor是其系数
        P_helper = np.round(np.identity(m) * np.matmul(u,u.T)[0,0] /2, 3)
        P_helper[diag_idx:, diag_idx:] = np.round(r1,3)
        p_factor *= round(r1_factor,3)
        P = np.round(np.matmul(P_helper,P),3)
        # print("P=")
        # ulti.print_array(p_factor*  P,m,m)

        # 矩阵mat_A = P*mat_A
        # A_factor = r1_factor
        A = np.round(np.matmul(r1_factor* r1, A),3)
        # print("A=")
        # ulti.print_array(A, m-diag_idx,n-diag_idx)

        # 把A复制到mat_A相应的位置
        # mat_A_factor *= A_factor
        # mat_A = np.matmul(u,u.T)[0,0] *mat_A /2
        mat_A[diag_idx:, diag_idx:] = A
        # print("mat_A=")
        # ulti.print_array(mat_A,m,n)
    P = np.round(p_factor *P, 3)
    T = mat_A #* mat_A_factor
    return P.T,T

if __name__ == "__main__":
    input_file=path+'/data/example2.txt'
    # output_file=''
    matrix, m, n = load_array(input_file,"HR")
    # ulti.print_array(matrix, m, n )
    if matrix.size ==0:
        print("input Error!")
        sys.exit()
    Q,R = Housholder_reduction(matrix,m,n)
    print("Q=")
    ulti.print_array(Q,m,m)
    print("R=")
    ulti.print_array(R,m,n)


import numpy as np
import cv2
# Reference : https://marcin-chwedczuk.github.io/iterative-algorithm-for-drawing-hilbert-curve

#estimate the last 2 digit's "binary AND" with 3(Binary: 11)
def LastTwoDigit(D):
    return D & 3
'''
my basic 2X2 unit
01 10
00 11   input : 00, output : 11
'''
def X_Coordinate_Hilbert(x):
    if x & 2 == 0:      #x binary and 10 == 00
        return 0
    elif x & 2 == 2:    #x binary and 10 == 10
        return 1

def y_Coordinate_Hilbert(y):
    if y & 2 == 0:      #y binary and 10 == 00
        return y & 1    #y binary and 01
    elif y & 2 == 2:    #y binary and 10 == 10
        return y ^ 3    #y binary XOR 11
'''
Hilbert function gives the corresponding coordinate of Index , N is the size of Hilbert curve
'''
def Hilbert(Index, N):
    count = Index
    '''
    Old version, if use this code, i should begin with value 4
    x = X_Coordinate_Hilbert(LastTwoDigit(Index))
    y = y_Coordinate_Hilbert(LastTwoDigit(Index))
    Index = Index >> 2
    '''
    x, y = (0, 0)
    i = 2
    while(i <= N):
        Half_Of_N = i / 2
        Case = LastTwoDigit(Index)
        if Case == 0:
            t = x
            x = y
            y = t
        elif Case == 1:
            y = y + Half_Of_N
        elif Case == 2:
            x = x + Half_Of_N
            y = y + Half_Of_N
        elif Case == 3:
            t = x
            x = -y + (Half_Of_N - 1) + Half_Of_N
            y = -t + (Half_Of_N - 1)
        Index = Index >> 2
        i *= 2
    #print("node", count,"x:", x,"y:", y)
    x, y = map(int, (x, y))
    return y, x
'''
Hilbert_Coordinate_to_Index function gives the corresponding Index of coordinate, N is the size of Hilbert curve
'''
def Hilbert_Coordinate_to_Index(x, y, N):
    Index = 0
    while(N >= 2):
        Half_Of_N = N / 2
        Cur_corr_x = 2 ** (2 * np.log2(N) - 1)
        Cur_corr_y = 2 ** (2 * np.log2(N) - 2)
        if x < Half_Of_N:
            if y < Half_Of_N:
                Index = Index + Cur_corr_x * 0 + Cur_corr_y * 0
                t = x
                x = y
                y = t
                N /= 2
                continue
            elif y >= Half_Of_N and y <= N - 1:
                Index = Index + Cur_corr_x * 0 + Cur_corr_y * 1
                y = y - Half_Of_N
                N /= 2
                continue
        elif x >= Half_Of_N and x <= N-1:
            if y >= Half_Of_N and y <= N - 1:
                Index = Index + Cur_corr_x * 1 + Cur_corr_y * 0
                x = x - Half_Of_N
                y = y - Half_Of_N
                N /= 2
                continue
            elif y < Half_Of_N:
                Index = Index + Cur_corr_x * 1 + Cur_corr_y * 1
                t = y
                y = -x + (Half_Of_N - 1) + Half_Of_N
                x = -t + (Half_Of_N - 1)
                N /= 2
                continue
    return int(Index)

'''
Main function begins
'''
N = 32
img = np.zeros((900, 900, 3), np.uint8) + 255   #make an empty image, the part "+255" is to make it white (original one is black)
Siz_Fix = int(900/N)                            #let the Hilbert curve fit the image size 900 * 900
for j in range(N*N-1):
    print('node', j, 'x:', Hilbert(j, N)[0], 'y:', Hilbert(j, N)[1])
    Start_x, Start_y = map(lambda x : x * Siz_Fix, Hilbert(j, N))
    End_x, End_y = map(lambda x : x * Siz_Fix, Hilbert(j + 1, N))
    cv2.line(img, (Start_x, 900 - Start_y), (End_x, 900 - End_y), (0, 140, 255), 3)
    cv2.imshow('Hilbert', img)
    cv2.waitKey(1)
cv2.waitKey(0)


"""
Sierpinsky triangle using chaos game
Rule:
    draw vertices of eq.triangle
    make a randon point inside triangle
    take a random vertex
    plot midpoint
    take that midpoint as next random point
    repeat
"""

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

# Comment this if you want a white backround
plt.style.use("dark_background")

N = 15000
x = np.zeros(N)
y = np.zeros(N)
c = np.zeros(N, dtype=np.object)

V = ((0, 0), (1, 0), (0.5, np.sqrt(3)/2))
p = (0.5, 0.5)

x[:3] = [j[0] for j in V]
y[:3] = [j[1] for j in V]
c[:3] = ["#FF7029","#3AFF21", "#B450C9"]

for i in range(3, N):
    n = np.random.choice([0, 1, 2])
    v = V[n]
    xm = (p[0] + v[0])/2.
    ym = (p[1] + v[1])/2.
    x[i] = xm
    y[i] = ym
    p = (xm, ym)
    c[i] = c[n]

# print(x)
# print(y)
# print(c)
fig = plt.figure(figsize = (12, 12))
plt.axis("off")
cont_index = 0
for i in tqdm(range(3, N, 50)):
    plt.scatter(x[cont_index:i], y[cont_index:i], c=c[cont_index:i], s=5)
    cont_index = i
    plt.savefig(f"images/Sierpinsky{str((i-3)//50).zfill(4)}.png")

# Note : Inorder to work this, You need to setup ffmpeg.
# Or, you can take images from images folder and make animation.
fps = 20
os.system(f'ffmpeg -r {fps} -s 1920x1080 -i "images/Sierpinsky%04d.png"\
 -vcodec libx264 -crf 20 -pix_fmt yuv420p "video/Sierpinsky.mp4"')


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

def main():
    x1 = np.random.uniform(low=-2, high=10, size=12)
    x_train = get_x_train(x1)
    y_train = get_y_train(x1)

    print_training_data(x1, y_train)

    w = linear_regression(x_train, y_train)
    best_r = determine_reg_param(x_train, y_train)
    w_reg = ridge_regression(x_train, y_train, regularizer=best_r)

    print_regression_eq('without reg', w, round(calculate_error(w, x_train, y_train), 2))
    print()
    print_regression_eq('with reg', w_reg, round(calculate_error(w_reg, x_train, y_train), 2))

    plot_exp(x1, y_train, w, w_reg)

def determine_reg_param(x_train, y_train):
    regularizers = np.array([0.1, 1, 10, 100])
    cv_error = np.zeros_like(regularizers)
    ein = np.zeros_like(regularizers)

    for i, r in enumerate(regularizers):
        w = ridge_regression(x_train, y_train, regularizer=r)
        ein[i] = calculate_error(w, x_train, y_train)
        cv_error[i] = cross_validation(x_train, y_train, 3, r)

    print_cross_validation_results(regularizers, ein, cv_error)

    return regularizers[np.argmin(cv_error)]

def print_cross_validation_results(regularizers, ein, cv_error):
    cv_summary = np.round(np.column_stack((regularizers, ein, cv_error)), 2)
    df = pd.DataFrame(cv_summary, columns=['lambda', 'in-sample error', 'cv error'])
    print(str(df))
    print('choose lambda = ' + str(regularizers[np.argmin(cv_error)]) + '\n')

def cross_validation(x_train, y_train, num_splits, regularizer):
    d = np.column_stack((x_train, y_train))
    cv_error = np.zeros(num_splits)

    for i, this_d in enumerate(np.split(d, num_splits)):
        x_train, y_train = this_d[:, :-1], this_d[:, -1]
        w = ridge_regression(x_train, y_train, regularizer)
        cv_error[i] = calculate_error(w, x_train, y_train)

    return np.average(cv_error)

def calculate_error(w, x_train, y_train):
    y = np.dot(x_train, w)
    return np.average(np.square(np.subtract(y, y_train)))

def ridge_regression(x_train, y_train, regularizer):
    I = np.identity(x_train.shape[1])
    xTx = np.dot(x_train.T, x_train)
    xTy = np.dot(x_train.T, y_train)
    return np.dot(np.linalg.pinv(np.add(xTx, regularizer * I)), xTy)

def linear_regression(x_train, y_train):
    return np.dot(np.linalg.pinv(x_train), y_train)

def get_x_train(x1):
    bias = np.ones_like(x1)
    return np.column_stack((bias, x1))

def get_y_train(x1):
    return np.square(x1) + 10

def print_training_data(x1, y_train):
    d = np.column_stack((x1, y_train))
    d_sorted = d[np.argsort(d[:, 0])]
    df = pd.DataFrame(np.round(d_sorted, 2), columns=['x', 'y'])
    print(str(df) + '\n')

def print_regression_eq(label, w, error):
    print('{0:12}: y = {1}x + {2}'.format(label, round(w[1], 2), round(w[0], 2)))
    print('{0:12}: {1}'.format('error', error))

def plot_exp(x1, y_train, w, w_reg):
    plt.style.use('seaborn-whitegrid')
    fig, ax = plt.subplots()

    ax.set(title='Ridge Regression')
    ax.scatter(x1, y_train, color='b', marker='x', label='training data')
    ax.plot(x1, line(w[1], x1, w[0]), color='g', label='regression line')
    ax.plot(x1, line(w_reg[1], x1, w_reg[0]), color='r', label='ridge regression line')

    ax.legend(facecolor='w', fancybox=True, frameon=True, edgecolor='black', borderpad=1)
    plt.show()

def line(m, x, b):
    return m * x + b

if __name__ == '__main__':
    main()


"""
This folder contains helper functions for common mathematical functions.
Note: this package is not equivalent to PyTorch's functional API, because
no backwards() methods are provided for these functions!

To use these functions as layers, please use the implementation in
layers/ or losses/ instead.
"""
import numpy as np

from edutorch.typing import NPArray

def softmax(f: NPArray) -> NPArray:
    """Numerically stable implementation of softmax."""
    f -= np.max(f)
    exp_f = np.exp(f)
    if len(f.shape) == 1:
        return exp_f / np.sum(exp_f, axis=0)
    return exp_f / np.sum(exp_f, axis=1).reshape(-1, 1)

def sigmoid(x: NPArray) -> NPArray:
    """A numerically stable version of the logistic sigmoid function."""
    pos_mask = x >= 0
    neg_mask = x < 0
    z = np.zeros_like(x)
    z[pos_mask] = np.exp(-x[pos_mask])
    z[neg_mask] = np.exp(x[neg_mask])
    top = np.ones_like(x)
    top[neg_mask] = z[neg_mask]
    return top / (1 + z)

__all__ = ("softmax", "sigmoid")


#Python code for chapter 17 DSILT: Statistics

import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder, MinMaxScaler, StandardScaler
from sklearn.manifold import MDS, Isomap, LocallyLinearEmbedding, TSNE
import matplotlib.pyplot as plt

#Set seed for repeatability
seed = 14
np.random.seed(seed)

#Load Iris data and specify dependent variable
alldata = pd.read_csv('/home/dsilt/Desktop/dsilt-stats-code/17-20 and 22 Iris and Motor Trends Cars/iris.csv')
print(alldata.info())
print(alldata.head())

#Split data into x and y, and format as numpy arrays
array = alldata.values
x = array[:, 0:4].astype(float)
y = array[:, 4]
#Convert the classes (species) into integers
encoder = LabelEncoder()
encoder.fit(y)
y = encoder.transform(y)

#Scale every feature using min-max normalization and z-score standardization
#Note that y is not scaled because it is categorical, but if it weren't, it would have to be scaled too
x_norm = MinMaxScaler().fit_transform(x)
x_std = StandardScaler().fit_transform(x)

'''
-------------------------------------------------------------------------------
-------------------------Multi-Dimensional Scaling-----------------------------
-------------------------------------------------------------------------------
'''

#Apply metric MDS, keeping n components < the number of original features
#kernel choices: linear (default), poly (polynomial of degree=degree), rbf, sigmoid, cosine
mds_model = MDS(n_components=2, metric=True, random_state=seed)
mds_model.fit_transform(x_std)
print(mds_model.get_params())
mds_dim = mds_model.embedding_
print(mds_dim.shape)  #There should be 2 latent variables represented
print('Stress:', mds_model.stress_)

#Plot first 2 extracted features and the observation class
plt.figure(figsize=(10, 5))
plt.xlabel('Latent Variable 1')
plt.ylabel('Latent Variable 2')
plt.title('Metric MDS 2-Dimension Plot with Observation Class')
plt.scatter(mds_dim[:, 0], mds_dim[:, 1], c=y)
plt.colorbar()
plt.show()

#Apply non-metric MDS, keeping n components < the number of original features
#kernel choices: linear (default), poly (polynomial of degree=degree), rbf, sigmoid, cosine
mds_model = MDS(n_components=2, metric=False, random_state=seed)
mds_model.fit_transform(x_std)
print(mds_model.get_params())
mds_dim = mds_model.embedding_
print(mds_dim.shape)  #There should be 2 latent variables represented
print('Stress:', mds_model.stress_)

#Plot first 2 extracted features and the observation class
plt.figure(figsize=(10, 5))
plt.xlabel('Latent Variable 1')
plt.ylabel('Latent Variable 2')
plt.title('Nonmetric MDS 2-Dimension Plot with Observation Class')
plt.scatter(mds_dim[:, 0], mds_dim[:, 1], c=y)
plt.colorbar()
plt.show()

#Apply metric MDS for many different choices of dimensions
#Limitation is that nbr dimensions must be < the number of original features
nbr_dim = range(3)
mds_dim_nbr = []
mds_stress_results = []
for nd in nbr_dim:
    mds_model = MDS(n_components=nd+1, metric=True, random_state=seed)
    mds_model.fit_transform(x_std)
    mds_dim_nbr.append(nd+1)
    mds_stress_results.append(mds_model.stress_)
mds_results = {'nbr_dim': mds_dim_nbr, 'stress': mds_stress_results}
mds_results = pd.DataFrame.from_dict(mds_results)
#See which number of dimensions has the lowest stress
plt.plot(mds_results['nbr_dim'], mds_results['stress'])
plt.xlabel('Number of Latent Dimensions')
plt.ylabel('Stress')
plt.title('Scree Plot of Stress by Number of Latent Variables')
plt.show()

#Build MDS model with one less than the number of dimensions at the kneee of the scree plot
#In this case, that would be 1, so the index is substituted for the second latent variable
mds_model = MDS(n_components=1, metric=True, random_state=seed)
mds_model.fit_transform(x_std)
mds_dim = mds_model.embedding_
plt.figure(figsize=(10, 5))
plt.xlabel('Index')
plt.ylabel('Latent Variable 1')
plt.title('Metric MDS 1-Dimension Plot with Observation Class')
plt.scatter(mds_dim[:, 0], list(alldata.index), c=y)
plt.colorbar()
plt.show()

'''
-------------------------------------------------------------------------------
-----------------------------------Isomap--------------------------------------
-------------------------------------------------------------------------------
'''

#Apply isomap embedding, keeping n components < the number of original features
iso_model = Isomap(n_neighbors=5, n_components=2)
iso_model.fit_transform(x_std)
print(iso_model.get_params())
iso_dim = iso_model.embedding_
print(iso_dim.shape)  #There should be 2 latent variables represented

#Plot first 2 extracted features and the observation class
plt.figure(figsize=(10, 5))
plt.xlabel('Latent Variable 1 (explains most variance)')
plt.ylabel('Latent Variable 2 (explains second most variance)')
plt.title('Isomap 2-Dimension Plot with Observation Class')
plt.scatter(iso_dim[:, 0], iso_dim[:, 1], c=y)
plt.colorbar()
plt.show()

#Apply isomap for many different choices of dimensions
#Limitation is that nbr dimensions must be < the number of original features
nbr_dim = range(3)
iso_dim_nbr = []
iso_reconstruction_errors = []
for nd in nbr_dim:
    iso_model = Isomap(n_neighbors=5, n_components=nd+1)
    iso_model.fit_transform(x_std)
    iso_dim_nbr.append(nd+1)
    iso_reconstruction_errors.append(iso_model.reconstruction_error())
iso_results = {'nbr_dim': iso_dim_nbr, 'error': iso_reconstruction_errors}
iso_results = pd.DataFrame.from_dict(iso_results)
#See which number of dimensions has the lowest reconstruction error
plt.plot(iso_results['nbr_dim'], iso_results['error'])
plt.xlabel('Number of Latent Dimensions')
plt.ylabel('Reconstruction Error')
plt.title('Plot of Error by Number of Latent Variables')
plt.show()

#Use iso_model.transform(x_test) to fit the isomap from the training set onto the test set

'''
-------------------------------------------------------------------------------
-------------------------------Modified LLE------------------------------------
-------------------------------------------------------------------------------
'''

#Apply modified LLE, keeping n components < the number of original features
#method = 'standard' for LLE, 'hessian' for HELLE, or 'modified' for modified LLE
mlle_model = LocallyLinearEmbedding(n_neighbors=5, n_components=2, method='modified', random_state=seed)
mlle_model.fit_transform(x_std)
print(mlle_model.get_params())
mlle_dim = mlle_model.embedding_
print(mlle_dim.shape)  #There should be 2 latent variables represented

#Plot first 2 extracted features and the observation class
plt.figure(figsize=(10, 5))
plt.xlabel('Latent Variable 1 (explains most variance)')
plt.ylabel('Latent Variable 2 (explains second most variance)')
plt.title('Modified LLE 2-Dimension Plot with Observation Class, 5 neighbors')
plt.scatter(mlle_dim[:, 0], mlle_dim[:, 1], c=y)
plt.colorbar()
plt.show()

#Try a different number of neighbors
mlle_model = LocallyLinearEmbedding(n_neighbors=15, n_components=2, method='modified', random_state=seed)
mlle_model.fit_transform(x_std)
mlle_dim = mlle_model.embedding_
plt.figure(figsize=(10, 5))
plt.xlabel('Latent Variable 1 (explains most variance)')
plt.ylabel('Latent Variable 2 (explains second most variance)')
plt.title('Modified LLE 2-Dimension Plot with Observation Class, 15 neighbors')
plt.scatter(mlle_dim[:, 0], mlle_dim[:, 1], c=y)
plt.colorbar()
plt.show()

#Use mlle_model.transform(x_test) to fit the modified LLE from the training set onto the test set

'''
-------------------------------------------------------------------------------
-------------------------------------t-SNE-------------------------------------
-------------------------------------------------------------------------------
'''

#Build TSNE model, learning rate defaults to 1000 but usually best around 200
#Perplexity balances local and global aspects of neighbors, usually best between 5 and 50
tsne_model = TSNE(n_components=2, perplexity=30.0, learning_rate=100.0,
                  n_iter=2000, n_iter_without_progress=30,
                  random_state=seed, method='barnes_hut')
tsne_model.fit_transform(x_std)
print(tsne_model.get_params())
tsne_dim = tsne_model.embedding_
print(tsne_dim.shape)  #There should be 2 latent variables represented
#print('Kullback-Leibler divergence:', tsne_model.kl_divergence_)

#Plot first 2 extracted features and the observation class
plt.figure(figsize=(10, 5))
plt.xlabel('Latent Variable 1')
plt.ylabel('Latent Variable 2')
plt.title('t-SNE 2-Dimension Plot with Observation Class \nperplexity=30, learning_rate=100')
plt.scatter(tsne_dim[:, 0], tsne_dim[:, 1], c=y)
plt.colorbar()
plt.show()

17-20 and 22 Iris and Motor Trends Cars/17_nonlinear_dimension_reduction.py


import numpy as np
import proj_gd as gd
import utils
import matplotlib.pyplot as plt
import matplotlib.patches as mp

X = np.array([[2, 0, 0], [0, 1, 0]]).T
y = np.array([3, 2, 2])
t = 1

def f(w):
    return 0.5*np.sum((X@w - y)**2)

def fp(w):
    return X.T@(X@w - y)

def proj_l1_ball(x, t):
    if np.linalg.norm(x, 1) <= t:
        return x
    x2 = np.sort(x)[::-1]
    y = np.cumsum(x2)
    n = len(x)
    for k in range(n):
        c = (y[k]-t) / (k + 1)
        if c > x2[k]:
            mu = (y[k-1]-t) / k
            break
    else:
        mu = (y[n-1]-t) / n
    return np.maximum(0, x - mu)

w0 = np.array([-1, 0.5])
stepsize = 0.1

w_traces, y_traces = gd.proj_gd(fp, lambda x: proj_l1_ball(
    x, t), w0, stepsize=stepsize, tol=1e-8)

f_value = f(w_traces[-1])

print()
print('t = ', t)
print('number of iterations:', len(w_traces)-1)
print('solution:', w_traces[-1])
print('value:', f_value)

# visualization
Q = X.T@X
b = X.T@y
c = y@y

def f_2d(w1, w2):
    return 0.5 * Q[0, 0] * w1**2 + 0.5 * Q[1, 1] * w2**2 + Q[0, 1] * w1 * w2 \
        - b[0] * w1 - b[1] * w2 - 0.5 * c

def gap(w):
    return f(w) - f_value

path = 'figures/'
feasible_set = mp.Polygon(
    [(-t, 0), (0, t), (t, 0), (0, -t)], alpha=0.5, color='y')
utils.plot_traces_2d(f_2d, w_traces, y_traces, feasible_set,
                     path+f'lasso_traces_t{t}.png')
utils.plot(gap, w_traces, path+f'lasso_gap_t{t}.png')


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

def logistic(z: np.ndarray, a: float, b: float) -> np.ndarray:
    """ Compute logistic function
      Inputs:
         a: exponential parameter
         b: exponential prefactor
         z: numpy array; domain
      Outputs:
         f: numpy array of floats, logistic function
    """

    den = 1.0 + b * np.exp(-a * z)
    return 1.0 / den

def stretch_tanh(z: np.ndarray, a: float, b: float, c: float) -> np.ndarray:
    """ Compute stretched hyperbolic tangent
      Inputs:
         a: horizontal stretch parameter (a>1 implies a horizontal squish)
         b: vertical stretch parameter
         c: vertical shift parameter
         z: numpy array; domain
      Outputs:
         g: numpy array of floats, stretched tanh
    """
    return b * np.tanh(a * z) + c

def relu(z: np.ndarray, eps: float = 0.01) -> np.ndarray:
    """ Compute rectificed linear unit
      Inputs:
         eps: small positive parameter
         z: numpy array; domain
      Outputs:
         h: numpy array; relu
    """
    return np.fmax(z, eps * z)

x = np.linspace(-5.0, 5.0, 100) # Equally spaced grid of 100 pts between -5 and 5

# First get the data
f = logistic(x, 2.0, 1.0)
g = stretch_tanh(x, 2.0, 0.5, 0.5)
h = relu(x)

fig, ax = plt.subplots(1,1, figsize=(10,6)) # Create figure object

# Make actual plots
# (Notice the label argument!)
ax.plot(x, f, lw=4, ls='-', label=r'$L(x;1)$')
ax.plot(x, g, lw=4, ls='--', label=r'$\tanh(2x)$')
ax.plot(x, h, lw=4, ls='-.', label=r'$relu(x; 0.01)$')

# Make the tick labels readable
ax.tick_params(labelsize=24)

# Set axes limits to make the scale nice
ax.set_xlim(x.min(), x.max())
ax.set_ylim(h.min(), 1.1)

# Make readable labels
ax.set_xlabel(r'$x$', fontsize=24)
ax.set_ylabel(r'$h(x)$', fontsize=24)
ax.set_title('Activation Functions', fontsize=24)

# Set up grid
ax.grid(True, lw=1.75, ls='--', alpha=0.75)

# Put legend on figure
ax.legend(loc='best', fontsize=24);

#fig.savefig('figs/nice_plots.png')


# Implementation of Naive Bayes(NB) classifier.
# Tested on MNIST dataset.

# Code Flow:
    # 1. Import all relevant libraries.
    # 2. NB class definition.
        # 2.1 Fit function.
        # 2.2 Predict function.
        # 2.3 Score function.
    # 3. Main Function.
        # 3.1 Read the MNIST dataset.
        # 3.2 Test train split.
        # 3.3 NB function call.

# 1. Import all relevant libraries:
import numpy as np
import pandas as pd
from datetime import datetime
from scipy.stats import multivariate_normal as mvn
from pathlib import Path

# 2. Naive Bayes class definition:
class NaiveBayes(object):
    # Variables: gaussians, priors
    # Methods: fit, predict, score

    # 2.1 Fit function:
    def fit(self, X, Y, smoothing=1e-2): # smoothing to avoid div by 0 for variance.
        self.gaussians = dict() # tuples (mean, variance)
        self.priors = dict()
        labels = set(Y)
        for c in labels: # loop through each labels.
            current_x = X[Y == c]
            self.gaussians[c] = {
                'mean': current_x.mean(axis=0),
                'var': current_x.var(axis=0) + smoothing,
            }
            self.priors[c] = float(len(Y[Y == c])) / len(Y)

    # 2.2 Predict function:
    def predict(self, X):
        N, D = X.shape
        K = len(self.gaussians)
        P = np.zeros((N, K))
        for c, g in (self.gaussians).items():
            mean, var = g['mean'], g['var']
            # Use scipy logpdf function because exp slows it down
            # Covariance can be specified as vector
            P[:,c] = mvn.logpdf(X, mean=mean, cov=var) + np.log(self.priors[c])
        return np.argmax(P, axis=1)

    # 2.3 Score function:
    def score(self, X, Y):
        P = self.predict(X)
        return np.mean(P == Y)

# 3. Main Function:
if __name__ == '__main__':

    # 3.1 Read the MNIST dataset:
    p = Path(__file__).parents[2]
    df = pd.read_csv(p /'0.Data' / 'train.csv')
    np.random.seed(101) # Set seed before shuffling
    data = df.as_matrix() # DF to matrix
    np.random.shuffle(data) # Shuflle data
    X = data[:, 1:] / 255.0 # Scale input data such that it is between [0,1] from [0,255]
    Y = data[:, 0]
    limit = 2000
    # Limit the number of data points to speed things up:
    if limit is not None:
        X, Y = X[:limit], Y[:limit]

    # 3.2 Test train split:
    Ntrain = len(Y) // 2
    Xtrain, Ytrain = X[:Ntrain], Y[:Ntrain]
    Xtest, Ytest = X[Ntrain:], Y[Ntrain:]

    # 3.3 NB function call:
    model = NaiveBayes() # Initilalize the model

    # Training:
    t0 = datetime.now()
    model.fit(Xtrain, Ytrain)
    print("Training time:", (datetime.now() - t0))

    # Prediction on training dataset:
    t0 = datetime.now()
    print("Train accuracy:", model.score(Xtrain, Ytrain))
    print("Time to compute train accuracy:", (datetime.now() - t0), "Train size:", len(Ytrain))

    # Prediction on test dataset:
    t0 = datetime.now()
    print("Test accuracy:", model.score(Xtest, Ytest))
    print("Time to compute test accuracy:", (datetime.now() - t0), "Test size:", len(Ytest))

4.Bayes Classifier/1.Code - Using Theory/0.Naive_Bayes.py


import numpy as np  # Matrix
from sklearn.datasets import make_regression  # Random dataset
import matplotlib.pyplot as plt  # Graphic

# Linear regression module
class Lr:
    # Hyper parameters
    learning_rate = 0.01
    n_iteration = 100
    n_samples = 100

    # Configuration
    n_param_more = 0
    use_normal_vector = False
    verbose = False
    name = ""

    # dataset
    x = None
    y = None
    X = None
    n_features = 1
    theta = None

    # result
    theta_final = None
    coef = 0

    def run(self, name=""):  # return the coef and the final theta
        if name == "":
            name = self.name

        self.y = self.y.reshape(self.y.shape[0], 1)

        self.X = self.make_X(self.n_features + self.n_param_more)  # X -> arguments input [[a, 1],[b, 1]...]

        if not self.use_normal_vector:

            if self.theta is None:
                self.theta = np.random.randn(self.X.shape[1], 1)  # Matrix with the arguments of the function

            # Learn
            self.theta_final, cost_history = self.gradient_descent()
        else:
            self.theta = self.normal_vector()
            self.theta_final = self.theta

        self.coef = self.coef_determination()  # Compute the coef / 1

        if self.verbose:
            print("\nStats: Linear regression ({})".format(name))  # Show Stats
            print("Use normal vector: " + str(self.use_normal_vector))
            print("Samples: " + str(self.n_samples))
            print("Features: " + str(self.n_features))
            print("More parameters: " + str(self.n_param_more))
            if not self.use_normal_vector:
                print("Iteration: " + str(self.n_iteration))
                print("Learning rate: " + str(self.learning_rate))
            print("y: " + str(self.y.shape))
            print("x: " + str(self.x.shape))
            print("X: " + str(self.X.shape))
            print("Theta: " + str(self.theta_final.shape))
            print("Theta final: " + str(self.theta_final))
            print("Coef: {0:9.3f}/1 ({0})".format(self.coef))

            # Show graphs
            for i in range(0, self.n_features):
                plt.scatter(self.x[:, i], self.y)
                plt.scatter(self.x[:, i], self.model(self.X), c='r')
                plt.show()

            #  Show cost evolution
            if not self.use_normal_vector:
                plt.plot(range(self.n_iteration), cost_history)
                plt.show()

        return self.theta_final, self.coef

    """=================================================================================================================
    ¦¦¦ Machine Learning FUNCTION                                                                                ¦¦¦
    ================================================================================================================="""

    def model(self, x):
        return x.dot(self.theta)

    def cost(self):
        m = len(self.y)
        return 1 / (2 * m) * np.sum((self.model(self.X) - self.y) ** 2)

    def grad(self):
        m = len(self.y)
        return 1 / m * self.X.T.dot(self.model(self.X) - self.y)

    def gradient_descent(self):
        if self.verbose:
            cost_history = np.zeros(self.n_iteration)

        for i in range(0, self.n_iteration):
            self.theta = self.theta - self.learning_rate * self.grad()
            if self.verbose:
                cost_history[i] = self.cost()
        return self.theta, cost_history

    def normal_vector(self):
        return np.linalg.inv(self.X.T.dot(self.X)).dot((self.X.T.dot(self.y)))

    def coef_determination(self):
        pred = self.model(self.X)
        u = ((self.y - pred) ** 2).sum()
        v = ((self.y - self.y.mean()) ** 2).sum()
        return 1 - u / v

    """=================================================================================================================
    ¦¦¦ CONSTRUCTION FUNCTION                                                                                ¦¦¦
    ================================================================================================================="""

    def make_X(self, n_param):
        if n_param <= 2:
            return np.hstack((self.x, np.ones((self.x.shape[0], 1))))
        else:
            return np.hstack((self.x ** (n_param - 1), self.make_X(n_param - 1)))

    def random_dataset(self, noise):
        self.x, self.y = make_regression(n_samples=self.n_samples, n_features=self.n_features,
                                         noise=noise)  # x -> inputs  y -> outputs
        self.y = self.y.reshape(self.y.shape[0], 1)
        return self.x, self.y


import numpy as np
import matplotlib.pyplot as plt
from psecas import Solver, FourierGrid, System

"""
The Mathieu equation is given by

    -uₓₓ + 2 q cos(2x) = σ u

where σ is the eigenvalue and q is a parameter.

We solve for u(x) and σ by using the Fourier grid.

This example is taken from the book *Spectral methods in Matlab*
by Lloyd Trefethen and this Python script reproduces the figure on
page 89.
"""

# Create grid
grid = FourierGrid(64, zmin=0, zmax=2*np.pi, z='x')

# Create the system
system = System(grid, variables='u', eigenvalue='sigma')
system.q = 1

# Add the first (and only) equation
system.add_equation("sigma*u = 2*q*np.cos(2*x)*u - dx(dx(u))")

# Create a solver object
solver = Solver(grid, system)

def sorting_strategy(E):
    """Sorting strategy. E is a list of eigenvalues"""
    # Sort from smallest to largest eigenvalue
    index = np.argsort(E)
    return (E, index)

solver.sorting_strategy = sorting_strategy

sigmas = []
for q in np.arange(0, 15, 0.2):

    # Set q in system object
    system.q = q

    # Solve
    solver.solve(saveall=True)

    # Append 11 lowest eigenvalues
    sigmas.append(solver.E[:11])

# Now plot the results
plt.figure(1)
plt.clf()
fig, axes = plt.subplots(num=1)
sigmas = np.array(sigmas)
for mode in range(11):
    axes.plot(np.arange(0, 15, 0.2), sigmas[:, mode].real)

axes.set_xlabel(r'$q$')
axes.set_ylabel(r'$\sigma$')
plt.show()


%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack

fig = plt.figure(figsize=[14,4])
N = 600           # Number of samplepoints
Fs = 800.0
T = 1.0 / Fs      # N_samps*T (#samples x sample period) is the sample spacing.
N_fft = 80        # Number of bins (chooses granularity)
x = np.linspace(0, N*T, N)     # the interval
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)   # the signal

# removing the mean of the signal
mean_removed = np.ones_like(y)*np.mean(y)
y = y - mean_removed

# Compute the fft.
yf = scipy.fftpack.fft(y,n=N_fft)
xf = np.arange(0,Fs,Fs/N_fft)

##### Plot the fft #####
ax = plt.subplot(121)
pt, = ax.plot(xf,np.abs(yf), lw=2.0, c='b')
p = plt.Rectangle((Fs/2, 0), Fs/2, ax.get_ylim()[1], facecolor="grey", fill=True, alpha=0.75, hatch="/", zorder=3)
ax.add_patch(p)
ax.set_xlim((ax.get_xlim()[0],Fs))
ax.set_title('FFT', fontsize= 16, fontweight="bold")
ax.set_ylabel('FFT magnitude (power)')
ax.set_xlabel('Frequency (Hz)')
plt.legend((p,), ('mirrowed',))
ax.grid()

##### Close up on the graph of fft#######
# This is the same histogram above, but truncated at the max frequence + an offset.
offset = 1    # just to help the visualization. Nothing important.
ax2 = fig.add_subplot(122)
ax2.plot(xf,np.abs(yf), lw=2.0, c='b')
ax2.set_xticks(xf)
ax2.set_xlim(-1,int(Fs/6)+offset)
ax2.set_title('FFT close-up', fontsize= 16, fontweight="bold")
ax2.set_ylabel('FFT magnitude (power) - log')
ax2.set_xlabel('Frequency (Hz)')
# ax2.hold(True)
ax2.grid()

plt.yscale('log')


"""
These Scene are made in 3Blue1Brown's Manim.
These Scenes will be considered as Externally Animated Scenes.
"""

from manimlib import *
from numpy import *

class KleinBottle(ThreeDScene):
    def construct(self):
        frame = self.camera.frame
        frame.reorient(-45, 70)
        frame.add_updater(
            lambda m, dt: m.increment_theta(2 * dt * DEGREES)
        )
        light = self.camera.light_source
        light.move_to([-10, -10, 20])
        self.add(frame)

        klein_bottle = ParametricSurface(
            lambda u, v : np.array([
                (-2/15)*cos(u)*( 3*cos(v) - 30*sin(u) + 90*(cos(u)**4)*sin(u) - 60*(cos(u)**6)*sin(u) + 5*cos(u)*cos(v)*sin(u) ),
                (-1/15)*sin(u)*( 3*cos(v) - 3*(cos(u)**2)*cos(v) - 48*(cos(u)**4)*cos(v) + 48*(cos(u)**6)*cos(v) - 60*sin(u) + 5*cos(u)*cos(v)*sin(u)
                - 5*(cos(u)**3)*cos(v)*sin(u) - 80*(cos(u)**5)*cos(v)*sin(u) + 80*(cos(u)**7)*cos(v)*sin(u) ),
                (2/15)*( 3 + 5*cos(u)*sin(u) )*sin(v)
                ]),
            u_range = [0, np.pi],
            v_range = [0, 2*np.pi]
        )
        klein_bottle.set_gloss(1.0)
        klein_bottle.set_opacity(0.5)
        klein_bottle.sort_faces_back_to_front(DOWN)
        mesh = SurfaceMesh(klein_bottle, resolution = (21, 11))
        mesh.set_stroke(BLUE, 1, 1)
        klein_bottle = Group(klein_bottle, mesh)
        klein_bottle.move_to(ORIGIN)
        klein_bottle.scale(2)
        self.add(klein_bottle)
        self.wait(2)


import pymm
import numpy as np
import math
import torch

# based on https://pytorch.org/tutorials/beginner/pytorch_with_examples.html

s = pymm.shelf('myShelf',size_mb=1024,pmem_path='/mnt/pmem0',force_new=True)

dtype = torch.float
device = torch.device("cpu")
# device = torch.device("cuda:0") # Uncomment this to run on GPU

# Create random input and output data
s.x = torch.linspace(-math.pi, math.pi, 2000, dtype=dtype)

# create reference to shelf object; use as_tensor to get the subclass representation
# so that it looks like a Tensor type. this will prevent transactions happening where
# they are not needed
#x = s.x.as_tensor()
s.y = torch.sin(s.x)

#Create random Tensors for weights. For a third order polynomial, we need
# 4 weights: y = a + b x + c x^2 + d x^3
# Setting requires_grad=True indicates that we want to compute gradients with
# respect to these Tensors during the backward pass.
a = torch.randn((), device=device, dtype=dtype, requires_grad=True)
b = torch.randn((), device=device, dtype=dtype, requires_grad=True)
c = torch.randn((), device=device, dtype=dtype, requires_grad=True)
d = torch.randn((), device=device, dtype=dtype, requires_grad=True)

learning_rate = 1e-6
for t in range(2000):
    # Forward pass: compute predicted
    s.y_pred = a + b * s.x + c * s.x ** 2 + d * s.x ** 3

    # Compute and print loss using operations on Tensors.
    # Now loss is a Tensor of shape (1,)
    # loss.item() gets the scalar value held in the loss.
    loss = (s.y_pred - s.y).pow(2).sum()
    if t % 100 == 99:
        print(t, loss.item())

    # Use autograd to compute the backward pass. This call will compute the
    # gradient of loss with respect to all Tensors with requires_grad=True.
    # After this call a.grad, b.grad. c.grad and d.grad will be Tensors holding
    # the gradient of the loss with respect to a, b, c, d respectively.
    loss.backward()

    # Manually update weights using gradient descent. Wrap in torch.no_grad()
    # because weights have requires_grad=True, but we don't need to track this
    # in autograd.
    with torch.no_grad():
        a -= learning_rate * a.grad
        b -= learning_rate * b.grad
        c -= learning_rate * c.grad
        d -= learning_rate * d.grad

    # Manually zero the gradients after updating weights
        a.grad = None
        b.grad = None
        c.grad = None
        d.grad = None

print(f'Result: y = {a.item()} + {b.item()} x + {c.item()} x^2 + {d.item()} x^3')


# File      :CompareHist.py
# Author    :WJ
# Function  :
# Time      :2021/01/11
# Version   :
# Amend     :

import numpy as np
from matplotlib import pyplot as plt

def hist(array=[0,1],bins=20,start=0,end=1):
    hist=np.zeros((bins+1,1))
    x=np.linspace(start=start,stop=end,num=bins+1,endpoint=True)
    for i in range(0,len(array)):
        for j in range(0,len(x)-1):
            if abs(array[i])>=x[j] and abs(array[i])<x[j+1]:
                hist[j]=hist[j]+1
    return hist

def calcSimilarity(hist1, hist2,Similarity=False):
    # 若Simlarity==Ture，则返回相似度，否则返回相异度
    # 计算两直方图的相似度
    # 计算直方图的重合度
    degree = 0
    for i in range(len(hist1)):
        if hist1[i] != hist2[i]:
            degree = degree + \
                (1 - abs(abs(hist1[i]) - abs(hist2[i]))/ max(abs(hist1[i]), abs(hist2[i])))
        else:
            degree = degree + 1
    degree = degree / len(hist1)
    if Similarity==True:
        return degree
    else:
        return 1-degree

def calaHistCorrelation(U1k,U2l,bins=10,start=0,end=1):
    hist1=hist(U1k,bins,start,end)
    hist2=hist(U2l,bins,start,end)
    CorrelationDegree = calcSimilarity(hist1, hist2)
    return CorrelationDegree

if __name__=='__main__':
    U = np.array([-0.1, -0.1, -0.2, -0.9, 0, 0.5, 0.2, 0.6, 0.63, 0.7, 0.8])
    hist1 = hist(U)
    hist2 =np.array(hist1)
    hist2[2]=3
    plt.subplot(1, 2, 1)
    plt.title("hist1")
    plt.plot(hist1)
    plt.subplot(1, 2, 2)
    plt.title("hist2")
    plt.plot(hist2)
    plt.pause(5)
    degree=calcSimilarity(hist1,hist2)
    print(degree)


#!/usr/bin/env python
"""
lhcb_rich_cerenkov_angles_pid.py
===================================

https://physics.stackexchange.com/questions/471722/cherenkov-light-and-refractive-index

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

def beta(E, mec2):
    gamma = E / mec2
    return np.sqrt(1 - 1 / np.power(gamma, 2))

def theta(beta, n):
    return np.arccos(1 / (beta * n))

mec2_kaon = 493.68  # MeV / c^2
mec2_pion = 139.57  # MeV / c^2
mec2_muon = 105.65  # MeV / c^2

E = np.logspace(np.log10(5e3), 6, 100) # MeV

beta_pion = beta(E, mec2_pion)
beta_kaon = beta(E, mec2_kaon)
beta_muon = beta(E, mec2_muon)

n_1 = 1.0014
n_2 = 1.0005

fig, ax = plt.subplots()

plt.semilogx(E, theta(beta_kaon, n_1), color="crimson", ls="-", label=r"$K, n_1=1.0014$")
plt.semilogx(E, theta(beta_pion, n_1), color="crimson", ls="--", label=r"$\pi, n_1=1.0014$")
plt.semilogx(E, theta(beta_muon, n_1), color="crimson", ls="-.", label=r"$\mu, n_1=1.0014$")

plt.semilogx(E, theta(beta_kaon, n_2), color="k", ls="-", label=r"$K, n_2=1.0005$")
plt.semilogx(E, theta(beta_pion, n_2), color="k", ls="--", label=r"$\pi, n_2=1.0005$")
plt.semilogx(E, theta(beta_muon, n_2), color="k", ls="-.", label=r"$\mu, n_2=1.0005$")

plt.axvline(8e4, color="crimson", ls=":")
plt.axvline(1.1e5, color="k", ls=":")

plt.xlabel("E / MeV")
plt.ylabel(r"$\theta_{\rm C}\,/\,rad$")
plt.legend()
plt.show()

path = "/tmp/qudarap/lhcb_rich_cerenkov_angles_pid.png"
fold = os.path.dirname(path)
if not os.path.isdir(fold):
    os.mkdirs(fold)
pass
fig.savefig(path)


""" Area pattern analysis tests.

Author:

    C.M. Gosmeyer

Date:

    Apr 2018

References:

    "Introduction to Statistical Problem Solving in Geography",
    J.C. McGrew, Jr., A.J. Lembo, Jr., C.B. Monroe
"""

import numpy as np

class JointCountBinary(object):
    """ Determine whether a random process has generated a binary (two-
    category) area pattern.

    Requirements
    ------------
    1. Each area is assigned to one of two categories.
    2. Each pair of areas must be defined as either adjacent ("joined")
    or nonadjacent (not "joined") in a consistent manner.

    Null Hypthothesis
    -----------------
    H0 : ObservedNumberBlack-WhiteJoins = ExpectedNumberBlack-WhiteJoins
        (area pattern is random)
    HA : ObservedNumberBlack-WhiteJoins != ExpectedNumberBlack-WhiteJoins
        (area pattern is NOT random)
    HA : ObservedNumberBlack-WhiteJoins > ExpectedNumberBlack-WhiteJoins
        (area is more dispersed than random)
    HA : ObservedNumberBlack-WhiteJoins < ExpectedNumberBlack-WhiteJoins
        (area pattern is is more clustered than random)

    Test Statistic
    --------------

    Z_b = (ObservedNumberBlack-WhiteJoins - ExpectedNumberBlack-WhiteJoins)
           / StandardErrorExpectedNumberBlack-WhiteJoins

    where

    ExpectedNumberBlack-WhiteJoins = 2*J*B*W / N*(N-1)

    where

    J = total number of joins
    B = number of black areas
    W = number of white areas
    N = total number of areas  = B + W

    and

    StandardErrorExpectedNumberBlack-WhiteJoins = sqrt( ExpectedNumberBlack-WhiteJoins +
        [ sum(L)*(L-1)*B*W) / N(N-1) ] +
        [ 4*{J*(J-1) - sum(L)*(L-1)}*B*(B-1)*W*(W-1) / N*(N-1)*(N-2)*(N-3) ] -
        ExpectedNumberBlack-WhiteJoins^2 )

    where

    L = list of links for each area
    sum(L) = total number of links = 2J
    """
    def __init__(self, B, W, J, link_list, observed_joins):
        """
        Parameters
        ----------
        B : int
            Number of black areas.
        W : int
            Number of white areas.
        J : int
            Total number of joins.
        link_list : list
            List of links for each area.
        observed_joins : int
            Observed number of black-white joins.
        """
        self.B = float(B)
        self.W = float(W)
        self.J = float(J)
        self.observed_joins = float(observed_joins)
        self.link_list = np.asarray(link_list)

        self.N = self.B + self.W
        self.expected_joins = self.return_expected_joins()
        self.sigma_expected_joins = self.return_sigma_expected_joins()
        self.Z_b = None
        self.test_statistic()
        self.test_stat = self.Z_b

    def return_expected_joins(self):
        B = self.B
        W = self.W
        J = self.J
        N = self.N
        expected_joins = 2*J*B*W / (N*(N-1))

        return expected_joins

    def return_sigma_expected_joins(self):
        B = self.B
        W = self.W
        J = self.J
        N = self.N
        L_sums = sum([ L*(L-1) for L in self.link_list ])

        sigma_expected_joins = np.sqrt( self.expected_joins +
            (L_sums*B*W / (N*(N-1))) +
            ((4*(J*(J-1)-L_sums)*B*(B-1)*W*(W-1)) / (N*(N-1)*(N-2)*(N-3))) -
            self.expected_joins**2 )

        return sigma_expected_joins

    def test_statistic(self):
        self.Z_b = (self.observed_joins - self.expected_joins) / self.sigma_expected_joins

    def get_Zb(self):
        print(self.Z_b)

class MoransIndexGlobal(object):
    """ Identify significant spatial patterns within a study area.

    Requirements
    ------------
    1. Minimum of 30 geographic features.
    2. Attribute values measures on an ordinal or interval/ratio scale.

    Null Hypthothesis
    -----------------
    H0 : Attribute values are randomly distributed across features in
    study area.

    Test Statistic
    --------------

    I = n * sum( (x_i - x_mean)*(x_j - x_mean) ) / J * sum( x - x_mean)^2

    where

    n = number of objects
    J = number of joins
    x = area attribute value
    x_mean = mean of all area attribute values
    x_i, x_j = values of contiguous pairs

    Interpretation
    --------------

    Assuming significant p-value:

    I < 0 : observed pattern is dispersed
    I = 0 : observed pattern is random
    I > 0 : observed pattern is clustered

    """
    def __init__(self, area_joins, area_attributes, assumption='normal'):
        """
        Parameters
        ----------
        area_joins : list of ints
            The number of joins for each area.
        area_attributes : list of lists
            The i, j area attributes for each join.
        assumption : str
            Either "normal" or "random"; will determine the calculated
            variance of the distribution.
        """
        self.area_joins = np.asarray(area_joins) # L
        self.area_attributes = np.asarray(area_attributes) # x_i, x_j
        self.assumption = assumption

        self.n = float(len(area_joins))
        self.J = float(len(area_attributes))
        self.I = None
        self.test_statistic()
        self.test_stat = self.I
        self.var_I = self.variance()
        self.z_score = self.z_score()

    def test_statistic(self):
        xs = list(set([x[0] for x in self.area_attributes]))
        x_mean = np.mean(xs)
        x_sum_pairs = sum( [(x_i-x_mean)*(x_j-x_mean) for x_i, x_j in self.area_attributes] )
        x_variance_attribute_vals = sum( [(x-x_mean)**2 for x in xs] )
        self.I = (self.n * x_sum_pairs) / (self.J *  x_variance_attribute_vals)

    def variance(self):
        sum_L2 = float(sum(self.area_joins**2))
        if self.assumption == 'normal':
            var_I = (self.J*self.n**2 + 3*self.J**2 - self.n*sum_L2) / \
                    (self.J**2 * (self.n**2 - 1.))

        elif self.assumption == 'random':
            xs = list(set([x[0] for x in self.area_attributes]))
            x_mean = np.mean(xs)
            # Now calculate kurtosis.
            k = sum( [(x-x_mean)**4 for x in xs] ) / (len(xs) * np.std(xs)**4) - 3
            var_I = ( self.n * ( self.J*(self.n**2+3-3*self.n) + \
                               + 3*self.J**2 - self.n*sum_L2 ) - \
                      k * ( self.J*(self.n**2 - self.n) + \
                            6*self.J**2 - \
                            2*self.n*sum_L2 ) ) / \
                    ( self.J**2*(self.n-1)*(self.n-2)*(self.n-3) )

        else:
            var_I = 0

        return var_I

    def z_score(self):
        expected_I = -1. / (self.n - 1.)
        z_score = (self.I - expected_I) / np.sqrt(self.var_I)
        return z_score


from matplotlib.pyplot import step
import numpy as np

def soft_th(w, th):
    """
    w: input vector
    th: threshold

        soft_th(w, th) = sgn(w) * (|w| - th)^+

    """
    return np.sign(w) * np.maximum(0, np.abs(w) - th)

def ista(X, y, lambd, w0, stepsize, tol=1e-9, maxiter=100000):
    """
    This function implements the iterative soft-thresholding algorithm (ISTA) for
    solving Lasso in penalized form

        minimize 0.5 * ||X * w - y||_2^2 + lambd * ||w||_1

    w0: initial point
    stepsize: constant step size used in ISTA
    tol: toleracne parameter in the stopping criterion. Here we stop when the
         norm of the difference between two succesive iterates is smaller than tol
    maxiter: maximum number of iterations in ISTA.
    """

    w_traces = [np.array(w0)]
    w = np.array(w0)

    for k in range(maxiter):
        w_next = soft_th(w - stepsize * X.T @ (X @ w - y), stepsize * lambd)

        if np.linalg.norm(w_next - w) < tol:
            break

        w = w_next
        w_traces.append(np.array(w))

    return w_traces