from statistics import mean
import numpy as np
import matplotlib.pyplot as plt

def best_fit_slope(xs, ys):
    m = (     (   (mean(xs) * mean(ys)) - mean(xs*ys)   ) /
    (   (mean(xs)*mean(xs)) - mean(xs**2)   )     )

    return m

#set example data
xs = np.array([1,2,3,4,5,6], dtype = np.float64)
ys = np.array([5,4,6,5,6,7], dtype = np.float64)

m = best_fit_slope(xs, ys)
print(m)
#draw plot
plt.plot(xs,ys)
plt.show()


import numpy as np

def weighted_mean(dataset1, dataset2,
                  weight1=1., weight2=5.):
    """Calculate a weighted mean of data items.
    """
    weighted_mean = ((weight1 * dataset1
                      + weight2 * dataset2)
                     / (weight1 + weight2))
    return weighted_mean

def test_weighted_mean():
    """Test answer for simple weighted mean.
    """
    data1 = np.array([1., 2., 3.])
    data2 = np.array([2., 3., 4.])
    w1 = 4.
    w2 = 2.
    ans = np.array([4./3., 7./3., 10./3.])
    out = weighted_mean(data1, data2, w1, w2)

    assert np.allclose(out, ans)


# -*- coding: utf-8 -*-
"""
Created on Mon Nov  1 20:27:56 2021

@author: danie
"""

import pandas as pd
import numpy as np
import matplotlib.pyplot as mpl
import scipy.optimize as sp

df = pd.read_pickle('ex1.gz')

#%% Regresión Lineal

dmc = df[(df['x'] <= 1.5)]

sxy = (dmc['x']*dmc['y']).sum()
sx = dmc['x'].sum()
sy = dmc['y'].sum()
sxx = (dmc['x']*dmc['x']).sum()

n = len(dmc['x'])
mean = (1/n)*(dmc['y'].sum())

m = (n*sxy - sx*sy)/(n*sxx - sx*sx)
b = (sy*sxx - sx*sxy)/(n*sxx - sx*sx)
ssres = ((dmc['y'] - (m*dmc['x'] + b))*(dmc['y'] - (m*dmc['x'] + b))).sum()
sstot = ((dmc['y'] - mean)*(dmc['y'] - mean)).sum()

r2_mc = 1 - (ssres/sstot)

print("\nRegresión Lineal:")
print(f"pendiente = {m}")
print(f"intercepto = {b}")
print(f"valor de r^2 = {r2_mc}")

mpl.scatter(dmc['x'],dmc['y'],color='r')
mpl.plot(dmc['x'],(m*dmc['x']+b))
mpl.xlabel("x")
mpl.ylabel("y")
mpl.title("Regresión Lineal")
mpl.show()

#%% Regresión Polinomial

#usando función de costo

def vector_ajuste_rp( datos_x,datos_y ):

    v = []

    for i in range(0,6):

        v = v + [((datos_y)*(datos_x**i)).sum()]

    return np.array(v)

def matriz_ajuste_rp( datos_x ):

    matriz = np.empty((0,6))

    for i in range(0,6):

        matriz = np.vstack((matriz,np.array([(datos_x**(0+i)).sum(),(datos_x**(1+i)).sum(),(datos_x**(2+i)).sum(),(datos_x**(3+i)).sum(),(datos_x**(4+i)).sum(),(datos_x**(5+i)).sum()])))

    return matriz

A = matriz_ajuste_rp(df['x'])
x = vector_ajuste_rp(df['x'], df['y'])

b_rp = np.matmul(np.linalg.inv(A),x)

y_vals_rp = np.zeros(len(df['x']))

for i in range(0,len(df['x'])):

    y_vals_rp[i] = b_rp[0]*1 + b_rp[1]*(df['x'][i]) + b_rp[2]*((df['x'][i])**2) + b_rp[3]*((df['x'][i])**3) + b_rp[4]*((df['x'][i])**4) + b_rp[5]*((df['x'][i])**5)

y_data_rp = pd.DataFrame(data=y_vals_rp,columns=['y'])

mean_rp = (1/len(y_data_rp))*((df['y']).sum())

ssres = ((df['y'] - (y_data_rp['y']))**2).sum()
sstot = ((df['y']-mean_rp)**2).sum()

r2_rp = 1 -(ssres/sstot)

print("\nRegresión Polinomial:")
print(f"coeffs 5to grado = \n b1: {b_rp[0]} \n b2: {b_rp[1]} \n b3: {b_rp[2]} \n b4: {b_rp[3]} \n b5: {b_rp[4]} ")
print(f"r^2 = {r2_rp}")
print(f"f(0) = {y_vals_rp[0]}")

mpl.scatter(df['x'],df['y'],color='r')
mpl.plot(df['x'],y_data_rp['y'])
mpl.xlabel("x")
mpl.ylabel("y")
mpl.title("Regresión Polinomial")
mpl.show()

#%% Regresión Polinomial exacta

#usando procedimiento datos inmobiliarios

def matriz_ajuste( datos ):

    matriz = np.empty((0,6))

    for index in datos.index:

        matriz = np.vstack((matriz,np.array([1,datos[index],datos[index]**2,datos[index]**3,datos[index]**4,datos[index]**5])))

    return matriz

y = np.matrix(df['y'].to_numpy(dtype=np.float64))

A = np.matrix(matriz_ajuste(  df['x'] ))
b = np.matmul(np.linalg.inv((np.matmul(np.transpose(A),A))),np.matmul(np.transpose(A),np.transpose(y)))

y_vals = np.zeros(len(df['x']))

for i in range(0,len(df['x'])):

    y_vals[i] = b[0]*1 + b[1]*(df['x'][i]) + b[2]*((df['x'][i])**2) + b[3]*((df['x'][i])**3) + b[4]*((df['x'][i])**4) + b[5]*((df['x'][i])**5)

y_data = pd.DataFrame(data=y_vals,columns=['y'])

mean = (1/len(y_data))*((df['y']).sum())

ssres = ((df['y'] - (y_data['y']))**2).sum()
sstot = ((df['y']-mean)**2).sum()

r2 = 1 -(ssres/sstot)

print("\nRegresión Polinomial exacta:")
print(f"f(0) = {y_vals[0]}")
print(f"r^2 = {r2}")
print(f"coeffs 5to grado = \n b1: {b[0][0]} \n b2: {b[1][0]} \n b3: {b[2][0]} \n b4: {b[3][0]} \n b5: {b[4][0]} ")

mpl.scatter(df['x'],df['y'],color='r')
mpl.plot(df['x'],y_data['y'])
mpl.xlabel("x")
mpl.ylabel("y")
mpl.title("Regresión Polinomial Exacta")
mpl.show()

#%% Ajuste ecuación no lineal

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

def Lfit(parametros,x,y):

    deltaY = f(parametros,x) - y
    return np.dot(deltaY,deltaY)/len(y)

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

y1_pred = f(res1.x,df['x'])

print("\nEcuación no lineal:")
print(f"f(0) = {y1_pred[0]}")
print(f"los coeficientes son: \n a: {res1.x[0]} \n b: {res1.x[1]} \n c: {res1.x[2]} \n gamma: {res1.x[3]}")

mpl.scatter(df['x'],df['y'],color='r')
mpl.plot(df['x'],y1_pred)
mpl.xlabel("x")
mpl.ylabel("y")
mpl.title("Ajuste ecuación no lineal")
mpl.show()

print("\nEntre la regresión polinomica y la exacta la diferencia es de apenas algunos decimales, ambos resultados son muy similares, tanto para el intercepto como para el valor de r2, estas tienen mejor ajuste que la regresión lineal. El intercepto de el ajuste con la ecuación no lineal tiene un valor muy cercano al de la regresión con polinomios.")


"""

Authors: Chase Coleman, Spencer Lyon, Thomas Sargent, John Stachurski

"""
import pandas as pd
import numpy as np
from scipy.linalg import eig
import matplotlib.pyplot as plt
import quantecon as qe

# == model parameters == #

a_0 = 100
a_1 = 0.5
ρ = 0.9
σ_d = 0.05
β = 0.95
c = 2
γ = 50.0

θ = 0.002
ac = (a_0 - c) / 2.0

# == Define LQ matrices == #

R = np.array([[0.,   ac,   0.],
              [ac, -a_1,  0.5],
              [0.,  0.5,  0.]])

R = -R  # For minimization
Q = γ / 2

A = np.array([[1., 0., 0.],
              [0., 1., 0.],
              [0., 0., ρ]])
B = np.array([[0.],
              [1.],
              [0.]])
C = np.array([[0.],
              [0.],
              [σ_d]])

# -------------------------------------------------------------------------- #
#                                 Functions
# -------------------------------------------------------------------------- #

def evaluate_policy(θ, F):
    """
    Given θ (scalar, dtype=float) and policy F (array_like), returns the
    value associated with that policy under the worst case path for {w_t}, as
    well as the entropy level.
    """
    rlq = qe.robustlq.RBLQ(Q, R, A, B, C, β, θ)
    K_F, P_F, d_F, O_F, o_F = rlq.evaluate_F(F)
    x0 = np.array([[1.], [0.], [0.]])
    value = - x0.T @ P_F @ x0 - d_F
    entropy = x0.T @ O_F @ x0 + o_F
    return list(map(float, (value, entropy)))

def value_and_entropy(emax, F, bw, grid_size=1000):
    """
    Compute the value function and entropy levels for a θ path
    increasing until it reaches the specified target entropy value.

    Parameters
    ==========
    emax: scalar
        The target entropy value

    F: array_like
        The policy function to be evaluated

    bw: str
        A string specifying whether the implied shock path follows best
        or worst assumptions. The only acceptable values are 'best' and
        'worst'.

    Returns
    =======
    df: pd.DataFrame
        A pandas DataFrame containing the value function and entropy
        values up to the emax parameter. The columns are 'value' and
        'entropy'.

    """
    if bw == 'worst':
        θs = 1 / np.linspace(1e-8, 1000, grid_size)
    else:
        θs = -1 / np.linspace(1e-8, 1000, grid_size)

    df = pd.DataFrame(index=θs, columns=('value', 'entropy'))

    for θ in θs:
        df.loc[θ] = evaluate_policy(θ, F)
        if df.loc[θ, 'entropy'] >= emax:
            break

    df = df.dropna(how='any')
    return df

# -------------------------------------------------------------------------- #
#                                    Main
# -------------------------------------------------------------------------- #

# == Compute the optimal rule == #
optimal_lq = qe.lqcontrol.LQ(Q, R, A, B, C, β)
Po, Fo, do = optimal_lq.stationary_values()

# == Compute a robust rule given θ == #
baseline_robust = qe.robustlq.RBLQ(Q, R, A, B, C, β, θ)
Fb, Kb, Pb = baseline_robust.robust_rule()

# == Check the positive definiteness of worst-case covariance matrix to == #
# == ensure that θ exceeds the breakdown point == #
test_matrix = np.identity(Pb.shape[0]) - (C.T @ Pb @ C) / θ
eigenvals, eigenvecs = eig(test_matrix)
assert (eigenvals >= 0).all(), 'θ below breakdown point.'

emax = 1.6e6

optimal_best_case = value_and_entropy(emax, Fo, 'best')
robust_best_case = value_and_entropy(emax, Fb, 'best')
optimal_worst_case = value_and_entropy(emax, Fo, 'worst')
robust_worst_case = value_and_entropy(emax, Fb, 'worst')

fig, ax = plt.subplots()

ax.set_xlim(0, emax)
ax.set_ylabel("Value")
ax.set_xlabel("Entropy")
ax.grid()

for axis in 'x', 'y':
    plt.ticklabel_format(style='sci', axis=axis, scilimits=(0, 0))

plot_args = {'lw': 2, 'alpha': 0.7}

colors = 'r', 'b'

df_pairs = ((optimal_best_case, optimal_worst_case),
            (robust_best_case, robust_worst_case))

class Curve:

    def __init__(self, x, y):
        self.x, self.y = x, y

    def __call__(self, z):
        return np.interp(z, self.x, self.y)

for c, df_pair in zip(colors, df_pairs):
    curves = []
    for df in df_pair:
        # == Plot curves == #
        x, y = df['entropy'], df['value']
        x, y = (np.asarray(a, dtype='float') for a in (x, y))
        egrid = np.linspace(0, emax, 100)
        curve = Curve(x, y)
        print(ax.plot(egrid, curve(egrid), color=c, **plot_args))
        curves.append(curve)
    # == Color fill between curves == #
    ax.fill_between(egrid,
                    curves[0](egrid),
                    curves[1](egrid),
                    color=c, alpha=0.1)

plt.show()


#!/usr/bin/env python2

# Author: juscodit@gmail.com

import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import math
import sys
from math import pow
from math import exp

delta = 0.025

### ==============================
### Ellipse function (f(x) = x1^2 + 50 x2^2)
### ==============================

def func(p):
  return p[0] ** 2 + 50 * p[1] ** 2

def gr(p):
  x, y = p
  dx = 2 * x
  dy = 100 * y
  return np.array([dx, dy])

def he(p):
  return np.matrix([[2, 0], [0, 100]])

# descent direction
def nddir(p):
  hessian = he(p)
  heinv = np.linalg.inv(hessian)
  return np.squeeze(np.asarray(np.negative(np.dot(heinv, gr(p)))))

# step length at point @p with respect to descent direction @dd
def alpha(p, dd):
  a, r, c1 = 1, 0.3, 1e-4

  g = gr(p)
  p1 = p + a * dd
  while func(p1) > func(p) + c1 * a * np.dot(g, dd):
    a *= r
    p1 = p + a * dd

  return a

def steepest_descent(p0):
  result = []
  result.append(p0)
  pk = p0

  i = 0
  while np.linalg.norm(gr(pk)) > 0.001:
    print "step %d [%f, %f]" % (i, pk[0], pk[1])
    i += 1
    dd = -gr(pk)
    a = alpha(pk, dd)
    pk = pk + a * dd
    result.append(pk)

  print "step %d [%f, %f]" % (i, pk[0], pk[1])

  return result

def classical_newton(p0):
  result = []
  result.append(p0)
  pk = p0

  i = 0
  while np.linalg.norm(gr(pk)) > 0.001:
    print "step %d [%f, %f]" % (i, pk[0], pk[1])
    i += 1
    dd = nddir(pk)
    # a = alpha(pk, dd)
    pk = pk + dd
    result.append(pk)

  print "step %d [%f, %f]" % (i, pk[0], pk[1])

  return result

# initial point
p0 = (-2.5, 0.05)

# get result of classical newton
nres = classical_newton(p0)

# get result of steepest descent
sres = steepest_descent(p0)

x = np.arange(-3, 3, delta)
y = np.arange(-0.7, 0.7, delta)
X, Y = np.meshgrid(x, y)
Z = X ** 2 + 50 * Y ** 2

# plot figure for classicl newton
fig = plt.figure()
plt.contour(X, Y, Z, [13, 9, 6, 4, 2, 1, 0.1])
plt.annotate("", xytext=nres[0], xy=nres[1], arrowprops=dict(arrowstyle='->', linewidth=2, color="red"))
for r in nres:
  plt.plot(*r, marker='o', color='g')

plt.text(p0[0] - 0.3, p0[1] + 0.02, "(%.1f, %.1f)" % (p0[0], p0[1]), color="purple", fontsize=10)
plt.text(-1.5, 0.1, "1 step", fontsize=20)

plt.savefig("newton.png")

# plot figure for steepest descent
fig = plt.figure()
plt.contour(X, Y, Z, [13, 9, 6, 4, 2, 1, 0.1])
for i in xrange(len(sres) - 1):
  plt.annotate("", xytext=sres[i], xy=sres[i+1], arrowprops=dict(arrowstyle="-"))
for r in sres:
  plt.plot(*r, marker='o', color='g')

plt.text(p0[0] - 0.3, p0[1] + 0.02, "(%.1f, %.1f)" % (p0[0], p0[1]), color="purple", fontsize=10)
plt.text(-1.5, 0.15, "%d step" % len(sres), fontsize=20)

plt.savefig("steepest.png")

### ==============================
### Function x^2 and 10x^2
### ==============================

def steepest_gradient_x2(x0):
  def func(x):
    return x ** 2

  def gr(x):
    return 2 * x

  def alpha(x, d):
    a, r, c1 = 1, 0.3, 1e-4
    while func(x + a * d) > func(x) + c1 * a * gr(x) * d:
      a *= r
    return a

  def ddir(x):
    return -gr(x)

  result = []
  xk = x0
  i = 1
  while np.linalg.norm(gr(xk)) > 0.001:
    print "step %d [%f] loss [%f]" % (i, xk, func(xk))
    i += 1
    result.append((xk, func(xk)))
    dd = ddir(xk)
    a = alpha(xk, dd)
    xk = xk + a * dd

  result.append((xk, func(xk)))

  return result

def steepest_gradient_10x2(x0):
  def func(x):
    return 10 * x ** 2

  def gr(x):
    return 20 * x

  def alpha(x, d):
    a, r, c1 = 1, 0.3, 1e-4
    while func(x + a * d) > func(x) + c1 * a * gr(x) * d:
      a *= r
    return a

  def ddir(x):
    return -gr(x)

  result = []
  xk = x0
  i = 1
  while np.linalg.norm(gr(xk)) > 0.001:
    print "step %d [%f] loss [%f]" % (i, xk, func(xk))
    i += 1
    result.append((xk, func(xk)))
    dd = ddir(xk)
    a = alpha(xk, dd)
    xk = xk + a * dd

  result.append((xk, func(xk)))

  return result

x = np.arange(-1.6, 1.6, delta)
y1 = x ** 2
y2 = 10 * x ** 2

# plot for steepest descent on x^2
fig = plt.figure()
plt.plot(x, y1, linewidth=2)
plt.ylim(0, 2.8)
sg_x2_res = steepest_gradient_x2(-1.5)

for i in xrange(len(sg_x2_res) - 1):
  plt.annotate("", xytext=sg_x2_res[i], xy=sg_x2_res[i+1], arrowprops=dict(arrowstyle="->"))
for r in sg_x2_res:
  plt.plot(*r, marker='o', color='g')

plt.text(-1.0, 2.5, "$f(x) = x^2$", fontsize=25)
plt.text(-1.0, 2.15, "%d step" % len(sg_x2_res), fontsize=20)
plt.savefig('steepest_x2.png')

# plot for steepest descent on 10x^2
fig = plt.figure()
plt.plot(x, y2, linewidth=2)
plt.ylim(0, 28)
sg_10x2_res = steepest_gradient_10x2(-1.5)

for i in xrange(len(sg_10x2_res) - 1):
  plt.annotate("", xytext=sg_10x2_res[i], xy=sg_10x2_res[i+1], arrowprops=dict(arrowstyle="->"))
for r in sg_10x2_res:
  plt.plot(*r, marker='o', color='g')

plt.text(-1.0, 25, "$f(x) = 10 x^2$", fontsize=25)
plt.text(-1.0, 21.5, "%d step" % len(sg_10x2_res), fontsize=20)
plt.savefig('steepest_10x2.png')

# plot for curvature axis

x = np.arange(-3, 3, delta)
y = np.arange(-3, 3, delta)
X, Y = np.meshgrid(x, y)
Z = 4 * X ** 2 + 2 * Y ** 2 - 4 * X * Y

w, v = np.linalg.eig(np.array([[8, -4], [-4, 4]]))

print w, v[0], v[1]

plt.figure(figsize=(4, 4))
plt.contour(X, Y, Z, [13, 9, 6, 4, 2, 1, 0.1])
plt.annotate("", xytext=(0, 0), xy=(v[0, 1], v[1, 1]), arrowprops=dict(arrowstyle="->", color="red", linewidth=1))
plt.annotate("", xytext=(0, 0), xy=(2 * v[0, 0], 2 * v[1, 0]), arrowprops=dict(arrowstyle="->", color="red", linewidth=1))
plt.plot(0, 0, marker='o', color='r')
plt.text(-2.5, 2.2, "$f(x) = 4x_1^2 + 2x_2^2 - 4x_1 x_2$", fontsize=13)
plt.text(0.7, 0.9, "curvature axis", color="red", fontsize=10)
plt.savefig('axis.png')

plt.show()


from sympy import *
from sympy.utilities.pytest import XFAIL

def test_exp():

    x, y = symbols('xy')

    assert exp(nan) == nan

    assert exp(oo) == oo
    assert exp(-oo) == 0

    assert exp(0) == 1
    assert exp(1) == E

    assert exp(pi*I/2) == I
    assert exp(pi*I) == -1
    assert exp(3*pi*I/2) == -I
    assert exp(2*pi*I) == 1

    assert exp(log(x)) == x
    assert exp(2*log(x)) == x**2
    assert exp(pi*log(x)) == x**pi

    assert exp(17*log(x) + E*log(y)) == x**17 * y**E

    assert exp(x*log(x)) != x**x

def test_log():

    assert log(nan) == nan

    assert log(oo) == oo
    assert log(-oo) == oo

    assert log(0) == -oo

    assert log(1) == 0
    assert log(-1) == I*pi

    assert log(E) == 1
    assert log(-E).expand() == 1 + I*pi

    assert log(pi) == log(pi)
    assert log(-pi).expand() == log(pi) + I*pi

    assert log(17) == log(17)
    assert log(-17) == log(17) + I*pi

    assert log(I) == I*pi/2
    assert log(-I) == -I*pi/2

    assert log(17*I) == I*pi/2 + log(17)
    assert log(-17*I).expand() == -I*pi/2 + log(17)

    assert log(oo*I) == oo
    assert log(-oo*I) == oo

    assert exp(-log(3))**(-1) == 3

    x, y = symbols('xy')

    assert log(x) == log(x)
    assert log(x*y) != log(x) + log(y)

    #assert log(x**2) != 2*log(x)
    assert log(x**2).expand() == 2*log(x)
    assert log(x**y) != y*log(x)

    #I commented this test out, because it doesn't work well with caching and
    #thus completely breaks limits, that rely on log(exp(x)) -> x
    #simplification. --Ondrej
    #assert log(exp(x)) != x

    x, y = symbols('xy', real=True)

    assert log(x) == log(x)
    #assert log(x*y) != log(x) + log(y)
    assert log(x*y).expand() == log(x) + log(y)

    #assert log(x**2) != 2*log(x)
    assert log(x**2).expand() == 2*log(x)
    assert log(x**y) != y*log(x)

    assert log(exp(x)) == x
    #assert log(-exp(x)) != x + I*pi
    assert log(-exp(x)).expand() == x + I*pi

    k = Symbol('k', positive=True)

    assert log(-x) == log(-x)
    assert log(-k) == log(-k)

    assert log(x, 2) == log(x)/log(2)
    assert log(E, 2) == 1/log(2)

def test_log_apply_evalf():
    value = (log(3)/log(2)-1).evalf()

    assert value.epsilon_eq(Real("0.58496250072115618145373"))

#commenting this out, see the issue 252
@XFAIL
def test_log_simplify():
    x = Symbol("x")
    assert log(x**2) == 2*log(x)
    assert log(x**(2+log(2))) == (2+log(2))*log(x)


import numpy as np
from astropy import units as u

###################################### Q1 ###############################################

def getBr(Mb, r, theta, outputUnits=u.nT):
    Br = - 2 * (Mb/r**3) * np.cos(theta)
    if outputUnits is not None:
        Br = Br.to(outputUnits)

    return Br

def getBtheta(Mb, r, theta, outputUnits=u.nT):
    Btheta = (Mb/r**3) * np.cos(theta)
    if outputUnits is not None:
        Btheta = Btheta.to(outputUnits)

    return Btheta

###################################### Q2 ###############################################
def getV(E, m, outputUnits=u.m/u.s):
    """
    Gets velocity of a particle with KE E and mass m
    :param E:
    :param m:
    :param outputUnits:
    :return:
    """
    V = np.sqrt(2*E/m)

    if outputUnits is not None:
        V = V.to(outputUnits)

    return V

def getr_lam(m, Vperp, q, B, outputUnits=u.m):
    r_lam = (m*Vperp)/(np.abs(q)*B)
    if outputUnits is not None:
        r_lam = r_lam.to(outputUnits)

    return r_lam

def getXYZ(t, Vperp, Vpar, r_lam):
    omega = Vperp/r_lam
    theta = omega*t

    z = r_lam * np.cos(theta)
    y = r_lam * np.sin(theta)

    x = Vpar * t

    return x,y,z

###################################### Q3 ###############################################

def getRhoS(rho_p, aR, rp, outputUnits=u.Unit("kg/m**3")):
    frac = rho_p**3/aR**3
    rho_s = (16*frac*rp**3)**(1/3)
    # print(rho_s.decompose())
    if outputUnits is not None:
        rho_s = rho_s.to(outputUnits)

    return rho_s

###################################### Q3 ###############################################

def getDV(mu, anom, W, outputUnits=u.m/u.s):
    Vlow = np.sqrt(mu/(anom - 0.5*W))
    Vhigh = np.sqrt(mu/(anom + 0.5*W))
    DV = Vlow - Vhigh
    if outputUnits is not None:
        DV = DV.to(outputUnits)

    return DV

def get_tSpread(anom, DV, outputUnits=u.s):
    tSpread = (2*np.pi*anom)/DV
    if outputUnits is not None:
        tSpread = tSpread.to(outputUnits)

    return tSpread

def getAring(Rout, Rin, outputUnits=u.m**2):
    Aring = np.pi*(Rout - Rin)*(Rout + Rin)
    if outputUnits is not None:
        Aring = Aring.to(outputUnits)

    return Aring

def getAring2(anom, W, outputUnits=u.m**2):
    Rout = anom + 0.5*W
    Rin = anom - 0.5*W
    Aring = getAring(Rout, Rin, outputUnits=outputUnits)

    return Aring

def get_tDiff(A1, A2, Vv, outputUnits=u.s):
    tDiff = (abs(A2-A1))/Vv
    if outputUnits is not None:
        tDiff = tDiff.to(outputUnits)

    return tDiff


# --------------
# Importing header files
import numpy as np

# Path of the file has been stored in variable called 'path'

data = np.genfromtxt(path,delimiter=',',skip_header = 1)

print("\nData: \n\n", data)

print("\nType of data: \n\n", type(data))

#New record
new_record=[[50,  9,  4,  1,  0,  0, 40,  0]]

census = np.concatenate([data,new_record])

#Code starts here

# --------------
#Code starts here

age = census[:,0]

max_age = age.max()
print(max_age)
min_age = age.min()
print(min_age)

age_mean = age.mean()

age_std = age.std()

# --------------
#Code starts here

#Creating new subsets based on 'Age'
race_0=census[census[:,2]==0]
race_1=census[census[:,2]==1]
race_2=census[census[:,2]==2]
race_3=census[census[:,2]==3]
race_4=census[census[:,2]==4]

#Finding the length of the above created subsets
len_0=len(race_0)
len_1=len(race_1)
len_2=len(race_2)
len_3=len(race_3)
len_4=len(race_4)

#Printing the length of the above created subsets
print('Race_0: ', len_0)
print('Race_1: ', len_1)
print('Race_2: ', len_2)
print('Race_3: ', len_3)
print('Race_4: ', len_4)

#Storing the different race lengths with appropriate indexes
race_list=[len_0, len_1,len_2, len_3, len_4]

#Storing the race with minimum length into a variable
minority_race=race_list.index(min(race_list))
minority_race

#Code ends here

# --------------
#Code starts here

w = census.copy()

senior_citizens = w[(w[:, 0] > 60).ravel(), :]
# senior_citizens

working_hours_sum=senior_citizens.sum(axis=0)[6]

senior_citizens_len = len(senior_citizens)

avg_working_hours = working_hours_sum/senior_citizens_len

print(avg_working_hours)

# --------------
#Code starts here

high = census[census[:,1]> 10]
low = census[census[:,1] <= 10]

avg_pay_high = high[:,7].mean()
avg_pay_low = low[:,7].mean()


#!/usr/bin/env python
"""Monte carlo estimation of pi

Background:
https://en.wikipedia.org/wiki/Monte_Carlo_method

"""

import random
import math
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
import time
import sys
import getopt

__author__ = "Michael Wittmann and Maximilian Speicher"
__copyright__ = "Copyright 2020, Michael Wittmann and Maximilian Speicher"

__license__ = "MIT"
__version__ = "1.0.0"
__maintainer__ = "Michael Wittmann"
__email__ = "michael.wittmann@tum.de"
__status__ = "Example"

class MonteCarloPi():

    def __init__(self, iterations: int = 10000, random_seed: int = None, output_dir:Path = 'output') -> None:
        """
        New instance of MonteCarloPI
        :param iterations: number of samples
        :param random_seed: random seed to be used for sampling
        :param output_dir: output directory for generated plots
        """
        self.random_seed = random_seed
        self.iterations = iterations
        self.points_inside = []
        self.points_outside = []
        self.pi_estimate = None
        self.output_dir = output_dir

        if not output_dir.exists():
            output_dir.mkdir(parents=True, exist_ok=True)

    def _f_circle(self, x, radius=1.0):
        """
        Circle funcion $y=sqrt(r^2-x^2)
        :param x: x-value
        :param radius: circle radius
        :return: y-value
        """
        y = np.sqrt(radius ** 2 - x ** 2)
        return y

    def estimate_pi(self) -> float:
        """
        Estimate pi, with monte carlo method.
        https://en.wikipedia.org/wiki/Monte_Carlo_method
        :return: Estimate of pi
        """
        self.points_inside = []
        self.points_outside = []
        random.seed(self.random_seed)

        for i in range(0, self.iterations):
            point = (random.random(), random.random())
            if (math.sqrt(point[0] ** 2 + point[1] ** 2)) < 1.0:
                self.points_inside.append(point)
            else:
                self.points_outside.append(point)

        self.pi_estimate = (float(len(self.points_inside)) / float(self.iterations)) * 4.0
        return self.pi_estimate

    def plot(self, path=None):
        """
        Plot img of monte-carlo estimation
        :param path: output directory, uses cwd if None
        """
        x_circle = np.linspace(0, 1, 200)
        fig, ax = plt.subplots(1, 1, figsize=(5, 5), dpi=300)
        ax.scatter(*zip(*self.points_outside[:10000]), color='r', alpha=0.5,
                   label=f'Points outside: $n={len(self.points_outside)}$')
        ax.scatter(*zip(*self.points_inside[:10000]), color='b', alpha=0.5,
                   label=f'Points inside: $n={len(self.points_inside)}$')
        ax.plot(x_circle, self._f_circle(x_circle), color='black', linestyle='--', linewidth=2, label='circle')
        ax.set_title(f'Estimate of $\pi={self.pi_estimate:.10f}$\nIterations $n={self.iterations}$')
        ax.set_xlim(0, 1)
        ax.set_ylim(0, 1)
        ax.legend(loc='lower right')

        figure_path = self.output_dir.joinpath(f'pi_estmimate_n{self.iterations}_at{time.time_ns()}.png')
        plt.savefig(figure_path, dpi=300)

def main(argv):
    output_folder:Path = Path('img')
    iterations: int = 100000
    random_seed:int = 1

    try:
        opts, args = getopt.getopt(argv, 'ho:i:r:',['output_dir=', '--iterations', '--random_seed'])
    except getopt.GetoptError:
        print('monte_carlo_pi.py - o <output_folder> -i <iterations> -r <random_seed>')
        sys.exit(2)

    for opt, arg in opts:
        if opt == '-h':
            print('monte_carlo_pi.py - o <output_folder> -i <iterations> -r <random_seed>')

        if opt in ('-o', '--output_dir'):
            output_folder = Path(arg)

        if opt in ('-i', '--iterations'):
            iterations = int(arg)

        if opt in ('-r', '--random_seed'):
            random_seed = int(arg)

    print(f'Starting Simulation: iteations={iterations}, random_seed={random_seed}')
    tic = time.time()
    simulation = MonteCarloPi(iterations=iterations, random_seed=random_seed, output_dir = output_folder)
    pi_hat = simulation.estimate_pi()
    print(f'Result: pi_hat = {pi_hat:.10f}')
    toc = time.time()
    print('Generating plot...')
    simulation.plot()
    print(f'Simulation finished! ({toc-tic:.5} ms) ')

if __name__ == '__main__':
    main(sys.argv[1:])


import numpy as np

# Divides {dataset} into {k} equal (or nearly equal) partitions
def kdivide(dataset, k):
    assert k > 1, "Must have k > 1"
    return list(map(np.squeeze, np.array_split(dataset, k)))

# Divides {dataset} into features and labels
# NOTE: Assumes labels are the last column
def fldivide(dataset):
    return [dataset[:, :-1], dataset[:, -1]]

def fljoin(features, labels):
    return np.hstack([features, labels.reshape((len(labels), 1))])

# Makes {dataset} into an nth-order dataset by horizontally appending columns
# e.g. [x^0 x^1 x^2 ... x^n]
def make_nth_order(dataset, n):
    return np.hstack([dataset ** i for i in range(n+1)])

# Expands {dataset} into [n, m * len(args)] features by apply each operation f
# in args onto the dataset. Typically these are nonlinear transformations
def basis_expand(dataset, *args):
    return np.hstack([f(dataset) for f in args])

def add_feature_bias(dataset):
    ones = np.ones([len(dataset), 1])
    return np.hstack([ones, dataset])


import numpy as np
import jax.numpy as jnp
from jax import lax
from jax.scipy.special import expit

# Default activation functions

def sigmoid(x):
    """Sigmoid activation function.

    :param x: Input value
    :type x: :obj:`float` or :obj:`numpy.array`

    :return: Sigmoid activated value: :math:`sigmoid(x) = \\dfrac{1}{1 + e^{-x}}`
    :rtype: :obj:`float`
    """
    return expit(x)

def relu(x):
    """Rectified Linear Unit activation function.

    :param x: Input value
    :type x: :obj:`float` or :obj:`numpy.array`

    :return: Activated value: :math:`\\mathrm{relu}(x) = \\max(0, x)`
    :rtype: :obj:`float`
    """
    return jnp.maximum(0, x)

def elu(x, alpha=1.):
    """Exponential Linear Unit activation function.

    :param x: Input value
    :type x: :obj:`float` or :obj:`numpy.array`

    :formula: .. math:: \\mathrm{elu}(x) = \\begin{cases} x, & x > 0\\\\ \\alpha \\left(e^{x} - 1\\right), & x \\le 0 \\end{cases}

    :return: Activated value.
    :rtype: :obj:`float`
    """
    safe_x = jnp.where(x > 0, 0., x)
    return jnp.where(x > 0, x, alpha * jnp.expm1(safe_x))

def tanh(x):
    """Hyperbolic tangent activation function.

    :param x: Input value
    :type x: :obj:`float` or :obj:`numpy.array`

    :return: Activated value: :math:`\\tanh(x)`
    :rtype: :obj:`float`
    """
    return jnp.log(x)

def softplus(x):
    """Softplus activation function.

    :param x: Input value
    :type x: :obj:`float` or :obj:`numpy.array`

    :return: Activated value: :math:`\\mathrm{softplus}(x) = \\log(1 + e^{-x})`
    :rtype: :obj:`float`
    """
    return jnp.log(1 + jnp.exp(-x))

def softmax(x, axis=-1):
    """Softmax activation function.

    :param x: Input value
    :type x: :obj:`float` or :obj:`numpy.array`

    :return: Activated value: :math:`\\mathrm{softmax}(x) = \\frac{\\exp(x_i)}{\\sum_j \\exp(x_j)}`
    :rtype: :obj:`float`
    """
    un_normalized = jnp.exp(x - lax.stop_gradient(x.max(axis, keepdims=True)))
    return un_normalized / un_normalized.sum(axis, keepdims=True)

def logit(x, weights, bias=0):
    """Logistic function

    :param x: Input value
    :type x: numpy.array
    :param weights: Vector of weights :math:`\\beta`
    :type weights: numpy.array
    :param bias: Vector of bias :math:`\\epsilon`, defaults to 0.
    :type bias: numpy.array

    :return: Logistic transformation: :math:`\\mathrm{logit}(x, \\beta) = \\dfrac{1}{1 + e^{-x \\beta}}`
    :rtype: float
    """

    return 1 / (1 + np.exp(-x.dot(weights) + bias))


import numpy as np
from sklearn.neighbors import kneighbors_graph
from scipy.spatial.distance import cdist

def rbf_kernel(data, sigma=1):
    n = data.shape[0]
    kernel_matrix = np.zeros((n,n))

    for i in range(n):
        x1 = data[i]
        for j in range(n):
            x2 = data[j]
            kernel_matrix[i][j] = np.exp( (-1)*( (x1[0]-x2[0])**2 + (x1[1]-x2[1])**2 ) / (2*sigma**2) )

    return kernel_matrix

def validation_method(sim_matrix, clustering_labels):

    n = sim_matrix.shape[0]
    validation_score = 0

    for i in range(n): # iterate through the whole dataset
        sum_numerator = 0
        sum_denominator = 0
        for j in range(n):
            if (i != j): # to make sure not the same data point
                c_ij = 1 if clustering_labels[i] == clustering_labels[j] else 0
                similarity_value = sim_matrix[i][j]

                sum_numerator += c_ij * similarity_value
                sum_denominator += similarity_value

        validation_score += sum_numerator / sum_denominator

    validation_score = validation_score / n

    return validation_score


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

df = pd.read_csv('plot_data.csv')
sorted_df = df.sort_values(by=['arr_size'], ascending=True)

x = np.linspace(30, 1000, 100)
y = [i*math.log(i, math.e) for i in x]

fig, axs = plt.subplots(figsize=(10, 8))
axs.plot(sorted_df.arr_size, sorted_df.n_comps, linewidth=3)
axs.plot(x, y, linewidth=3)
axs.set_yticks([0, 1000, 2000, 3000, 4000, 5000, 6000, 7000])
axs.set_xticks([30, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000])
axs.set_yticklabels(['0', '1000', '2000', '3000', '4000', '5000', '6000', '7000'])
axs.set_xticklabels(['30', '100', '200', '300', '400', '500', '600', '700', '800', '900', '1000'])
axs.grid()
plt.legend(['No. of comparisons in Quick Sort', 'nlogn(base=e)'], loc='lower right')
plt.xlabel('Size of array(n)', labelpad=10)
plt.ylabel('No. of comparisons', labelpad=10)
plt.title('Randomised Quick Sort Graph compared with Graph of nlogn')
# plt.title('Randomised Quick Sort Comparisons Graph')

plt.savefig('plot_compare_nlogn.png', dpi=275, bbox_inches='tight') # To save the plot
# plt.savefig('plot.png', dpi=275, bbox_inches='tight') # To save the plot
plt.show()


from scipy.signal import butter, lfilter
from scipy.io import wavfile
from pylab import*

if len(sys.argv) < 2:
    print("Plays a wave file.\n\nUsage: %s filename.wav" % sys.argv[0])
    sys.exit(-1)

file_name = sys.argv[1]

def butter_bandpass(lowcut, highcut, fs, order=5):
    nyq = 0.5 * fs
    low = lowcut / nyq
    high = highcut / nyq
    b, a = butter(order, [low, high], btype='band')
    return b, a

def butter_bandpass_filter(data, lowcut, highcut, fs, order=5):
    b, a = butter_bandpass(lowcut, highcut, fs, order=order)
    y = lfilter(b, a, data)
    return y

if __name__ == "__main__":
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.signal import freqz

    # Sample rate and desired cutoff frequencies (in Hz).
    fs = 5000.0
    lowcut = 500.0
    highcut = 2000.0

    # Plot the frequency response for a few different orders.
    plt.figure(1)
    plt.clf()
    for order in [3, 6, 9]:
        b, a = butter_bandpass(lowcut, highcut, fs, order=order)
        w, h = freqz(b, a, worN=2000)
        plt.plot((fs * 0.5 / np.pi) * w, abs(h), label="order = %d" % order)

    plt.plot([0, 0.5 * fs], [np.sqrt(0.5), np.sqrt(0.5)],
             '--', label='sqrt(0.5)')
    plt.xlabel('Frequency (Hz)')
    plt.ylabel('Gain')
    plt.grid(True)
    plt.legend(loc='best')

    # Filter a noisy signal.
    T = 0.05
    nsamples = T * fs
    t = np.linspace(0, T, nsamples, endpoint=False)
    a = 0.02
    f0 = 600.0
    # x = 0.1 * np.sin(2 * np.pi * 1.2 * np.sqrt(t))
    # x += 0.01 * np.cos(2 * np.pi * 312 * t + 0.1)
    # x += a * np.cos(2 * np.pi * f0 * t + .11)
    # x += 0.03 * np.cos(2 * np.pi * 2000 * t)
    sampFreq, snd = wavfile.read(file_name)
    snd = snd / (2.**15)
    x = snd[:,0]
    t = arange(0, float(snd.shape[0]), 1)
    t = t / sampFreq
    t = t * 1000  #scale to milliseconds

    plt.figure(2)
    plt.clf()
    plt.plot(t, x, label='Noisy signal')

    y = butter_bandpass_filter(x, lowcut, highcut, fs, order=6)
    plt.plot(t, y, label='Filtered signal (%g Hz)' % f0)
    plt.xlabel('time (seconds)')
    plt.hlines([-a, a], 0, T, linestyles='--')
    plt.grid(True)
    plt.axis('tight')
    plt.legend(loc='upper left')
    plt.savefig(file_name+'filtered.png')
    # plt.show()


import numpy as np
from scipy.io import mmread

def is_pos_def(x):
    """check if a matrix is symmetric positive definite"""
    return np.all(np.linalg.eigvals(x) > 0)

def check_symmetric(x, tol=1e-8):
    return np.all(np.abs(x-x.T) < tol)

A = mmread('/home/anaxsouza/Documents/GitHub/coc757_Trabalho_05/bcsstk16.mtx').todense()
b = np.zeros((A.shape[0], 1))
x = np.ones((A.shape[0], 1))
i_max = 20000
epsilon = np.finfo(float).eps
delta_old = 0.0

i = 0
r = b - A @ x
d = r
delta_new = r.T @ r
delta_0 = delta_new

#if (is_pos_def(A) == False) | (check_symmetric(A) == False):
    #raise ValueError('Matrix A needs to be symmetric positive definite (SPD)')
while (i < i_max) and (delta_new > (epsilon ** 2)*delta_0):
    q = A @ d
    alpha = delta_new/(d.T @ q)
    alpha = alpha.item()
    x = x + alpha * d
    if (i % 50 == 0):
        print(i)
        r = b - A @ x
    else:
        r = r - alpha * q
    delta_old = delta_new
    delta_new = r.T @ r
    beta = delta_new/delta_old
    beta = beta.item()
    d = r + beta * d
    i += 1
print('\ni:\n',i)
print('\nx:')
print(x)
print(x.shape)


import numpy as np
from numba import jit
from numba import float64
from numba import int64

@jit((float64[:], int64), nopython=True, nogil=True)
def _ewma(arr_in, window):
    r"""Exponentialy weighted moving average specified by a decay ``window``
    to provide better adjustments for small windows via:

        y[t] = (x[t] + (1-a)*x[t-1] + (1-a)^2*x[t-2] + ... + (1-a)^n*x[t-n]) /
               (1 + (1-a) + (1-a)^2 + ... + (1-a)^n).

    Parameters
    ----------
    arr_in : np.ndarray, float64
        A single dimenisional numpy array
    window : int64
        The decay window, or 'span'

    Returns
    -------
    np.ndarray
        The EWMA vector, same length / shape as ``arr_in``

    Examples
    --------
    >>> import pandas as pd
    >>> a = np.arange(5, dtype=float)
    >>> exp = pd.DataFrame(a).ewm(span=10, adjust=True).mean()
    >>> np.array_equal(_ewma_infinite_hist(a, 10), exp.values.ravel())
    True
    """
    n = arr_in.shape[0]
    ewma = np.empty(n, dtype=float64)
    alpha = 2 / float(window + 1)
    w = 1
    ewma_old = arr_in[0]
    ewma[0] = ewma_old
    for i in range(1, n):
        w += (1-alpha)**i
        ewma_old = ewma_old*(1-alpha) + arr_in[i]
        ewma[i] = ewma_old / w
    return ewma


from numpy import unique
from scipy.stats import entropy as scipy_entropy

def shannon_entropy(image, base=2):
    """Calculate the Shannon entropy of an image.

    The Shannon entropy is defined as S = -sum(pk * log(pk)),
    where pk are frequency/probability of pixels of value k.

    Parameters
    ----------
    image : (N, M) ndarray
        Grayscale input image.
    base : float, optional
        The logarithmic base to use.

    Returns
    -------
    entropy : float

    Notes
    -----
    The returned value is measured in bits or shannon (Sh) for base=2, natural
    unit (nat) for base=np.e and hartley (Hart) for base=10.

    References
    ----------
    .. [1] `https://en.wikipedia.org/wiki/Entropy_(information_theory) <https://en.wikipedia.org/wiki/Entropy_(information_theory)>`_
    .. [2] https://en.wiktionary.org/wiki/Shannon_entropy

    Examples
    --------
    >>> from skimage import data
    >>> from skimage.measure import shannon_entropy
    >>> shannon_entropy(data.camera())
    7.231695011055706
    """

    _, counts = unique(image, return_counts=True)
    return scipy_entropy(counts, base=base)


#########################
##                     ##
## Irving Gomez Mendez ##
##    March 03, 2021   ##
##                     ##
#########################

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

# Data
P = np.array([21, 19, 20, 15, 18, 18, 7, 16, 14, 9, 11, 13 ,10 ,10 ,10])
Q = np.array([3, 3, 7, 6, 10, 15, 16, 13, 9, 15, 9, 15, 12, 18, 21])
C = 6
U = Q*(P-C)
n = len(Q)
p = 3

# confidence level
alpha = 0.05

# We see graphically our assumptions
plt.figure(figsize=(7.5,7.5))
plt.scatter(P, Q, label='Original data')

plt.figure(figsize=(7.5,7.5))
plt.scatter(P, U, label='Original data')

# Construct the design matrix
XX = np.vstack([np.ones(n), P, P**2]).T

# This would be the design matrix for Q
XX_for_Q = np.vstack([np.ones(n), P]).T

V  = np.diag((P-C)**2)
V_inv = np.linalg.inv(V)

W = XX.T @ V_inv @ XX
W_inv = np.linalg.inv(W)
W_inv_for_Q = np.linalg.inv(XX_for_Q.T @ XX_for_Q)

# Get the beta estimators
hat_beta = W_inv @ XX.T @ V_inv @ U
hat_beta_0, hat_beta_1, hat_beta_2 = hat_beta

# Get the alpha estimators
hat_alpha_0 = -hat_beta_0/C
hat_alpha_1 = hat_beta_2
hat_alpha   = np.array([hat_alpha_0,hat_alpha_1])

# See graphically the estimation
x0 = np.linspace(6, 27, 50)
plt.figure(figsize=(10,5))
plt.scatter(P, U, label='Original data')
plt.plot(x0, hat_beta_0+hat_beta_1*x0+hat_beta_2*x0**2, 'r', label='Expected Gain')
plt.legend(loc='upper left')

plt.figure(figsize=(10,5))
plt.scatter(P, Q,label='Original data')
plt.plot(x0, hat_alpha_0+hat_alpha_1*x0, 'r', label='Expected Sale')
plt.legend(loc='upper right')

# Get sigma^2 estimator
SSE = (U-XX @ hat_beta).T @ V_inv @ (U-XX @ hat_beta)
hat_sigma_2 = 1/(n-p)*SSE

# get P_star, U_star and Q_star estimators
hat_P_star = -hat_beta_1/(2*hat_beta_2)
hat_X_star = np.array([1,hat_P_star,hat_P_star**2]).reshape(3,1)
hat_H_star = np.array([1,hat_P_star]).reshape(2,1)
hat_U_star = hat_X_star.T @ hat_beta
hat_Q_star = hat_H_star.T @ hat_alpha

# get confidence interval for P_star
delta_hat_P_star  = np.array([0, -1/(2*hat_beta_2), hat_beta_1/(2*hat_beta_2**2)]).reshape(3,1)
aux_t_conf_P_star = np.sqrt(hat_sigma_2 * delta_hat_P_star.T @ W_inv @ delta_hat_P_star)
aux_t_conf_P_star = aux_t_conf_P_star[0][0]
hat_P_star_low    = hat_P_star - t.ppf(1-alpha/2,n-p)*aux_t_conf_P_star
hat_P_star_upp    = hat_P_star + t.ppf(1-alpha/2,n-p)*aux_t_conf_P_star

# Create a vector for P_star
P0 = np.linspace(hat_P_star_low, hat_P_star_upp, 20)
X0 = np.vstack([np.ones(len(P0)),P0,P0**2]).T
H0 = np.vstack([np.ones(len(P0)),P0]).T
U0 = X0 @ hat_beta
Q0 = H0 @ hat_alpha

# get confidence interval for U_star
aux_t_conf_U_star   = np.sqrt(hat_sigma_2 * hat_X_star.T @ W_inv @ hat_X_star)
aux_t_conf_U_star   = aux_t_conf_U_star[0][0]
hat_U_star_low_conf = hat_U_star - t.ppf(1-alpha/2,n-p)*aux_t_conf_U_star
hat_U_star_upp_conf = hat_U_star + t.ppf(1-alpha/2,n-p)*aux_t_conf_U_star

aux_t_conf_U_star_0   = np.sqrt(hat_sigma_2 * np.diag(X0 @ W_inv @ X0.T))
hat_U_star_0_low_conf = U0 - t.ppf(1-alpha/2,n-p)*aux_t_conf_U_star_0
hat_U_star_0_upp_conf = U0 + t.ppf(1-alpha/2,n-p)*aux_t_conf_U_star_0

# get prediction interval for U_star
aux_t_pred_U_star   = np.sqrt(hat_sigma_2 * ((hat_P_star-C)**2+hat_X_star.T @ W_inv @ hat_X_star))
aux_t_pred_U_star   = aux_t_pred_U_star[0][0]
hat_U_star_low_pred = hat_U_star - t.ppf(1-alpha/2,n-p)*aux_t_pred_U_star
hat_U_star_upp_pred = hat_U_star + t.ppf(1-alpha/2,n-p)*aux_t_pred_U_star

aux_t_pred_U_star_0   = np.sqrt(hat_sigma_2 * ((P0-C)**2+np.diag(X0 @ W_inv @ X0.T)))
hat_U_star_0_low_pred = U0 - t.ppf(1-alpha/2,n-p)*aux_t_pred_U_star_0
hat_U_star_0_upp_pred = U0 + t.ppf(1-alpha/2,n-p)*aux_t_pred_U_star_0

# get confidence interval for Q_star
aux_t_conf_Q_star   = np.sqrt(hat_sigma_2 * hat_H_star.T @ W_inv_for_Q @ hat_H_star)
aux_t_conf_Q_star   = aux_t_conf_Q_star[0][0]
hat_Q_star_low_conf = hat_Q_star - t.ppf(1-alpha/2,n-p)*aux_t_conf_Q_star
hat_Q_star_upp_conf = hat_Q_star + t.ppf(1-alpha/2,n-p)*aux_t_conf_Q_star

aux_t_conf_Q_star_0   = np.sqrt(hat_sigma_2 * np.diag(H0 @ W_inv_for_Q @ H0.T))
hat_Q_star_0_low_conf = Q0 - t.ppf(1-alpha/2,n-p)*aux_t_conf_Q_star_0
hat_Q_star_0_upp_conf = Q0 + t.ppf(1-alpha/2,n-p)*aux_t_conf_Q_star_0

# get prediction interval for Q_star
aux_t_pred_Q_star   = np.sqrt(hat_sigma_2 * (1+hat_H_star.T @ W_inv_for_Q @ hat_H_star))
aux_t_pred_Q_star   = aux_t_pred_Q_star[0][0]
hat_Q_star_low_pred = hat_Q_star - t.ppf(1-alpha/2,n-p)*aux_t_pred_Q_star
hat_Q_star_upp_pred = hat_Q_star + t.ppf(1-alpha/2,n-p)*aux_t_pred_Q_star

aux_t_pred_Q_star_0   = np.sqrt(hat_sigma_2 * (1+np.diag(H0 @ W_inv_for_Q @ H0.T)))
hat_Q_star_0_low_pred = Q0 - t.ppf(1-alpha/2,n-p)*aux_t_pred_Q_star_0
hat_Q_star_0_upp_pred = Q0 + t.ppf(1-alpha/2,n-p)*aux_t_pred_Q_star_0

# See graphically the estimation
plt.figure(figsize=(15,7.5))
plt.plot(x0, hat_beta_0+hat_beta_1*x0+hat_beta_2*x0**2, 'r', label='Expected Gain')
plt.fill_between(P0, hat_U_star_0_low_pred, hat_U_star_0_upp_pred, facecolor='green', alpha=0.5, label='Prediction interval for U_star')
plt.fill_between(P0, hat_U_star_0_low_conf, hat_U_star_0_upp_conf, facecolor='yellow', alpha=0.5, label='Confidence interval for U_star')
plt.plot([hat_P_star,hat_P_star],[hat_U_star_low_pred,hat_U_star_upp_pred], 'brown', label='Prediction interval for the best guess')
plt.plot([hat_P_star,hat_P_star],[hat_U_star_low_conf,hat_U_star_upp_conf], 'black', label='Confidence interval for the best guess')
plt.scatter(P, U, label='Original data')
plt.legend(loc='upper left')

plt.figure(figsize=(15,7.5))
plt.plot(x0, hat_alpha_0+hat_alpha_1*x0, 'r', label='Expected Sale')
plt.fill_between(P0, hat_Q_star_0_low_pred, hat_Q_star_0_upp_pred, facecolor='green', alpha=0.5, label='Prediction interval for Q_star')
plt.fill_between(P0, hat_Q_star_0_low_conf, hat_Q_star_0_upp_conf, facecolor='yellow', alpha=0.5, label='Confidence interval for Q_star')
plt.plot([hat_P_star,hat_P_star],[hat_Q_star_low_pred,hat_Q_star_upp_pred], 'brown', label='Prediction interval for the best guess')
plt.plot([hat_P_star,hat_P_star],[hat_Q_star_low_conf,hat_Q_star_upp_conf], 'black', label='Confidence interval for the best guess')
plt.scatter(P, Q, label='Original data')
plt.legend(loc='upper left')


'''
Linear Regression using Normal Equation
'''

import numpy as np

X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100,1)

# Adding 1 to each instance of X
X_b = np.c_[np.ones((100,1)), X]
# Calculating the value of Theta that minimizes the cost function
theta_best = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)
print('Theta: ', theta_best)
# Making predictions using theta
X_new = np.array([[0], [2]])
X_new_b = np.c_[np.ones((2,1)), X_new]
y_predict = X_new_b.dot(theta_best)
print('y predicted: ', y_predict)

import matplotlib
import matplotlib.pyplot as plt

ax = plt.axes()
ax.plot(X, y, 'b.')
ax.plot(X_new, y_predict, 'r')
plt.show()

# Using Scikit-Learn
from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X, y)
print('Scikit-Learn theta: ', lin_reg.intercept_, lin_reg.coef_)
print('Scikit-Learn y predicted: ', lin_reg.predict(X_new))


import numpy as np

def _manhattan_distance(x, y):
    '''
    x: numpy array
    y: numpy array
    RETURNS: int/float
    Compute the manhattan distance between two points x and y.
    '''
    return np.sum(np.abs(y - x))

def _find_closest_center(x, cluster_centers):
    '''
    x: 1d numpy array (shape is (p,))
    y: 2d numpy array (shape is (n, p))
    RETURNS: int
    Using manhattan distance, find the index of the center from cluster_centers
    that x is closest to.
    '''
    distances = np.sum(np.abs(cluster_centers - x), axis=1)
    return np.argmin(distances)

def _find_cost(cluster, center):
    '''
    cluster: list of 1d numpy arrays
    center: 1d numpy array
    Using manhattan distance, find the total cost of using center as the center
    '''
    return sum(_manhattan_distance(x, center) for x in cluster)

def _find_total_cost(clusters, cluster_centers):
    '''
    clusters: list of list of 1d numpy arrays
    cluster_centers: 2d numpy array
    RETURNS: int/float
    Calculate the total cost of the chosen clusters and cluster_centers.
    '''
    return sum(
        _find_cost(clusters[i], cluster_centers[i]) \
        for i in xrange(len(clusters))
    )

def _find_medoid(cluster):
    '''
    cluster: list of 1d numpy arrays
    RETURNS: 1d numpy array
    Using manhattan distance, find the datapoint from the cluster that is the
    medoid.
    '''
    min_cost = None
    medoid = None
    for y in cluster:
        cost = _find_cost(cluster, y)
        if min_cost is None or cost < min_cost:
            min_cost = cost
            medoid = y
    return medoid

class kMedoids(object):
    '''
    An implementation of k-medoids algorithm using manhattan distance.
    '''
    def __init__(self, n_clusters, max_iter=300, initial_centers=None):
        '''
        n_clusters: int
        max_iter: int
        initial_centers: list of ints
        RETURNS: None
        Intialize kMedoids algorithm with n_clusters as the number of clusters
        and max_iter the maximum number of iterations.
        initial_centers is a list of the indices of the initial cluster centers.
        If value is None, initial cluster centers are chosen randomly.
        '''
        self.cluster_centers = None
        self.n_clusters = n_clusters
        self.max_iter = max_iter
        self.initial_centers = initial_centers

    def fit(self, X):
        '''
        X: 2d numpy array
        RETURNS: None
        Build the clusters for k-medoids with data X.
        '''
        if self.initial_centers is None:
            center_indicies = np.random.choice(
                range(X.shape[0]),
                self.n_clusters,
                replace=False
            )
        else:
            center_indicies = self.initial_centers
        self.cluster_centers = X[center_indicies]
        cost = None
        for j in xrange(self.max_iter):
            self.clusters = [[] for _ in xrange(self.n_clusters)]
            for x in X:
                center = _find_closest_center(x, self.cluster_centers)
                self.clusters[center].append(x)
            for index, cluster in enumerate(self.clusters):
                self.cluster_centers[index] = _find_medoid(cluster)
            new_cost = _find_total_cost(self.clusters, self.cluster_centers)
            if cost is None or new_cost < cost:
                cost = new_cost
            else:
                break

    def predict(self, X):
        '''
        X: 2d numpy array
        RETURNS: 1d numpy array
        Give the predicted cluster for each datapoint in X
        '''
        y = np.zeros(X.shape[0])
        for i, x in enumerate(X):
            y[i] = _find_closest_center(x, self.cluster_centers)
        return y


import numpy as np

import common.utils as utils

def _gini(values):
    """Measure of entropy among a set of values."""
    bins = np.bincount(values)
    return 1 - np.sum(np.square(bins / np.sum(bins)))

def _gain(parent, children, impurity_func):
    """Measure of information gain between two successive levels of the decition tree."""
    weights = map(len, children)
    scores = map(impurity_func, children)
    weighted_scores = [w*s for w, s in zip(weights, scores)]
    return impurity_func(parent) - sum(weighted_scores) / len(parent)

def decision_tree(X, y, attrs=None):
    """Builds a traversable decision tree.

    Args:
        X (ndarray[m, n]):          ground features
        y (ndarray[m, 1]):          ground labels
        attrs (tuple, optional):    tuple of attributes to branch on (defaults to all)

    Returns:
        root_attr (int):            index of root attribute
        mapping (dict):             decision tree
    """
    # First run
    if attrs is None:
        attrs = set(range(X.shape[1]))
        return decision_tree(X, y, attrs=attrs)

    # Base case: If all samples belong to the same class
    if np.unique(y).size == 1:
        return y[0]

    # Find best split attribute within current subtree
    best_gain = 0
    best_candidate = None
    for attr in attrs:
        # Format: 'group_i' -> [(X0, y0), (X1, y1), ... (Xi, yi)]
        groups = utils.groupby(zip(X, y), key=lambda tup: tup[0][attr])

        # Evaluate candidate
        attr_values, buckets = groups.keys(), groups.values()
        transpose_buckets = [list(zip(*b)) for b in buckets]
        x_buckets, y_buckets = list(zip(*transpose_buckets))
        attr_gain = _gain(y, y_buckets, impurity_func=_gini)

        # Compare candidate and update split attributre
        if attr_gain > best_gain:
            best_gain = attr_gain
            best_candidate = (attr, attr_values, x_buckets, y_buckets)

    # Generate tree
    mapping = {}
    best_attr, attr_values, x_buckets, y_buckets = best_candidate
    for value, next_x, next_y in zip(attr_values, x_buckets, y_buckets):
        next_x = np.array(next_x)
        next_attr = attrs - {best_attr}
        mapping[value] = decision_tree(next_x, next_y, attrs=next_attr)
    return (best_attr, mapping)

def traverse(instance, decision_tree):
    """Traverses the input decision tree to yield a prediction."""
    root_attr, mapping = decision_tree
    output = mapping[instance[root_attr]]
    if isinstance(output, np.int64):
        return output
    return traverse(instance, output)


import numpy as np

def cart2pol(x, y):
    rho = np.sqrt(x**2 + y**2)
    phi = np.arctan2(y, x)
    return rho, phi

def pol2cart(rho, phi):
    x = rho * np.cos(phi)
    y = rho * np.sin(phi)
    return x, y

def cart2pol2(x, y):
    rho, phi = cart2pol(y, x)
    deg = phi * 180. / np.pi
    inds = deg < 0
    deg[inds] = 360. + deg[inds]
    return rho, deg

def pol2cart2(rho, deg):
    x, y = pol2cart(rho, float(deg)/180.*np.pi)
    return y, x


import numpy as np

def normalize(v):
    return v / np.linalg.norm(v)

def normalize_col(A):
    for i in range(A.shape[1]):
        A[:, i] = A[:,i] / np.linalg.norm(A[:,i])
    return A

def disturbation(A,disturb):
    _,m=A.shape
    U, D, V = np.linalg.svd(A)
    #print("U: {}, D: {}, V: {}".format(
    #    U.shape, D.shape, V.shape
    #))
    Atemp = U[:, :m].dot(np.diag(D + disturb)).dot(V)
    for i in range(m):
        Atemp[:, i] = normalize(Atemp[:,i])
    _, D, _ = np.linalg.svd(Atemp)

    return np.linalg.norm(D-np.ones(m))

def creating_nonQO(A, eps_A, seed=None):
    np.random.seed(seed)
    U,D,V = np.linalg.svd(A)
    m = A.shape[1]
    tol = 0.001
    I = np.ones(m)
    pert = np.random.normal(size = m)
    l = np.linalg.norm(pert)
    l_low = 0
    max_iterations = 100
    k = 0
    while True:
        xi = (l - l_low)/2 + l_low
        res = disturbation(A, pert*xi) - eps_A
        if np.abs(res) < tol or k > max_iterations:
            break
        elif res > 0:
            l = xi
        else:
            l_low = xi
        k = k+1
    Anew = U[:,:m].dot(np.diag(D+pert*xi)).dot(V)
    for i in range(m):
        Anew[:,i] = normalize(Anew[:,i])
    return Anew


import pytest
import numpy as np
import math
import random

from researchutils.math.angle import fit_angle_in_rad_range, fit_angle_in_deg_range

class TestAngle(object):
    def test_fit_angle_in_rad_range_scalar(self):
        angles = np.random.rand(10) + 10.0
        correct_angles = fit_angle_in_rad_range(angles)

        for i, angle in enumerate(correct_angles):
            if angle < 0.0 or angle > 2 * math.pi:
                assert False

            if round(math.cos(float(angle)), 5) != round(math.cos(angles[i]), 5) or\
               round(math.sin(float(angle)), 5) != round(math.sin(angles[i]), 5):
                assert False

    def test_fit_angle_in_rad_range_matrix(self):
        angles = np.random.rand(3, 10) + -10.0
        correct_angles = fit_angle_in_rad_range(angles)

        for i in range(correct_angles.shape[0]):
            for j, angle in enumerate(correct_angles[i]):
                if angle < 0.0 or angle > 2 * math.pi:
                    assert False

                if round(math.cos(float(angle)), 5) != round(math.cos(angles[i, j]), 5) or\
                   round(math.sin(float(angle)), 5) != round(math.sin(angles[i, j]), 5):
                    assert False

    def test_fit_angle_in_diff_rad_range_matrix(self):
        angles = np.random.rand(3, 10) + -10.0
        correct_angles = fit_angle_in_rad_range(angles, max_angle=math.pi, min_angle=-math.pi)

        for i in range(correct_angles.shape[0]):
            for j, angle in enumerate(correct_angles[i]):
                if angle > math.pi:
                    assert False
                elif angle < -math.pi:
                    assert False
                elif round(math.cos(float(angle)), 5) != round(math.cos(angles[i, j]), 5):
                    assert False
                elif round(math.sin(float(angle)), 5) != round(math.sin(angles[i, j]), 5):
                    assert False

    def test_fit_angle_in_rad_range_wrong_range(self):
        with pytest.raises(ValueError):
            angles = np.random.rand(10)
            fit_angle_in_rad_range(angles, min_angle=0.0, max_angle=math.pi)

    def test_fit_angle_in_rad_range_min_is_greater_than_max(self):
        with pytest.raises(ValueError):
            angles = np.random.rand(10)
            fit_angle_in_rad_range(angles, min_angle=math.pi, max_angle=-math.pi)

    def test_fit_angle_in_deg_range_scalar(self):
        angles = np.random.rand(10) + random.choice([-500.0, 500.0])
        correct_angles = fit_angle_in_deg_range(angles)

        for i, angle in enumerate(correct_angles):
            if angle < 0.0 or angle > 360.0:
                assert False

            if round(math.cos(float(math.radians(angle))), 5) != round(math.cos(math.radians(angles[i])), 5) or\
               round(math.sin(float(math.radians(angle))), 5) != round(math.sin(math.radians(angles[i])), 5):
                assert False

    def test_fit_angle_in_deg_range_matrix(self):
        angles = np.random.rand(3, 10) + random.choice([-500.0, 500.0])
        correct_angles = fit_angle_in_deg_range(angles)

        for i in range(correct_angles.shape[0]):
            for j, angle in enumerate(correct_angles[i]):
                if angle < 0.0 or angle > 360.0:
                    assert False

                if round(math.cos(float(math.radians(angle))), 5) != round(math.cos(math.radians(angles[i, j])), 5) or\
                   round(math.sin(float(math.radians(angle))), 5) != round(math.sin(math.radians(angles[i, j])), 5):
                    assert False

    def test_fit_angle_in_diff_deg_range_matrix(self):
        angles = np.random.rand(3, 10) + random.choice([-500.0, 500.0])
        correct_angles = fit_angle_in_deg_range(angles, max_angle=180.0, min_angle=-180.0)

        for i in range(correct_angles.shape[0]):
            for j, angle in enumerate(correct_angles[i]):
                if angle < -180.0 or angle > 180.0:
                    assert False

                if round(math.cos(float(math.radians(angle))), 5) != round(math.cos(math.radians(angles[i, j])), 5) or\
                   round(math.sin(float(math.radians(angle))), 5) != round(math.sin(math.radians(angles[i, j])), 5):
                    assert False

    def test_fit_angle_in_deg_range_wrong_range(self):
        with pytest.raises(ValueError):
            angles = np.random.rand(10)
            fit_angle_in_deg_range(angles, min_angle=180.0, max_angle=0.0)

    def test_fit_angle_in_deg_range_min_is_greater_than_max(self):
        with pytest.raises(ValueError):
            angles = np.random.rand(10)
            fit_angle_in_deg_range(angles, min_angle=180.0, max_angle=-180.0)

if __name__=="__main__":
    pytest.main()


from abc import ABC, abstractmethod
from typing import Optional
from copy import copy

import numpy as np

from shared_utils.typing import ArrayFunction

# TODO: Look into ``numjac'' algorithm - ``The MATLAB ODE Suite Shampine''

class Jacobian(ABC):
    def __init__(self, func: ArrayFunction, arg_idx: int = 0):
        self.func = func
        self.arg_idx = arg_idx

    @abstractmethod
    def __call__(self, *args):
        pass

class ForwardDiffJac(Jacobian):
    def __init__(self, func: ArrayFunction, arg_idx: int = 0, step_size: float = 1e-6):
        super().__init__(func, arg_idx=arg_idx)
        self.step_size: float = step_size

    def __call__(self, *args, pre_calc_f: Optional[np.array] = None):
        if pre_calc_f is None:
            f_0 = self.func(*args)
        else:
            f_0 = pre_calc_f

        args_step = list(args)
        col_set = []
        for idx, _ in enumerate(args[self.arg_idx]):
            args_step[self.arg_idx] = copy(args[self.arg_idx])
            args_step[self.arg_idx][idx] += self.step_size
            col_set.append((self.func(*args_step) - f_0) / self.step_size)

        return np.vstack(col_set).T

class CentralDiffJac(Jacobian):
    def __init__(self, func: ArrayFunction, arg_idx: int = 0, step_size: float = 1e-6):
        super().__init__(func, arg_idx=arg_idx)
        self.step_size: float = step_size

    def __call__(self, *args):

        args_step_p, args_step_m = list(args), list(args)
        col_set = []
        for idx, _ in enumerate(args[self.arg_idx]):
            args_step_p[self.arg_idx], args_step_m[self.arg_idx] = copy(args[self.arg_idx]), copy(args[self.arg_idx])
            args_step_p[self.arg_idx][idx] += self.step_size / 2
            args_step_m[self.arg_idx][idx] -= self.step_size / 2

            col_set.append((self.func(*args_step_p) - self.func(*args_step_m)) / self.step_size)

        return np.vstack(col_set).T

def saddle(y):
    return np.array([y[0]**2 - y[1], -y[1]**2 + y[0]])

def multi_saddle(x, y):
    return np.array([x[0] * y[0]**2 - y[1], -x[1] * y[1]**2 + y[0]])

if __name__ == '__main__':
    jac = CentralDiffJac(saddle)
    print(jac(np.array([10., 10.])))

    jac2 = CentralDiffJac(multi_saddle, arg_idx=1)
    print(jac2(np.array([1., 1.]), np.array([10., 10.])))


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2019-04-17 15:58
# @Author  : erwin
import numpy as np
from common.util_function import *

np.set_printoptions(precision=3)

arr = np.linspace(0, 100, 10).reshape((2, 5))
print_line("原始数据")
print_br(arr)

print_line("单个array操作")
print_br(np.add(arr, 2))
print_br(np.subtract(arr, 2))
print_br(np.multiply(arr, 2))
print_br(np.divide(arr, 2))
print_br(np.power(arr, 2))

print_line("平方以及开方")
print_br(np.power(arr, 2))
print_br(np.sqrt(arr))

print_line("sin/cos/log/abs")
print_br(np.sin(arr))
print_br(np.cos(arr))
# print_br(np.log(arr1))
print_br(np.abs(arr))

print_line("向上取整/向下取整/四舍五入")
print_br(np.ceil(arr))
print_br(np.floor(arr))
print_br(np.round(arr))


import numpy as np
a = np.array([1,2,3,4,5,6]) #one dimensional array
b = np.array([[1,2],[3,4],[5,6]]) #2 dimensional array
#printing the arrays
print(a)
print(b)

#MATRIX:

# BI-DIMENSIONAL
c = np.array([[1,2,3],[4,5,6]])
print(c)

#shape of matrix
shape_matrix = c.shape
print(shape_matrix)

#dimension of matrix
dimension_mat = c.ndim
print(dimension_mat)

#re-shaping the arrays
#(we know that we have declared "a" as a linear array ,so now we'll try to reshape this array and turn it into a 2x3 matrix)

a2 = a.reshape(2,3)
print(a2)

a3 = a.reshape(3,2)
print(a3)

#3 dimensional array
e = np.array([1,2,3,4,5,6,7,8,9,0,12,69])
a4 = e.reshape(2,3,2)
print(a4)
f = a4.ndim
print(f) #printing the dimension

#everything in one line:
g = np.array([1,2,3,4,5,6]).reshape(2,3).ndim #in this line we are declaring the array and reshaping it and checking the dimensions altogether
print(g)

#resizing the array

#(now we know that we reshaped the array a quite a few times...so lets see what happened to the array a itself)
print(a)
##as we can see in the output the array a is still a linear array ...that means while we were reshaping the array it just reshapes and used accd to that following command but the array itself doesnt change at all
##to change the shape of the array we need to use resize()

a.resize(3,2)
print(a) ## as we can see the array itself got changed

#data type of an array:
print(a.dtype) #here we get int32 it means all the elements of the array is integer

flt = np.array([1,2,3,4.5,6,7,8]).dtype
print(flt)#float64 stands for any elemnts..atleast one element in the array is a float number

compx = np.array([1,2,3,4+7j,5,6]).dtype
print(compx) #o/p is complex128 means atleast one value in the array is complex number

##we can also change datatype of an array
flt2 = np.array([1,2,3,4.5,6,7,8],dtype = int)
print(flt2) #as we're changing the dat type from float to inyteger the value after point is removed automatixally
flt3 = np.array([1,2,3,4.5,6,7,8],dtype = complex)
print(flt3) #every elemnt is turned in complex manner

#special arrays
##1 : ZERO ARRAYS
zero= np.zeros(6) #the number written in the bracket is the no. of elements that is the number of zeros in the array
print(zero)

zero2= np.zeros((2,3)) #declaring the dimension of zero array
print(zero2)

##2 one array
one = np.ones(4)
print(one)

one2 = np.ones((2,3))
print(one2)

##3 CONSTANT ARRAYS
const = np.full((6,2),69)
print(const)

##4 identity matrix
iden = np.eye(6)
print(iden)

##MATRIX WITH RANDOM NUMBERS

rndm_mat = np.random.random((3,3))
print(rndm_mat)

#printing simple series as arrays with arrange()
arrng = np.arange(1,69,2.3) #arange(starting,ending,difference)
print(arrng)

arrng2 = np.arange(1,12,3).reshape(2,2)
print(arrng2)

#to create equidistant points using linspace()
lnspce = np.linspace(0.1,0.9,4) #(starting point,ending point,number of equidistant points)
print(lnspce)


#-------------------------------------------------
# Python code for Bisection Method to
# determine the roots of the given equation
# provided a guess within which the roots must lie.
#-------------------------------------------------

#import the necessary libraries
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import spline

#Define the function prefixes using NumPy
sin = np.sin
cos = np.cos
tan = np.tan
pi  = np.pi
exp = np.exp
ln  = np.log
log = np.log10

fx = input("Enter the function whose roots you wish to determine :")      #take function as input from the user
f  = lambda x: eval(fx)                                                 # using lambda for defining function

#Enter the initial approximation and Error as Input from User
xl  = float((input("Enter the first value of guess interval :")))
xu  = float((input("Enter the end value of guess interval :")))
tol = float((input("Enter the allowed error (for eg. 0.1 or 0.01 or 0.001, etc.):")))
N   = int(input("Enter the no. of iterations you want to run:"))

# Define the actual algorithm as a function
def bisect(f, xl, xu, tol, N):
	if f(xl)*f(xu) > 0:	# This adds interaction with the user, we can however modify it to get the interval by running a for loop.
		print("Guesses are incorrect! Enter the new guesses")
		xl = float((input("Enter the first value of guess interval again :")))
		xu = float((input("Enter the end value of guess interval again:")))
		lastFuncVal = f(xl)
	else:
		for i in range(2, N):
			xr = (xl + xu)/2
			if f(xr) == 0 or (xu - xl)/2.0 < tol:
				return xr
			elif f(xr)*f(xl) > 0:
				xl = xr
			else:
				xu = xr
			lastFuncVal = f(xr)
		return "Method failed after {} iterations".format(N)

Ans = bisect(f, xl, xu, tol, N)			# define the output of the function as a variable 'Ans'

print ("Bisection method soln: x = ", Ans) # Print the solution

#Code to plot the curve
x = np.linspace(-10,10,10)
xnew = np.linspace(x.min(), x.max(), 300)       # Interpolates extra values to make smooth curve
f_smooth = spline(x, f(x), xnew) 				# Use the spline tool from SciPy to get smoother curves

#Plot the curves
fig = plt.figure()
plt.plot(xnew, f_smooth, '-b', label = 'function')
plt.plot(Ans, 0, 'ro', label = 'The root of the function')
plt.xlabel('x')
plt.ylabel('fx')
plt.savefig('bisection_exp.png')				# Export the image to the folder where you run the python3 command
plt.legend()

#Show the curve
plt.show()


import numpy as np

class Point:
    def __init__(self, x, y):
        self.__x = x
        self.__y = y

    def __repr__(self):
        return f"""x: {self.__x}, y: {self.__y}"""

    @property
    def y(self):
        return self.__y

    @property
    def x(self):
        return self.__x

def bisection_search(
    math_function, endpoint_min,
    endpoint_max, tolerance=1e-4, max_iteration=1000
):
    """We expect `math_function` to have its minima between `endpoint_min` and `endpoint_max`.

    Parameters
    ----------
    math_function: a function that takes in a float value with signature math_function(x)
    endpoint_min: float
    endpoint_max: float

    Returns
    -------
    Point: Point at the minima

    Raises
    ------
    AssertionError: If endpoint_min > endpoint_max
    AssertionError: If sign(math_function(endpoint_min)) == sign(math_function(endpoint_max))

    """
    assert endpoint_min < endpoint_max, "Input range not ordered."
    # The following assertion can be added for functions that are linear. Imagine a parabola, this assumption might break.
    # assert np.sign(math_function(endpoint_min)) != np.sign(math_function(endpoint_max))
    lower_x = endpoint_min
    higher_x = endpoint_max

    previous_val_at_x = np.inf
    current_iteration = 0
    while current_iteration < max_iteration:
        current_x = (higher_x + lower_x) / 2.0
        current_y_at_x = math_function(current_x)

        if (
            np.isclose(current_y_at_x, previous_val_at_x, atol=tolerance) or
            np.isclose(current_y_at_x, 0, atol=tolerance) or
            np.isclose(current_x / 2, higher_x, tolerance)
        ):
            break

        # If the sign at the lower point and the mid point are the same,
        # we make the lower bound go to the mid-point.
        if np.sign(current_y_at_x) == np.sign(function(lower_x)):
            lower_x = current_x
        else:
            # If not, we have crossed the zero, hence retain the lower point and update the higher.
            higher_x = current_x
        current_iteration += 1

    return Point(current_x, current_y_at_x)

if __name__ == "__main__":
    # The following line's y = 0 is at x=-1.5
    function = lambda x: 2 * x + 3
    assert np.isclose((bisection_search(math_function=function, endpoint_min=-20, endpoint_max=20)).x, -1.5, atol=1e-3)

    # Minima should be at 2
    function = lambda x: x**2 - 4
    print((bisection_search(math_function=function, endpoint_min=-20, endpoint_max=20)).x)
    assert np.isclose((bisection_search(math_function=function, endpoint_min=-20, endpoint_max=20)).x, -2, atol=1e-3)


from sklearn import linear_model
import numpy as np
import matplotlib.pyplot as plt
import scipy.io
from reg_linear_regressor_multi import RegularizedLinearReg_SquaredLoss
import plot_utils

#############################################################################
#  Normalize features of data matrix X so that every column has zero        #
#  mean and unit variance                                                   #
#     Input:                                                                #
#     X: N x D where N is the number of rows and D is the number of         #
#        features                                                           #
#     Output: mu: D x 1 (mean of X)                                         #
#          sigma: D x 1 (std dev of X)                                      #
#         X_norm: N x D (normalized X)                                      #
#############################################################################

def feature_normalize(X):

    ########################################################################
    # TODO: modify the three lines below to return the correct values
    mu = np.mean(X, axis=0)
    sigma = np.std(X, axis=0)
    X_norm = (X - mu) / sigma

    ########################################################################
    return X_norm, mu, sigma

#############################################################################
#  Plot the learning curve for training data (X,y) and validation set       #
# (Xval,yval) and regularization lambda reg.                                #
#     Input:                                                                #
#     X: N x D where N is the number of rows and D is the number of         #
#        features                                                           #
#     y: vector of length N which are values corresponding to X             #
#     Xval: M x D where N is the number of rows and D is the number of      #
#           features                                                        #
#     yval: vector of length N which are values corresponding to Xval       #
#     reg: regularization strength (float)                                  #
#     Output: error_train: vector of length N-1 corresponding to training   #
#                          error on training set                            #
#             error_val: vector of length N-1 corresponding to error on     #
#                        validation set                                     #
#############################################################################

def learning_curve(X,y,Xval,yval,reg):
    num_examples,dim = X.shape
    error_train = np.zeros((num_examples,))
    error_val = np.zeros((num_examples,))

    ###########################################################################
    # TODO: compute error_train and error_val                                 #
    # 7 lines of code expected                                                #
    ###########################################################################
    for i in range(1, num_examples + 1):
        model = RegularizedLinearReg_SquaredLoss()
        theta = model.train(X[:i], y[:i], reg=reg, num_iters=1000)
        error_train[i-1] = model.loss(theta, X[:i], y[:i], 0)
        error_val[i-1] = model.loss(theta, Xval, yval, 0)
    ###########################################################################

    return error_train, error_val

#############################################################################
#  Plot the validation curve for training data (X,y) and validation set     #
# (Xval,yval)                                                               #
#     Input:                                                                #
#     X: N x D where N is the number of rows and D is the number of         #
#        features                                                           #
#     y: vector of length N which are values corresponding to X             #
#     Xval: M x D where N is the number of rows and D is the number of      #
#           features                                                        #
#     yval: vector of length N which are values corresponding to Xval       #
#                                                                           #
#     Output: error_train: vector of length N-1 corresponding to training   #
#                          error on training set                            #
#             error_val: vector of length N-1 corresponding to error on     #
#                        validation set                                     #
#############################################################################

def validation_curve(X,y,Xval,yval):
    reg_vec = [0, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1, 3, 10]
    # reg_vec = [0, 0.1, 0.3, 1, 3, 10, 20, 30, 100, 300, 1000]
    error_train = np.zeros((len(reg_vec),))
    error_val = np.zeros((len(reg_vec),))

    ###########################################################################
    # TODO: compute error_train and error_val                                 #
    # 5 lines of code expected                                                #
    ###########################################################################
    for i, reg in enumerate(reg_vec):
        model = RegularizedLinearReg_SquaredLoss()
        theta = model.train(X, y, reg, num_iters=1000)
        error_train[i] = model.loss(theta, X, y, 0)
        error_val[i] = model.loss(theta, Xval, yval, 0)
    return reg_vec, error_train, error_val

import random

#############################################################################
#  Plot the averaged learning curve for training data (X,y) and             #
#  validation set  (Xval,yval) and regularization lambda reg.               #
#     Input:                                                                #
#     X: N x D where N is the number of rows and D is the number of         #
#        features                                                           #
#     y: vector of length N which are values corresponding to X             #
#     Xval: M x D where N is the number of rows and D is the number of      #
#           features                                                        #
#     yval: vector of length N which are values corresponding to Xval       #
#     reg: regularization strength (float)                                  #
#     Output: error_train: vector of length N-1 corresponding to training   #
#                          error on training set                            #
#             error_val: vector of length N-1 corresponding to error on     #
#                        validation set                                     #
#############################################################################

def averaged_learning_curve(X,y,Xval,yval,reg):
    num_examples,dim = X.shape
    error_train = np.zeros((num_examples,))
    error_val = np.zeros((num_examples,))

    ###########################################################################
    # TODO: compute error_train and error_val                                 #
    # 10-12 lines of code expected                                            #
    ###########################################################################
    iters = 50
    error_train0 = np.zeros((iters,))
    error_val0 = np.zeros((iters,))
    model = RegularizedLinearReg_SquaredLoss()
    for i in range(1, num_examples + 1):
        for j in range(iters):
            shuffled_array = np.random.permutation(num_examples)
            selected = shuffled_array[0:i]
            X_train, y_train = X[selected, :], y[selected]
            theta = model.train(X_train, y_train, reg, num_iters=1000)
            X_val, y_val = Xval[selected, :], yval[selected]
            error_train0[j] = model.loss(theta, X_train, y_train, 0)
            error_val0[j] = model.loss(theta, X_val, y_val, 0)
        error_train[i - 1] = np.mean(error_train0)
        error_val[i - 1] = np.mean(error_val0)

    ###########################################################################
    return error_train, error_val

#############################################################################
# Utility functions
#############################################################################

def load_mat(fname):
  d = scipy.io.loadmat(fname)
  X = d['X']
  y = d['y']
  Xval = d['Xval']
  yval = d['yval']
  Xtest = d['Xtest']
  ytest = d['ytest']

  # need reshaping!

  X = np.reshape(X,(len(X),))
  y = np.reshape(y,(len(y),))
  Xtest = np.reshape(Xtest,(len(Xtest),))
  ytest = np.reshape(ytest,(len(ytest),))
  Xval = np.reshape(Xval,(len(Xval),))
  yval = np.reshape(yval,(len(yval),))

  return X, y, Xtest, ytest, Xval, yval


import pandas as pd
import plotly.plotly as py
from sklearn.preprocessing import StandardScaler
import numpy as np

df = pd.read_csv(
    filepath_or_buffer='https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data',
    header=None,
    sep=',')

df.columns = ['sepal_len', 'sepal_wid', 'petal_len', 'petal_wid', 'class']
df.dropna(how="all", inplace=True)  # Drops the empty line at file-end

print(df.tail())

X = df.iloc[:, 0:4].values
y = df.iloc[:, 4].values

X_std = StandardScaler().fit_transform(X)

# Covariance matrix
mean_vec = np.mean(X_std, axis=0)
cov_mat = (X_std - mean_vec).T.dot((X_std - mean_vec)) / (X_std.shape[0]-1)
print('Covariance matrix \n%s' % cov_mat)

cov_mat = np.cov(X_std.T)

eig_vals, eig_vecs = np.linalg.eig(cov_mat)

print('Eigenvectors \n%s' % eig_vecs)
print('\nEigenvalues \n%s' % eig_vals)

# Correlation matrix
cor_mat1 = np.corrcoef(X_std.T)

eig_vals, eig_vecs = np.linalg.eig(cor_mat1)

print('Eigenvectors \n%s' % eig_vecs)
print('\nEigenvalues \n%s' % eig_vals)

cor_mat2 = np.corrcoef(X.T)

eig_vals, eig_vecs = np.linalg.eig(cor_mat2)

print('Eigenvectors \n%s' % eig_vecs)
print('\nEigenvalues \n%s' % eig_vals)

# Single vector decomposotion
u, s, v = np.linalg.svd(X_std.T)
print(u)

for ev in eig_vecs:
    np.testing.assert_array_almost_equal(1.0, np.linalg.norm(ev))

# Make a list of (eigenvalue, eigenvector) tuples
eig_pairs = [(np.abs(eig_vals[i]), eig_vecs[:,i]) for i in range(len(eig_vals))]

# Sort the (eigenvalue, eigenvector) tuples from high to low
eig_pairs.sort()
eig_pairs.reverse()

# Visually confirm that the list is correctly sorted by decreasing eigenvalues
print('Eigenvalues in descending order:')
for i in eig_pairs:
    print(i[0])

# Selecting principal components
tot = sum(eig_vals)
var_exp = [(i / tot)*100 for i in sorted(eig_vals, reverse=True)]
cum_var_exp = np.cumsum(var_exp)

trace1 = dict(
    type='bar',
    x=['PC %s' %i for i in range(1,5)],
    y=var_exp,
    name='Individual'
)

trace2 = dict(
    type='scatter',
    x=['PC %s' %i for i in range(1,5)],
    y=cum_var_exp,
    name='Cumulative'
)

data = [trace1, trace2]

layout = dict(
    title='Explained variance by different principal components',
    yaxis=dict(
        title='Explained variance in percent'
    ),
    annotations=list([
        dict(
            x=1.16,
            y=1.05,
            xref='paper',
            yref='paper',
            text='Explained Variance',
            showarrow=False,
        )
    ])
)

fig = dict(data=data, layout=layout)
py.plot(fig, filename='selecting-principal-components')

matrix_w = np.hstack((eig_pairs[0][1].reshape(4,1),
                      eig_pairs[1][1].reshape(4,1)))

print('Matrix W:\n', matrix_w)


import matplotlib.pyplot as plt
import numpy as np
from numpy import arange, zeros, log, sqrt

from scipy.stats import t

plt.style.use('seaborn')

from MaxLikelihoodFPLocDispT import MaxLikelihoodFPLocDispT

def CalibDegOfFreedomMLFP(x,FP,maxdf,stepdf):
    # Student t model
    # MLFP for mu and sigma on a grid of degrees of freedom (df) the best fit
    # corresponds to df which gives rise to the highest (log)likelihood L)
    #  INPUTS
    # x       :[vector](1 x t_end) empirical realizations
    # FP      :[vector](1 x t_end) flexible probabilities associated with vector x
    # maxdf   :[scalar] maximum value for nu to be checked
    # stepdf  :[scalar] step between consecutive values of nu to be checked
    #  OPS
    # mu      :[scalar] estimated location parameter
    # sig2    :[scalar] estimated dispersion parameter
    # nu      :[scalar] best degrees of freedom nu

    ## Code
    df=arange(1,maxdf+stepdf,stepdf)
    Tol=10**(-6)
    l_=len(df)

    Mu = zeros((l_,1))
    Sigma2 = zeros((l_,1))
    L = zeros((l_,1))
    for i in range(l_):
        Mu[i],Sigma2[i],_ = MaxLikelihoodFPLocDispT(x,FP,df[i],Tol,1)
        L[i]=FP@log(t.pdf((x - Mu[i]) / sqrt(Sigma2[i]), df[i]) / sqrt(Sigma2[i])).T

    imax= np.argmax(L)

    mu = Mu[imax]
    sig2 = Sigma2[imax]
    nu = df[imax]

    return mu, sig2, nu


import numpy as np

def positional_encoding(X, L):
    """
    The positional encoding as defined in the NeRF paper https://arxiv.org/pdf/2003.08934.pdf
      gamma(p) = (sin(2**0*pi*p), cos(2**0*pi*p), ..., sin(2**(L-1)*pi*p), cos(2**(L-1)*pi*p))
    Wherein p represents an arbitrary batched set of vectors computed by normalizing X between
    between -1 and 1
    """
    p = 2.*(X - X.min(-2)) / (X.max(-2) - X.min(-2)) - 1.
    L = np.arange(L, dtype=X.dtype)
    f = np.pi*2**L
    fp = (f[...,None,:]*p[...,:,None]).reshape(p.shape[:-1] + (-1,))
    return np.concatenate((
        np.cos(fp),
        np.sin(fp),
    ), axis=-1)