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

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1YgzGZJkGYz-1W9-dJG2N-AVO5RWqW_JZ
"""

#Tarea 4 Metodos Copmutacionales
#Samuel David Cañas Molina - 201922001

#A Integrales

"""$f(x$) = $\int_{0}^{1}x^{-1/2}\,\text{d}x$

$g(x)$ = $\int_{0}^{\infty}e^{-x}\ln{x}\,\text{d}x$

$h(x)$ = $\int_{0}^{\infty}\frac{\sin{x}}{x}\,\text{d}x$
"""

import numpy as np
import pandas as pd
import scipy as sp
import sklearn as sl
import time

#Primer metodo Cuadraturas Gaussianas

xi = 1/2
xf = 1
xf2 = 10
n = 11

X = np.linspace(xi,xf, n)
X2 = np.linspace(xi,xf2, n)

V = np.matrix([X**i for i in range(len(X))]  )
V_inv = np.linalg.inv(V)

V2 = np.matrix([X2**i for i in range(len(X2))]  )
V2_inv = np.linalg.inv(V2)

I = np.matrix([ (   ( xf**(n+1) - xi**(n+1) ) /(n+1)   ) for n in range(len(X)) ]).T
I2 = np.matrix([ (   ( xf2**(n+1) - xi**(n+1) ) /(n+1)   ) for n in range(len(X2)) ]).T

def f(x):
    return x**(-1/2)

def g(x):
    return np.exp(-x)*np.log(x)

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

vec_f = np.matrix([ f(X[i]) for i in range(len(X))]  ).T
vec_g = np.matrix([ g(X2[i]) for i in range(len(X2))]  ).T
vec_h = np.matrix([ h(X2[i]) for i in range(len(X2))]  ).T

print("El calculo de las integrales por medio del metodo de  Cuadraturas Gaussianas es: ")
print("El calculo de la integral f(x) es: ", (vec_f.T*V_inv*I)[0,0])
print("El calculo de la integral g(x) es: ", (vec_g.T*V2_inv*I)[0,0])
print("El calculo de la integral h(x) es: ", (vec_h.T*V_inv*I)[0,0])

#Segundo Metodo Trapecio

inicio = time.time()

n=100
x_f = np.linspace(0.000001,1,1000001)
x = np.linspace(0.000001,n,1000001)

def f(x):
    return x**(-1/2)

def g(x):
    return np.exp(-x)*np.log(x)

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

def integrate(x,f):
    calculo=0
    for i in range(len(x)-1):
        calculo = calculo + (f(x[i+1])+(f(x[i])))*abs(x[i+1]-x[i])/2
    return(calculo)

integral_f = integrate(x_f,f)
integral_g = integrate(x,g)
integral_h = integrate(x,h)

print("El calculo de las integrales por medio del metodo del Trapecio es: ")
print(f"El calculo de la integral f(x) es: {integral_f}")
print(f"El calculo de la integral g(x) es: {integral_g}")
print(f"El calculo de la integral h(x) es {integral_h}")

#Tercer Metodo Simspon

inicio = time.time()

x_f_ini = 0.000001
x_f_fin = 1
x_ini =0.000001
x_fin =100
nodos=1000001

def f(x):
    return x**(-1/2)
def g(x):
    return np.exp(-x)*np.log(x)
def h(x):
    return np.sin(x)/x
def simpson_integrate(desde, hasta, nodos, f):
    x, delta_x = np.linspace( desde, hasta, num=nodos-1 , retstep=True  )
    return (delta_x/3)*(   f(x[0]) + 2*np.sum(f(x[2:len(x)-1:2])) + 4*np.sum(f(x[1::2])) + f(x[-1]) )

integral_f = simpson_integrate(x_f_ini, x_f_fin, nodos, f)
integral_g = simpson_integrate(x_ini, x_fin, nodos, g)
integral_h = simpson_integrate(x_ini, x_fin, nodos, h)

print("El calculo de las integrales por medio del metodo de Simpson es: ")
print(f"El calculo de la integral f(x) es: {integral_f}")
print(f"El calculo de la integral g(x) es: {integral_g}")
print(f"El calculo de la integral h(x) es: {integral_h}")

#B Fourier

#Datos Tarea 3
#Tarea 3 Metodos Computacionales
#Samuel David Cañas Molina - 201922001

import numpy as np
import matplotlib as mpl
import scipy as sp
import pandas as pd
import sklearn as sl
import seaborn as sns; sns.set()

from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from matplotlib import cm

# get_ipython().run_line_magic('matplotlib', 'inline')

#Tarea 3: Encuentre la regresión
#Usted recibe unos datos x y y cómo se muestran a continuación. Usted debe responder cuatro preguntas a partir de estos datos.
#Suponga que usted tiene un modelo tal que y=f(x) más aún desconoce f.

df = pd.read_pickle("ex1.gz")
sns.scatterplot(x ='x',y ='y',data=df, label = "Datos")
plt.legend(loc="upper right")
plt.show()
df

# Punto (A) Pendiente e intercepto
# Determine la pendiente de los datos en el intervalo [0,1.5] y el valor del intercepto con el eje y.
#Es decir, f(0)=?. ¿Cuál es el valor de r^2?

lx = df["x"]
ly = df["y"]

xt = []
yt = []
for i in range(len(lx)):
    if(0 <= lx[i] <= 1.5):
        xt.append(lx[i])
        yt.append(ly[i])

x = np.array(xt)
y = np.array(yt)

n = len(x)
sumx = sum(x)
sumy = sum(y)
sumxy = sum(x*y)
sumx2 = sum(x**2)
sumy2 = sum(y**2)
promx = sumx/n
promy = sumy/n

m = (sumx*sumy-(n*sumxy))/(sumx**2-(n*sumx2))
b = promy - m*promx

m, b

sns.scatterplot(x='x',y='y',data=df, label = "Datos")
plt.plot(x, m*x + b, color = "k", label = "Ajuste")
plt.legend(loc="upper right")
plt.title("Regresión polinomial en intervalo de 0 a 1.5")
plt.show()

sigmax = np.sqrt((sumx2/n) - promx**2)
sigmay = np.sqrt(sumy2/n - promy**2)
covar = (sumxy/n) - (promx*promy)
r2 = (covar/(sigmax*sigmay))**2

#Punto (B) Regresión polinomial
# Suponga que quiere realizar la siguiente regresión polinomial:
#y=\beta+\beta_1x+\beta_2x^2+\beta_2x^3+\beta_2x^4+\beta_2x^5.
# Plantee la función de costo que le permita calcular los coeficientes y calcule:
#$\beta_1, \beta_2, \beta_3, \beta_4, y \beta_5. ¿Cuál es el r^2?

# Calcule f(0) y compare con los resultados anteriores

A = []
for i in range(len(lx)):
    A.append([1, lx[i], lx[i]**2, lx[i]**3, lx[i]**4, lx[i]**5])

Matriz = np.matrix(A)

b = np.array([ly]).reshape(-1,1)

Mb = np.matrix(b)

def L(k,Matriz,Mb):

    m,n = Matriz.shape
    X = np.matrix(k).T
    DeltaB=(Matriz*X - Mb)
    return (DeltaB.T*DeltaB)[0,0]/m

def dLdx(k,Matriz,Mb):

    m,n = Matriz.shape
    X = np.matrix(k).T
    DeltaB=(Matriz*X - Mb)
    return (2/m)*np.array(Matriz.T*DeltaB).flatten()

e = 1e-10

res1 = sp.optimize.minimize(fun=L,x0=np.zeros(Matriz.shape[1]), args = (Matriz,Mb), tol=1e-10)
res1['x']

#Calculo de f(0) y de cada coeficiente
# $f(0)$ =  0.35735768,
# $\beta_1$ = -0.84260174,
# $\beta_2$ = 3.78478429,
# $\beta_3$ = -3.00338516,
# $\beta_4$ =  0.85844412,
# $\beta_5$ = -0.08305811

L(res1['x'],Matriz,Mb)

#Valor de la función de costo
# L = 0.012550626817337412

k =  np.linspace(0,4,100)

def Poli(c5,c4,c3,c2,c1,b,x):
    return  b +  c1*x +c2*(x**2) + c3*(x**3)+ c4*(x**4) +c5*(x**5)

pre = Poli(res1['x'][5],res1['x'][4],res1['x'][3],res1['x'][2],res1['x'][1],res1['x'][0],k)

r2 = 1-np.sum((pre - ly)**2)/np.sum((ly-ly.mean())**2)
r2, pre[0]

#r^2 = 0.9111078914676154
#f(0)= 0.3573580251551316

sns.scatterplot(x ='x',y ='y',data=df, label = "Datos")
plt.plot(lx,pre,"--", color='k', label = "Ajuste")
plt.title("Regresión polinomial")
plt.legend(loc="upper right")

# Punto (C) Regresión polinomial exacta
# Resulta, que cuando se quiere hacer alguna regresión polinomial esta se puede hacer de forma exacta.
#¿Cómo? Suponga que ud va a considerar que su problema en lugar de tener $1$ variable ($x$) tiene $n+1$,
#siendo $n$ el orden del polinomio a ajustar. Es decir, sus nuevas variables van a ser:
#$\{x_0,\,x_1,\,x_2,\,x_3,\dots,\,x_n\}$ definiendo $x_j=x^j$.
#Así pues, siguiendo el mismo procedimiento para la regresión lineal multidimensional que realizamos para el ejercicio de datos inmobiliarios, puede encontrar los valores de los coeficientes $\beta_1$, $\beta_2$, $\beta_3$, $\beta_4$, y $\beta_5$. Encuentre estos valores y compare con los resultados en la sección (B).
# Calcule f(0) y compare con los resultados anteriores.
# Si ud se pregunta si esto es posible la respuesta es sí. Inclusive, esto se puede extender a cualquier a cualquier conjunto de funciones, tal que $x_j=f_j(x)$, que represente un conjunto "linealmente independiente" (¡Me estoy adelantando a Fourier!). Para quienes quieran explorar algunas curiosidades matemáticas, cuando $n+1$ es igual al número de puntos o valores de $x$ (y todos diferentes) la matriz es siempre invertible y resulta ser la inversa de una matriz de Vandermonde.

lx = df["x"]
ly = df["y"]

X = np.array(lx).reshape(-1, 1)
Y = np.array(ly).reshape(-1, 1)

P = np.array([np.ones([len(lx), 1]), X, X**2, X**3, X**4, X**5]).reshape(6, len(lx)).T
coeffs = np.linalg.inv(P.T @ P) @ P.T @ Y

b, c1, c2, c3, c4, c5 = coeffs

coeffs

Ajuste = b + (c1*X) + (c2*X**2) + (c3*X**3) +  (c4*X**4) + (c5*X**5)

plt.figure()
sns.scatterplot(x='x',y='y',data = df, label = "datos")
plt.plot(X, Ajuste, c ='k', label = "Ajuste")
plt.legend(loc="upper left")
plt.title("Regresión polinomial exacta")
plt.ylabel('y')
plt.xlabel('x')
plt.show()

p = np.array(P@coeffs).flatten()
o = np.array(Y).flatten()
k = o.mean()

r2 = 1 - (np.linalg.norm(p - o)**2)/(np.linalg.norm(o - k)**2)

# r^2 = 0.9199225041318263
#f(0)=0.35644669

# Punto (D) Regresión a un modelo teórico
# Suponga que su modelo teórico es el siguiente:y=\frac{a}{\left[(x-b)^2+c\right]^\gamma}.Halle a, b, c y \gamma.
# Calcule f(0) y compare con los resultados anteriores

def f(parametro,x):
    return (parametro[0])/((x-parametro[1])**2 + parametro[2])**parametro[3]

def Lfit(parametro,x,y):
    deltaY=f(parametro,x) - y
    return np.dot(deltaY,deltaY)/len(y)

e = 1e-8

res2 = sp.optimize.minimize(fun=Lfit, x0=np.array([0,1,0,0]), args = (x,y), method='L-BFGS-B', tol=e)

res2["x"]

# a =0.94519587,
#b = 1.43859817
#c = 0.7390972
#\gamma = 1.12724243

pre2 = f(res2.x,lx)

b = f(res2.x,0)

# f(0)=0.2950897972713322

plt.figure()
plt.scatter(lx,ly, label = "Datos")
plt.plot(lx,pre2, c = 'k', label = "Ajuste")
plt.legend(loc="upper left")
plt.title("Regresión a un modelo teórico")
plt.ylabel('y')
plt.xlabel('x')
plt.show()

"""Calcule la transformada rápida de Fourier para la función de la Tarea 3 (D) en el intervalo $[0,4]$ ($k$ máximo $2\pi n/L$ para $n=25$). Ajuste la transformada de Fourier para los datos de la Tarea 3 usando el método de regresión exacto de la Tarea 3 (C) y compare con el anterior resultado. Para ambos ejercicios haga una interpolación y grafique para comparar."""

# Fourier
import numpy as np
import matplotlib as mpl
import scipy as sp
import pandas as pd
import sklearn as sl
import seaborn as sns; sns.set()

from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from matplotlib import cm

df = pd.read_pickle("ex1.gz")
sns.scatterplot(x ='x',y ='y',data=df, label = "Datos")
plt.legend(loc="upper right")
plt.show()
df

x = df["x"]
y = df["y"]

listax = []
listay = []
for i in range(len(x)):
    if x[i]<=1.5 :
        listax.append(x[i])
        listay.append(y[i])

x_a = np.array(listax)
y_a = np.array(listay)

def f(vec,x_a):
    return (vec[0])/((x_a-vec[1])**2 + vec[2])**vec[3]

def L_fit(vec,x_a,y_a):
    deltaY=f(vec,x_a) - y_a
    return np.dot(deltaY,deltaY)/len(y_a)

res2 = sp.optimize.minimize(fun=L_fit, x0=np.array([0,1,0,0]), args = (x_a,y_a), method='L-BFGS-B', tol=1e-8)
b = f(res2.x,0)

plt.figure()
plt.scatter(x,y, label = "Datos")
plt.plot(x,f(res2.x,x), c = 'r', label = "Ajuste")
plt.xlabel('x')
plt.ylabel('y')
plt.show()


import numpy as np

def mean_absolute_relative_error(y_true, y_pred):
    assert y_true.shape == y_pred.shape
    return np.mean(np.abs((y_true - y_pred) / y_true))

def coefficient_of_determination(y_true, y_pred):
    assert y_true.shape == y_pred.shape
    u = ((y_true - y_pred) ** 2).sum()
    v = ((y_true - np.mean(y_true)) ** 2).sum()
    R2_val = 1-u/v
    return R2_val


import tensorflow as tf
import numpy as np
from matplotlib import pyplot as plt

trX = np.linspace(-1, 1, 101)
trY = 2 * trX + np.random.randn(*trX.shape) * 0.33 # create a y value which is approximately linear but with some random noise

#Draw example

fig = plt.figure()
ax = fig.add_subplot(111)

plt.plot(trX,trY)

plt.grid()
plt.show()

#define palceholders and variables

x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)

w = tf.Variable(0.0, name="weights")

#define model, cost function and GradientDescentOptimizer

y_model = w*x
cost = tf.square(y- y_model)

optimizer = tf.train.GradientDescentOptimizer(0.01).minimize(cost)

with tf.Session() as sess :
  tf.global_variables_initializer().run()

  for i in range(100) :
    for (a,b) in zip(trX, trY) :
      sess.run(optimizer, feed_dict = {x: a, y:b})
    print(f"w: {sess.run(w)}  y_model: {sess.run(y_model, feed_dict = {x: a})}  cost: {sess.run(cost, feed_dict = {x: a, y: b})}")


#Euler problem 10
'''
The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

Find the sum of all the primes below two million.
'''

import numpy as np

#Generate numbers that can actually be prime (exclude 2,3)
def plusPrime(n):
    return 6*n + 1
def minusPrime(n):
    return 6*n - 1

#Checks for primality, doesn't work for numbers < 3
def isPrime(n):
    #Discards even numbers
    if n%2 == 0:
        return False
    #Checks for primality by determining if there is a divisor up to sqrt(n)+1
    for i in range(3,int(np.sqrt(n))+1, 2):
        if n%i == 0:
            return False
    return True

#Finds the n'th prime, doesnt work for n < 3
def nPrime(n):
    #Starts primes at 2 to account for exceptions to 6n+-1 rule
    p = 2
    #Starts number to be subbed into plusPrime and minusPrime to 0
    pmPrime = 0
    #Holds the state of last used generator of possible primes
    pmState = 0

    #Checks for primes in generated numbers, stops when n'th prime is found
    while p < n:
        pmPrime += 1
        if isPrime(minusPrime(pmPrime)) == True:
            pmState = -1
            p += 1
        if isPrime(plusPrime(pmPrime)) == True and p<n:
            pmState = +1
            p += 1

    #Returns n'th prime using generator number and states
    return (6*pmPrime + pmState)

'''
FAILED ATTEMPT AT OPTIMISATION OF NPRIME(N)

listPrimes=[2,3]
#Can't even use this, its depended on nprime2()
def isPrime2(n):
    #Checks for primality by determining if there is a prime composition
    for i in listPrimes:
        if i > int(np.sqrt(n))+1:
            return True
        if n%i == 0:
            return False
    return True

#Slower than nPrime()
def nPrime2(n):
    global listPrimes
    listPrimes = [2,3]
    #Starts primes at 2 to account for exceptions to 6n+-1 rule
    p = 2
    #Starts number to be subbed into plusPrime and minusPrime to 0
    pmPrime = 0
    #Holds the state of last used generator of possible primes
    pmState = 0

    #Checks for primes in generated numbers, stops when n'th prime is found
    while p < n:
        pmPrime += 1
        if isPrime2(minusPrime(pmPrime)) == True:
            listPrimes.append(minusPrime(pmPrime))
            pmState = -1
            p += 1
        if isPrime2(plusPrime(pmPrime)) == True and p<n:
            listPrimes.append(plusPrime(pmPrime))
            pmState = +1
            p += 1
    #Returns n'th prime using generator number and states
    return (6*pmPrime + pmState)
'''

#Finds the sum of all the primes up to and including n
def sumPrime(n):
    currentPrime = 0
    total = 5
    pmPrime = 0
    while n > currentPrime:
        pmPrime += 1
        if isPrime(minusPrime(pmPrime)) == True:
            currentPrime = minusPrime(pmPrime)
            if currentPrime>n:
                break
            total += currentPrime
        if isPrime(plusPrime(pmPrime)) == True and currentPrime < n:
            currentPrime = plusPrime(pmPrime)
            if plusPrime(pmPrime)>n:
                break
            total += currentPrime
    return(total)


import numpy as np

def computeShockConditions(M0, rho0, T0, LOUD=False):
    # Define constants
    Cv     = 1.   # specific heat
    gamma  = 5./3  # thermodynamic constant

    # Define preshock conditions
    e0    = Cv * T0   # presock specific energy density
    cs0   = np.sqrt(e0 * gamma*(gamma-1)) # preshock sound speed (cm/sh)
    v0    = M0 * cs0  # preshock velocity (cm/sh)

    # Define postshock conditions
    v1    = v0*(gamma-1)/(gamma+1) + 2*cs0**2/(v0*(gamma+1)) # postshock velocity
    rho1  = rho0 * v0/v1 # postshock density
    e1    = e0 + (v0**2 - v1**2)/(2*gamma) # postshock specific energy density
    T1    = e1/Cv # postshock temperature
    cs1   = np.sqrt(e1*gamma*(gamma-1)) # postshock sound speed
    M1    = v1/cs1  # postshock Mach number

    # Print preshock and postshock states
    if LOUD:
        print('\n')
        print('Preshock Velocity = %.3e' %v0, '(cm/sh) = ', M0, '(M)')
        print('Postshock Velocity = %.3e' %v1, '(cm/sh) = ', M1, '(M)')
        print('\n')
        print('Preshock Temperature = %.3e' %T0, '(keV)')
        print('Postshock Temperature = %.3e' %T1, '(keV)')
        print('\n')
        print('Preshock Density = %.3e' %rho0, '(g/cm^3)')
        print('Postshock Density = %.3e' %rho1, '(g/cm^3)')

    # Check jump conditions
    rmass = (rho0*v0) / (rho1*v1)
    rmom  = (rho0*v0**2 + rho0*e0*(gamma-1)) / (rho1*v1**2 + rho1*e1*(gamma-1))
    rten  = (0.5*rho0*v0**3 + rho0*e0*v0*gamma) / (0.5*rho1*v1**3 + rho1*e1*v1*gamma)

    if LOUD:
        print('\n')
        print('Mass Flux Jump Ratio: ',         rmass)
        print('Momentum Flux Jump Ratio: ',     rmom)
        print('Total Energy Flux Jump Ratio: ', rten)

    # Transform to frame where preshock velocity is zero
    ss = -v0    # shock speed
    v0 = v0 + ss    # preshock velocity in dynamic frame
    v1 = v1 + ss    # postshock velocity in dynamic frame
    M0 = (v0-ss)/cs0    # preshock Mach number in dynamic frame
    M1 = (v1-ss)/cs1    # postshock Mach number in dynamic frame

    if LOUD:
        print('\n')
        print('Dynamic Preshock Velocity = %.3e' %v0, '(cm/sh) = ', M0, '(M)' )
        print('Dynamic Postshock Velocity = %.3e' %v1, '(cm/sh) = %.3e' %M1, '(M)')

    # Compute ratios of delta flux to delta solution
    ratio_mass = (rho0*v0 - rho1*v1) / (rho0-rho1)

    flux0      = rho0*v0**2 + rho0*e0*(gamma-1)
    flux1      = rho1*v1**2 + rho1*e1*(gamma-1)
    ratio_mom  = (flux0 - flux1) / (rho0*v0 - rho1*v1)

    flux0      = 0.5*rho0*v0**3 + rho0*e0*v0*gamma
    flux1      = 0.5*rho1*v1**3 + rho1*e1*v1*gamma
    u0         = 0.5*rho0*v0**2 + rho0*e0
    u1         = 0.5*rho1*v1**2 + rho1*e1
    ratio_ten  = (flux0 - flux1) / (u0 - u1)

    # Print flux to solution ratios in dynamic frame
    if LOUD:
        print('\n')
        print('The following verification parameters should all equal the shock speed:')
        print('Dynamic Mass Flux-to-Solution Ratio = %.3e' %ratio_mass)
        print('Dynamic Momentum Flux-to-Solution Ratio = %.3e' %ratio_mom)
        print('Dynamic Total Energy Flux-to-Solution Ratio = %.3e' %ratio_ten)

    return v0-ss, rho1, v1-ss, T1


import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from scipy import stats
# 生成各种正态分布随机数
np.random.seed(1234)
rn1 = np.random.normal(loc = 0, scale = 1, size = 1000)
rn2 = np.random.normal(loc = 0, scale = 2, size = 1000)
rn3 = np.random.normal(loc = 2, scale = 3, size = 1000)
rn4 = np.random.normal(loc = 5, scale = 3, size = 1000)
# 绘图
plt.style.use('ggplot')
sns.distplot(rn1, hist = False, kde = False, fit = stats.norm,
             fit_kws = {'color':'black','label':'u=0,s=1','linestyle':'-'})
sns.distplot(rn2, hist = False, kde = False, fit = stats.norm,
             fit_kws = {'color':'red','label':'u=0,s=2','linestyle':'--'})
sns.distplot(rn3, hist = False, kde = False, fit = stats.norm,
             fit_kws = {'color':'blue','label':'u=2,s=3','linestyle':':'})
sns.distplot(rn4, hist = False, kde = False, fit = stats.norm,
             fit_kws = {'color':'purple','label':'u=5,s=3','linestyle':'-.'})
# 呈现图例
plt.legend()
# 呈现图形
plt.show()

# 生成各种指数分布随机数
np.random.seed(1234)
re1 = np.random.exponential(scale = 0.5, size = 1000)
re2 = np.random.exponential(scale = 1, size = 1000)
re3 = np.random.exponential(scale = 1.5, size = 1000)
# 绘图
sns.distplot(re1, hist = False, kde = False, fit = stats.expon,
             fit_kws = {'color':'black','label':'lambda=0.5','linestyle':'-'})
sns.distplot(re2, hist = False, kde = False, fit = stats.expon,
             fit_kws = {'color':'red','label':'lambda=1','linestyle':'--'})
sns.distplot(re3, hist = False, kde = False, fit = stats.expon,
             fit_kws = {'color':'blue','label':'lambda=1.5','linestyle':':'})
# 呈现图例
plt.legend()
# 呈现图形
plt.show()


import numpy as np
import matplotlib.pyplot as plt

N = 4
D = 2

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

ones = np.ones((N, 1))

# plt.scatter(X[:, 0], X[:, 1], c=T)
# plt.show()

xy = (X[:, 0] * X[:, 1]).reshape(N, 1)
Xb = np.concatenate((ones, xy, X), axis=1)

w = np.random.randn(D + 2)
z = Xb.dot(w)

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

Y = sigmoid(z)

def cross_entropy(T, Y):
    E = 0
    for i in range(N):
        if T[i] == 1:
            E -= np.log(Y[i])
        else:
            E -= np.log(1 - Y[i])
    return E

learning_rate = 0.01
error = []
for i in range(5000):
    e = cross_entropy(T, Y)
    error.append(e)
    if i % 100 == 0:
        print(e)

    w += learning_rate * (np.dot((T - Y).T, Xb) - 0.01 * w)

    Y = sigmoid(Xb.dot(w))

plt.plot(error)
plt.show()

print('Final w', w)
print('Final classification rate', 1 - np.abs(T - np.round(Y)).sum() / N)


"""
.. _ref_mapdl_math_eigen_solve:

Using APDLMath to solve Eigenproblems
-------------------------------------
Use APDLMath to solve eigenproblems.

This example uses a verification manual input file, but you can use
your own sparse or dense matrices and solve those.

"""
import matplotlib.pylab as plt
import time
import numpy as np

from ansys.mapdl.core.examples import vmfiles
from ansys.mapdl.core import launch_mapdl

# Start MAPDL as a service and create an APDLMath object
mapdl = launch_mapdl(loglevel="ERROR")
mm = mapdl.math

###############################################################################
# First we get the `STIFF` and `MASS` matrices from the full file
# after running the input file from Verification Manual 153
#
out = mapdl.input(vmfiles["vm153"])

k = mm.stiff(fname="PRSMEMB.full")
m = mm.mass(fname="PRSMEMB.full")

###############################################################################
# Display size of the M and K matrices
print(m.shape)
print(k.shape)

###############################################################################
# Allocate an array to store the eigenshapes.
# where `nev` is the number of eigenvalues requested
#
nev = 10
a = mm.mat(k.nrow, nev)
a

###############################################################################
# Perform the the modal analysis.
#
# The algorithm is automatically chosen with respect to the matrices
# properties (e.g. scalar, storage, symmetry...)
#
print("Calling MAPDL to solve the eigenproblem...")

t1 = time.time()
ev = mm.eigs(nev, k, m, phi=a)
print(f"Elapsed time to solve this problem: {time.time() - t1}")

###############################################################################
# This is the vector of eigenfrequencies.
print(ev)

###############################################################################
# Verify the accuracy of eigenresults
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Check the residual error for the first eigenresult
# :math:`R_1=||(K-\lambda_1.M).\phi_1||_2`
#
# First, we compute :math:`\lambda_1 = \omega_1^2 = (2.\pi.f_1)^2`

# Eigenfrequency (Hz)
i = 0
f = ev[0]
omega = 2 * np.pi * f
lam = omega * omega

###############################################################################
# Then we get the 1st Eigenshape :math:`\phi_1`, and compute
# :math:`K.\phi_1` and :math:`M.\phi_1`

# shape
phi = a[0]

# APDL Command: *MULT,K,,Phi,,KPhi
kphi = k.dot(phi)

# APDL Command: *MULT,M,,Phi,,MPhi
mphi = m.dot(phi)

######################################################################
# Next, compute the `math`:||K.\phi_1||_2 quantity and normalize the
# residual value.

# APDL Command: *MULT,K,,Phi,,KPhi
kphi = k.dot(phi)

# APDL Command: *NRM,KPhi,NRM2,KPhiNrm
kphinrm = kphi.norm()

###############################################################################
# Then we add these two vectors, using the :math:`\lambda_1` scalar
# factor and finally compute the normalized residual value
# :math:`\frac{R_1}{||K.\phi_1||_2}`

# APDL Command: *AXPY,-lambda,,MPhi,1,,KPhi
mphi *= lam
kphi -= mphi

# Compute the residual
res = kphi.norm() / kphinrm
print(res)

###############################################################################
# This residual can be computed for all eigenmodes
#

def get_res(i):
    """Compute the residual for a given eigenmode"""
    # Eigenfrequency (Hz)
    f = ev[i]

    # omega = 2.pi.Frequency
    omega = 2 * np.pi * f

    # lambda = omega^2
    lam = omega * omega

    # i-th eigenshape
    phi = a[i]

    # K.Phi
    kphi = k.dot(phi)

    # M.Phi
    mphi = m.dot(phi)

    # Normalization scalar value
    kphinrm = kphi.norm()

    # (K-\lambda.M).Phi
    mphi *= lam
    kphi -= mphi

    # return the residual
    return kphi.norm() / kphinrm

mapdl_acc = np.zeros(nev)

for i in range(nev):
    f = ev[i]
    mapdl_acc[i] = get_res(i)
    print(f"[{i}] : Freq = {f}\t - Residual = {mapdl_acc[i]}")

###############################################################################
# Plot Accuracy of Eigenresults

fig = plt.figure(figsize=(12, 10))
ax = plt.axes()
x = np.linspace(1, nev, nev)
plt.title("APDL Math Residual Error (%)")
plt.yscale("log")
plt.ylim([10e-13, 10e-7])
plt.xlabel("Frequency #")
plt.ylabel("Errors (%)")
ax.bar(x, mapdl_acc, label="MAPDL Results")


import numpy as np
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
from kmeans import KMeans

# X, y = make_blobs(centers=4, n_samples=500, n_features=2, shuffle=True, random_state=42)
X, y = make_blobs(centers=3, n_samples=500, n_features=2, shuffle=True, random_state=40)
print(X.shape)

clusters = len(np.unique(y))
print(clusters)
k = KMeans(K=clusters, max_iters=150, plot_steps=True)
y_pred = k.predict(X)

k.plot()


from ..monte_carlo import monteCarloSkeleton, monteCarloStats

import numpy as np

def blackScholes(current: float, volatility: float, ttm: float, strike: float,
                 rf: float, dividend: float, sim_count: int, eval_count: int,
                 opt_type: str='C', **kwargs) -> dict:
    """Function to model the price of a European Option, under the
    Black-Scholes pricing model heuristic, using an antithetic variates method
    variance-reduced Monte-Carlo simulation.

    This function simulates two perfectly negatively correlated simple Geometric
    Brownian Motion (GBM) processes of the underlying asset price, before
    computing the terminal contract value for a given number of simulated paths,
    as the arithmetic average of the payouts of each of the two GBMs.

    Then, Monte Carlo simulation statistics are computed for each of the
    simulations, and a dict of results is returned.

    Arguments:
        current {float} -- Current price of the underlying asset.
        volatility {float} -- Volatility of the underlying asset price.
        ttm {float} -- Time to expiration (in years).
        strike {float} -- Strike price of the option contract.
        rf {float} -- Risk-free rate (annual).
        dividend {float} -- Dividend yield (annual).
        sim_count {int} -- Number of paths to simulate.
        eval_count {int} -- Number of evaluations per path simulation.

    Keyword Arguments:
        opt_type {str} -- Option type; must be 'C' or 'P' (default: {'C'}).

    Raises:
        ValueError: Raised if `opt_type` is not 'C' or 'P'.

    Returns:
        dict -- Formatted dictionary of Monte Carlo simulation results.
    """

    # Verify option choice
    if opt_type not in ['C', 'P']:
        raise ValueError('Incorrect option type; must be "C" or "P".')

    # Computing delta t
    dt = ttm / eval_count
    # Computing initial value
    init_val = np.log(current)
    # Computing nudt
    nudt = (rf - dividend - (np.power(volatility, 2) / 2)) * dt

    # Defining lambda functions to model Geometric Brownian Motion (GBM);
    # for both assets (negatively correlated)
    gbm1 = lambda x: nudt + (volatility * np.sqrt(dt) * x)
    gbm2 = lambda x: nudt + (volatility * np.sqrt(dt) * (-1 * x))

    # Defining simulation function
    def sim_func(x: np.array) -> float:
        if (opt_type == 'C'):
            # Call option
            return np.exp(-1 * rf * ttm) * 0.5 * (
                np.maximum(np.exp(init_val + np.sum(gbm1(x))) - strike, 0) +
                np.maximum(np.exp(init_val + np.sum(gbm2(x))) - strike, 0))
        else:
            # Put option
            return np.exp(-1 * rf * ttm) * 0.5 * (
                np.maximum(strike - np.exp(init_val + np.sum(gbm1(x))), 0) +
                np.maximum(strike - np.exp(init_val + np.sum(gbm2(x))), 0))

    # Running simulation
    mc_output = monteCarloSkeleton(sim_count=sim_count,
                                   eval_count=eval_count,
                                   sim_func=sim_func)

    # Computing and returning sample statistics
    return monteCarloStats(mc_output=mc_output)


import numpy as np
import matplotlib.pyplot as plt
from pyclustering.cluster.cure import cure
from pyclustering.cluster import cluster_visualizer_multidim
from scipy.spatial import distance
from sklearn.decomposition import PCA

def read_data(path):
	data = np.genfromtxt(path, delimiter=';')
	data = np.delete(data, 0, 0)
	data = data.tolist()
	return data

# Calculates the average distance to centroid of all clusters
def avg_dist_to_centroid(clusters, centroids, input_data):
	avg_dist = []
	_cluster = 0
	for cluster in clusters:
		sum_of_distances = 0
		points_cluster = len(cluster)
		for index in range(0, points_cluster):
			point = input_data[cluster[index]]
			centroid =  centroids[_cluster]
			sum_of_distances += distance.euclidean(point,
				centroid)
		avg_dist.append(sum_of_distances/points_cluster)
		_cluster += 1
	return sum(avg_dist)/len(avg_dist)

# Visualize obtained clusters in multi-dimensional space
def visualize_multidim():
	visualizer = cluster_visualizer_multidim()
	visualizer.append_clusters(clusters, sample_4d)
	visualizer.show(max_row_size=3)

if __name__ == '__main__':

	input_data = read_data('Data/Dataset(Clustering).csv')
	#Delete Outliers
	#outliers = [524, 512, 435, 432, 424, 387, 373, 285, 271, 213, 167, 147, 60, 47, 44, 40] #522, 213
	#outliers =[524, 40, 522, 213] #Aaron
	outliers = [524, 512, 435, 432, 424, 387, 373, 285, 271, 213, 167, 147, 60, 47, 44 ] #Adrian

	input_data = np.delete(input_data, outliers, 0)

	k_d_plot = {}
	k_centroids = {}
	k_clusters = {}
	for k in range(1,11):
		# Define parameters for the CURE algorithm
		cure_instance = cure(
			input_data, number_cluster=k,
			number_represent_points=4,
			compression=0.2, ccore=True);
		# Run the algorithm
		cure_instance.process();
		# Get list of allocated clusters.
		# Each cluster contains indexes of objects in list of data.
		clusters = cure_instance.get_clusters();
		# Returns list of point-representors of each cluster
		representatives_points = cure_instance.get_representors()
		# Mean of points that make up each cluster
		centroids = cure_instance.get_means()
		#Clusters average distance to centroids
		avg_dist = avg_dist_to_centroid(clusters,
			centroids, input_data)

		#K-Clusters vs Avg Distance to Cluster
		k_d_plot[k] = avg_dist
		#Appending centroid value of each cluster for each different value of K
		k_centroids[k] = centroids
		#List of clusters with the indexes of objects for each K
		k_clusters [k] = clusters

	print('K-Clusters vs Avg. Distance to Centroid:\n', k_d_plot)
	tmp = sorted(k_d_plot.items())
	k, dist = zip(*tmp)
	plt.plot(k, dist)
	plt.xlabel('K-Clusters')
	plt.ylabel('Avg Distance to Centroid')
	plt.show()

	#Solucion Optima
	optimal_k = 2
	print('\nOptimal Solution K = ', optimal_k)

	#Centroid of each cluster
	for i in range (0, len(k_centroids[optimal_k])):
		print('\nCentroid Cluster ',
			i+1, ':\n', k_centroids[optimal_k][i])

	#Number of observations in each cluster
	for i in range (0, len(k_clusters[optimal_k])):
		print('Number of instances in Cluster ',
				i+1, ': ', len(k_clusters[optimal_k][i]))


import numpy as np

from sklearn.preprocessing import MinMaxScaler, StandardScaler, RobustScaler

from O4 import prepare_data

X_train, X_test, y_train, y_test = prepare_data(split=True)

# Normalization (Min-Max)

min_max_scaler = MinMaxScaler()

X_train_norm = min_max_scaler.fit_transform(X_train)
X_test_norm = min_max_scaler.transform(X_test)

print(X_test[:5, :4], X_test_norm[:5, :4], sep='\n')

# Standardization

# Manual Standardization

example = np.array([0, 1, 2, 3, 4, 5])
print('standardized: ', (example - example.mean()) / example.std())
print('normalized: ',
      (example - np.min(example)) / (np.max(example) - np.min(example)))

# Using scikit-learn

standard_scaler = StandardScaler()

X_train_std = standard_scaler.fit_transform(X_train)
X_test_std = standard_scaler.transform(X_test)

# Again, it is also important to highlight that we fit the StandardScaler
# class only once—on the training data—and use those parameters to transform
# the test dataset or any new data point.

# Other, more advanced methods for feature scaling are available from scikit-
# learn, such as the RobustScaler . The RobustScaler is especially helpful and
# recommended if we are working with small datasets that contain many outliers.
# Similarly, if the machine learning algorithm applied to this dataset is prone
# to overfitting, the RobustScaler can be a good choice. Operating on each
# feature column independently, the RobustScaler removes the median value and
# scales the dataset according to the 1st and 3rd quartile of the dataset
# (that is, the 25th and 75th quartile, respectively) such that more extreme
# values and outliers become less pronounced. The interested reader can find
# more information about the RobustScaler in the official scikit-learn
# documentation at:
# https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.RobustScaler.html

robust_scaler = RobustScaler()

X_test_robust = robust_scaler.fit_transform(X_test)
X_train_robust = robust_scaler.fit(X_train)


import numpy as np
from scipy.optimize import curve_fit

class MODELS:

    LINEAR = {
        'id': 'linear',
        'f': lambda x,a,b: a * x + b,
        'str': '{}*x + {}',
        'min_values': 2
    }

    LOG = {
        'id': 'logarithmic',
        'f': lambda x,a,b: a * np.log(x) + b,
        'str': '{}*log(x) + {}',
        'min_values': 2
    }

    POLY2DEG = {
        'id': '2 degree polynomial',
        'f': lambda x,a,b,c: a * x + b * (x ** 2) + c,
        'str': '{}*x + {}*x^2 + {}',
        'min_values': 3
    }

    POLY3DEG = {
        'id': '3 degree polynomial',
        'f': lambda x,a,b,c,d: a * x + b * (x ** 2) + c * (x ** 3) + d,
        'str': '{}*x + {}*x^2 + {}*x^3 + {}',
        'min_values': 4
    }

    POLY4DEG = {
        'id': '4 degree polynomial',
        'f': lambda x,a,b,c,d,e: a*x+b*(x**2)+c*(x**3)+d*(x**4)+e,
        'str': '{}*x + {}*x^2 + {}*x^3 + {}*x^4 + {}',
        'min_values': 5
    }

    MAPPER = {
        'lin': LINEAR,
        'log': LOG,
        'poly2deg': POLY2DEG,
        'poly3deg': POLY3DEG,
        'poly4deg': POLY4DEG
    }

def build_regression_model(func, raw_data):
    x = np.arange(1, len(raw_data) + 1)
    y = np.array(raw_data)
    popt, pcov = curve_fit(func, x, y)

    x1 = np.arange(len(raw_data) + 1, len(raw_data) + 4)

    data = func(np.append(x, x1), *popt)
    residuals = y - func(x, *popt)
    ss_res = np.sum(residuals ** 2)
    ss_tot = np.sum((y - np.mean(y)) ** 2)
    r_squared = 1 - (ss_res / ss_tot)

    return data, r_squared, popt

def _safe_value(value):
    if np.isnan(value) or value in [np.inf, np.NINF]:
        return str(value)
    else:
        return value

def predictions(raw_data, models=[]):
    result = {}

    for model in models:
        if len(raw_data) < model['min_values']:
            result[model['id']] = {
                'values': ('Not enough input values. '
                           'Expected={}, current={}'.format(model['min_values'],
                                                            len(raw_data))),
                'r2': '',
                'function': '',
                'params': ''
            }
        else:
            values, r2, params = build_regression_model(model['f'], raw_data)
            result[model['id']] = {
                'values': values.tolist(),
                'r2': _safe_value(r2),
                'function': model['str'].format(*params),
                'params': params.tolist()
            }

    return result


from sklearn.metrics import (
    r2_score,
    mean_squared_log_error,
    mean_squared_error,
    mean_absolute_error,
    max_error
)
import numpy as np

def calculateR2Score(y_true, y_pred):
    r2 = r2_score(y_true, y_pred)
    return r2

def calculateMSE(y_true, y_pred):
    mse = mean_squared_error(y_true, y_pred)
    return mse

def calculateMAE(y_true, y_pred):
    mae = mean_absolute_error(y_true, y_pred)
    return mae

def calculateMaxError(y_true, y_pred):
    if len(y_true.shape) > 1 and y_true.shape and y_true.shape[1] > 1:
        maxerror = None
    else:
        maxerror = max_error(y_true, y_pred)
    return maxerror

def calculateMetrics(y_true, y_pred):
    r2 = r2_score(y_true, y_pred)
    mse = mean_squared_error(y_true, y_pred)
    mae = mean_absolute_error(y_true, y_pred)

    if len(y_true.shape) > 1 and y_true.shape and y_true.shape[1] > 1:
        maxerror = None
    else:
        maxerror = max_error(y_true, y_pred)
    return [r2, mse, mae, maxerror]

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

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

def relu(x):
    return np.maximum(x, 0)

def relu_vectorized(x):
    return np.vectorize(relu)

def leaky_relu(x, a):
    return np.maximum(x, a*x)

def leaky_relu_vectorized(x, a):
    return np.vectorize(leaky_relu)

def elu(x, a):
    if x >= 0:
        return x
    else:
        return a*(np.exp(x) - 1)


# -*- coding: utf-8 -*-

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

def loadData(filename):
    df = pd.read_table(filename, '\t', header=None)
    return np.array(df.loc[:,0:1]), np.array(df.loc[:,2])

def showData(X, y, w=None, b=None):
    plt.scatter(x=X[:,0], y=X[:,1], c=y)
    if (w is None) or (b is None):
        pass
    else:
        a = -w[1,0] / w[0,0]
        b = -b / w[1,0]
        plt.plot(X[:,0], a * X[:,0]+b, c='red')

def init_w_b(shape_w, shape_b, seed):
    np.random.seed(seed)
    w = np.random.rand(shape_w[0], shape_w[1])
    b = np.random.rand(shape_b[0])+0.01
    return w, b

def forward(X, w, b):
    z = np.dot(X, w) + b
    a = 1.0 / (1.0 + np.exp(-z))
    return a

def cost_func(y_, y):
    y_ = y_.flatten()
    y = y.flatten()
    #cost = np.average( -(y*np.log(y_) + (1-y)*np.log(1-y_)) )
    cost = np.sum(np.power(y_ - y, 2)) / y.shape[0]
    return cost

def train(maxloop, lr, X, y, w, b):
    m = X.shape[0]
    y = y.reshape((m,1))
    for i in range(maxloop):
        a = forward(X, w, b)
        d_z = a - y
        d_w = np.dot(X.T, d_z) / m
        d_b = np.sum(d_z) / m
        w = w - lr * d_w
        b = b - lr * d_b
        y_ = a
        #print(cost_func(y_, y))
        print(calc_accuarcy(y_, y))
    return w, b

def harden(y_, sepNum):
    y_[y_ > sepNum] = 1
    y_[y_ <= sepNum] = 0
    return y_

def calc_accuarcy(y_, y):
    y = y.flatten()
    y_ = y_.flatten()
    y_ = harden(y_, 0.5)
    correctNum = len(y_[y_ == y])
    return float(correctNum) / y.shape[0]

# ------------ main -------------- #
X, y = loadData('./data/testSet.txt')
showData(X, y)

w, b = init_w_b([2,1], [1], seed=314)
a = forward(X, w, b)
y_ = a.flatten()
cost = cost_func(y_, y)
w, b = train(100, 0.1, X, y, w, b)
y_ = forward(X, w, b)
y_ = harden(y_, 0.5)

showData(X, y_, w, b)


import logging
from numpy import random,meshgrid,power,sin,pi
def grv(lat,lon=None,shape_wanted=None):
    """
    purpose:give gravity cste depending of the latitude
    note: grv module returns vector if lat is a vector, to force the output to be a matrix of the same shape
    than over input fields, one can provide the lon vector as well or directly the shape of the matrix wanted.
    Args:
        lat (float ndarray): latitudes
        lon (float ncarray): longitudes [optional]
        shape_wanted (tuple): shape of the matrix wanted [optional]
    Returns:
        gg (float ndarray): gravity constant
    """
    gamma = 9.7803267715
    c1 = 0.0052790414
    c2 = 0.0000232718
    c3 = 0.0000001262
    c4 = 0.0000000007
    logging.debug('grv | lat:%s',lat.shape)
    if lon is not None:
        lon_m,lat_m = meshgrid(lon,lat)
    elif shape_wanted is not None and isinstance(lat, (int, long, float, complex))==False and len(shape_wanted)>1:
        randy = random.rand(shape_wanted[1])
#         lat_m = tile(lat,shape_wanted[1])
        lon_m,lat_m = meshgrid(randy,lat)
#         lat_m = lat_m.T
        logging.debug('grv | shape_wanted :%s lat_m:%s',shape_wanted,lat_m.shape)
    else:
        lat_m = lat
    phi = lat_m*pi/180.
    xx = sin(phi)
    gg = gamma*(1+c1*power(xx,2)+c2*power(xx,4)+c3*power(xx,6)+c4*power(xx,8))
    return gg


from qcodes.instrument.base import Instrument
import numpy as np

class SphereCor(Instrument):
    '''
    Class to form spherical coordinates out of 3 input parameters in cartesian coordiantes.
    '''
    def __init__(self, name, paramX, paramY, paramZ, **kwargs):
        super().__init__(name, **kwargs)

        self.paramX = paramX
        self.paramY = paramY
        self.paramZ = paramZ

        # Get current values
        self.rtp_get()

        self.add_parameter('radius',
                            get_cmd=self._get_r,
                            set_cmd=self._set_r,
                            get_parser=float,
                            label = 'radius',
                            unit='')
        self.add_parameter('theta',
                            get_cmd=self._get_theta,
                            set_cmd=self._set_theta,
                            get_parser=float,
                            label = 'theta',
                            unit='degree')
        self.add_parameter('phi',
                            get_cmd=self._get_phi,
                            set_cmd=self._set_phi,
                            get_parser=float,
                            label = 'phi',
                            unit='degree')

    def rtp_get(self):
        x = self.paramX()
        y = self.paramY()
        z = self.paramZ()
        sphere = self._carttosphere([x , y , z])
        self._radius, self._theta, self._phi = sphere
        return sphere

    def rtp_set(self, sphere):
        x, y, z = self._spheretocart(sphere)
        self._radius, self._theta, self._phi = sphere
        self.paramX(x)
        self.paramY(y)
        self.paramZ(z)

    def _get_r(self):
        self.rtp_get()
        return self._radius

    def _set_r(self, val):
        self._radius = val
        self.rtp_set([self._radius, self._theta, self._phi])

    def _get_theta(self):
        self.rtp_get()
        return self._theta

    def _set_theta(self, val):
        self._theta = val
        self.rtp_set([self._radius, self._theta, self._phi])

    def _get_phi(self):
        self.rtp_get()
        return self._phi

    def _set_phi(self, val):
        self._phi = val
        self.rtp_set([self._radius, self._theta, self._phi])

    def _spheretocart(self, sphere):
        """
        r,  theta,  phi = sphere
        """
        r,  theta,  phi = sphere
        theta = theta*np.pi/180
        phi = phi*np.pi/180
        x = (r * np.sin(theta) * np.cos(phi))
        y = (r * np.sin(theta) * np.sin(phi))
        z = (r * np.cos(theta))
        return [x,  y,  z]

    def _carttosphere(self, cartesian):
        x, y, z = cartesian
        r = np.sqrt(x**2 + y**2 + z**2)
        if r < 1e-6:
            theta = 0
            phi = 0
        else:
            theta = np.arccos(z / r)*180/np.pi
            phi = np.arctan2(y,  x)*180/np.pi
            if phi<0:
                phi = phi+360
        return [r, theta, phi]


import math
import numpy as np

class MatrixFactory(object):

    @staticmethod
    def makeIdentity():
        return np.array( [[1,0,0,0],
                          [0,1,0,0],
                          [0,0,1,0],
                          [0,0,0,1]] )

    @staticmethod
    def makeTranslation(x, y, z):
        return np.array([[1,0,0,x],
                         [0,1,0,y],
                         [0,0,1,z],
                         [0,0,0,1]])

    # rotation around x axis
    @staticmethod
    def makeRotationX(angle):
        c = math.cos(angle)
        s = math.sin(angle)
        return np.array([[1,0,0,0],
                         [0,c,-s,0],
                         [0,s,c,0],
                         [0,0,0,1]])

    # rotation around y axis
    @staticmethod
    def makeRotationY(angle):
        c = math.cos(angle)
        s = math.sin(angle)
        return np.array([[c,0,s,0],
                          [0,1,0,0],
                          [-s,0,c,0],
                          [0,0,0,1]])

    # rotation around z axis
    @staticmethod
    def makeRotationZ(angle):
        c = math.cos(angle)
        s = math.sin(angle)
        return np.array([[c,-s,0,0],
                          [s,c,0,0],
                          [0,0,1,0],
                          [0,0,0,1]])

    # translation along a specified (normalized) axis
    @staticmethod
    def makeTranslationAxisDistance(axis, distance):
        displacement = np.array(axis) * distance
        return np.array( [[1, 0, 0, displacement[0]],
                           [0, 1, 0, displacement[1]],
                           [0, 0, 1, displacement[2]],
                           [0, 0, 0, 1]] )

    # rotation around a specified (normalized) axis
    @staticmethod
    def makeRotationAxisAngle(axis, angle):
        c = math.cos(angle)
        s = math.sin(angle)
        t = 1 - c
        x = axis[0]
        y = axis[1]
        z = axis[2]
        tx = t*x
        ty = t*y
        return np.array([[tx*x+c,   tx*y-s*z, tx*z+s*y, 0],
                          [tx*y+s*z, ty*y+c,   ty*z-s*x, 0],
                          [tx*z-s*y, ty*z+s*x, t*z*z+c,  0],
                          [0, 0, 0, 1]])

    # make scale
    @staticmethod
    def makeScaleUniform(s):
        return np.array([[s,0,0,0],
                         [0,s,0,0],
                         [0,0,s,0],
                         [0,0,0,1]])

    @staticmethod
    def makePerspective(fov=60, aspect=1, near=0.1, far=1000):
        D2R = 3.1415926 / 180.0
        yScale = 1.0 / math.tan(D2R * fov / 2)
        xScale = yScale / aspect
        c = (far + near) / (near - far)
        d = 2*far*near / (near - far)
        return np.array([[xScale,0,0,0],
                         [0,yScale,0,0],
                         [0, 0,  c, d],
                         [0, 0, -1, 0]])

    @staticmethod
    def makeOrthographic(left=-1, right=1, top=1, bottom=-1, far=1, near=-1):
        return np.array([[2/(right-left), 0, 0, -(right+left)/(right-left)],
                         [0, 2/(top-bottom), 0, -(top+bottom)/(top-bottom)],
                         [0, 0,  -2/(far-near), -(far+near)/(far-near)],
                         [0, 0, 0, 1]])

    @staticmethod
    def makeLookAt(position, target, up):

        forward = np.subtract(target, position)
        forward = np.divide( forward, np.linalg.norm(forward) )

        right = np.cross( forward, up )

        # if forward and up vectors are parallel, right vector is zero;
        #   fix by perturbing up vector a bit
        if np.linalg.norm(right) < 0.001:
            epsilon = np.array( [0.001, 0, 0] )
            right = np.cross( forward, up + epsilon )

        right = np.divide( right, np.linalg.norm(right) )

        up = np.cross( right, forward )
        up = np.divide( up, np.linalg.norm(up) )

        return np.array([[right[0], up[0], -forward[0], position[0]],
                         [right[1], up[1], -forward[1], position[1]],
                         [right[2], up[2], -forward[2], position[2]],
                         [0, 0, 0, 1]])


from __future__ import annotations

import math

import numpy as np
from numpy.linalg import inv, det, slogdet

class UnivariateGaussian:
    """
    Class for univariate Gaussian Distribution Estimator
    """
    def __init__(self, biased_var: bool = False) -> UnivariateGaussian:
        """
        Estimator for univariate Gaussian mean and variance parameters

        Parameters
        ----------
        biased_var : bool, default=False
            Should fitted estimator of variance be a biased or unbiased estimator

        Attributes
        ----------
        fitted_ : bool
            Initialized as false indicating current estimator instance has not been fitted.
            To be set as True in `UnivariateGaussian.fit` function.

        mu_: float
            Estimated expectation initialized as None. To be set in `UnivariateGaussian.fit`
            function.

        var_: float
            Estimated variance initialized as None. To be set in `UnivariateGaussian.fit`
            function.
        """
        self.biased_ = biased_var
        self.fitted_, self.mu_, self.var_ = False, None, None

    def fit(self, X: np.ndarray) -> UnivariateGaussian:
        """
        Estimate Gaussian expectation and variance from given samples

        Parameters
        ----------
        X: ndarray of shape (n_samples, )
            Training data

        Returns
        -------
        self : returns an instance of self.

        Notes
        -----
        Sets `self.mu_`, `self.var_` attributes according to calculated estimation (where
        estimator is either biased or unbiased). Then sets `self.fitted_` attribute to `True`
        """
        expectency = variance = 0
        for sample in X:
            expectency += sample
        if not X.size == 0:
            expectency = expectency / X.size
        for sample in X:
            variance += (sample - expectency) ** 2
        if self.biased_ and X.size:
            variance = variance / X.size
        elif not self.biased_ and X.size > 1:
            variance = variance / (X.size - 1)
        self.mu_, self.var_ = expectency, variance
        self.fitted_ = True
        return self

    def pdf(self, X: np.ndarray) -> np.ndarray:
        """
        Calculate PDF of observations under Gaussian model with fitted estimators

        Parameters
        ----------
        X: ndarray of shape (n_samples, )
            Samples to calculate PDF for

        Returns
        -------
        pdfs: ndarray of shape (n_samples, )
            Calculated values of given samples for PDF function of N(mu_, var_)

        Raises
        ------
        ValueError: In case function was called prior fitting the model
        """
        if not self.fitted_:
            raise ValueError("Estimator must first be fitted before calling `pdf` function")
        pdfed_samples = []
        for val in X:
            pdfed_samples.append(self.__cal_density(val))
        return np.array(pdfed_samples)

    def __cal_density(self, val):
        # a function that calculates the pdf of each value
        if self.var_ == 0:
            return 0
        return (math.e ** -(((val - self.mu_) ** 2)/(2 * self.var_)))/(1/math.sqrt(2 * math.pi * self.var_))

    @staticmethod
    def log_likelihood(mu: float, sigma: float, X: np.ndarray) -> float:
        """
        Calculate the log-likelihood of the data under a specified Gaussian model

        Parameters
        ----------
        mu : float
            Expectation of Gaussian
        sigma : float
            Variance of Gaussian
        X : ndarray of shape (n_samples, )
            Samples to calculate log-likelihood with

        Returns
        -------
        log_likelihood: float
            log-likelihood calculated
        """
        # calculate the log-likelihood according to the formula found in the
        # course book
        sample_sum = 0
        for val in X:
            sample_sum += (val - mu) ** 2
        sample_sum = sample_sum / -(2 * sigma )
        divide_by = math.pow(2 * math.pi * sigma, X.size / 2)
        return sample_sum - math.log(divide_by)

class MultivariateGaussian:
    """
    Class for multivariate Gaussian Distribution Estimator
    """
    def __init__(self):
        """
        Initialize an instance of multivariate Gaussian estimator

        Attributes
        ----------
        fitted_ : bool
            Initialized as false indicating current estimator instance has not been fitted.
            To be set as True in `MultivariateGaussian.fit` function.

        mu_: ndarray of shape (n_features,)
            Estimated expectation initialized as None. To be set in `MultivariateGaussian.fit`
            function.

        cov_: ndarray of shape (n_features, n_features)
            Estimated covariance initialized as None. To be set in `MultivariateGaussian.fit`
            function.
        """
        self.mu_, self.cov_ = None, None
        self.fitted_ = False

    def fit(self, X: np.ndarray) -> MultivariateGaussian:
        """
        Estimate Gaussian expectation and covariance from given samples

        Parameters
        ----------
        X: ndarray of shape (n_samples, n_features)
            Training data

        Returns
        -------
        self : returns an instance of self

        Notes
        -----
        Sets `self.mu_`, `self.cov_` attributes according to calculated estimation.
        Then sets `self.fitted_` attribute to `True`
        """
        self.mu_ = np.mean(X, axis=0)
        centered_X_matrix = X - np.tile(self.mu_, (X.shape[0], 1))
        divide_by = X.shape[0] - 1
        self.cov_ = (centered_X_matrix.T @ centered_X_matrix) / (divide_by)
        self.fitted_ = True
        return self

    def pdf(self, X: np.ndarray):
        """
        Calculate PDF of observations under Gaussian model with fitted estimators

        Parameters
        ----------
        X: ndarray of shape (n_samples, n_features)
            Samples to calculate PDF for

        Returns
        -------
        pdfs: ndarray of shape (n_samples, )
            Calculated values of given samples for PDF function of N(mu_, cov_)

        Raises
        ------
        ValueError: In case function was called prior fitting the model
        """
        if not self.fitted_:
            raise ValueError("Estimator must first be fitted before calling `pdf` function")
        # calculate the pdf according to the formula found in the course book
        pdf_values = []
        for x in X:
            mult = -0.5 * (x - self.mu_).T @ np.linalg.inv(self.cov_) @ (x - self.mu_)
            divide_by = math.sqrt(((2 * math.pi) ** x.shape[0]) * np.linalg.det(self.cov_))
            pdf_values.append((math.e ** mult) / divide_by)
        return np.array(pdf_values)

    @staticmethod
    def log_likelihood(mu: np.ndarray, cov: np.ndarray, X: np.ndarray) -> float:
        """
        Calculate the log-likelihood of the data under a specified Gaussian model

        Parameters
        ----------
        mu : ndarray of shape (n_features,)
            Expectation of Gaussian
        cov : ndarray of shape (n_features, n_features)
            covariance matrix of Gaussian
        X : ndarray of shape (n_samples, n_features)
            Samples to calculate log-likelihood with

        Returns
        -------
        log_likelihood: float
            log-likelihood calculated over all input data and under given parameters of Gaussian
        """
        #calculate the log-likelihood according to the formula solved in the
        #theoritcal part
        cov_det = np.linalg.det(cov)
        cov_inverse = np.linalg.inv(cov)
        inner_mult = 0
        for vec in X:
            inner_mult += -0.5 * (vec - mu).T @ cov_inverse @ (vec - mu)
        return inner_mult - (X.size / 2) * math.log(cov_det) - X.size * X.shape[1] * 0.5 * math.log(2 * math.pi)


# **************************************************************************** #
#                                                                              #
#                                                         :::      ::::::::    #
#    gradientDescent.py                                 :+:      :+:    :+:    #
#                                                     +:+ +:+         +:+      #
#    By: pmasson <marvin@42.fr>                     +#+  +:+       +#+         #
#                                                 +#+#+#+#+#+   +#+            #
#    Created: 2019/03/26 14:16:32 by pmasson           #+#    #+#              #
#    Updated: 2019/03/28 10:59:11 by pmasson          ###   ########.fr        #
#                                                                              #
# **************************************************************************** #

import numpy as np
import sys
import signal
import utils
import os

signal.signal(signal.SIGINT, utils.close_prog)

def get_data():
    x = list()
    y = list()
    if (os.path.isfile(utils.dataFile) == False):
        print("Error, no data file")
        sys.exit(0)
    else:
        try:
            with open(utils.dataFile, "r") as datafile:
                rdata = datafile.read()
                ldata = utils.manage_file(rdata, ",")
                i = 2
                if (len(ldata) % 2 != 0):
                    print("Error, wrong number of data")
                    sys.exit(0)
                while (i < len(ldata)):
                    try:
                        x.append([1, float(ldata[i])])
                        y.append([float(ldata[i + 1])])
                        i = i + 2
                    except ValueError:
                        print("Error, wrong value in data")
                        sys.exit(0)
        except IOError:
            print("Error, no reading rights on data file")
            sys.exit(0)
    x1 = np.asarray(x)
    y1 = np.asarray(y)
    return (x1, y1)

def cost(theta, x, y):
    m = len(x)
    if (m == 0):
        print("Error, no data to make gradient descent")
        sys.exit(0)
    try:
        j = np.sum((np.dot(x, theta) - y)**2) * 2 / m
    except FloatingPointError:
       print("an error occured, try changing alpha value")
       sys.exit(0)
    return (j)

def gradient(x,y):
    alpha = utils.alpha
    m = len(x)
    if (m == 0):
        print("Error, no data to make gradient descent")
        sys.exit(0)
    dj = 1
    theta = np.array([[1],[1]])
    while (dj > 0.01):
        j1 = cost(theta, x, y)
        tmp0 = theta[0, 0] - np.vdot((np.dot(x,theta) - y).T, x[:,0]) * alpha / m
        tmp1 = theta[1, 0] - np.vdot((np.dot(x,theta) - y).T, x[:,1]) * alpha /  m
        theta = np.array([[tmp0], [tmp1]])
        j = cost(theta, x, y)
        dj = abs(j1 - j)
    return (theta)

def write_theta(theta, mu, sigma):
    ret = str()
    ret = "theta0 = " + str(theta[0, 0]) + "\n" + "theta1 = " + str(theta[1, 0])
    ret = ret + "\nmu = " + str(mu) + "\nsigma = " + str(sigma)
    try:
        with open(utils.thetaFile, "w") as tfile:
            tfile.write(ret)
    except IOError:
        print("Error, no writting rights on thetas file")
        sys.exit(0)

def normal_equ(x, y):
    try:
        theta2 = np.dot(np.dot(np.linalg.inv(np.dot(x.T, x)), x.T), y)
    except np.linalg.LinAlgError:
        print("singular matrix, normal equ can't work")
    return(theta2)

def gradient_descent():
    np.seterr(all='raise')
    x, y = get_data()
    x1 = x.copy()
    x , mu, sigma = utils.normalize(x)
    theta = gradient(x,y)
    #utils.draw_points(x1, y, theta, mu, sigma)
    write_theta(theta, mu, sigma)
    theta2 = normal_equ(x,y)
    print("normal equ :\ntheta0 = {}\ntheta1 = {}".format(theta2[0,0], theta2[1,0]))

if __name__ == "__main__":
    gradient_descent()


# -*- coding: utf-8 -*-
"""
Created on Mon Jan 24 18:46:15 2022

1D Lucas Kanade

@author: guido
"""

import numpy as np
from matplotlib import pyplot as plt

def fun(x, offset=10, slope = -0.5, a = 1, fun_type = 'sine_slope'):

    if(fun_type == 'sine_slope'):
        y = offset + slope * x + np.sin(a * x)
    elif(fun_type == 'quadratic'):
        y = offset + slope * x + a * x**2
    elif(fun_type == 'linear'):
        y = offset + slope * x

    return y

def fun_dx(x, offset=10, slope = -0.5, a = 1, fun_type = 'sine_slope'):

    if(fun_type == 'sine_slope'):
        dy_dx = slope + a * np.cos(a * x)
    elif(fun_type == 'quadratic'):
        dy_dx = slope + 2* a * x
    elif(fun_type == 'linear'):
        dy_dx = slope

    return dy_dx

def fun_dx2(x, offset=10, slope = -0.5, a = 1, fun_type = 'sine_slope'):

    if(fun_type == 'sine_slope'):
         dy_dxdx = -a*a * np.sin(a * x)
    elif(fun_type == 'quadratic'):
         dy_dxdx = 2 * a
    elif(fun_type == 'linear'):
        dy_dxdx = 0

    return dy_dxdx

# ground-truth shift:
dx = 0.5

# properties of the function

#fun_type = 'quadratic'
#offset= 10
#slope = 0
#a = 2
#dx = 0.5

#fun_type = 'linear'
#offset= 0
#slope = 0
#a = 0
#dx = 0.5

fun_type = 'sine_slope'
offset= 5
slope = 0 #0.5
a = 5
# ground-truth shift:
dx = 2*np.pi/(a*2) # + 0.1

# range in which we show the function:
max_x = 3
step = 0.01

# We take a simple 1D function and shift it in the x-axis:
x = np.arange(-max_x, max_x, step)
f = fun(x, offset, slope, a, fun_type)
g = fun(x+dx, offset, slope, a, fun_type)

# Plot the functions
plt.figure()
plt.plot(x, f, x, g)
plt.xticks(np.arange(-max_x, max_x,1))
plt.grid()
plt.legend(['f', 'g'])
plt.show()

plt.pause(1)

x_query = float(input('Where do you want to determine optic flow? x = '))

# Determine f'(x) and apply Eq. 4:
small = 0.01
df_dx = (fun(x_query+small, offset, slope, a, fun_type) - fun(x_query, offset, slope, a, fun_type)) / small
h = (fun(x_query+dx, offset, slope, a, fun_type) - fun(x_query, offset, slope, a, fun_type)) / df_dx

# Output result:
print(f'Lucas and Kanade say that the shift at {x_query} = {h}, while the ground truth is {dx}')
print(f'Approximation df/dx = {df_dx}, real value = {fun_dx(x_query, offset, slope, a, fun_type)}')
print(f'df/dx({x_query}) = {fun_dx(x_query, offset, slope, a, fun_type)}, df/dx2({x_query}) = {fun_dx2(x_query, offset, slope, a, fun_type)}')


import sys

#Imports
import numpy as np
import math
import matplotlib.pyplot as plt

question = sys.argv[1]

def berkan_ozdamar_21602353_hw1(question):
    if question == '1' :

        A = np.array([[1, 0, -1, 2], [2, 1, -1, 5], [3, 3, 0, 9]])
        b = np.array([1, 4, 9])

        # Part a
        print('Part a')
        print('\n')
        # Since x_3 and x_4 are free variables, we will assign them random numbers with numpy.random
        x_3 = np.random.random()
        x_4 = np.random.random()

        x_n = np.array([x_3 - 2 * x_4, -x_3 - x_4, x_3, x_4])
        print('Solution for Ax = 0')
        print(x_n)
        print('\n')
        result = np.around(A.dot(x_n), 6)
        print('Confirming that Ax = 0')
        print(result)

        # Part b
        print('Part b')
        print('\n')
        # Since x_3 and x_4 are free variables, we will write solution set in terms of them. And since we are looking for
        # a particular solution, assigning x_3 and x_4 as 0 will make x_p = [1 2 0 0]^T. Then check whether A.x_p = b where
        # b is [1 4 9]^T
        x_3 = 0
        x_4 = 0

        print('Solution for Ax = b')
        x_p = np.array([1 + x_3 - 2 * x_4, 2 - x_3 - x_4, x_3, x_4])
        print(x_p)
        print('\n')
        print('Confirming that Ax = b')
        result = A.dot(x_p)
        print(result)

        # Part c
        print('Part c')
        print('\n')
        x_3 = np.random.random()
        x_4 = np.random.random()

        x_c = np.array([1 + x_3 - 2 * x_4, 2 - x_3 - x_4, x_3, x_4])

        print('Confirming that Ax = b')
        result = A.dot(x_c)
        print(result)

        # Part d
        print('Part d')
        u, s, v = np.linalg.svd(A)

        # Make sigma in the correct form which is 3x4 matrix
        sigma = np.zeros((3, 4))
        for i in range(len(sigma[:, 0])):
            for j in range(len(sigma[0])):
                if (i == j):
                    # Instead of zero, it assigns third sigma value as 2*10^-16, which makes problem when taking reciprocal.
                    # To resolve that issue, i have just assigned 0 instead 2*10^-16
                    if (s[i] > 10 ** -15):
                        sigma[i, j] = s[i]
                    else:
                        sigma[i, j] = 0

        # To find sigma_plus, take reciprocals of the non-zero values.
        sigma_plus = np.zeros((3, 4))
        for i in range(len(sigma[:, 0])):
            for j in range(len(sigma[0])):
                if (i == j and sigma[i, j] != 0):
                    sigma_plus[i, j] = 1 / sigma[i, j]

        print('U is:')
        print(u)
        print('V is:')
        print(v)
        print('sigma is:')
        print(sigma)

        A_pseudo = (v.T).dot(sigma_plus.T).dot(u.T)
        print('Pseudo inverse of A by SVD decomposition :')
        print(A_pseudo)
        print('\n')
        print('To see how accurate our pseudo inverse of A, is we check A.A_pseudo.A = A')
        print(A.dot(A_pseudo).dot(A))

        # Finally, find pseudo inverse of A with numpy.linalg.pinv(A)
        A_pseudo_2 = np.linalg.pinv(A)
        print('\n')
        print('Pseudo inverse of A with numpy.linalg.pinv(A)')
        print(A_pseudo_2)

        # Part e
        print('Part e')
        print('\n')
        # 1. Set free variables to zero
        x_3 = 0
        x_4 = 0
        x_sparsest = np.array([1 + x_3 - 2 * x_4, 2 - x_3 - x_4, x_3, x_4])

        print('Sparsest solution example for x is')
        print(x_sparsest)

        # 2. Set one of the free variables to zero. And set other free variable such that one of the pivots become 0.
        x_3 = 0
        x_4 = 1 / 2
        x_sparsest = np.array([1 + x_3 - 2 * x_4, 2 - x_3 - x_4, x_3, x_4])

        print('Sparsest solution example for x is')
        print(x_sparsest)

        # 3.Set free variables such that both pivots are zero.
        x_3 = 1
        x_4 = 1
        x_sparsest = np.array([1 + x_3 - 2 * x_4, 2 - x_3 - x_4, x_3, x_4])

        print('Sparsest solution example for x is')
        print(x_sparsest)

        # Part f
        print('Part f')
        print('\n')
        L2 = A_pseudo.dot(b)
        print('Least norm solution is:')
        print(L2)

    elif question == '2' :

        # Part a
        print('Part A')
        print('\n')

        def nChooseK(n, k):
            return math.factorial(n) / (math.factorial(k) * math.factorial(n - k))

        def bernoulliDist(n, k, p):
            return nChooseK(n, k) * (p ** k) * ((1 - p) ** (n - k))

        x = np.arange(0, 1.001, 0.001)
        likelihood_lang = bernoulliDist(869, 103, x)
        likelihood_notlang = bernoulliDist(2353, 199, x)

        index = np.arange(0, 1001)
        plt.xlim(0, 200)
        plt.bar(index, likelihood_lang)
        plt.xlabel('Probability * 1000')
        plt.ylabel('Likelihood')
        plt.title('Likelihood distribution of language involved tasks')
        plt.show(block=False)

        plt.xlim(0, 200)
        plt.bar(index, likelihood_notlang)
        plt.xlabel('Probability * 1000')
        plt.ylabel('Likelihood')
        plt.title('Likelihood distribution of tasks that do not involve language')
        plt.show(block=False)

        # Part b
        print('Part b')
        print('\n')

        max_l = np.amax(likelihood_lang)
        max_nl = np.amax(likelihood_notlang)

        max_l_prob = 0
        max_nl_prob = 0
        for i in range(len(likelihood_lang)):
            if (likelihood_lang[i] == max_l):
                # Dividing the i by 1000 since the probability is scaled by 1000.
                max_l_prob = i / 1000

            if (likelihood_notlang[i] == max_nl):
                max_nl_prob = i / 1000

        print(
            'The probability that maximizes the likelihood of language involving tasks: (probability, likelihood of that probability)')
        print(max_l_prob, max_l)
        print(
            'The probability that maximizes the likelihood of not language involving tasks: (probability, likelihood of that probability)')
        print(max_nl_prob, max_nl)

        # Part c
        print('Part c')
        print('\n')
        # x has 1001 values, and since it is given that uniformly distributed, prior P(X) = 1/1001
        prior = 1 / 1001

        normalizer_l = 0
        posterior_l = np.zeros(len(likelihood_lang))
        normalizer_nl = 0
        posterior_nl = np.zeros(len(likelihood_notlang))

        for i in range(len(likelihood_lang)):
            normalizer_l += likelihood_lang[i] * prior
            normalizer_nl += likelihood_notlang[i] * prior

        posterior_l[:] = likelihood_lang[:] * prior / normalizer_l
        posterior_nl[:] = likelihood_notlang[:] * prior / normalizer_nl

        plt.xlim(0, 200)
        plt.bar(index, posterior_l)
        plt.xlabel('Probability * 1000')
        plt.ylabel('Posterior')
        plt.title('Posterior distribution of language involved tasks')
        plt.show(block=False)

        plt.xlim(0, 200)
        plt.bar(index, posterior_nl)
        plt.xlabel('Probability * 1000')
        plt.ylabel('Posterior')
        plt.title('Posterior distribution of tasks that do not involve language')
        plt.show(block=False)

        def pdf_to_cdf(posterior):
            lowerbound = 0
            temp_min = 0
            upperbound = np.inf
            temp_max = np.inf
            cdf = np.zeros(len(posterior) + 1)
            for i in range(1, len(posterior) + 1):
                for j in range(i):
                    cdf[i] += posterior[j]
                    # Since i have iterated i by 1, when finding lowerbound and upperbound, i decrease 1 from i.
                if (cdf[i] >= 0.025 and lowerbound <= temp_min):
                    temp_min = cdf[i]
                    lowerbound = (i - 1) / 1000
                if (cdf[i] >= 0.975 and upperbound >= temp_max):
                    temp_max = cdf[i]
                    upperbound = (i - 1) / 1000
            return cdf, lowerbound, upperbound

        cdf_l, lower_l, upper_l = pdf_to_cdf(posterior_l)
        cdf_nl, lower_nl, upper_nl = pdf_to_cdf(posterior_nl)

        index2 = np.arange(0, 1002)
        plt.bar(index2, cdf_l)
        plt.xlabel('Probability * 1000')
        plt.ylabel('P(X < x|data)')
        plt.title('CDF of posterior distribution of tasks that involve language')
        plt.show(block=False)

        plt.bar(index2, cdf_nl)
        plt.xlabel('Probability * 1000')
        plt.ylabel('P(X < x|data)')
        plt.title('CDF of posterior distribution of tasks that do not involve language')
        plt.show(block=False)

        print('Confidence interval of x_l is (', lower_l, ',', upper_l, ')')
        print('Confidence interval of x_nl is (', lower_nl, ',', upper_nl, ')')

        # Part d
        print('Part d')
        print('\n')

        matrixPosterior_l = np.matrix(posterior_l)
        matrixPosterior_nl = np.matrix(posterior_nl)
        joint_dist = (matrixPosterior_l.T).dot(matrixPosterior_nl)

        plt.imshow(joint_dist)
        plt.xlabel('x_nl * 1000')
        plt.ylabel('x_l * 1000')
        plt.colorbar()
        plt.show(block=False)

        x_l_greater = 0
        x_l_notgreater = 0
        for i in range(len(joint_dist)):
            for j in range(len(joint_dist)):
                if (i > j):
                    x_l_greater += joint_dist[i, j]
                else:
                    x_l_notgreater += joint_dist[i, j]

        print('Sum of posteriors such that x_l > x_nl')
        print(x_l_greater)
        print('Sum of posteriors such that x_l <= x_nl')
        print(x_l_notgreater)

        # Part e
        print('Part e')
        print('\n')
        PROB_LANG = 0.5

        prob_lang_active = (max_l_prob * PROB_LANG) / ((max_l_prob * PROB_LANG) + max_nl_prob * (1 - PROB_LANG))
        print('P(language | activation) is :')
        print(prob_lang_active)

berkan_ozdamar_21602353_hw1(question)


import numpy as np
from Numeric_Integration import m
from Numeric_Integration import RR1f
from Numeric_Integration import MR2f
from Numeric_Integration import RR1a
from Numeric_Integration import SR4a
import matplotlib.pyplot as plt

def linear(x):
    return x

def RR1f_MR2f_Test():
    accu = 1

    sine = m(np.sin)
    skip = 1000
    step = 10
    interval = 10
    err = np.zeros(step)
    a = 0
    b = np.pi/2

    for i in range(step):
        n = skip+(i + 1)*interval
        err[i] = abs(accu - RR1f(a, b, n, sine)) * n

    plt.title("RR1f vs MR2f Test")
    plt.plot(np.arange(step)+1, err, 'r')

    for i in range(step):
        n = skip+(i + 1)*interval
        err[i] = abs(accu - MR2f(a, b, n, sine)) * n**2

    plt.plot(np.arange(step)+1, err, 'y')
    plt.show()

def Part_D():
    skip = 1000
    step = 10
    interval = 10
    a = 0
    b = 1
    err = np.zeros(step)
    weight_2 = 1000 #weight to make the graph more visible for small constant
    weight_3 = 100

    accu_1 = 2

    def f_1(x):
        return 1/np.sqrt(x)

    integ_1 = m(f_1)

    for i in range(step):
        n = skip+(i + 1)*interval
        err[i] = abs(accu_1 - MR2f(a, b, n, integ_1)) * n
    plt.title("Part D Function Comparison")
    plt.plot(np.arange(step)+1, err, 'r')

    accu_2 = 2/3

    def f_2(x):
        return np.sqrt(x)

    integ_2 = m(f_2)

    for i in range(step):
        n = skip+(i + 1)*interval
        err[i] = abs(accu_2 - MR2f(a, b, n, integ_2)) * n * weight_2
    plt.plot(np.arange(step)+1, err, 'y')

    accu_3 = 2/5

    def f_3(x):
        return x**(3/2)

    integ_3 = m(f_3)

    for i in range(step):
        n = skip+(i + 1)*interval
        err[i] = abs(accu_3 - MR2f(a, b, n, integ_3)) * n**2 * weight_3
    plt.plot(np.arange(step)+1, err, 'g')
    plt.show()

def Part_E(lam):
    def exponential(x):
        return lam*np.exp(-lam*x)

    approx, n0, status = RR1a(0, 1, 1, m(exponential), 0.0000001)
    print("approx: ", approx, " n0: ", n0, " status: ", status)
    #Does not work: tol too small

    approx, n0, status = RR1a(0, 1, 1, m(exponential), 0.00001)
    print("approx: ", approx, " n0: ", n0, " status: ", status)
    #Converges at n0 = 131072

def Part_F(t):
    def trig(x):
        return np.cos(t*x**2)

    approx, n0, status = RR1a(0, 1, 1, m(trig), 0.0001)
    print("approx: ", approx, " n0: ", n0, " status: ", status)

def Part_G(t):
    def trig(x):
        return np.cos(t*x**2)

    approx, n0, status = SR4a(0, 1, 1, m(trig), 0.0001)
    print("approx: ", approx, " n0: ", n0, " status: ", status)

def main():
    """
    For the order graphs, we want the coefficient to stay relatively constant
    such that we know it is within constant multiples of the order. The
    reciprocal of the order has been multiplied at the end of the error.
    e.g. for O(h^2) we divide it by 1/h^2, which is n^2
    """

    RR1f_MR2f_Test()

    Part_D()

    print("Part E: ")
    Part_E(2)

    print("Part F: ")
    for t in [1, 10, 100, 200, 300, 400, 500]:
        #too large t results in scipy (for accurate answer) breaking
        Part_F(t)

    print("Part G: ")
    for t in [1, 10, 100, 200, 300, 400, 500]:
        Part_G(t)

if __name__ == "__main__":
    main()

Scientific Computing Projects (Code Parts)/2/main.py


# Mathematics > Linear Algebra Foundations > Linear Algebra Foundations #10 - Eigenvectors
# Compute the EigenVectors of the following 2x2 matrix.
#
# https://www.hackerrank.com/challenges/linear-algebra-fundamentals-10-eigenvectors/problem
#

import numpy as np

A = np.matrix([[ 0,  1],
               [-2, -3]])
eig, vec = np.linalg.eig(A)

print(eig, vec)

v1 = vec[0].A1
v2 = vec[1].A1

print(v1)
print(v2)

# v1 =  sqrt(1/2) -sqrt(2/5)
# v1 = -sqrt(1/2)  sqrt(4/5)

# réponse
# cf. http://www.wolframalpha.com/input/?i=%7B%7B0,+1%7D,+%7B-2,+-3%7D%7D
# -2 -1


import numpy as np
import neighbourlist
import system
import pbc
import numba as nb

@nb.jit(nopython = True)
def LJ_potential_ij(r, sigmaii, epsilonii, sigmajj, epsilonjj, r_cut):
    '''Computes and returns the Lennard Jones potential between two particles at distance r.
    '''
    sigmaij = 0.5 * (sigmaii + sigmajj) # Lorentz-Berthelot: https://en.wikipedia.org/wiki/Combining_rules
    epsilonij = np.sqrt(epsilonii * epsilonjj)

    q = (sigmaij / r)**6
    q_c = (sigmaij/r_cut)**6
    LJ_pot_ij = (4.0 * epsilonij * q * (q - 1.0)      # return lennard jones interaction energy between particle i and particle j
               - 4.0 * epsilonij * q_c *(q_c - 1.0))  # subtract value of potential at r_cut to avoid discontinuity (precompute?)
    return LJ_pot_ij

@nb.jit(nopython = True)
def LJ_potential(positions, LJneighbourlists, sigmas, epsilons, r_c, r_s, boxsize):
    '''Computes the total Lennard Jones potential for the system configuration given by *positions*.

    Arguments:
        positions (Nx3 numpy array (N=#particles) of float): array holding position for each particle in system
        LJneighbourlists (NxN numpy array of int (N = # particles)): the leftmost part of LJneigbourlists[i] (row i in the array) lists the indices
            of the "neighbouring particles" (particles within the LJ cutoff radius) of particle i [NB! LJneigbourlists[i] contains only the neighbours
            of particle i with indices j>i! Thus LJneighbourlists does contain all pairs of neighbours, but a particular row may not contain all the neighbours
            of that particle]. The rest of the row contains -1's.
        sigmas (numpy array of float): sigma for each particle
        epsilons (numpy array of float): epsilon for each particle
        r_c (float): cutoff radius for LJ potential
        r_s (float): size of skin region for LJ potential

    Returns:
        LJpot (float): the total LJ potential
    '''
    if LJneighbourlists is None:
        # raise Exception('Compute LJneighbourlists for particles before computing LJ potential!')
        return None

    r_cut = r_c + r_s

    LJpot = 0.0
    for i in range(len(positions)):
        k = 0
        j = LJneighbourlists[i][k]  # NB! LJneigbourlists[i] contains only the neighbours of particle i with indices j>i.
                                    # Thus interactions are NOT counted twice by computing in the manner below.
        while j!=-1: # -1 means no more neighbours in list
            r = np.linalg.norm(pbc.enforce_pbc_distance(positions[j] - positions[i], boxsize))
            LJpot += LJ_potential_ij(r, sigmas[i], epsilons[i], sigmas[j], epsilons[j], r_cut)
            k += 1
            j = LJneighbourlists[i][k]

    return LJpot


from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
import matplotlib.pyplot as graph
import numpy as np

# --- JAPANS COVID CASE POLYNOMIAL/LINEAR REGRESSION
# --- author KEVIN CRISTOPHER JUVENTINO ALVARADO MALDONADO 201222567
# --- data gathered from  https://ourworldindata.org/covid-cases

# =====================================================================================================================================================
# cases repesents our Y axis
# days represent our X axis
# Confirmed cases from  October 1st to Noviember 10th of 2020
cases = [83010, 84215, 84768, 85339, 85739, 86047, 86543, 87020, 87639, 88233, 88912, 89347, 89673, 90140, 90710, 91431, 92063, 92656, 93127, 93480, 93933,
         94524, 95138, 95835, 96534, 97074, 97498, 98116, 98852, 99622, 100392, 101146, 101813, 102281, 102900, 103838, 104782, 105914, 107086, 108084, 108983]

# October 1st
days = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
        22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41]

# November 1st                                         10th of November
# This could be done easily with pandas and in a much more efficient manner, but it was done this way
# in order to make the code and logic easier to understand while reading it
# =====================================================================================================================================================

# Conversions needed by Scikit library
cases = np.asarray(cases)
days = np.asarray(days)

cases = cases[:, np.newaxis]
days = days[:, np.newaxis]

# =====================================================================================================================================================
# we stablish the basic configuration of our prediction
poly = PolynomialFeatures(degree=4)

# adjust the days to fit for the X axis
days_poly = poly.fit_transform(days)

# The model is defined and correlates the X and Y axis
model = LinearRegression()
model.fit(days_poly, cases)

# A predition is cast mathematically using a polynomial regression
prediction = model.predict(days_poly)
new_x, new_y = zip(*sorted(zip(days, prediction)))

# the prediction graph is created
graph.figure(figsize=(10, 5))
graph.scatter(
    days,
    cases,
    c='green', marker='x'
)
graph.plot(
    new_x, new_y,
    c='blue'
)
graph.title("Japans confirmed cases vs days from october 1st to november 10th")
graph.xlabel('Day')
graph.ylabel('Confirmed Cases')
graph.show()


"""
Implement pairplots with probability ellipses on the lower diagonal.
"""

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from matplotlib.patches import Ellipse
from scipy.stats.distributions import chi2

def _get_parameters(x, y):
    mu = np.array([x.mean(), y.mean()])
    cov = np.cov(x, y)
    return mu, cov

def _get_eigen(cov):
    eigvals, eigvecs = np.linalg.eigh(cov)
    order = eigvals.argsort()[::-1]
    eigvals, eigvecs = eigvals[order], eigvecs[:, order]
    return eigvals, eigvecs

def _get_ellipse_parameters(cov, ci):

    eigvals, eigvecs = _get_eigen(cov)

    # Calculate angle of displacement from x-axis
    theta = np.arctan2(*eigvecs[:, 0][::-1])
    theta = np.degrees(theta)

    # Calculate scaling factor based on probability
    dof = len(eigvals)
    alpha = 1 - (1 - ci) / 2
    scale = chi2.ppf(alpha, dof)
    width, height = 2 * np.sqrt(scale * eigvals)

    return width, height, theta

def make_ellipse(x, y, ci, **kwargs):
    mu, cov = _get_parameters(x, y)
    width, height, theta = _get_ellipse_parameters(cov, ci)
    ellipse = Ellipse(mu, width, height, theta, alpha=0.5, **kwargs)
    return ellipse

def draw_probability_ellipse(x, y, ci, **kwargs):
    ellipse = make_ellipse(x, y, ci, **kwargs)
    ax = plt.gca()
    ax.add_artist(ellipse)

    plot_kws = dict(alpha=0.75, s=15, linewidth=0, marker="o")
    ax.scatter(x, y, **plot_kws, **kwargs)

def munge_embedding(embedding, labels):
    col_names = [f"Dimension {i}" for i in range(1, embedding.shape[1] + 1)]
    df = pd.DataFrame(embedding, columns=col_names)
    df["Strain"] = labels
    return df

def _pairgrid(embedding, labels):
    df = munge_embedding(embedding, labels)

    palette = ["#e7298a", "#1b9e77", "#d95f02", "#7570b3"]
    plot_kws = dict(alpha=0.75, s=15, linewidth=0, marker="o")

    with sns.plotting_context("paper", font_scale=1):
        g = sns.PairGrid(df, hue="Strain", palette=palette, height=1.5)
        g = g.map_upper(sns.scatterplot, **plot_kws)
        g = g.map_diag(sns.kdeplot, lw=1, shade=True)
        g.set(xticks=[], yticks=[])

    return g

def ellipse_pairgrid(embedding, labels, ci, **kwargs):
    g = _pairgrid(embedding, labels)
    kwargs["ci"] = ci
    g = g.map_lower(draw_probability_ellipse, **kwargs)
    return g

def kde_pairgrid(embedding, labels):
    g = _pairgrid(embedding, labels)
    g = g.map_lower(sns.kdeplot)
    return g


"""
In the DFP example we will search for z=(a, b, c, d)
that minimizes Sum_i || F(z, X_i) - Y_i ||^2
for the function F: R^2 -> R^2
F(x0, x1) = [
                a^3 + b * x0 + c * x1 + d * (x0^2+x1^2),
                2*a + 3*b * x0 + 4*c * x1 + 5*d * (x0^2+x1^2)
                ]

Suppose we have the following measurements
X_0 = [0, 1]; Y_0 = [15, 1]
X_1 = [1, 0]; Y_1 = [8, 16]
X_2 = [1, 1]; Y_2 = [80, 800]
X_3 = [3, 4]; Y_3 = [100, 120]
X_4 = [1, 15]; Y_4 = [150, 1500]

subjected to a>=4, c<=30
(we could handle other constraints as well: Ax <= b, Aeq x = beq, c(x) <= 0, h(x) = 0)
"""
from openopt import DFP
from numpy import *

f = lambda z, X: (z[0]**3 + z[1]*X[0] + z[2]*X[1] + z[3]*(X[0]+X[1])**2, 2*z[0] + 3*z[1]*X[0] + 4*z[2]*X[1] + 5*z[3]*(X[0]+X[1])**2)
#f = (lambda z, X: z[0]**3 + z[1]*X[0] + z[2]*X[1] + z[3]*(X[0]+X[1])**2,
#lambda z, X: 2*z[0] + 3*z[1]*X[0] + 4*z[2]*X[1] + 5*z[3]*(X[0]+X[1])**2)
df = lambda z, X: ([3*z[0]**2, X[0], X[1], (X[0]+X[1])**2], [2, 3*X[0], 4*X[1], 5*(X[0]+X[1])**2])
initEstimation = [0] * 4 # start point for solver: [0, 0, 0, 0]
X = ([0, 1], [1, 0], [1, 1], [3, 4], [1, 15]) # list, tuple, numpy array or array-like are OK as well
Y = [[15, 1], [8, 16], [80, 800], [100, 120], [150, 1500]]
lb = [4, -inf, -inf, -inf]
ub = [inf, inf, 30, inf]
p = DFP(f, initEstimation, X, Y, df=df, lb=lb, ub=ub)

r = p.solve('nlp:ralg', plot=0, iprint = 10)
print('solution: '+str(r.xf)+'\n||residuals||^2 = '+str(r.ff)+'\nresiduals: ')
rr = [array(f(p.xf, X[i]))-array(Y[i]) for i in xrange(len(Y))]
print(rr)
#solution: [  3.99999936  -1.9497013   18.25467922   0.24926213]
#||residuals||^2 = 653639.695247
#residuals:
#[array([ 67.50391074,  81.26502627]), array([ 54.29953022, -12.60279452]), array([   1.30199584, -719.84514565]), array([  43.38342685,  223.59677693]), array([ 249.68156224,  -83.51282276])]


'''
fractal-art.py

generate some fractal art

'''
import math
import matplotlib.pyplot as plt
import networkx as nx
import plot

'''
	DEFINITIONS:
		Point = [xcoordinate, ycoordinate]
		LineSegment = [Point1, Point2]
'''

'''
	fract1 -
		take a line segment, remove the middle third
		replace with two line segments equal in length to middle third
		these two segments meet at exactly 1 point

		---------------------------
		             ^
		            / \
		           /   \
		          /     \
		---------/       \---------

	Algorithm:
		take line segment, l = [p0, p1]
		compute l1, l2, l3
			l1 = [p0, p1/3]
			l2 = [p1/3, p2/3]
			l3 = [p2/3, p1]
		compute p1/2
			where p1/2 = [midpoint(p0,p1), y]
			and where y = sqrt((x/3)^2 - (x/6)^2), where x = dist(p0, p1)
				^^ consider right traingle of height y, created by midpoint(l), p1/2, and either p1/3, or p2/3
					using this triangle, solve for y coordinate of p1/2
		return linesegments = [
			[p0, p1/3],
			[p1/3, p1/2],
			[p1/2, p2/3],
			[p2/3, p1]
		]
'''
def fract1(linesegments, iterations):
	def distance(p0, p1):
		# print("DISTANCE FUCNTION:", p0, p1)
		return math.sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2)

	def midpoint(p1, p2):
		distancep1p2 = distance(p1, p2)
		return ((p1[0] + p2[0])/2, math.sqrt( (distancep1p2/3)**2 - (distancep1p2/6)**2 ))

	def third(p0, p1):
		a = p0[0]
		b = p0[1]
		c = p1[0]
		d = p1[1]
		#print(a,b)
		#print(c,d)
		v1x = c-a
		v1y = d-b
		#print("vector1:", v1x, v1y)
		v2x = v1x/2 - (math.sqrt(3)*v1y/2)
		v2y = (math.sqrt(3)*v1x/2) + v1y/2
		#print("vector2:", v2x, v2y)
		third = ((a+v2x, b+v2y))
		return(third)

	def fract1equation(linesegment):
		p0, p1 = linesegment[0], linesegment[1]

		#Compute points that make up middle line segment
		p23 = ( (p0[0] + 2 * p1[0]) / 3, (p0[1] + 2 * p1[1]) /3)
		p13 = ( (2 * p0[0] + p1[0]) / 3, (2 * p0[1]+ p1[1]) / 3)

		#compute the third point of the triangle
		p12 = third(p13, p23)

		#print("POINTS:",p0, p13, p12, p23, p1)
		l1 = (p0, p13)
		l2 = (p13, p12)
		l3 = (p12, p23)
		l4 = (p23, p1)
		return [l1, l2, l3, l4]

	segments = linesegments
	counter = 0
	while segments and counter < iterations:
		print("ITERATION: ", counter)
		frontier = []
		for segment in segments:
			for lineseg in fract1equation(segment):
				frontier.append(lineseg)
		segments = frontier
		counter += 1

	return segments

if __name__ == "__main__":
	iterations = 5
	orig_segments = [( (10, 0), (0, 0) ), ( (0, 0), (0, 10) ), ( (0, 10), (10, 10) ), ((10, 10), (10, 0))]
	G = plot.segments_to_graph(orig_segments)
	G, pos = plot.list_graph_to_networkx(G)
	plot.save_graph(G, pos, "orig_fract1_" + str(iterations) + "_", 100000)

	segments = fract1(orig_segments, iterations)
	# for i in range(2):
	# 	frontier = set()
	# 	for seg in segments:
	# 		print(seg)
	# 		frontier.update(fract1(seg))
	# 	segments = frontier

	# print("SEGEMNTS:", segments)

	G = plot.segments_to_graph(segments)

	# print("GRAPH:", G)

	G, pos = plot.list_graph_to_networkx(G)

	# print(G.nodes())

	plot.save_graph(G, pos, "fract1_" + str(iterations) + "_", 100000)


import numpy as np

class Point():
	def __init__(self, pt):
		self.x = pt[0]
		self.y = pt[1]

	def get_point(self):
		return self

	def get_point_tuple(self):
		return((self.x, self.y))

	def get_distance(self, pt):
		return np.sqrt((self.x - pt.x)**2 + (self.y - pt.y)**2)

	def get_projected_line(self, line):
		slope = line.get_slope()
		intercept = self.y - slope*self.x
		return slope, intercept

	def add_point(self, point):
		self.x += point[0]
		self.y += point[1]
		return self

	def switch_coordinate_system(self, img):
		# OpenCV image coordinate:| Math coordinate:
		# ----->x                 | y
		# |                       | ^
		# |                       | |
		# v                       | |
		# y                       | |------>x
		convert_pt = (self.x, img.shape[0] - self.y)
		return Point(convert_pt)

class Line():
	# Assmption: All the coordinates in this class use math coordinate system.
	def __init__(self, pt1, pt2):
		assert type(pt1) is Point and type(pt2) is Point, "Points are of wrong type."
		self.pt1 = pt1
		self.pt2 = pt2
		self.__compute()

	def __compute(self):
		self.slope = (self.pt2.y - self.pt1.y) / (self.pt2.x - self.pt1.x)
		self.intercept = self.pt1.y - self.slope*self.pt1.x

	def calculate_intersection(self, slope, intercept):
		x_intersect = (intercept - self.intercept)/(self.slope - slope)
		y_intersect = self.slope*x_intersect + self.intercept
		return Point((x_intersect, y_intersect))

	def get_slope(self):
		return self.slope

	def get_intercept(self):
		return self.intercept


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

class LossSurface:
    """A loss surface with L(x, y) = a * x ^2 + b * y ^2.

    """
    def __init__(self, a, b):
        self.a = a
        self.b = b

        N = 1000
        x_list = np.linspace(-2.5, 2.5, N)
        y_list = np.linspace(-0.5, 0.5, N)
        self.X, self.Y = np.meshgrid(x_list, y_list)
        self.Z = self.a * (self.X ** 2) + self.b * (self.Y ** 2)

    def plot(self):
        fig, ax = plt.subplots()
        cmap = cm.get_cmap('Greens_r')
        cp = ax.contour(self.X, self.Y, self.Z, 50, cmap=cmap)
        cbar = fig.colorbar(cp)
        cbar.set_label('loss')

        ax.set_xlim(-2.5, 2.5)
        ax.set_ylim(-0.5, 0.5)

        ax.set_xlabel('x')
        ax.set_ylabel('y')

        return fig, ax

if __name__ == '__main__':
    a = 1 / 16
    b = 9

    loss_surface = LossSurface(a, b)
    fig, ax = loss_surface.plot()
    fig_name = 'loss_surface.png'
    fig.savefig(fig_name)

    print('{} saved.'.format(fig_name))


import numpy as np
import networkx as nx
import matplotlib.pyplot as plt

D = np.array([[0,20,16,25,24],[20,0,12,12,27],[16,12,0,10,14],[25,12,10,0,20],[24,27,14,20,0]])

Graph = nx.Graph()
Graph.add_nodes_from(range(D.shape[0]))
for i in range(D.shape[0]):
    for j in range(D.shape[0]):
        Graph.add_edge(i,j,weight=D[i,j])

pos=nx.shell_layout(Graph)
nx.draw(Graph,pos,with_labels=True)
labels = nx.get_edge_attributes(Graph,'weight')
nx.draw_networkx_edge_labels(Graph,pos,edge_labels=labels)

plt.show()

from itertools import permutations

best_solution = [None,np.sum(D)]
for solution in list(permutations(range(1,D.shape[0]))):
    start,distance = (0,0)
    for next_one in solution:
        distance += D[start,next_one]
        start = next_one

    distance += D[start,0]
    if distance <= best_solution[1]:
        best_solution = [[0]+list(solution)+[0],distance]
        print('Лучшее решение к этому моменту : %s км'% str(best_solution)[1:-1])

from scipy.special import perm

print(perm(13,13)/2)

from itertools import combinations

memo = {(frozenset([0,idx+1]),idx+1):(dist,[0,idx+1]) for idx,dist in enumerate(D[0][1:])}

cities = D.shape[0]

for subset_size in range(2,cities):
    #Определение размера подмножества городов
    new_memo = dict()
    for subset in [frozenset(comb) | {0} for comb in combinations(range(1,cities),subset_size)]:
        #Перечесление подмножеств определенного размера
        for ending in subset - {0}:
            #Рассматриваем каждую конечную точку подмножества
            all_paths = list()
            for k in subset:
                #Проверяем кратчайший путь для каждого элемента подмножества
                if k != 0 and k!=ending:
                    lenght = memo[(subset-{ending},k)][0] + D[k][ending]
                    index = memo[(subset-{ending},k)][1] +[ending]
                    all_paths.append((lenght,index))
            new_memo[(subset,ending)] = min(all_paths)
    # Для экономии памяти записываем предыдущие подмножества
    # поскольку больше не хотим использовать более короткие подмножества
    memo = new_memo
#Завершае цикл и возвращаемся к началу тура - к городу 0
tours = list()
for distance,path in memo.values():
    distance += D[path[-1],0]
    tours.append((distance,path[0]))
# Выводим самый короткий тур
distance,path = min(tours)
print('Кратчайший тур : %s,%i км'%(path,distance))


import matplotlib.pyplot as plt
import numpy as np
from scipy.special import eval_legendre,legendre
from scipy.integrate import quad
import math
n = float(input("enter the positive integer n : "))
x = float(input("enter the value of x : "))
def gm(n):
    if n == 1:
        return 1
    elif n == 0.5:
        return np.sqrt(np.pi)
    else :
        return (n-1)*gm(n-1)
def leg(n,x,m=0,p=0):
    if (n %2) == 0 :
        m = int(n/2)
    else :
        m = int((n-1)/2)
    for i in range(m+1):
        p+= (((-1)**i) * (gm(2*n-2*i+1))* (x**(n-2*i)))/((2**n) * gm(i+1) * gm(n-i+1) * gm(n-2*i+1))
    return p

def leg_dif(n,x,m=0,p=0):
    m = 0
    if (n %2) == 0 :
        m = int(n/2)
    else :
        m = int((n-1)/2)
    p = 0
    for i in range(m+1):
        p+= ((n-2*i)*((-1)**i) * (gm(2*n-2*i+1))* (x**(n-2*i-1)))/((2**n) * gm(i+1) * gm(n-i+1) * gm(n-2*i+1))
    return p

print("legendre polynomial: ",leg(n,x,m=0,p=0))
print("Legendre derivative: ",leg_dif(n,x,m=0,p=0))
print('inbuilt leg :',eval_legendre(n,x))
print('inbuilt leg diff',np.polyval(legendre(n).deriv(),x))
xdata = np.linspace(-0.999999,0.999999,100)
p0,p1,p2,p3,p0_diff,p1_diff,p2_diff,p3_diff,=[],[],[],[],[],[],[],[]

for i in xdata:
    p0.append(leg(0 ,i))
    p1.append(leg(1 ,i))
    p2.append(leg(2, i))
    p3.append(leg(3, i))
    p0_diff.append(leg_dif(0, i))
    p1_diff.append(leg_dif(1, i))
    p2_diff.append(leg_dif(2, i))
    p3_diff.append(leg_dif(3, i))
def writeintofile(file1,xdata,p0,p1,p2):
    with open(file1,'w') as file :
        for i in range(len(xdata)):
            file.write(str(xdata[i])+' , '+str(p0[i])+' , '+str(p1[i])+' , '+str(p2[i])+'\n')
writeintofile('leg00.dat', xdata, p0, p1, p2)
writeintofile('leg01.dat', xdata, p1_diff, p2_diff, p3_diff)
#plotting graph
plt.title("PLOT OF xdata VS Pn ",c= 'b')
plt.plot(xdata,p0)
plt.plot(xdata,p1)
plt.plot(xdata,p2)
plt.legend(['p0','p1','p2'],loc = 'best')
plt.xlabel('xdata')
plt.ylabel('Pn')
plt.grid()
plt.show()
plt.title("PLOT OF xdata VS DIFF Pn")
plt.plot(xdata,p1)
plt.plot(xdata,p0_diff)
plt.plot(xdata,p2_diff)
plt.legend(['p1','p0 diff','p2 diff'],loc = 'best')
plt.xlabel('xdata')
plt.ylabel('Pn diff')
plt.grid()
plt.show()

n,LHS,RHS=2,[],[]
for i in range(len(xdata)):
    LHS.append(n*p2[i])
    RHS.append(xdata[i]*p2_diff[i] - p1_diff[i])
print("LHS \n",LHS[0:10])
print("RHS \n", RHS[0:10])
if np.allclose(LHS,RHS):
        print("Relation1 satisfied")
else:
    print("Relation1 not satisfied")
writeintofile('leg02.dat', xdata, p2, p2_diff, p1_diff)

# relation 2
n,LHS,RHS=2,[],[]
for i in range(len(xdata)):
    LHS.append((2*n+1)*xdata[i]*p2[i])
    RHS.append((n+1)*p3[i]+n*p1[i])
print("LHS \n",LHS[0:20])
print("RHS \n", RHS[0:20])
if np.allclose(LHS,RHS):
        print("Relation2 satisfied")
else:
    print("Relation2 not satisfied")
writeintofile('leg03.dat', xdata, p2, p1, p3)
#Relation 3
n,LHS,RHS=3,[],[]
for i in range(len(xdata)):
    LHS.append(n*p3[i])
    RHS.append((2*n-1)*xdata[i]*p2[i] - (n-1)*p1[i])
print("LHS \n",LHS[0:20])
print("RHS \n", RHS[0:20])
if np.allclose(LHS,RHS):
        print("Relation3 satisfied")
else:
    print("Relation3 not satisfied")
writeintofile('leg04.dat', xdata, p3, p2, p1)

#orthogonality
A=[] ; B =[]
for n in range(3):
    for m in range(3):
        if n == m:
           A.append(2/(2*n+1))
        else:
           A.append(0)
        f=legendre(n)*legendre(m)
        inte , err = quad(f, -1, 1)
        B.append(inte)
RHS = np.array(B).reshape(3,3)
LHS = np.array(A).reshape(3,3)
print("RHS = ",RHS)
print("LHS = ",LHS)
if np.allclose(LHS,RHS):
   print("Orthogonality verified")
else:
    print("Orthogonality not verified")


import numpy as np

#Function to interpolate
def func(x, y):
    return x*(1-x)*np.cos(4*np.pi*x) * np.sin(4*np.pi*y**2)**2

#Sample over these grids
grid_x, grid_y = np.mgrid[0:1:500j, 0:1:500j]

#Generate 1000 random 2D points
points = np.random.rand(1000, 2)
print(type(points))
#Calculate random points as function inputs
values = func(points[:,0], points[:,1])

print("pts ",points)
print("vals ",values)

from scipy.interpolate import griddata

grid_z0 = griddata(points, values, (grid_x, grid_y), method='nearest')
grid_z1 = griddata(points, values, (grid_x, grid_y), method='linear')
grid_z2 = griddata(points, values, (grid_x, grid_y), method='cubic')

xi =12
yi= 12

import matplotlib.pyplot as plt
plt.subplot(221)
plt.imshow(func(grid_x, grid_y).T, extent=(0,1,0,1), origin='lower')
plt.plot(points[:,0], points[:,1], 'k.', ms=1)
plt.title('Original')
plt.subplot(222)
plt.imshow(grid_z0.T, extent=(0,1,0,1), origin='lower')
plt.title('Nearest')
plt.subplot(223)
plt.imshow(grid_z1.T, extent=(0,1,0,1), origin='lower')
plt.title('Linear')
plt.subplot(224)
plt.imshow(grid_z2.T, extent=(0,1,0,1), origin='lower')
plt.title('Cubic')
plt.gcf().set_size_inches(6, 6)
plt.show()


"""
Ankit Khandelwal
15863
Exercise 4a,b
"""

import math

import matplotlib.pyplot as plt
import numpy as np

def f(x, c):
    return 1 - math.exp(-c * x)

# part 1
c = 2
x = 1
while abs(x - f(x, c)) > 10 ** -7:
    x = f(x, c)
print(x, 'Value for c = 2')

# part 2
c = np.linspace(0, 3, 301)
ans = []

for i in c:
    x = 1
    while abs(x - f(x, i)) > 10 ** -7:
        x = f(x, i)
    ans.append(x)

plt.plot(c, ans)
plt.xlabel('C')
plt.ylabel('X')
plt.title('Solutions of x = 1 - exp(-cx)')
plt.show()

Ankit Khandelwal_HW3/Exercise 4/exercise 4b.py