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

# In[25]:

import random as rn

import numpy as np

import math as ma

import matplotlib as mpl

import matplotlib.pyplot as plt

# In[80]:

#without drag

v_o = float(input('Starting velocity? '))

theta = float(input('Starting angle? '))

dt = float(input('Time step? '))

x = 0.0
y = 0.0
vx = v_o*ma.cos(ma.radians(theta))
vy = v_o*ma.sin(ma.radians(theta))
ax = 0.0
ay = -9.8

q = 1

x_positions = []
y_positions = []

while q == 1:
    while y >= 0:
        x = vx*dt + x
        x_positions.append(x)
        vx = ax*dt + vx
        y = vy*dt + y
        y_positions.append(y)
        vy = ay*dt + vy
    if 7.5 > x > 6.5:
        print('Hit!')
        print('Final position: ', x)
    else:
        print('Better luck next time!')
        print('Final position: ', x)
        print('You missed by: ', abs(7 - x))
    q = 0

print(x_positions)
print(y_positions)

# In[82]:

#with drag

v_o = float(input('Starting velocity? '))

theta = float(input('Starting angle? '))

dt = float(input('Time step? '))

g = -9.8

x2 = 0.0
y2 = 0.0
vx = v_o*ma.cos(ma.radians(theta))
vy = v_o*ma.sin(ma.radians(theta))
ax = 0.0
ay = g

print(vx)
print(vy)

b = 0.001

x2_positions = []
y2_positions = []

q = 1

while q == 1:
    while y2 >= 0:
        x2 = vx*dt + x2
        x2_positions.append(x2)
        vx = ax*dt + vx
        ax = 0 - b*vx
        y2 = vy*dt + y2
        y2_positions.append(y2)
        vy = ay*dt + vy
        ay = g - (b*vy)
    if 7.5 > x > 6.5:
        print('Hit!')
        print('Final position: ', x2)
    else:
        print('Better luck next time!')
        print('Final position: ', x2)
        print('You missed by: ', abs(7 - x2))
    q = 0

print(x2_positions)
print(y2_positions)

# In[83]:

#difference between analytical and simulated

difference = x - x2

print(difference)

# In[81]:

plt.scatter(x_positions, y_positions)
plt.show()

# In[79]:

plt.scatter(x2_positions, y2_positions)
plt.show()

# In[ ]:


from sympy import *

y, t = symbols('y, t')

arquivo_de_saida = None

def Printar_Arquivo(strr, y0, t0, h, qtde, vetor_y):
	print("Metodo de", strr, file=arquivo_de_saida)
	print("y(" + str(t0) + ") = " + str(y0), file=arquivo_de_saida)
	print("h = " + str(h), file=arquivo_de_saida)
	for j in range(0, qtde+1):
		print(j, vetor_y[j], file=arquivo_de_saida)
	arquivo_de_saida.write('\n')

class MetodosPassoSimples:
  def euler(y0, t0, h, qtde, func):
      vetor_x=[t0]
      vetor_y=[y0]
      y_aux=y0
      t_aux=t0

      for i in range(0, qtde):
          y_aux = y_aux + h * func.subs([(y, y_aux), (t, t_aux)]) # yn+1 = yn + h * f(yn, tn)
          t_aux = t_aux+h

          vetor_x.append(t_aux)
          vetor_y.append(y_aux)

      return vetor_y

  def euler_inverso(y0, t0, h, qtde, func):
      vetor_x=[t0]
      vetor_y=[y0]
      y_aux = y0
      t_aux = t0
      for i in range(0, qtde):
          #com metodo de previsao
          #y_prev = y_aux + func.subs([(y, y_aux), (t, t_aux)]) * h
          #t_aux = t_aux + h
          #y_aux = y_aux + func.subs([(y, y_prev), (t, t_aux)]) * h

		  #sem metodo de previsao
          t_aux = t_aux + h
          yn1 = solve(y_aux + h * (func.subs(t, t_aux) ) - y, y) #y yn+1 = yn + h * f(yn+1, tn+1)
          y_aux = yn1[0]
          vetor_y.append(y_aux)
          vetor_x.append(t_aux)

      return vetor_y

  def euler_aprimorado(y0, t0, h, qtde, func):
      vetor_x=[t0]
      vetor_y=[y0]
      y_aux = y0
      t_aux = t0
      for i in range(0, qtde):
          tn=t_aux
          t_aux = t_aux + h
          # com metodo de previsao
          y_prev = y_aux + func.subs([(y, y_aux), (t, tn)]) * h
          y_aux = y_aux + (func.subs([(y, y_prev), (t, t_aux)])+func.subs([(y, y_aux), (t, tn)])) * h/2

		  #sem metodo de previsao
          #yn1=solve(y_aux + h * (func.subs(t,t_aux) + func.subs([(t, tn), (y, y_aux)])) / 2 - y, y)
          #y_aux = yn1[0]
          vetor_y.append(y_aux)
          vetor_x.append(t_aux)

      return vetor_y

  def runge_kutta(y0, t0, h, qtde, func):
      vetor_x=[t0]
      vetor_y=[y0]
      y_aux = y0
      t_aux = t0
      for i in range(0, qtde):
          k1= func.subs([(y, y_aux), (t, t_aux)])
          k2= func.subs([(y, y_aux+((h/2)*k1)), (t, t_aux+(h/2))])
          k3= func.subs([(y, y_aux+((h/2)*k2)), (t, t_aux+(h/2))])
          k4= func.subs([(y, y_aux+(h*k3)), (t, t_aux+h)])

          y_aux = y_aux + ((h/6)*(k1+(2*k2)+(2*k3)+k4)) # yn+1 = yn + h/6 * (k1 + 2*k2 + 2*k3 + k4)
          t_aux = t_aux + h
          vetor_x.append(t_aux)
          vetor_y.append(y_aux)

      return vetor_y

coeficientes_adam_bashforth = [
	[],
	[1],
	[3/2,          -1/2],
	[23/12,        -4/3,            5/12],
	[55/24,        -59/24,          37/24,        -3/8],
	[1901/720,     -1387/360,       109/30,       -637/360,      251/720],
	[4277/1440,    -2641/480,       4991/720,     -3649/720,     959/480,        -95/288],
	[198721/60480, -18637/2520,     235183/20160, -10754/945,    135713/20160,   -5603/2520,    19087/60480],
	[16083/4480,   -1152169/120960, 242653/13440, -296053/13440, 2102243/120960, -115747/13440, 32863/13440, -5257/17280]
]

def Adam_Bashforth(ys, t0, h, qtde, func, ordem):
	cur_coef = coeficientes_adam_bashforth[ordem] # pega os coeficients da ordem atual
	t_vetor = [t0] # cria o t_vetor inicial
	for i in range(1, ordem):
		t_vetor.append(t_vetor[i - 1] + h)

	for i in range(ordem-1, qtde):
		sum_fn = 0
		for j in range(ordem): # calcula a soma dos fn * coeficiente
			sum_fn += cur_coef[j] * func.subs([(t, t_vetor[i - j]), (y, ys[i - j])])
		yn = ys[i] + h * sum_fn # calcula novo y
		tn = t_vetor[i] + h # calcula novo t
		ys.append(yn)
		t_vetor.append(tn)
	return ys

def Adam_Bashforth_by_method(y0, t0, h, qtde, func, ordem, strr):
	ys = getattr(MetodosPassoSimples, strr)(y0, t0, h, ordem-1, func) #procura na classe a funcao de strr e manda os parametros
	vetor_y = Adam_Bashforth(ys, t0, h, qtde, func, ordem)
	strr_2= 'Adam Bashforth por ' + strr + '(ordem=' +str(ordem)+')'
	Printar_Arquivo(strr_2, vetor_y[0], t0, h, qtde, vetor_y)
#coeficientes que vao ser usados para calcular adam moulton
coeficientes_adam_moulton = [
	[],
	[1],
	[1/2,         1/2],
	[5/12,        2/3,           -1/12],
	[3/8,         19/24,         -5/24,        1/24],
	[251/720,     323/360,       -11/30,       53/360,        -19/720],
	[95/288,      1427/1440,     -133/240,     241/720,       -173/1440,     3/160],
	[19087/60480, 2713/2520,     -15487/20160, 586/945,       -6737/20160,   263/2520,  -863/60480],
	[5257/17280,  139849/120960, -4511/4480,   123133/120960, -88547/120960, 1537/4480, -11351/120960, 275/24192]
]

def Adam_Multon(ys, t0, h, qtde, func, ordem):
	cur_coef = coeficientes_adam_moulton[ordem] # pega os coeficientes da ordem atual
	t_vetor = [t0] # cria o t_vetor inicial
	for i in range(1, ordem - 1):
		t_vetor.append(t_vetor[i - 1] + h)

	for i in range(ordem-2, qtde):
		sum_fn = 0
		for j in range(ordem-1): # calcula a soma dos fn * coeficiente
			sum_fn += cur_coef[j + 1] * func.subs([(t, t_vetor[i - j]), (y, ys[i - j])])
		t_aux = t_vetor[i] + h
		yn = solve(ys[i] + h * (sum_fn + cur_coef[0] * func.subs(t, t_aux)) - y, y)# calcula novo y
		y_aux = yn[0]
		ys.append(y_aux)
		t_vetor.append(t_aux)
	return ys

def Adam_Multon_by_method(y0, t0, h, qtde, func, ordem, strr):
	ys = getattr(MetodosPassoSimples, strr)(y0, t0, h, ordem-2, func) #procura na classe a funcao de strr e manda os parametros
	vetor_y = Adam_Multon(ys, t0, h, qtde, func, ordem)
	strr_2= 'Adam Multon por ' + strr + '(ordem=' +str(ordem)+')'
	Printar_Arquivo(strr_2, vetor_y[0], t0, h, qtde, vetor_y)

coeficientes_formula_inversa = [
	[],
	[],
	[1,           1],
	[2/3,         4/3,            -1/3],
	[6/11,        18/11,          -9/11,        2/11],
	[12/25,       48/25,          -36/25,       16/25,      -3/25],
	[60/137,      300/137,        -300/137,     200/137,    -75/137,   12/137],
	[60/147,      360/147,        -450/147,     400/147,    -225/147,  72/147,    -10/147],
]

def Formula_Inversa(ys, t0, h, qtde, func, ordem):
	cur_coef = coeficientes_formula_inversa[ordem] # pega os coeficientes da ordem atual
	t_vetor = [t0] # cria o t_vetor inicial
	for i in range(1, ordem - 1):
		t_vetor.append(t_vetor[i - 1] + h)

	for i in range(ordem-2, qtde):
		sum_fn = 0
		for j in range(ordem-1): # calcula a soma dos yn * coeficiente
			sum_fn += cur_coef[j + 1] * ys[i-j]
		t_aux = t_vetor[i] + h
		yn = solve(sum_fn + h * ( cur_coef[0] * func.subs(t, t_aux)) - y, y)# calcula novo y
		y_aux = yn[0]
		ys.append(y_aux)
		t_vetor.append(t_aux)
	return ys

def Formula_Inversa_by_method(y0, t0, h, qtde, func, ordem, strr):
	ys = getattr(MetodosPassoSimples, strr)(y0, t0, h, ordem-2, func) #procura na classe a funcao de strr e manda os parametros
	vetor_y = Formula_Inversa(ys, t0, h, qtde, func, ordem)
	strr_2= 'Formula Inversa de Diferenciacao por ' + strr + '(ordem=' +str(ordem)+')'
	Printar_Arquivo(strr_2, vetor_y[0], t0, h, qtde, vetor_y)
#-------------------------MAIN---------------------------------
def main():
	global arquivo_de_saida
	arquivo_de_saida = open("saida.txt", "w")
	arquivo_de_entrada = open("entrada.txt", "r")

	for linha in arquivo_de_entrada:
		valores = linha.split()
		if valores[0] == 'euler':

			vetor_y = MetodosPassoSimples.euler(float(valores[1]), float(valores[2]), float(valores[3]), int(valores[4]), sympify(valores[5]))
			Printar_Arquivo('Euler', float(valores[1]), float(valores[2]), float(valores[3]), int(valores[4]), vetor_y)
		elif valores[0] == 'euler_inverso':

			vetor_y = MetodosPassoSimples.euler_inverso(float(valores[1]), float(valores[2]), float(valores[3]), int(valores[4]), sympify(valores[5]))
			Printar_Arquivo('Euler Inverso', float(valores[1]), float(valores[2]), float(valores[3]), int(valores[4]), vetor_y)
		elif valores[0] == 'euler_aprimorado':

			vetor_y = MetodosPassoSimples.euler_aprimorado(float(valores[1]), float(valores[2]), float(valores[3]), int(valores[4]), sympify(valores[5]))
			Printar_Arquivo('Euler Aprimorado', float(valores[1]), float(valores[2]), float(valores[3]), int(valores[4]), vetor_y)

		elif valores[0] == 'runge_kutta':

			vetor_y = MetodosPassoSimples.runge_kutta(float(valores[1]), float(valores[2]), float(valores[3]), int(valores[4]), sympify(valores[5]))
			Printar_Arquivo('Runge Kutta', float(valores[1]), float(valores[2]), float(valores[3]), int(valores[4]), vetor_y)

		elif valores[0] == 'adam_bashforth':

			ordem = int(valores[-1])
			ys= valores[1 : ordem+1]
			ys=list(map(float, ys))
			vetor_y = Adam_Bashforth(ys, float(valores[ordem+1]), float(valores[ordem+2]), int(valores[ordem+3]), sympify(valores[ordem+4]), ordem)
			strr = 'Adam Bashforth (ordem = '+str(ordem)+')'
			Printar_Arquivo(strr, vetor_y[0], float(valores[ordem+1]), float(valores[ordem+2]), int(valores[ordem+3]), vetor_y)

		elif valores[0].startswith('adam_bashforth_by_'):
			metodo_auxiliar = valores[0][18:]
			Adam_Bashforth_by_method(float(valores[1]), float(valores[2]), float(valores[3]), int(valores[4]), sympify(valores[5]), int(valores[6]), metodo_auxiliar)

		elif valores[0] == 'adam_multon':
			ordem = int(valores[-1])
			ys = valores[1 : ordem]
			ys = list(map(float, ys))
			vetor_y = Adam_Multon(ys, float(valores[ordem]), float(valores[ordem+1]), int(valores[ordem+2]), sympify(valores[ordem+3]), ordem)
			strr = 'Adam Moulton (ordem = '+str(ordem)+')'
			Printar_Arquivo(strr, vetor_y[0], float(valores[ordem]), float(valores[ordem+1]), int(valores[ordem+2]), vetor_y)

		elif valores[0].startswith('adam_multon_by_'):
			metodo_auxiliar = valores[0][15:]
			Adam_Multon_by_method(float(valores[1]), float(valores[2]), float(valores[3]), int(valores[4]), sympify(valores[5]), int(valores[6]), metodo_auxiliar)

		elif valores[0] == 'formula_inversa':
			ordem = int(valores[-1])
			ys= valores[1 : ordem]
			ys=list(map(float, ys))
			vetor_y = Formula_Inversa(ys, float(valores[ordem]), float(valores[ordem+1]), int(valores[ordem+2]), sympify(valores[ordem+3]), ordem)
			strr = 'Formula Inversa de Diferenciacao (ordem = '+str(ordem)+')'
			Printar_Arquivo(strr, vetor_y[0], float(valores[ordem]), float(valores[ordem+1]), int(valores[ordem+2]), vetor_y)

		elif valores[0].startswith('formula_inversa_by_'):
			metodo_auxiliar = valores[0][19:]
			vetor_y = Formula_Inversa_by_method(float(valores[1]), float(valores[2]), float(valores[3]), int(valores[4]), sympify(valores[5]), int(valores[6]), metodo_auxiliar)

	arquivo_de_saida.close()

if __name__ == '__main__':
	main()


## Time Series Filters

from __future__ import print_function
import pandas as pd
import matplotlib.pyplot as plt

import statsmodels.api as sm

dta = sm.datasets.macrodata.load_pandas().data

index = pd.Index(sm.tsa.datetools.dates_from_range('1959Q1', '2009Q3'))
print(index)

dta.index = index
del dta['year']
del dta['quarter']

print(sm.datasets.macrodata.NOTE)

print(dta.head(10))

fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111)
dta.realgdp.plot(ax=ax);
legend = ax.legend(loc = 'upper left');
legend.prop.set_size(20);

#### Hodrick-Prescott Filter

# The Hodrick-Prescott filter separates a time-series $y_t$ into a trend $\tau_t$ and a cyclical component $\zeta_t$
#
# $$y_t = \tau_t + \zeta_t$$
#
# The components are determined by minimizing the following quadratic loss function
#
# $$\min_{\\{ \tau_{t}\\} }\sum_{t}^{T}\zeta_{t}^{2}+\lambda\sum_{t=1}^{T}\left[\left(\tau_{t}-\tau_{t-1}\right)-\left(\tau_{t-1}-\tau_{t-2}\right)\right]^{2}$$

gdp_cycle, gdp_trend = sm.tsa.filters.hpfilter(dta.realgdp)

gdp_decomp = dta[['realgdp']]
gdp_decomp["cycle"] = gdp_cycle
gdp_decomp["trend"] = gdp_trend

fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111)
gdp_decomp[["realgdp", "trend"]]["2000-03-31":].plot(ax=ax, fontsize=16);
legend = ax.get_legend()
legend.prop.set_size(20);

#### Baxter-King approximate band-pass filter: Inflation and Unemployment

##### Explore the hypothesis that inflation and unemployment are counter-cyclical.

# The Baxter-King filter is intended to explictly deal with the periodicty of the business cycle. By applying their band-pass filter to a series, they produce a new series that does not contain fluctuations at higher or lower than those of the business cycle. Specifically, the BK filter takes the form of a symmetric moving average
#
# $$y_{t}^{*}=\sum_{k=-K}^{k=K}a_ky_{t-k}$$
#
# where $a_{-k}=a_k$ and $\sum_{k=-k}^{K}a_k=0$ to eliminate any trend in the series and render it stationary if the series is I(1) or I(2).
#
# For completeness, the filter weights are determined as follows
#
# $$a_{j} = B_{j}+\theta\text{ for }j=0,\pm1,\pm2,\dots,\pm K$$
#
# $$B_{0} = \frac{\left(\omega_{2}-\omega_{1}\right)}{\pi}$$
# $$B_{j} = \frac{1}{\pi j}\left(\sin\left(\omega_{2}j\right)-\sin\left(\omega_{1}j\right)\right)\text{ for }j=0,\pm1,\pm2,\dots,\pm K$$
#
# where $\theta$ is a normalizing constant such that the weights sum to zero.
#
# $$\theta=\frac{-\sum_{j=-K^{K}b_{j}}}{2K+1}$$
#
# $$\omega_{1}=\frac{2\pi}{P_{H}}$$
#
# $$\omega_{2}=\frac{2\pi}{P_{L}}$$
#
# $P_L$ and $P_H$ are the periodicity of the low and high cut-off frequencies. Following Burns and Mitchell's work on US business cycles which suggests cycles last from 1.5 to 8 years, we use $P_L=6$ and $P_H=32$ by default.

bk_cycles = sm.tsa.filters.bkfilter(dta[["infl","unemp"]])

# * We lose K observations on both ends. It is suggested to use K=12 for quarterly data.

fig = plt.figure(figsize=(14,10))
ax = fig.add_subplot(111)
bk_cycles.plot(ax=ax, style=['r--', 'b-']);

#### Christiano-Fitzgerald approximate band-pass filter: Inflation and Unemployment

# The Christiano-Fitzgerald filter is a generalization of BK and can thus also be seen as weighted moving average. However, the CF filter is asymmetric about $t$ as well as using the entire series. The implementation of their filter involves the
# calculations of the weights in
#
# $$y_{t}^{*}=B_{0}y_{t}+B_{1}y_{t+1}+\dots+B_{T-1-t}y_{T-1}+\tilde B_{T-t}y_{T}+B_{1}y_{t-1}+\dots+B_{t-2}y_{2}+\tilde B_{t-1}y_{1}$$
#
# for $t=3,4,...,T-2$, where
#
# $$B_{j} = \frac{\sin(jb)-\sin(ja)}{\pi j},j\geq1$$
#
# $$B_{0} = \frac{b-a}{\pi},a=\frac{2\pi}{P_{u}},b=\frac{2\pi}{P_{L}}$$
#
# $\tilde B_{T-t}$ and $\tilde B_{t-1}$ are linear functions of the $B_{j}$'s, and the values for $t=1,2,T-1,$ and $T$ are also calculated in much the same way. $P_{U}$ and $P_{L}$ are as described above with the same interpretation.

# The CF filter is appropriate for series that may follow a random walk.

print(sm.tsa.stattools.adfuller(dta['unemp'])[:3])

print(sm.tsa.stattools.adfuller(dta['infl'])[:3])

cf_cycles, cf_trend = sm.tsa.filters.cffilter(dta[["infl","unemp"]])
print(cf_cycles.head(10))

fig = plt.figure(figsize=(14,10))
ax = fig.add_subplot(111)
cf_cycles.plot(ax=ax, style=['r--','b-']);

# Filtering assumes *a priori* that business cycles exist. Due to this assumption, many macroeconomic models seek to create models that match the shape of impulse response functions rather than replicating properties of filtered series. See VAR notebook.


import os

import numpy as np
from matplotlib import pyplot as pl

path = os.path.dirname(os.path.realpath(__file__)) + '/train_data.txt'
alpha = 0.0001
epsilon = 0.000001

def build_matrix(file_path):
    with open(file_path, 'r') as f:
        data_lines = f.readlines()
        total_lines = len(data_lines)
        train_matrix = np.zeros((total_lines, 2))
        index = 0
        for line in data_lines:
            train_matrix[index, :] = line.split(',')
            index += 1

    return train_matrix

def h_x(theta0, theta1, x):
    return theta0 + theta1 * x

def cost_function(theta0, theta1):
    m = matrix.shape[0]
    cost_sum = 0.
    for data in matrix:
        cost_sum += (h_x(theta0, theta1, data[0]) - data[1]) ** 2

    return cost_sum / (2 * m)

def pd_theta0(theta0, theta1):
    m = matrix.shape[0]
    pd_sum = 0.
    for data in matrix:
        pd_sum += (h_x(theta0, theta1, data[0]) - data[1])

    return pd_sum / m

def pd_theta1(theta0, theta1):
    m = matrix.shape[0]
    pd_sum = 0.
    for data in matrix:
        pd_sum += (h_x(theta0, theta1, data[0]) - data[1]) * data[0]

    return pd_sum / m

def gradient_descent():
    theta0 = 0.
    theta1 = 0.
    cost = cost_function(theta0, theta1)
    print('first time cost: ', cost)
    while True:
        count = 0
        if count > matrix.shape[0]:
            break

        temp_theta0 = theta0 - alpha * pd_theta0(theta0, theta1)
        temp_theta1 = theta1 - alpha * pd_theta1(theta0, theta1)

        theta0 = temp_theta0
        theta1 = temp_theta1

        current_cost = cost_function(theta0, theta1)
        print('current_cost: ', current_cost)

        if abs(current_cost - cost) < epsilon:
            break
        else:
            cost = current_cost
        count += 1

    return theta0, theta1

if __name__ == '__main__':
    matrix = build_matrix(path)
    p0, p1 = gradient_descent()

    X = np.linspace(0, 25, 2, endpoint=True)
    Y = np.ones((len(X), 1))
    i = 0
    for x in X:
        Y[i] = h_x(p0, p1, x)
        i += 1

    pl.plot(X, Y)
    pl.plot(matrix[:, 0], matrix[:, 1], 'o')
    pl.show()

    print('theta0: ', p0, 'theta1: ', p1)
    print('predict: ', h_x(p0, p1, 5.2524))


import numpy as np

# ========== HW04 SOLUTION [Python3] ========== #

# ========== 1 ========== #

np.random.seed(99)
sample = np.random.normal(27.0, 10.0, 100000)

print(sample.mean())
print(sample.std())
print(sample.max())
print(sample.min())

# ========== 2 ========== #

E = 80e10
L = 0.25

K = np.array([[0.00576, -0.00576, 0, 0],
              [-0.00576, 0.0095, -0.002687, 0],
              [0, -0.002687, 0.0075, -0.000733],
              [0, 0, -0.000733, 0.000733]])
# either works:
f = np.array([10000. / 6, 10000. / 3, 10000. / 3, 10000. / 6])
f = np.array([[10000. / 6],
              [10000. / 3],
              [10000. / 3],
              [10000. / 6]])
u = np.linalg.solve(E / L * K, f)
print(u)

# ========== 3 ========== #

a = np.array([[9, 5, 0],
              [9, 5, 0],
              [5, 4, 9]])
b = np.array([[5, 10, 5],
              [4, 4, 3],
              [6, 10, 4]])
# either works:
c = np.array([10, 6, 9])
c = np.matrix([[10],
               [6],
               [9]])

v = np.dot(np.dot(a, b), c)

# or use the @ operator (Python >= 3.5 ONLY)
v = a @ b @ c

# or use np.matrix:

a = np.matrix([[9, 5, 0],
               [9, 5, 0],
               [5, 4, 9]])
b = np.matrix([[5, 10, 5],
               [4, 4, 3],
               [6, 10, 4]])
c = np.matrix([[10], [6], [9]])

v = a * b * c

print(v)

# ========== 4 ========== #

np.random.seed(67)
ints = np.random.randint(3, 14, 100)

idx_max = np.argmax(ints)
print(ints[idx_max])
idx_min = np.argmin(ints)
print(ints[idx_min])

print(np.min(ints) == ints[idx_min])
print(np.max(ints) == ints[idx_max])

# ========== 5 ========== #

x = np.array([0.0, 0.7, 1.7, 2.1])
y = np.array([1.1, 2.99, 5.69, 6.77])
A = np.vstack([x, np.ones(len(x))]).T
# or
A = np.array([x, np.ones(len(x))]).T
c, residuals, rank, sing = np.linalg.lstsq(A, y)
print(c)
print(residuals)
print(rank)


import numpy as np
import scipy.stats

def random_points_in_triangle(p1,p2,p3,n):
    """Generate random points uniformly distributed in a triangle.

    The points can be in any number of dimensions.

    Params
    ------
    p1: 1D array
        Vector pointing to the first vertex
    p2: 1D array
        Vector pointing to the second vertex
    p3: 1D array
        Vector pointing to the third vertex
    n: int
        Number of points to generate

    Returns
    -------
    p: array
        n * ndim array of points in the triangle

    """
    # Find the edge vector
    v1 = p2-p1
    v2 = p3-p1

    # Generate 2n random uniform values
    # as a1 and a2
    a = np.random.uniform(0.,1.,2*n)
    a1 = a[:n]
    a2 = a[-n:]

    # Find any points that flipped over to being outside
    # the triangle and flip them back in
    w = np.where(a1+a2>1)
    a1[w] = 1 - a1[w]
    a2[w] = 1 - a2[w]

    # Generate p_{ij} = p1_{j} + a1_{i}*v1_{j} + a2_{i}*v2_{j}
    # which should be uniformly distributed in the quadrilateral
    p = p1[np.newaxis,:] + np.einsum('i,j->ij',a1,v1) + np.einsum('i,j->ij',a2,v2)

    return p

def random_points_in_quadrilateral(p1,p2,p3,p4,n):
    """Generate random points uniformly distributed in a quadrilateral.

    The points can be in any number of dimensions.  If two of them
    co-incide so you are actually specifying a triangle it will still work.

    As long as you specify the vertices consistently either clockwise or
    anti-clockwise is okay.

    Params
    ------
    p1: 1D array
        Vector pointing to the first vertex
    p2: 1D array
        Vector pointing to the second vertex
    p3: 1D array
        Vector pointing to the third vertex
    p4: 1D array
        Vector pointing to the fourth vertex
    n: int
        Number of points to generate

    Returns
    -------
    p: array
        n * ndim array of points in the quadrilateral

    """

    # Find the edge vectors
    v1 = p2-p1
    v2 = p3-p2
    v3 = p4-p3
    v4 = p1-p4

    # Find the area of the two triangles making up the quadrilateral,
    # And therefore the expected fraction of the points in each half.
    A1 = 0.5*np.linalg.norm(np.cross(v1,v2))
    A2 = 0.5*np.linalg.norm(np.cross(v3,v4))
    f1 = abs(A1)/abs(A1+A2)

    # We choose the actual number of points according to a binomial distribution
    n1 = scipy.stats.binom.rvs(n,f1)
    n2 = n - n1

    # Now generate the points in each half-triangle
    x1 = random_points_in_triangle(p1,p2,p3,n1)
    x2 = random_points_in_triangle(p1,p3,p4,n2)

    # Group the points and return
    return np.vstack((x1,x2))


# coding: utf-8

# In[2]:

# Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from sklearn.metrics import mean_squared_error, r2_score
from scipy import stats

# Import the dataset
dataset = pd.read_csv('train.csv')
full_dataset = dataset.iloc[:, :].values
print('Original Training Sample size : {}'.format(full_dataset.shape))
# get data for which area > 0
new_full_dataset_DF = dataset[dataset.area > 0]
new_full_dataset = new_full_dataset_DF.values
print('Training Sample size (with area > 0) : {}'.format(new_full_dataset.shape))
X = new_full_dataset[:, :-1]
y = new_full_dataset[:, 12]

dataset_test = pd.read_csv('test.csv')
full_test_dataset = dataset_test[dataset_test.area > 0].values
print('Test Sample size (with area > 0) : {}'.format(full_test_dataset.shape))
X_test = full_test_dataset[:, :-1]
y_test = full_test_dataset[:, 12]

# plot the heatmap showing correlation among features
corr = new_full_dataset_DF.corr()
fig = plt.subplots(figsize = (10,10))
sns.heatmap(corr, annot=True, fmt=".2f")
plt.show()

# NOTE : If a warning comes then just run this cell again,
# it's known error in the library

# In[3]:

# Plotting the graphs
import matplotlib.pyplot as plt

plt.hist(y, bins=10)
plt.title('Histogram of outcome variable')
plt.xlabel('Value of area')
plt.ylabel('Frequency')
plt.grid()
plt.show()

plt.hist(np.log(y))
plt.title('Histogram of outcome variable')
plt.xlabel('Value of log(area)')
plt.ylabel('Frequency')
plt.grid()
plt.show()

# In[4]:

print('True labels : {}'.format(y))

# In[5]:

print('True labels(log y) : {}'.format(np.log(y)))

# In[6]:

print('Feature Shape : {}'.format(X.shape))

# In[7]:

print('True Label Shape : {}'.format(y.shape))

# In[8]:

X[0]

# In[9]:

# Feature Standardization
import sklearn
from sklearn.preprocessing import StandardScaler
sc_x = StandardScaler()
X = sc_x.fit_transform(X)
X_test = sc_x.transform(X_test)

# In[10]:

X[0]

# In[11]:

X_test[0]

# In[12]:

y_test

# In[13]:

# Regression
# Fitting Multiple Linear Regression to the Training set
"""
from sklearn.linear_model import LinearRegression
regressor = LinearRegression()
regressor.fit(X, y)

# Predicting the Test set results
y_pred = regressor.predict(X_test)

print(regressor.score(X, y))
print(regressor.coef_)
print(np.corrcoef(y_pred, y_test))
print(np.correlate(y_pred, y_test))
print("Mean squared error: %.2f"
      % mean_squared_error(y_test, y_pred))
"""

# In[14]:

# Regression
# Using OLS to compute the weights
X = np.hstack([np.ones([X.shape[0],1]), X])

a = np.matmul(X.T, X)
a = np.linalg.inv(a)
b = np.matmul(X.T, y)
w = np.matmul(a, b)

print('Shape of weight vector : {}'.format(w.shape))
print('Computed weight vector : {}'.format(w))

# In[15]:

# Prediction
X_test = np.hstack([np.ones([X_test.shape[0],1]), X_test])
y_pred = X_test.dot(w)
print(np.corrcoef(y_pred, y_test))
print(np.cov(y_pred, y_test))
print("Mean squared error: %.2f"
      % mean_squared_error(y_test, y_pred))
RSS = sum((y_pred-y_test)**2)
print("Residual square error(RSS): %.2f"
      % RSS)
print(stats.pearsonr(y_pred, y_test))

# In[16]:

y_pred

# In[17]:

y_test

# In[18]:

# using log scale
# Using OLS to compute the weights with log of area

a = np.matmul(X.T, X)
a = np.linalg.inv(a)
y_log = np.log(y)
b = np.matmul(X.T, y_log)
w = np.matmul(a, b)

print(w.shape)
print(w)

# Prediction
y_pred = X_test.dot(w)
print(np.corrcoef(y_pred, np.log(y_test)))
print(np.cov(y_pred, np.log(y_test)))
print("Mean squared error: %.2f"
      % mean_squared_error(np.log(y_test), y_pred))
RSS = sum((y_pred-np.log(y_test))**2)
print("Residual square error(RSS): %.2f"
      % RSS)
print(stats.pearsonr(y_pred, np.log(y_test)))

# In[19]:

# Fitting Polynomial Regression to the dataset
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
poly_reg = PolynomialFeatures(degree=2)
X_poly = poly_reg.fit_transform(X)
lin_reg_2 = LinearRegression()
lin_reg_2.fit(X_poly, y)
print(X.shape)
print(X_poly.shape)

# In[20]:

# Predicting the Test set results
X_test_poly = poly_reg.transform(X_test)
y_pred = lin_reg_2.predict(X_test_poly)

print(np.corrcoef(y_pred, y_test))
print(np.cov(y_pred, y_test))
print("Test Mean squared error: %.2f"
      % mean_squared_error(y_test, y_pred))
RSS = sum((y_pred-y_test)**2)
print("Test Residual square error(RSS): %.2f"
      % RSS)

y_train_predict = lin_reg_2.predict(X_poly)
print("Train Mean squared error: %.2f"
      % mean_squared_error(y, y_train_predict))
RSS = sum((y_train_predict-y)**2)
print("Train Residual square error(RSS): %.2f"
      % RSS)
print("Training coreleation coefficient:")
print(stats.pearsonr(y, y_train_predict))

# In[21]:

y_test

# In[22]:

y_pred

# In[23]:

y_pred.shape

# In[24]:

# Fitting Polynomial Regression to the dataset using log of area
lin_reg_2 = LinearRegression()
lin_reg_2.fit(X_poly, np.log(y))
# Predicting the Test set results
X_test_poly = poly_reg.transform(X_test)
y_pred = lin_reg_2.predict(X_test_poly)

print(np.corrcoef(y_pred, np.log(y_test)))
print(np.cov(y_pred, np.log(y_test)))
print("Mean squared error: %.2f"
      % mean_squared_error(np.log(y_test), y_pred))
RSS = sum((y_pred-np.log(y_test))**2)
print("Residual square error(RSS): %.2f"
      % RSS)

y_train_predict = lin_reg_2.predict(X_poly)
print("Train Mean squared error: %.2f"
      % mean_squared_error(np.log(y), y_train_predict))
RSS = sum((y_train_predict-np.log(y))**2)
print("Train Residual square error(RSS): %.2f"
      % RSS)
print("Training coreleation coefficient:")
print(stats.pearsonr(np.log(y), y_train_predict))

# In[25]:

cube_reg = PolynomialFeatures(degree=3)
X_cube = cube_reg.fit_transform(X)
lin_reg_3 = LinearRegression()
lin_reg_3.fit(X_cube, y)

# Predicting the Test set results
X_test_cube = cube_reg.transform(X_test)
y_pred = lin_reg_3.predict(X_test_cube)

print(np.corrcoef(y_pred, y_test))
print(np.cov(y_pred, y_test))
print("Mean squared error: %.2f"
      % mean_squared_error(y_test, y_pred))
RSS = sum((y_pred-y_test)**2)
print("Residual square error(RSS): %.2f"
      % RSS)

y_train_predict = lin_reg_3.predict(X_cube)
print("Train Mean squared error: %.2f"
      % mean_squared_error(y, y_train_predict))
RSS = sum((y_train_predict-y)**2)
print("Train Residual square error(RSS): %.2f"
      % RSS)
print("Training coreleation coefficient:")
print(stats.pearsonr(y, y_train_predict))

# In[26]:

# Fitting Polynomial Regression to the dataset using log of area
lin_reg_3 = LinearRegression()
lin_reg_3.fit(X_cube, np.log(y))

# Predicting the Test set results
X_test_cube = cube_reg.transform(X_test)
y_pred = lin_reg_3.predict(X_test_cube)

print(np.corrcoef(y_pred, np.log(y_test)))
print(np.cov(y_pred, np.log(y_test)))
print("Test Mean squared error: %.2f"
      % mean_squared_error(np.log(y_test), y_pred))
RSS = sum((y_pred-np.log(y_test))**2)
print("Test Residual square error(RSS): %.2f"
      % RSS)

y_train_predict = lin_reg_3.predict(X_cube)
print("Train Mean squared error: %.2f"
      % mean_squared_error(np.log(y), y_train_predict))
RSS = sum((y_train_predict-np.log(y))**2)
print("Train Residual square error(RSS): %.2f"
      % RSS)
print("Training coreleation coefficient:")
print(stats.pearsonr(np.log(y), y_train_predict))

# In[ ]:

# In[ ]:


# -*- coding: utf-8 -*-
"""
Created on Fri Feb  8 15:24:14 2019

@author: William Zhang
#ID : 110768508
@email: William.Zhang@stonybrook.edu
"""

import numpy as np
import matplotlib.pyplot as plt
"The main method as a driver to plot the graph "
def main():
    plotting = np.arange(-1,2,0.001)
    plt.plot(plotting,function(plotting))

    plt.xlabel("x-axis")
    plt.ylabel("y-axis")
    plt.title("A function of X")
    plt.grid(True)
    bisectionMethod()
    plt.show()

"This is the function "
def function(x):
    h = -np.power(x,3)
    sinfunction = np.power(x,4)
    return np.power(2.019,h) - np.power(x,5) * np.sin(sinfunction) - 1.984
"This method to make sure these intervals are opposite signs "
def sameSign(a,b):
    return a * b > 0;
"Now we apply the bisection method "
def  bisectionMethod():
    #This are our boundary we think are on the graph are between [-1,2] #
    #Our X1 were = [-0.8,1.35,1.55,1.75,1.95]
    x1 = [-0.8,1.35,1.55,1.75,1.95 ]

    #These were my intervals and we are going to use. My program will also print the error  as well the root.
    intervals = [[-0.7,-0.9],[1.3,1.4],[1.5,1.6],[1.7,1.8],[1.9,2.0]]

    "Maximum number of iterations. Of course there are more optimal ways to determine this number"
    "but a  1000 iterations  can give us a number potentially  accurate to thousands place.The more iterations the more accurate the root is"
    iterations = 1000
    for x in range(0,5):
        #left boundary  interval
        a = intervals[x][0]
        #Right boundary interval
        b = intervals[x][1]
        #Check to make sure they are not the same sign
        assert not sameSign(function(a),function(b))

        for h in range(iterations):
            c = (a + b)/2
            #Check if the function is zero
            if(round(function(c),4) is 0.00000 ):
                error =  round(abs(x1[x]) -abs(intervals[x][0]),4)
                print("Boundaries: " + str(intervals[x]) + "\tRootX1: " + str(x1[x]) + "\tError: " + str(error) + "\tRootx0: " + str(c))
            #Check if they are the same sign
            elif(sameSign(function(a), function(c))):
                a = c
            else:
                b = c
        error = round(abs(x1[x]) -abs(intervals[x][0]),4)
        print("Boundaries: " + str(intervals[x]) + "\tRootx1: " + str(x1[x]) + "\tError: " + str(error) + "\tRootx0: " + str(c))

if __name__ is "__main__":
    main()


# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt

def target(x, v):
    return x ** 2 - v

n = 5
X = np.linspace(-5, 5, 100)
plt.plot(X, target(X, n), 'r:')
plt.grid(True)
plt.show()

def binary_method(n, epsilon):
    l, r, i = 0, n, 0
    while True:
        m = (l + r) / 2.0
        print('[ Epoch {0} ] l = {1}, r = {2}, m = {3}'.format(i, l, r, m))
        guess = m ** 2
        if abs(n - guess) <= epsilon:
            break
        elif guess > n:
            r = m
        else:
            l = m
        i += 1
    return m

# newton method, n is positive integer
#
# Theory:
#
# slope of the tangent line is f'(Xn)
# [Xn, f(Xn)] is one point of the tangent line
# f(Xn) - 0 = f'(Xn) * (Xn - Xn+1)
# Xn+1 = Xn - f(Xn) / f'(Xn)
# f(x) = x ** 2 - n
# f'(x) = 2 * x
# Xn+1 = Xn - (Xn - n / Xn) / 2
# Xn+1 = (Xn + n / Xn) / 2
def newton_method(n, epsilon):
    guess, i = n, 0
    while abs(guess ** 2 - n) > epsilon:
        print('[ Epoch {0} ] guess = {1}, n = {2}'.format(i, guess, n))
        # f(x) = x ** 2 - n => x0 - f(x0) / f'(x0) = (x0 + n / x0) / 2
        guess = (guess + n / guess) / 2.0
        i += 1
    return guess

print('[Binary] sqrt({0}) = {1}.\n'.format(n, binary_method(n, 1e-6)))
print('[Newton] sqrt({0}) = {1}.\n'.format(n, newton_method(n, 1e-6)))


import matplotlib.pyplot as plt
import pylab
import numexpr as ne
import numpy as np
import sympy as sp

x = sp.Symbol('x')

from sympy.parsing.sympy_parser import (
  parse_expr, # converts string to sympy expression
  standard_transformations, # eg. 5! = 5*4*3*2*1
  implicit_multiplication_application, # e.g. 2x = 2*x
  convert_xor # e.g. 2^x = 2**x
)

# <--------------[PARSE EXPRESSION]---------------> #

def parseExpression(expression):

  expression = expression.replace('y=', '')
  expression = expression.replace('^', '**')
  expression = expression.replace('e', 'E')

  transformations = (standard_transformations + (implicit_multiplication_application,) + (convert_xor,))
  equation = parse_expr(expression, transformations=transformations)

  return equation

# <-----------------[PLOT GRAPH]------------------> #

def plotGraph(equation, lower, upper):

  eq = parseExpression(equation)

  ax = plt.gca()

  x = np.linspace(lower, upper, 100)
  y = ne.evaluate(str(eq))

  ax.plot(
    x, y,
    label = f"$y={sp.latex(eq)}$",
    alpha = 0.5 # 50% transparent
  )

  ax.legend()
  ax.grid(True, linestyle=':')
  ax.spines['left'].set_position('zero')
  ax.spines['right'].set_color('none')
  ax.spines['bottom'].set_position('zero')
  ax.spines['top'].set_color('none')

  plt.xlim(lower, upper)
  plt.savefig('graph.png', dpi=300)
  plt.close()

  return

# <-----------------[RENDER TEX]------------------> #

def renderTeX(text):

  # change math font to Computer Modern
  plt.rcParams['mathtext.fontset'] = 'cm'
  # change normal font to DejaVu Serif
  plt.rcParams['font.family'] = 'DejaVu Serif'

  fig = pylab.figure()

  fig.text(
    0,
    0,
    text,
    color = 'black'
  )

  fig.savefig(
    'tex.png',
    dpi = 1000,
    bbox_inches = 'tight',
    pad_inches = 0.05,
    transparent = False
  )

  plt.close()

  return

# <-----------------[GET LIMIT]-------------------> #

def getLimit(equation, x_value):

  equation = parseExpression(equation)
  limit = sp.limit(equation, x, x_value)

  if 'oo' in str(x_value):
    x_value = x_value.replace('oo', '\infty')

  tex = (
    r'$\lim_{x \rightarrow ' +
    str(x_value) + '}' +
    f'({sp.latex(equation)}) = {sp.latex(limit)}$'
  )
  renderTeX(tex)

  return

# <---------------[GET DERIVATIVE]----------------> #

def getDerivative(equation):

  equation = parseExpression(equation)
  derivative = sp.diff(equation, x)
  renderTeX(f'${sp.latex(derivative)}$')

  return

# <----------------[GET INTEGRAL]-----------------> #

def getIntegral(equation, lt, ut):

  equation = parseExpression(equation)

  if lt != None and ut != None:

    definite_int = sp.integrate(equation, (x, lt, ut))
    definite_int = sp.latex(definite_int)
    definite_int = definite_int.replace(
      r'\text{NaN}', '\mathtt{undef}'
    )
    tex = (
      r'$\int_{' + str(lt) + '}^{' + str(ut) + '}' +
      '(' + sp.latex(equation) + ') \ dx' +
      '=' + definite_int + '$'
    )

  else:

    indefinite_int = sp.integrate(equation, x)
    tex = f'${sp.latex(indefinite_int)} + C$'

  renderTeX(tex)

  return

# <----------------[GET SOLUTION]-----------------> #

def getSolution(equation, domain):

  if domain.lower() == 'real':
    domain = sp.S.Reals
  else:
    domain = sp.S.Complexes

  equation = parseExpression(equation)
  sols = sp.solveset(equation, x, domain=domain)

  # equation has certain solutions
  if type(sols) == sp.sets.sets.FiniteSet:
    tex = f'$x={", ".join(sp.latex(s) for s in sols)}$'

  # equation has infinite solutions
  elif type(sols) == sp.sets.fancysets.ImageSet:

    tex = sp.latex(sols)
    tex = tex.replace('\left', '')
    tex = tex.replace('\middle', '')
    tex = tex.replace(r'\right', '')
    tex = tex.replace('\;', '')
    tex = tex.replace('\{', '')
    tex = tex.replace('\}', '')
    tex = tex.replace(' |', ',')
    tex = f'$x={tex}$'

  # equation has union solutions
  elif type(sols) == sp.sets.sets.Union:

    tex = sp.latex(sols)
    tex = tex.replace('\left', '')
    tex = tex.replace('\middle', '')
    tex = tex.replace(r'\right', '')
    tex = tex.replace('\;', '')
    tex = tex.replace('\{', '')
    tex = tex.replace('\}', '')
    tex = tex.replace(' |', ',')
    tex = f'$x={tex}$'

  # equation has no solutions
  elif type(sols) == sp.sets.sets.EmptySet:
    tex = 'No solution over ℝ'

  renderTeX(tex)

  return

# <---------------[GET EXPANSION]-----------------> #

def getExpansion(expression):

  expression = parseExpression(expression)
  expansion = sp.expand(expression, x)
  renderTeX(f'${sp.latex(expansion)}$')

  return

# <-------------[GET FACTORISATION]---------------> #

def getFactorisation(expression):

  expression = parseExpression(expression)
  factorisation = sp.factor(expression)
  renderTeX(f'${sp.latex(factorisation)}$')

  return

# <-------------[GET SIMPLIFICATION]--------------> #

def getSimplification(expression):

  expression = parseExpression(expression)
  simplification = sp.simplify(expression)
  renderTeX(f'${sp.latex(simplification)}$')

  return

# <--------------[CALC EXPRESSION]----------------> #

def calcExpression(expression):

  expression = parseExpression(expression)
  answer = ne.evaluate(str(expression))

  return answer

print(plotGraph('y=3x','10','-10'))

import numpy,import sympy,from sympy,import numexpr


import matplotlib.pyplot as plt
from scipy import *
from scipy import integrate
from scipy.integrate import ode, odeint
import numpy as np

plt.close()
fig,ax = plt.subplots(1,1,figsize=(8,8))
ax.set_facecolor(plt.cm.gray(.95))
#ax.axis('equal')
## Vector field function
def vf1(x,t, a,b):
  dx=np.zeros(2)
  dx[0]=-x[0] +a*x[1] + x[0]**2*x[1]
  dx[1]=b - a*x[1] - x[0]**2*x[1]
  return dx
#Integrate under curve
# Initial condition
xx0 = np.array([.25,1.5])
a = .08
b = .6
# Solve
t = np.linspace(0, 15, 1000)
ys = odeint(vf1, xx0, t, args=(a,b))

#Vector field
x1,y1 = np.linspace(0,3,200),np.linspace(0,b/a,200)
X,Y = np.meshgrid(x1,y1 )
U = -X +a*Y + X**2*Y
V = b - a*Y - X**2*Y

start = [[0,2],[.8,0]]

strm = ax.streamplot( X,Y,U, V,linewidth=.2)
strmS = ax.streamplot(x1,y1, U, V, start_points=start, color="crimson", linewidth=1)
fig.suptitle('Glycolysis in cells', size=16)
ax.set_title( 'Strogatz 7.3.2, p.207', size=12)
ax.plot(ys[:,0],ys[:,1],label=r'scipy.ode for $x_0 = ({0}, {1})$'.format(xx0[0],xx0[1]),lw=.5)
ax.plot(b,b/(a+b**2), 'k*', label='Fixed point at $({0}, {1})$'.format(b,np.round(b/(a+b**2),2)))
ax.plot(x1,b/(a+x1**2), 'k-.', lw=.8, label=r'y-nullcline $ \frac{b}{(a + x^2)}$')
ax.plot(x1,x1/(a+x1**2), 'k:',lw=1, label=r'x-nullcline $ \frac{x}{(a + x^2)}$')
#plt.xlim([-1,3])
plt.ylim([0,b/a+.2])
plt.xlabel(r"$ x$",size=14)
plt.ylabel(r"$ y$",size=14)
plt.legend()
plt.grid(True)
plt.show()


############################
# NON LINEAR DATA MODEL: POLYNOMIAL REGRESSION
############################
# Reproduce the same scripts than Linear Regression (linear_regression.py)
"""##### 1 [ Split into training ] #####"""
"""##### 2 [ Extract train and test idx for later merge with geography coord ] #####"""

"""##### 3 [ Fit: Polynomial Regression ] ######"""
## 3. 1 Fit Model: Polynomial Regression
### Fitting Polynomial Regression to the dataset
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression

poly_reg = PolynomialFeatures(degree=2)
X_poly = poly_reg.fit_transform(X_train)
pol_reg = LinearRegression()

### Train model
pol_reg.fit(X_poly, y_train)

## 3.2 Predict Test Results
### 3.2.1 TEST: Make prediction using test set
y_pred = pol_reg.predict(poly_reg.fit_transform(X_test))
y_pred

dataTest = pd.DataFrame({'Actual': y_test, 'Predicted': y_pred})
dataTest['residuals']=dataTest['Actual'] - dataTest['Predicted']
dataTest

#summary descriptive statistics
dataTest.describe()

### 3.2.2 TRAIN: Make prediction using TRAIN set
y_train_predicted = pol_reg.predict(X_poly)
y_train_predicted

dataTrain = pd.DataFrame({'Actual': y_train, 'Predicted': y_train_predicted})
dataTrain['residuals']=dataTrain['Actual'] - dataTrain['Predicted']
dataTrain

#summary descriptive statistics
dataTrain.describe()

### 3.2.3 Plot Predicted vs Observed | Test Set
### Plot A
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='whitegrid')
plt.style.use('seaborn-whitegrid')
plt.figure(figsize=(10, 6))

ax = sns.regplot(x="Actual", y="Predicted", data=dataTest, label='siteindex predicted', scatter_kws = {'color': 'white', 'alpha': 0.8, 'edgecolor':'blue', 's':10}, line_kws = {'color': '#f54a19'})
ax.set_ylim(0,55)
ax.set_xlim(0,55)
ax.plot([0, 55], [0, 55], 'k--', lw=2)

ax.legend(title="Test set:", frameon=  True, loc='upper left')
#ax.legend(bbox_to_anchor =(0.85, -0.20), ncol = 4)
plt.title('Goodness-of-fit in Validation Set',fontsize=12)

plt.savefig('actualvsPredicted_PolyReg_testSet.jpg', bbox_inches='tight', dpi=300)

### Plot B
ax = sns.regplot(x="Actual", y="Predicted", data=dataTest,
                 scatter_kws = {'color': 'orange', 'alpha': 0.3}, line_kws = {'color': '#f54a19'},
                 x_estimator=np.mean, logx=True)

ax.set_ylim(0,55)
ax.set_xlim(0,55)
ax.plot([0, 55], [0, 55], 'k--', lw=2)

### Plot C
ax = sns.regplot(x="Actual", y=y_pred, data=dataTest,
                 scatter_kws={"s": 80},
                 order=2, ci=None)

"""##### 4 [ Perfomance and Validation #####"""
## 4.1 ACCURACY FOR TRAINING & TEST SET:
print("Accuracy on train set:: {:.3f}".format(pol_reg.score(X_poly, y_train)))
print("Accuracy on test set:: {:.3f}".format(pol_reg.score(poly_reg.fit_transform(X_test), y_test)))

## 4.2 Accuracy Measures
print("R2 (explained variance) Train Set: {:.3f}".format(metrics.r2_score(y_train, y_train_predicted), 2))
print("R2 (explained variance) Test set: {:.3f}".format(metrics.r2_score(y_test, y_pred), 2))
print('MAE=Mean Absolute Error:', metrics.mean_absolute_error(y_test, y_pred))
print('MSE=Mean Squared Error:', metrics.mean_squared_error(y_test, y_pred))
print('RMSE=Root Mean Squared Error:', np.sqrt(metrics.mean_squared_error(y_test, y_pred)))

## 4.3 Calculate Squared Error
residSquare = np.square(dataTest['residuals'])
residSquare

### 4.3.1 Plot Squared Errror vs Observed
plt.style.use('seaborn-whitegrid')
fig=plt.figure(figsize = [8, 6])

ax = fig.add_subplot(111)

ax.scatter(x=dataTest['Actual'], y=residSquare, label='Squared Error', c='white', alpha=0.8, edgecolors='#1b346c', s=10)
ax.set_xlabel("Observed 'site index' values") #it's a good idea to label your axes
ax.set_ylabel('Squared Error')

plt.title("Squared Error vs Observed 'site index' values")
plt.legend(title="",loc='upper right', frameon=True)
plt.savefig('SquaredError_PolyReg.png', bbox_inches='tight', dpi=300)

"""##### 5 [ Evaluation: Slope of Coefficients ] #####"""
#pol_reg.coef_
from sklearn.metrics import mean_squared_error, r2_score
## 5.1 Model Output
# a. Intercept
print("Intercept:", pol_reg.intercept_)

for coef, col in enumerate(X_train.columns):
    print(f'{col}:  {pol_reg.coef_[coef]}')

## 5.2 Build table to check model output
pred_model = pd.DataFrame(['aspect','planCurvature','profileCurvature','slope','TPI','TWI_SAGA','Dh_diffuse','Ih_direct','DEM','meanJanRain','meanJulRain','maxJanTemp','minJulTemp','SYMBOL','soil_order','BDw','CLY','CFG','ECD','SOC','pHw','SND','SLT'])
coeff = pd.DataFrame(pol_reg.coef_)

df = pd.concat([pred_model,coeff], axis=1, join='inner')
df

## 5.3 Plot Slopes
# adding column name to the respective columns
df.columns =['Features', 'Coefficients']

# displaying the DataFrame
print(df)

df = df.sort_values(by='Coefficients', ascending=0)
df

### 5.3.1 Display contribution of features towards dependent variable: 'siteindex' (y)
# %matplotlib inline
import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize=(14,6))
sns.set(style="whitegrid")
plt.subplot(1, 1, 1) # 1 row, 2 cols, subplot 1

ax = sns.barplot(df.Features, df.Coefficients)

for p in ax.patches:
    ax.annotate(np.round(p.get_height(),decimals=2), (p.get_x()+p.get_width()/2., p.get_height()),
                ha='left',
                va='baseline',
                #textcoords='offset points',
                rotation='30')

#Rotate labels x-axis
plt.xticks(rotation=45, horizontalalignment='right')
plt.ylabel('independent variables (x)')
plt.xlabel('Coefficents')
plt.title("Contribution of features towards dependent variable: 'siteindex' (y)")

plt.savefig('polyreg_FI.png', bbox_inches='tight', dpi=300)

## 5.4 Feature Importance
from sklearn.inspection import permutation_importance
r = permutation_importance(polyreg, X_test, y_test,
                          n_repeats=30,
                           random_state=0)

for i in r.importances_mean.argsort()[::-1]:
     if r.importances_mean[i] - 2 * r.importances_std[i] > 0:
       print(f"{EDAsurvey.columns[i]:<8}"
              f"{r.importances_mean[i]:.3f}"
             f" +/- {r.importances_std[i]:.3f}")

"""##### 6 [ Fit Model: Polynomial regression | K-fold Cross Validation ] #####"""
"""## Model with 10-fold cross-validation with all features ##"""
"""### Option 1 | Assessing Quality of Regression Model ###"""
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score
# Fitting Polynomial Regression to the dataset
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression

poly_reg = PolynomialFeatures(degree=2)
X_poly = poly_reg.fit_transform(X_train)
pol_reg = LinearRegression()

# Train model
pol_reg.fit(X_poly, y_train)

cv_scores_Kfold10 = cross_val_score(pol_reg,X_poly, y_train, cv=10, scoring='r2')
print("Cross-validation scores: {}".format(cv_scores_Kfold10))
print("Average cross-validation score: {:.3f}".format(cv_scores_Kfold10.mean()))

"""### Option 2 | Polynomial Regression | cv=10 ###"""
from sklearn.model_selection import cross_val_score
# Fitting Polynomial Regression to the dataset
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression

###1. evaluate the model
poly_reg = PolynomialFeatures(degree=2)
X_poly = poly_reg.fit_transform(X_train)
pol_reg = LinearRegression()

poly10 = cross_val_score(pol_reg , X_poly, y_train, cv=10, scoring='r2')
print("Cross-validation scores: {}".format(poly10))

### 2. report performance
from numpy import mean
from numpy import std

print("Average cross-validation score: {:.3f}".format(poly10.mean()))
print('MAE: %.3f (%.3f)' % (mean(poly10), std(poly10)))
print("Accuracy: %0.3f (+/- %0.3f)" % (poly10.mean(), poly10.std()))

#The mean score and the 95% confidence interval of the score estimate are hence given by:
print("Accuracy for 95perc confidence interval: %0.3f (+/- %0.3f)" % (poly10.mean(), poly10.std() * 2))

# 2.1 Measure for boxplots
import statistics
from scipy import stats
# Median for predicted value
median = statistics.median(poly10)

q1, q2, q3= np.percentile(poly10,[25,50,75])
# IQR which is the difference between third and first quartile
iqr = q3 - q1

# lower_bound is 15.086 and upper bound is 43.249, so anything outside of 15.086 and 43.249 is an outlier.
lower_bound = q1 -(1.5 * iqr)
upper_bound = q3 +(1.5 * iqr)

print('upper_bound: %.3f' % upper_bound)
print('Third quartile (q3): %.3f' % q3)
print('Median: %.3f' % median)
print('First quartile (q1): %.3f' % q1)
#print('Median (q2): %.3f' % q2)
print('IQR: %.3f' % iqr)
print('lower_bound: %.3f' % lower_bound)

# 3. plot performance
# Cool Boxplot
fig = plt.figure()
fig.suptitle('Model with 10-fold cross-validation')
ax = fig.add_subplot(111)
import matplotlib.pyplot as plt
plt.style.use('classic')

fig.set_size_inches(4, 4)
medianprops = dict(linewidth=1.5, linestyle='-', color='#fc3468')
meanprops =  dict(marker='D', markerfacecolor='indianred', markersize=4.5)

plt.gca().spines['right'].set_color('#D9D8D6')
plt.gca().spines['top'].set_color('#D9D8D6')
plt.gca().spines['left'].set_color('#D9D8D6')
plt.gca().spines['bottom'].set_color('#D9D8D6')

plt.grid(color='grey', linestyle='-', linewidth=0.25)

plt.boxplot(poly10, medianprops=medianprops, meanprops=meanprops, showmeans=True )
ax.set_xticklabels('')
plt.xlabel('Polynomial Regression')
plt.ylabel('Accuracy Model')
plt.savefig('accuracy_polyReg.png', bbox_inches='tight', dpi=300)

# Boring boxplot
fig = plt.figure()
fig.suptitle('Model with 10-fold cross-validation')
ax = fig.add_subplot(111)
import seaborn as sns
sns.set(style="whitegrid")

plt.boxplot(poly10)
ax.set_xticklabels('')
plt.xlabel('Polynomial Regression')
plt.ylabel('Accuracy Model')
plt.savefig('accuracy_polyReg.png', bbox_inches='tight', dpi=300)


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

# # NumPy and pandas
#
# Review of NumPy and examples using pandas.
#
# [Recording of lecture from 1/12/2022](https://uci.zoom.us/rec/share/ZX9cbbE7zeJR-MRWu9Rmj1_r7IMlliQOe01P27fln1RgxddHgchdl8x6HYmFKnvU.DVx5i65Sb_b3JrC_)

# ## Warm-up exercise
#
# 1. Define an 8x4 NumPy array A of random integers between 1 and 10 (inclusive).
#
# 2. Each row of A has four columns.  Let [x,y,z,w] denote one of these rows.  What is the probability that x > y?

# In[1]:

import numpy as np

# In[2]:

rng  = np.random.default_rng()

# In[3]:

help(rng.integers)

# In[4]:

A = rng.integers(1,11,size=(8,4))
A

# In mathematics, it doesn't make sense to ask if a vector is strictly greater than another vector.  In NumPy, this comparison is done *elementwise*.

# In[5]:

A[:,0] > A[:,1]

# It's the same with equality: they are compared elementwise.

# In[6]:

A[:,0] == A[:,1]

# With a `list` instead of an `np.array`, then equality means "are the lists exactly the same, with the same elements in the same positions?"

# In[7]:

[4,2,3] == [4,2,3]

# In[8]:

[4,2,3] == [4,3,2]

# In[9]:

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

# In[10]:

set([4,2,3]) == set([4,3,2,2,4,2,2])

# In[11]:

[1,2,3] == [4,2,3]

# This next cell produces an example of a Boolean array.

# In[12]:

A[:,0] > A[:,1]

# Counting how often `True` appears.

# In[13]:

np.count_nonzero(A[:,0] > A[:,1])

# We think of each row as being one "experiment".  We can find the number of rows using `len`.

# In[14]:

# number of experiments = number of rows
len(A)

# We estimate the probability using "number of successes"/"number of experiments".  It won't be accurate yet, because we are using so few experiments.

# In[15]:

# prob estimate using len(A) experiments
np.count_nonzero(A[:,0] > A[:,1])/len(A)

# Using ten million experiments.

# In[16]:

A = rng.integers(1,11,size=(10**7,4))
np.count_nonzero(A[:,0] > A[:,1])/len(A)

# If we do the same thing, we should get a very similar answer, but it won't be exactly the same, since these are estimates using random experiments.

# In[17]:

A = rng.integers(1,11,size=(10**7,4))
np.count_nonzero(A[:,0] > A[:,1])/len(A)

# ## pandas
#
# Probably the most important Python library for Math 10.  Essentially everything we did earlier in this notebook, we can also do in pandas.  The library pandas also has a lot of extra functionality that will help us work with datasets.

# In[18]:

import pandas as pd

# In[19]:

A = rng.integers(1,11,size=(8,4))
type(A)

# In[20]:

A.shape

# We convert this NumPy array to a pandas DataFrame.  (Make sure you capitalize DataFrame correctly.)

# In[21]:

df = pd.DataFrame(A)
df

# The syntax for getting the zeroth column of a pandas DataFrame is a little longer than the NumPy syntax.

# In[22]:

# zeroth column of df
df.iloc[:,0]

# This column is a pandas Series.

# In[23]:

type(df.iloc[:,0])

# We can compare the entries in these columns elementwise, just like we did using NumPy.

# In[24]:

df.iloc[:,0] > df.iloc[:,1]

# Here is the most efficient way I know to count `True`s in a pandas Boolean Series.

# In[25]:

(df.iloc[:,0] > df.iloc[:,1]).sum()

# We can again get the number of rows using `len`.

# In[26]:

len(df)

# In[27]:

df.shape

# Here is the probability estimate.

# In[28]:

# Not using enough experiments
((df.iloc[:,0] > df.iloc[:,1]).sum())/len(df)

# Here we increase the number of experiments, but we forget to change `df`.

# In[29]:

# forgot to update df
A = rng.integers(1,11,size=(10**7,4))
((df.iloc[:,0] > df.iloc[:,1]).sum())/len(df)

# Here is the correct version.

# In[30]:

A = rng.integers(1,11,size=(10**7,4))
df = pd.DataFrame(A)
((df.iloc[:,0] > df.iloc[:,1]).sum())/len(df)

# In[31]:

A = rng.integers(1,11,size=(8,4))
df = pd.DataFrame(A)

# In[32]:

A

# In[33]:

df

# Changing column names.

# In[34]:

df.columns = ["a","b","m","chris"]

# In[35]:

df

# There are two similar operations, `df.loc` and `df.iloc`.  The operation `df.loc` refers to rows and columns by their names, whereas `df.iloc` refers to rows and columns by their index.

# In[36]:

df.loc[:,"b"]

# In[37]:

df.iloc[:,1]

# There is a common shortcut for referring to a column by its name.

# In[38]:

# abbreviation
df["b"]

# This next command says, give me the 1st-4th rows (not including the right endpoint) in the 2nd column.

# In[39]:

df.iloc[1:4,2]

# Somewhat confusingly, right endpoints are included when using `loc`.

# In[40]:

df.loc[1:4,"m"]

# You can use this same sort of notation to set values.

# In[41]:

df

# In[42]:

df.iloc[1:4,2] = -1000

# In[43]:

df

# That same sort of notation also works for NumPy arrays.

# In[44]:

B = np.array(df)
B

# In[45]:

B[1:4,0] = 3

# In[46]:

B

# You can also set multiple different values.  The following says, in the 1st column (remember that we start counting at 0), set the elements from the 5th, 6th, 7th rows to be 100, 200, 300, respectively.

# In[47]:

B[5:,1] = [100,200,300]

# In[48]:

B


import numpy as np
import random
"""
D:\FluidSim\FluidSim\MultiGri\Poisson_FDM_Multigrid-master

https://github.com/EnigmaHuang/Poisson_FDM_Multigrid
"""
p = 5
n = 2**p - 1
A = np.zeros((n,n))
A[0,0] = 2
A[0,1] = -1
for i in range(1,n-1):
    A[i,i-1] = -1
    A[i,i] = 2
    A[i,i+1] = -1
A[n-1,n-1] = 2
A[n-1,n-2] = -1
b = np.zeros((n))
directn = 16

def VCycle(Amat,directn):

    while(n > directn):
        coarse_n = int(np.floor((n-1)/2))
        R = np.zeros((coarse_n,n))
        for i in range(coarse_n):
            col = 2 * i
            R[i,col] = 1 / 4
            R[i,col+1] = 1 / 2
            R[i,col+2] = 1 / 4

def Gauss(Amat,bmat,xmat):
    eps = 1e-2 # 可允许误差范围很大
    err = 1
    size = Amat.shape[0]
    while(err > eps):
        err = 0
        for i in range(size):
            summ = 0
            for j in range(size):
                summ += Amat[i,j] * xmat[j]
            xmat[i] = xmat[i] + 0.5 * (bmat[i] - summ)
            err = max(err,bmat[i] - summ)
            test = 1
    return xmat

def MultiGri(size,Amat,bmat,xmat):
    if size < 16:
        xmat = np.dot(np.linalg.inv(Amat),bmat)
        return xmat
    xmat = Gauss(Amat, bmat,xmat)
    fine_n = size
    coarse_n = int(np.floor((fine_n-1)/2))

    R = np.zeros((coarse_n,fine_n))
    for i in range(coarse_n):
            col = 2 * i
            R[i,col] = 1 / 4
            R[i,col+1] = 1 / 2
            R[i,col+2] = 1 / 4

    coarse_A = np.dot(np.dot(R,A),2*np.transpose(R))

    P = np.transpose(R) * 2

    r = bmat - np.dot(Amat,xmat)
    coarse_b = np.dot(R,r)
    x0 = np.zeros((coarse_n))
    d_x = MultiGri(coarse_n, coarse_A, coarse_b,x0)

    xmat = xmat + np.dot(P,d_x)
    xmat = Gauss(Amat, bmat,xmat)

    return xmat

for i in range(n):
    b[i] = 1

exactAinv = np.linalg.inv(A)
exactx = np.dot(exactAinv,b)

eps = 1e-6
norm = 1
x = np.zeros((n))
while(norm > eps):

    x = MultiGri(n,A,b,x)

    r = b - np.dot(A,x)
    norm = np.linalg.norm(r)
    print(norm)


import numpy as np
from matplotlib import pyplot as plt
from scipy.stats import norm

data_num = 1000
ndist = 3
nrepeat = 3

np.random.seed(0)
def data_generate(n):
    return (np.random.randn(n) + np.where(np.random.rand(n) > 0.3, 2., -2.))

def initialize():
    ws = np.array([0.2,0.5,0.3])
    mus = np.array([-3,0,3])
    sigmas = np.array([1,1,1])
    return ws,mus,sigmas

def phi(x,mu,sigma):
    return np.exp(- ((x-mu) * (x-mu) / ( 2 * sigma * sigma))) / np.sqrt(2 * np.pi * sigma * sigma)

def em_step(ws,mus,sigmas,data):
    #calculate eta
    eta = np.zeros((data_num,ndist))
    for i in range(data_num):
        #calculate denominator
        denom = 0
        for j in range(ndist):
            denom = denom + ws[j] * phi(data[i],mus[j],sigmas[j])
        for j in range(ndist):
            eta[i][j] = ws[j] * phi(data[i],mus[j],sigmas[j]) / denom

    #update hyper-parameters
    newws = np.array([])
    newmus = np.array([])
    newsigmas = np.array([])
    for j in range(ndist):
        #update ws
        neww = 0
        for i in range(data_num):
            neww = neww + eta[i][j]
        neww = neww / data_num
        newws = np.append(newws,neww)

        #update mus
        newmu = 0
        denom = 0
        for i in range(data_num):
            denom = denom + eta[i][j]
        for i in range(data_num):
            newmu = newmu + eta[i][j] * data[i]
        newmu = newmu / denom
        newmus = np.append(newmus,newmu)

        #update sigmas
        newsigma = 0
        for i in range(data_num):
            newsigma = newsigma + eta[i][j] * (data[i] - mus[j]) * (data[i] - mus[j])
        newsigma = np.sqrt(newsigma / denom)
        newsigmas = np.append(newsigmas,newsigma)

    return newws, newmus, newsigmas

if __name__ == "__main__":

    #initialize hyper-parameters and data
    data = data_generate(data_num)
    ws,mus,sigmas = initialize()

    #calculate distribution
    X = np.arange(-6,6,0.1)
    Y = ws[0] * norm.pdf(X,mus[0],sigmas[0])
    for i in range(ndist-1):
        Y = Y + ws[i+1] * norm.pdf(X,mus[i+1],sigmas[i+1])
    # draw
    plt.figure()
    plt.plot(X,Y)
    plt.hist(data,bins=30,density=True)
    plt.savefig("test" + "0" + ".png")

    #EM algorithm
    for i in range(nrepeat):
        ws,mus,sigmas = em_step(ws,mus,sigmas,data)

        #calculate distribution
        X = np.arange(-6,6,0.1)
        Y = ws[0] * norm.pdf(X,mus[0],sigmas[0])
        for j in range(ndist-1):
            Y = Y + ws[j+1] * norm.pdf(X,mus[j+1],sigmas[j+1])

        # draw
        plt.figure()
        plt.plot(X,Y)
        plt.hist(data,bins=30,density=True)
        plt.savefig("test" + str(i+1) + ".png")


from matplotlib import cm, rcParams
import matplotlib.pyplot as plt
import numpy as np
import math as math
import random as rand

""" G(phi) function in Rinzel & Lewis' article (2003) under weak coupling """
""" This is under weak coupling theory, although one can note that gamma only serves to scale the function """

c = ['#aa3863', '#d97020', '#ef9f07', '#449775', '#3b7d86']
rcParams.update({'figure.autolayout': True})

def T(I):
    return math.log(I/(I-1))

def G(phi, I, gamma):
    if phi != 0 and phi != 1:
        return gamma*(2/T(I))*(phi*math.sinh((1-phi)*T(I)) - (1-phi)*math.sinh(phi*T(I))) + gamma*(beta/(I*T(I)*T(I)))*(math.exp(phi*T(I)) - math.exp((1-phi)*T(I)))
    else :
        return 0

""" Varying Gamma """

gamma = [0.4, 0.3, 0.2, 0.1, 0.01]
beta = 0.1
I = 1.8

plt.figure(figsize=(8,5))
vector_phi = np.linspace(0,1,1000)
zero_line = np.zeros(len(vector_phi))
plt.plot(vector_phi, zero_line, color='black', linestyle='--')

k = 0
for g in gamma :
    vector_G = []
    for el in vector_phi:
        vector_G.append(G(el, I, g))
    vector_G = np.array(vector_G)
    plt.plot(vector_phi, vector_G, label=f'$\gamma = {g}$', color = c[k])
    k += 1

plt.xlabel('$\phi$', size=14)
plt.ylabel('$G(\phi)$', size=14)
plt.title(f'G function for $I={I}, \\beta={beta}$')

zero_crossings = np.where(np.diff(np.sign(vector_G-zero_line)))[0]
print(zero_crossings)

plt.legend(loc='upper left')
plt.savefig(f'G_function_range_gammas_I={I}.png', dpi=600)
plt.show()
plt.close()

""" Varying I """
"""
gamma = 1
beta = 0.2
I = [1.15, 1.2, 1.4]

plt.figure(figsize=(8,5))
vector_phi = np.linspace(0,1,1000)
zero_line = np.zeros(len(vector_phi))
plt.plot(vector_phi, zero_line, linestyle='--', color='k')

k = 0
for current in I :
    vector_G = []
    for el in vector_phi:
        vector_G.append(G(el, current, gamma))
    vector_G = np.array(vector_G)
    plt.plot(vector_phi, vector_G, label=f'$I = {current}$', color = c[k])
    k += 1

plt.xlabel('$\phi$', size=14)
plt.ylabel('$G(\phi)$', size=14)

zero_crossings = np.where(np.diff(np.sign(vector_G-zero_line)))[0]
print(zero_crossings)

plt.legend()
plt.show()
"""


"""
收录深度学习中用的数学函数并可视化
"""
import numpy
import matplotlib.pyplot as plt
import math

def tanh(x, vis=False):
    """
    实现tanh函数=（exp(x)-exp(x)）/(exp(x)+exp(-x))
    :param x:输入的数据, list格式[x1,x2,x3]
    :param vis:是否可视化
    :return:
    """
    y = [(math.exp(x_)-math.exp(-x_))/(math.exp(x_)+math.exp(-x_))
         for x_ in x ]
    print('Input data2:{}, \nCompute Result:{}'.format(x, y))
    if vis:
        visual(x, y, 'tanh')

def logistic(x, vis=True):
    """
    实现sigmoid函数中的Logistic函数，log=1/(1+exp(-x))
    :param x:输入数据，list格式
    :param vis:是否可视化
    :return:
    """
    y = [1.0/(1+math.exp(-x_)) for x_ in x]
    print('Input data2:{}\n Compute Result:{}'.format(x, y))
    if vis:
        visual(x, y, 'Logistic')

def visual(x, y, name='math'):
    plt.plot(x, y, color='blue', marker='o')
    plt.title(name)
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.show()

if __name__ == '__main__':
    x = [-6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0,
         1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
    tanh(x, vis=True)
    logistic(x, vis=True)


import numpy as np

def cross_entropy(y, y_hat):
    # n = 1e-6
    # return -np.sum(y * np.log(y_hat + n) + (1 - y) * np.log(1 - y_hat + n), axis=1)
    assert y.shape == y_hat.shape
    res = -np.sum(np.nan_to_num(y * np.log(y_hat) + (1 - y) * np.log(1 - y_hat)))
    return round(res, 3)

def softmax(y):
    y_shift = y - np.max(y, axis=1, keepdims=True)
    y_exp = np.exp(y_shift)
    y_exp_sum = np.sum(y_exp, axis=1, keepdims=True)
    return y_exp / y_exp_sum

if __name__ == "__main__":
    y = np.array([1, 0, 0, 1]).reshape(-1, 1)
    y_hat = np.array([1, 0.4, 0.5, 0.1]).reshape(-1, 1)
    print(cross_entropy(y, y_hat))
    # y = np.array([[1,2,3,4],[1,3,4,5],[3,4,5,6]])
    # print(softmax(y))


# -*- coding: utf-8 -*-
"""
Created on Mon Dec 21 02:05:02 2020

@author: Larisa
"""

import numpy as np

# Laborator 11
def SplinePatratica(X, Y, dfa, dfb, x):
    n = len(X) - 1
    a = np.zeros((n, 1))
    b = np.zeros((n, 1))
    c = np.zeros((n, 1))
    d = np.zeros((n, 1))
    h = np.zeros((n, 1))
    for i in range(n):
        a[i] = Y[i]
        h[i] = X[i + 1] - X[i]

    # Rezolvam sistemul (20 curs11) in bj
    A = np.zeros((n + 1, n + 1))
    w = np.zeros((n + 1, 1))
    A[0][0] = 1
    A[n][n] = 1
    w[0] = dfa
    for j in range(1, n):
        A[j][j] = 2 / h[j] + 2 / h[j - 1]
        A[j][j - 1] = 1 / h[j - 1]
        A[j][j + 1] = 1 / h[j]
        w[j] = (-3 / (h[j - 1] * 2)) * Y[j - 1] + (3 / h[j - 1] * 2 - 3 / h[j] * 2) * Y[j] + (3 / h[j] * 2) * Y[j + 1]
    w[n] = dfb

    b = np.linalg.solve(A, w)
    # Calculam cj,dj din relatiile (19 curs11)
    for j in range(n):
        d[j] = - (2 / h[j] * 3) * (Y[j + 1] - Y[j]) + (1 / h[j] * 2) * (b[j + 1] + b[j])
        c[j] = (3 / h[j] ** 2) * (Y[j + 1] - Y[j]) - (1 / h[j]) * (b[j + 1] + 2 * b[j])

    S = np.zeros((len(x), 1))
    dS = np.zeros((len(x), 1))
    d2S = np.zeros((len(x), 1))

    for i in range(len(x)):
        for j in range(n):
            if x[i] >= X[j] and x[i] <= X[j + 1]:
                S[i] = a[j] + b[j] * (x[i] - X[j]) + c[j] * (x[i] - X[j]) ** 2 + d[j] * (x[i] - X[j]) * 3
                dS[i] = b[j] + 2 * c[j] * (x[i] - X[j]) + 3 * d[j] * (x[i] - X[j]) ** 2
                d2S[i] = 2 * c[j] + 6 * d[j] * (x[i] - X[j])
                break

    return S, dS, d2S

Calcul Numeric (CN)/Laborator/Laborator 11/proceduri.py


import numpy as np

np.random.seed(12345678)

def stoc_walk(p,dr,vol,periods):
    w = np.random.normal(0,1,size=periods)
    for i in range(periods):
        p += dr*p + w[i]*vol*p
    return p

# Parameters
s0 = 114.64		          	# Actual price
drift = 0.0016273		      # Drift term (daily)
volatility = 0.088864	  	# Volatility (daily)
t_ = 365 		            	# Total periods in a year
r = 0.033 			          # Risk free rate (yearly)
days = 2			            # Days until option expiration
N = 100000		          	# Number of Monte Carlo trials
zero_trials = 0		      	# Number of trials where the option payoff = 0
k = 100				            # Strike price

avg = 0			            	# Temporary variable to be assigned to the sum
				                  # of the simulated payoffs

# Simulation loop
for i in range(N):
    temp = stoc_walk(s0,drift,volatility,days)
    if temp > k:
        payoff = temp-k
        payoff = payoff*np.exp(-r/t_*days)
        avg += payoff
    else:
        zero_trials += 1

# Averaging the payoffs
price = avg/float(N)

# Priting the results
print("MONTE CARLO PLAIN VANILLA CALL OPTION PRICING")
print("Option price: ",price)
print("Initial price: ",s0)
print("Strike price: ",k)
print("Daily expected drift: ",drift*100,"%")
print("Daily expected volatility: ",volatility*100,"%")
print("Total trials: ",N)
print("Zero trials: ",zero_trials)
print("Percentage of total trials: ",zero_trials/N*100,"%")


import matplotlib
matplotlib.rcParams['pdf.fonttype'] = 42
matplotlib.rcParams['ps.fonttype'] = 42
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d

# =============================================================================
# # Rastrigin plot
# =============================================================================
fig = plt.figure()
ax = plt.axes(projection='3d')

def rastrigin(x, y):
    return 20 + x**2 - 10*np.cos(2*np.pi*x) + y**2 - 10*np.cos(2*np.pi*y)

x = np.linspace(-5.12, 5.12, 100)
y = np.linspace(-5.12, 5.12, 100)
X, Y = np.meshgrid(x, y)
Z = rastrigin(X, Y)
ax = plt.axes(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
                cmap='jet', edgecolor='none')
ax.set_title('Rastrigin function (2 dimensions)');
plt.savefig("rastrigin_landscape.eps", format="eps")

# =============================================================================
# # Sphere plot
# =============================================================================
fig = plt.figure()
ax = plt.axes(projection='3d')

def sphere(x, y):
    return x**2 + y**2

x = np.linspace(-5.12, 5.12, 100)
y = np.linspace(-5.12, 5.12, 100)
X, Y = np.meshgrid(x, y)
Z = sphere(X, Y)

ax = plt.axes(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
                cmap='jet', edgecolor='none')
ax.set_title('Sphere function (2 dimensions)');
plt.savefig("sphere_landscape.eps", format="eps")

# =============================================================================
# # Ackley plot
# =============================================================================
fig = plt.figure()
ax = plt.axes(projection='3d')

def ackley(x, y):
    return -20*np.exp(-0.2*np.sqrt(0.5*(x**2+y**2))) - np.exp(0.5*(np.cos(2*np.pi*x) + np.cos(2*np.pi*y))) + 20 + np.exp(1)

x = np.linspace(-32.768, 32.768, 100)
y = np.linspace(-32.768, 32.768, 100)
X, Y = np.meshgrid(x, y)
Z = ackley(X, Y)

ax = plt.axes(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
                cmap='jet', edgecolor='none')
ax.set_title('Ackley function (2 dimensions)');
plt.savefig("ackley_landscape.eps", format="eps")


import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return 0.1*x**4 - 1.5*x**3 + 0.6*x**2 + 1.0*x + 20.0

def df_dx(x):
    return 0.4*x**3 - 4.5*x**2 + 1.2*x + 1.0

def gradientDescent(x, eps=1e-5, lr=0.01, max_epoch=1000):
    min_x = x
    min_y = f(min_x)

    x_log = [x]

    for _ in range(max_epoch):
        grad = df_dx(x)
        new_x = x - lr * grad
        y = f(new_x)

        x_log.append(new_x)

        if min_y > y:
            min_x = new_x
            min_y = y

        if (np.abs(x - new_x) < eps):
            break

        x = new_x

    return min_x, min_y, x_log

if __name__ == '__main__':
    min_x1, min_y1, x_log1 = gradientDescent(5)
    min_x2, min_y2, x_log2 = gradientDescent(-5)
    min_x3, min_y3, x_log3 = gradientDescent(0.5)
    min_x4, min_y4, x_log4 = gradientDescent(15, lr=0.005)

    y_log1 = f(np.array(x_log1))
    y_log2 = f(np.array(x_log2))
    y_log3 = f(np.array(x_log3))
    y_log4 = f(np.array(x_log4))

    plt.plot(x_log1, y_log1, '.-')
    plt.plot(x_log2, y_log2, '.-')
    plt.plot(x_log3, y_log3, '.-')
    plt.plot(x_log4, y_log4, '.-')
    plt.show()