import numpy as np

import matplotlib.pyplot as plt
import matplotlib.animation as animation

dt = 0.005
tf = 50
dx = 0.05
xmin = -60
xmax = 60
k0 = 1
sigma0 = 3
x0 = -10
L = 2
V0 = 2
M = 2401

i = 1j

N = int((10/k0)/dt) # Round to the nearest integer number

N = 10000 # Override Number of iterations to get more data

alpha = dt / ( 4 * dx **2 )
beta = 1 + 2*i*alpha
a = -alpha*i # Subdiagonal element of L matrix

def d(j:int)->complex: # Diagonal element of L matrix. From 1 to M
    return beta + i*dt*V(x(j))/2

def V(x:float, L:float = L, V0:float = V0)->float:  # What happens when x==0 or x==L ?
    return 0 if x < 0 or x > L else V0

def x(j:int, xmin:float = xmin, dx:float = dx)->float:
    return xmin + (j-1)*dx

def t(k:int, dt:float = dt)->float: # Something is wrong here because the last element is 9.99 instead of tf (==50)
    return (k-1)*dt

def psi_0(x:float, k0_:float = k0)->complex:
    return np.power((1/( np.pi * sigma0**2 ) ), 1/4)*np.exp( i*k0_*x )*np.exp(-( (x-x0)**2 / (2*sigma0**2) ))

a_dev_cache = {}
def a_dev(j:int)->complex:
    a_dev_cache[j] = (a/d(j)) if j==1 else (a/(d(j) - a*a_dev_cache[j-1]))
    return a_dev_cache[j]

s_dev_cache = {}
def s_dev(j:int, s:np.array, a_dev:np.array)->complex:
    s_dev_cache[j] = (s[j-1]/d(j)) if j==1 else ( (s[j-1] -a*s_dev_cache[j-1] )/( d(j) -a*a_dev[(j-1)-1] ) )
    return s_dev_cache[j]

x_next_cache = {}
def x_next(j:int, s_dev:np.array, a_dev:np.array)->complex:
    x_next_cache[j] = s_dev[j-1] if j==(M) else ( s_dev[j-1] - a_dev[j-1]*x_next_cache[j+1] )
    return x_next_cache[j]

def probability_density(psi:np.array):
    return psi.conjugate()*psi

def check_psi_stability(psi: np.array, dx:float = dx)-> float:
    temp_psi__square_k = probability_density(psi=psi)
    temp_psi__square_k[0] /= 2
    return dx * (sum(temp_psi__square_k))

R = np.zeros((M,M), dtype=np.complex)

np.fill_diagonal(R, [ beta.conjugate() - i*dt*V( x(j))/2 for j in range(M) ]) # Revise this
R[ [i+1 for i in range(M-1)], [i for i in range(M-1)] ] = i*alpha #Modifying the subdiagonal
R[ [i for i in range(M-1)], [i+1 for i in range(M-1)] ] = i*alpha #Modifying the superdiagonal

L = R.conjugate()

v_x = np.array([x(j) for j in range(1, M+1)]) # Store all positions
v_t = np.array([t(k) for k in range(1, N+1)]) # Store all times

def get_all_states(k0_:float = k0, N_:int = N, save_stability=False, save_density_function=True, filename_density_function='psi.npy', filename_stability='psi_stability.npy'):

    psi_temp = np.array([psi_0(x, k0_) for x in v_x])
    psi_temp_density = probability_density(psi=psi_temp)

    v_stability = np.zeros((M))
    v_stability[0] = check_psi_stability(psi=psi_temp)

    m_psi = np.zeros((M,N_))
    m_psi[:, 0] = psi_temp_density

    for k in range(1,N_):

        s_trid = R.dot(psi_temp)

        v_a_dev = np.array([a_dev(j) for j in range(1, M)]) # Store all recursive a'
        v_s_dev = np.array([s_dev(j, s=s_trid, a_dev=v_a_dev) for j in range(1, M+1)]) # Store all recursive s'

        psi_temp = np.array([x_next(j, s_dev=v_s_dev, a_dev=v_a_dev) for j in range(M, 0, -1)])[::-1]
        psi_temp_density = probability_density(psi=psi_temp)

        m_psi[:, k] = psi_temp_density

        if k<=2400:
            v_stability[k] = check_psi_stability(psi=psi_temp)
        # stability = np.array([check_psi_stability(psi=psi_density) for psi_density in m_psi[:, ]])
    if save_stability:
        np.save(filename_stability, v_stability)

    if save_density_function:
        np.save(filename_density_function, m_psi)

    return m_psi, v_stability

def get_T_probability(psi_density_at_k:np.array, x:np.array = v_x, dx:float = dx)-> float:
    # np.where(...)... == Getting the index at which the position of the density is 0
    temp_psi__square_k = psi_density_at_k[np.where(x==2)[0][0]:]
    temp_psi__square_k[0] /= 2
    return dx * (sum(temp_psi__square_k))

def get_T_density(psi_density:np.array, x:np.array = v_x, dx:float = dx)-> np.array:
    return np.array([get_T_probability(psi_density_at_k=psi_density[:,i], x=x, dx=dx) for i in range(psi_density.shape[1])])

##############################   Sketchy method, DO NOT USE   ##############################

def get_next_state():

    v_x = np.array([x(j) for j in range(1, M+1)]) # Store all positions
    v_t = np.array([t(k) for k in range(1, N+1)]) # Store all times

    psi_current = np.array([psi_0(x) for x in v_x])
    psi_current_density = probability_density(psi=psi_current)

    # plt.plot(v_x, psi_current_density, color="g")
    # plt.show()

    s_trid = R.dot(psi_current)

    v_a_dev = np.array([a_dev(j) for j in range(1, M)]) # Store all recursive a'
    v_s_dev = np.array([s_dev(j, s=s_trid, a_dev=v_a_dev) for j in range(1, M+1)]) # Store all recursive s'
    psi_next = np.array([x_next(j, s_dev=v_s_dev, a_dev=v_a_dev) for j in range(M, 0, -1)])

    print("\n \n", psi_current.shape, v_s_dev.shape, psi_next.shape, "\n \n")
    print(check_psi_stability(psi=psi_next), "\n \n")

if __name__ == '__main__':
    get_all_states(save_stability=True, save_density_function=True)


# -*- coding: utf-8 -*-
import numpy as np

def derivada(x, y):
    """
    Devuelve la derivada de una función, considerando que en extremo izquierdo sólo se puede
    aplicar derivada forward, en extremo derecho sólo se puede aplicar derivada backward y
    entremedio puede aplicad derivada central, que es más precisa.

    param x: vector en el que se evaluará la función, tiene largo N.
    param y: vector de la función evaluada en x.
    """

    N = len(x)

    # Calculamos dx, que tendrá N-1 valores
    dx = []

    for i in range(N-1):
            dx.append(x[i + 1] - x[i])

    # OJO: Si el vector x fuese definido de forma equiespaciada, por ejemplo, con linspace
    # , basta con dx = x[1] - x[0].
    # Además, en ese caso, dx[0] = dx[N - 1] = dx y dx[i + 1] + dx[i - 1] = 2*dx

    derivada = []

    for i in range(N):

        if i == 0:                   # Extremo izquierdo: usamos derivada forward
            deriv = (y[1] - y[0]) / dx[0]
            derivada.append(deriv)

        elif i == N - 1:             # Extremo derecho: usamos derivada backward (recordar que índice de x e y llega hasta N-1
            deriv = (y[N - 1] - y[N - 2]) / dx[N - 2]
            derivada.append(deriv)

        else:                        # Centro: usamos derivada central
            deriv = (y[i + 1] - y[i - 1]) / (dx[i] + dx[i - 1])
            derivada.append(deriv)

    return derivada


import math
import matplotlib.pyplot as plt
import matplotlib.animation as ani
from scipy.integrate import solve_ivp
import sys
import numpy as np
np.set_printoptions(suppress=True)
fig, ax = plt.subplots()

#Value Initialization
global angleDegrees
angleDegrees = 0 #degreesQueried@Entry
rhoA = 1.2 #Density air
Cwa = 0.45 #Resistance air
rK = 0.08 #Radius uf ball in m
rhoK = 2700 #Density of ball
flK = 0 #surface ball
g = 9.81 #gravitation
timeSteps = 100 #for plot
timeMin = 0

def queryAngle():
    while True:
        angleDegrees = float(input("Please enter angle in degrees: "))
        try:
            angleDegrees = int(angleDegrees)
            return angleDegrees
            if (0 < angleDegrees < 90):
                break
            else:
                print("False Entry - Retry")
                continue
        except:
            print("Not possible entry - retry")

def v0Query():
    v0 = float(input("Please enter departure velocity in m/s: "))
    try:
        v0 = int(v0)
        return v0

    except:
        print("Not possible entry - retry")

def windQuery():
    wind = float(input("Please enter wind coming in x direction (-values for facing against direction of throw) "))
    try:
        wind = int(wind)
        return wind

    except:
        print("Not possible entry - retry")

def basicCalculations():
    vK = (4/3)*np.pi*(rK*rK*rK)
    mK = vK* rhoK
    global angleB
    angleB = angleDegrees * np.pi / 180
    flK = np.pi*rK**2
    global K
    K = (Cwa*rhoA*flK)/(2 * mK)
    global timeMax
    timeMax = 2*v0*math.sin(angleB)/g
    global v0x
    global v0y
    v0x = v0 * math.cos(angleB)
    v0y = v0 * math.sin(angleB)

def printGraf(arr1, arr2):
    plt.figure(1, figsize=(10, 8))
    plt.title('Toss parable with wind resistance')
    plt.xlabel('x')
    plt.ylabel('y(x)')
    plt.grid()
    plt.plot(arr1, arr2,'-')
    plt.ylim(bottom=0)
    plt.show()

def solverThrowWithWind(v, aBPhi):
    timeMax = 2 * v * math.sin(aBPhi) / g
    y = [0, v0x, 0, v0y]
    res = solve_ivp(compderiv, (0, timeMax), y, first_step=0.1, max_step=0.1)
    return [res.t, res.y[0], res.y[2]]

def compderiv(t, y ):
  nf = len(y)
  dy = np.zeros(nf)
  totvel = np.sqrt((y[1] - wind)**2 + y[3]**2)
  dy[0] = y[1]
  dy[1] = - K*totvel*(y[1]-wind)
  dy[2] = y[3]
  dy[3] = - g - K*totvel*y[3]
  return dy

b = int(input("Press: '0' for specific params.   |||   Enter '1' for Demo (wind: -10m/s, speed:30m/s, angle: 45Degrees) |||  Enter '2' for Demo (wind: 0m/s, speed:30m/s, angle: 45Degrees)"))
if (b==1):
    angleDegrees = 45
    v0 = 30
    wind = -10
    basicCalculations()
    wWind = solverThrowWithWind(v0, angleB)
    widthRes = wWind[1].max()
    heightRes = wWind[2].max()
    widthRes = round(widthRes, 2)
    heightRes = round(heightRes, 2)
    print("=================>  Length with wind Resistance " + str(widthRes) + "m  <=================")
    print("=================>  Height with wind Resistance " + str(heightRes) + "m  <=================")
    printGraf(wWind[1], wWind[2])

elif (b == 2):
    angleDegrees = 45
    v0 = 30
    wind = 0
    basicCalculations()
    wWind = solverThrowWithWind(v0, angleB)
    widthRes = wWind[1].max()
    heightRes = wWind[2].max()
    widthRes = round(widthRes, 2)
    heightRes = round(heightRes, 2)
    print("=================>  Length with no extra wind Resistance " + str(widthRes) + "m  <=================")
    print("=================>  Height with no extra wind Resistance " + str(heightRes) + "m  <=================")
    printGraf(wWind[1], wWind[2])

elif (b==0):
    angleDegrees = queryAngle()
    v0 = v0Query()
    wind = windQuery()
    basicCalculations()
    wWind = solverThrowWithWind(v0, angleB)
    widthRes = wWind[1].max()
    heightRes = wWind[2].max()
    widthRes = round(widthRes, 2)
    heightRes = round(heightRes, 2)
    print("=================>  Length with Wind Resistance " + str(widthRes) + "m  <=================")
    print("=================>  Height with Wind Resistance " + str(heightRes) + "m  <=================")
    printGraf(wWind[1], wWind[2])
    diff = widthRes - 83.41 #hardcoded due to const value & performance
    diff = round(diff, 2)
    print("Distance difference (10m/s wind distance value subtracted) is about: " + str(diff) + "m")

else:
    print("Invalid Input, exiting - Restart Script and try with correct input")
    sys.exit()


import scipy.stats as spst
import numpy as np

def d1(S, K, r, sigma, T):
    return (np.log(S/K) + (r+sigma*sigma/2)*T)/(sigma*np.sqrt(T))

def d2(S, K, r, sigma, T):
    return d1(S, K, r, sigma, T) - sigma*np.sqrt(T)

def norm_cdf(x):
    return spst.norm.cdf(x)

def norm_pdf(x):
    return spst.norm.pdf(x)

def call_price(S, K, r, sigma, T):
    return np.maximum(S - K, 0) if T == 0 else\
        S*norm_cdf(d1(S, K, r, sigma, T)) - K*np.exp(-r*T) * \
        norm_cdf(d2(S, K, r, sigma, T))

def call_delta(S, K, r, sigma, T):
    return norm_cdf(d1(S, K, r, sigma, T))

def gamma(S, K, r, sigma, T):
    return norm_pdf(d1(S, K, r, sigma, T))/(S*sigma*np.sqrt(T))

def speed(S, K, r, sigma, T):
    return - (gamma(S, K, r, sigma, T) / S) * (d1(S, K, r, sigma, T) / (sigma * np.sqrt(T)) + 1)

def vega(S, K, r, sigma, T):
    return S*norm_pdf(d1(S, K, r, sigma, T))*np.sqrt(T)

def call_theta(S, K, r, sigma, T):
    aux1 = -S*norm_pdf(d1(S, K, r, sigma, T))*sigma/(2*np.sqrt(T))
    aux2 = -r*K*np.exp(-r*T)*norm_cdf(d2(S, K, r, sigma, T))
    return aux1+aux2

def call_rho(S, K, r, sigma, T):
    return K*T*np.exp(-r*T)*norm_cdf(d2(S, K, r, sigma, T))

def put_price(S, K, r, sigma, T):
    return np.maximum(K-S, 0) if T == 0 else\
        K*np.exp(-r*T)*norm_cdf(-1*d2(S, K, r, sigma, T)) - \
        S*norm_cdf(-1*d1(S, K, r, sigma, T))

def put_delta(S, K, r, sigma, T):
    return norm_cdf(d1(S, K, r, sigma, T)) - 1

def put_theta(S, K, r, sigma, T):
    aux1 = -S*norm_pdf(d1(S, K, r, sigma, T))*sigma/(2*np.sqrt(T))
    aux2 = r*K*np.exp(-r*T)*norm_cdf(-1*d2(S, K, r, sigma, T))
    return aux1+aux2

def put_rho(S, K, r, sigma, T):
    return -K*T*np.exp(-r*T)*norm_cdf(-1*d2(S, K, r, sigma, T))


from abc import ABC, abstractmethod
import numpy as np

class Loss(ABC):
    def __init__(self):
        pass

    @abstractmethod
    def forward(self, y_pred, y_true):
        """
        :param y_pred: 2D prediction batches numpy array
        :param y_true: true values
        :return: losses value
        """
        raise NotImplementedError

    def get_loss(self, y_pred, y_true):
        """
        Get mean losses
        :param y_pred: 2D prediction batches numpy array
        :param y_true: true values
        :return: mean losses value
        """
        losses = self.forward(y_pred, y_true)
        mean_loss = np.mean(losses)
        return mean_loss

class CrossEntropy(Loss):
    def forward(self, y_pred, y_true):
        """
        Cross entropy losses
        :param y_pred: 2D prediction batches numpy array
        :param y_true: 1D numeric labels or 2D one-hot labels
        :return: losses value
        """
        y_pred = np.clip(y_pred, 1e-7, 1-1e-7)  # prevent confidence from being exactly 0
        if y_true.ndim == 1:  # numeric categorical labels
            confidences = y_pred[range(len(y_pred)), y_true]
        elif y_true.ndim == 2:  # one-hot labels
            confidences = np.sum(y_pred * y_true, axis=1)
        else:
            raise Exception
        return -np.log(confidences)  # averaged losses per batch

if __name__ == '__main__':
    softmax_outputs = np.array([[0.7, 0.1, 0.2],
                                [0.1, 0.5, 0.4],
                                [0.02, 0.9, 0.08]])
    class_targets = np.array([[1, 0, 0],
                              [0, 1, 0],
                              [0, 1, 0]])

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

    print(CrossEntropy().get_loss(softmax_outputs, class_targets))


###############    Arrays   ################

import numpy

def arrays(arr):
    # complete this function
    # use numpy.array
    return(numpy.array(arr[::-1], float))

arr = input().strip().split(' ')
result = arrays(arr)
print(result)

###############    Shape and Reshape   ################

import numpy as np

arr = input().split(' ')

arr = np.array(arr).astype(int)
print(np.reshape(arr, (3,3)))

###############    Transpose and Flatten   ################

import numpy as np

Size = list(map(int, input().split(' ')))

Matrix = np.array([list(map(int, input().split(' '))) for i in range(Size[0])])

print(np.transpose(Matrix))
print(Matrix.flatten())

###############    Concatenate   ################

import numpy as np

Size = list(map(int, input().split(' ')))

First_Matrix = np.array([list(map(int, input().split(' '))) for i in range(Size[0])])
Second_Matrix = np.array([list(map(int, input().split(' '))) for i in range(Size[1])])

print (np.concatenate((First_Matrix, Second_Matrix)))

###############    Zeros and Ones   ################

import numpy as np

N = tuple(map(int,input().strip().split()))
Zero = np.zeros(N, dtype=np.int)
One = np.ones(N, dtype=np.int)
print (Zero)
print (One)

###############    Eye and Identity   ################

import numpy as np

Size = list(map(int, input().split(' ')))
print(str(np.eye(Size[0], Size[1])).replace('1',' 1').replace('0',' 0'))

###############    Array Mathematics   ################

import numpy
N, M = list(map(int, input().split()))

Array_1 = numpy.array([input().split() for _ in range(N)], int)
Array_2 = numpy.array([input().split() for _ in range(N)], int)

print(*[eval('Array_1'+i+'Array_2') for i in ['+','-','*','//','%','**']], sep='\n')

###############    Floor, Ceil and Rint   ################

import numpy
numpy.set_printoptions(sign=' ')

The_Array = numpy.array(list(map(float, input().split(' '))))
print (numpy.floor(The_Array))
print (numpy.ceil(The_Array))
print (numpy.rint(The_Array))

###############    Sum and Prod   ################

import numpy
N,M = map(int,input().split())
The_Array = numpy.array([input().split() for i in range(N)], int)
print(numpy.prod((numpy.sum(The_Array,axis=0))))

###############    Min and Max   ################

import numpy as np
Size = list(map(int, input().split(' ')))

Matrix = np.array([list(map(int, input().split(' '))) for i in range(Size[0])])
print(np.max((np.min(Matrix, axis = 1))))

###############    Mean, Var, and Std   ################

import numpy
numpy.set_printoptions(legacy='1.13')

Size = list(map(int, input().split(' ')))

Matrix = numpy.array([list(map(int, input().split(' '))) for i in range(Size[0])])
print(numpy.mean(Matrix, axis = 1))
print(numpy.var(Matrix, axis = 0))
print(numpy.std(Matrix))

###############    Dot and Cross  ################

import numpy as np
N=int(input())
First_Arr,Second_Arr=[(np.array([list(map(int,input().split())) for _ in range(N)])) for _ in range(2)]
print (np.dot(First_Arr,Second_Arr))

###############    Inner and Outer  ################

import numpy
numpy.set_printoptions(legacy='1.13')

First_Mtx = numpy.array(list(map(int, input().split(' '))))
Second_Mtx = numpy.array(list(map(int, input().split(' '))))

print(numpy.inner(First_Mtx, Second_Mtx))
print(numpy.outer(First_Mtx, Second_Mtx))

###############    Polynomials  ################

import numpy

N = list(map(float,input().split()));
M = input();
print(numpy.polyval(N,int(M)));

###############    Linear Algebra  ################

import numpy
numpy.set_printoptions(legacy='1.13')
Size = int(input())
Matrix = numpy.array([list(map(float, input().split(' '))) for i in range(Size)])

print(numpy.linalg.det(Matrix))


# from Numerical Methods in Engineering With Python

import numpy as np
from math import sqrt

def RK4(F,x,y,xStop,h):
    def run_kut4(F,x,y,h):
        # Computes increment of y from Eqs. (7.10)
        K0 = h*F(x,y)
        K1 = h*F(x + h/2.0, y + K0/2.0)
        K2 = h*F(x + h/2.0, y + K1/2.0)
        K3 = h*F(x + h, y + K2)
        return (K0 + 2.0*K1 + 2.0*K2 + K3)/6.0
    X = []
    Y = []
    X.append(x)
    Y.append(y)
    while x < xStop:
        h = min(h,xStop - x)
        y = y + run_kut4(F,x,y,h)
        # Runge-Kutta Methods
        x = x + h
        X.append(x)
        Y.append(y)
    return array(X),array(Y)

def _rkf45(F, x, y, h):
    # Runge-Kutta-Fehlberg formulas
    C = [37./378, 0., 250./621, 125./594, 0., 512./1771]
    D = [2825./27648, 0., 18575./48384, 13525./55296, 277./14336, 1./4]
    n = len(y)
    K = np.zeros((6,n),dtype=np.float64)
    K[0] = h*F(x,y)
    K[1] = h*F(x + 1./5*h, y + 1./5*K[0])
    K[2] = h*F(x + 3./10*h, y + 3./40*K[0] + 9./40*K[1])
    K[3] = h*F(x + 3./5*h, y + 3./10*K[0]- 9./10*K[1] + 6./5*K[2])
    K[4] = h*F(x + h, y - 11./54*K[0] + 5./2*K[1] - 70./27*K[2] + 35./27*K[3])
    K[5] = h*F(x + 7./8*h, y + 1631./55296*K[0] + 175./512*K[1] + 575./13824*K[2] + 44275./110592*K[3] + 253./4096*K[4])
    # Initialize arrays {dy} and {E}
    E  = np.zeros((n),dtype=np.float64)
    dy = np.zeros((n),dtype=np.float64)
    # Compute solution increment {dy} and per-step error {E}
    for i in range(6):
        dy = dy + C[i]*K[i]
        E  = E + (C[i] - D[i])*K[i]
    # Compute RMS error e
    e = sqrt(sum(E**2)/n)
    return dy,e

def RKF45(F, x, y, xStop, h, tol=1.0e-6):

    X = []
    Y = []
    X.append(x)
    Y.append(y)
    stopper = 0 # Integration stopper(0 = off, 1 = on)
    for i in range(10000):
        dy,e = _rkf45(F,x,y,h)
        # Accept integration step if error e is within tolerance
        if e <= tol:
            y = y + dy
            x = x + h
            X.append(x)
            Y.append(y)
            # Stop if end of integration range is reached
            if stopper == 1: break
        # Compute next step size from Eq. (7.24)
        if e != 0.0:
            hNext = 0.9*h*(tol/e)**0.2
        else: hNext = h
        # Check if next step is the last one; is so, adjust h
        if (h > 0.0) == ((x + hNext) >= xStop):
            hNext = xStop - x
            stopper = 1
        h = hNext
    return array(X),array(Y)


import math
import struct
import numpy as np

def binary(number: float):
    """Print the mantissa and exponent of a float.

    Parameters
    ----------
    number : float
        A floating point number

    Returns
    -------
    None : NoneType
        Returns nothing, prints output.

    Examples
    --------
    >>> binary(1.25)
     Decimal: 1.25 x 2^0
      Binary: 1.01 x 2^0

        Sign: 0 (+)
    Mantissa: 01 (0.25)
    Exponent: 0 (0)
    """
    packed = struct.pack("!d", float(number))
    integers = [c for c in packed]
    binaries = [bin(i) for i in integers]
    stripped_binaries = [s.replace("0b", "") for s in binaries]
    padded = [s.rjust(8, "0") for s in stripped_binaries]
    final = "".join(padded)
    assert len(final) == 64, "something went wrong..."
    sign, exponent_plus_1023, mantissa = final[0], final[1:12], final[12:]
    sign_str = "" if int(sign) == 0 else "-"
    mantissa_base10 = (
        int(mantissa, 2) / 2 ** 52
    )  # shift decimal point from end of binary string to beginning of it
    mantissa_base10_str = str(mantissa_base10)[2:]  # throw away the leading "0."
    mantissa_index = mantissa.rfind("1")
    mantissa_index = 0 if mantissa_index == -1 else mantissa_index
    exponent_base10 = int(exponent_plus_1023, 2) - 1023
    print(f" Decimal: {sign_str}1.{mantissa_base10_str} x 2^{exponent_base10}")
    print(
        f"  Binary: {sign_str}1.{mantissa[:mantissa_index + 1]} x 2^{exponent_base10:b}"
    )
    print()
    print(f"    Sign: {sign} ({'+' if sign == '0' else '-'})")
    print(f"Mantissa: {mantissa[:mantissa_index + 1]} ({mantissa_base10})")
    print(f"Exponent: {exponent_base10:b} ({exponent_base10})")

def calc_spacing(number: float):
    """Calculate spacing at the given float."""
    return np.nextafter(number, 2 * number) - number

def float_rep(num):
    if not isinstance(num, float):
        raise ValueError("Please enter a floating point number.")
    sig_digits = 52 + abs(math.frexp(num)[1])
    num_str = f"{num}"
    num_str_float = f"{num:.{sig_digits}f}"
    print(f"You entered: {num}")
    if sum(int(_) for _ in num_str_float[len(num_str) :]) > 0:
        print(f"Which is inexactly stored as: {num_str_float}")
    else:
        print(f"Which is exactly stored as: {num}")


## M-Estimators for Robust Linear Modeling

from __future__ import print_function
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

import statsmodels.api as sm
from statsmodels.compat.pandas import sort_values

# * An M-estimator minimizes the function
#
# $$Q(e_i, \rho) = \sum_i~\rho \left (\frac{e_i}{s}\right )$$
#
# where $\rho$ is a symmetric function of the residuals
#
# * The effect of $\rho$ is to reduce the influence of outliers
# * $s$ is an estimate of scale.
# * The robust estimates $\hat{\beta}$ are computed by the iteratively re-weighted least squares algorithm

# * We have several choices available for the weighting functions to be used

norms = sm.robust.norms

def plot_weights(support, weights_func, xlabels, xticks):
    fig = plt.figure(figsize=(12,8))
    ax = fig.add_subplot(111)
    ax.plot(support, weights_func(support))
    ax.set_xticks(xticks)
    ax.set_xticklabels(xlabels, fontsize=16)
    ax.set_ylim(-.1, 1.1)
    return ax

#### Andrew's Wave

help(norms.AndrewWave.weights)

a = 1.339
support = np.linspace(-np.pi*a, np.pi*a, 100)
andrew = norms.AndrewWave(a=a)
plot_weights(support, andrew.weights, ['$-\pi*a$', '0', '$\pi*a$'], [-np.pi*a, 0, np.pi*a]);

#### Hampel's 17A

help(norms.Hampel.weights)

c = 8
support = np.linspace(-3*c, 3*c, 1000)
hampel = norms.Hampel(a=2., b=4., c=c)
plot_weights(support, hampel.weights, ['3*c', '0', '3*c'], [-3*c, 0, 3*c]);

#### Huber's t

help(norms.HuberT.weights)

t = 1.345
support = np.linspace(-3*t, 3*t, 1000)
huber = norms.HuberT(t=t)
plot_weights(support, huber.weights, ['-3*t', '0', '3*t'], [-3*t, 0, 3*t]);

#### Least Squares

help(norms.LeastSquares.weights)

support = np.linspace(-3, 3, 1000)
lst_sq = norms.LeastSquares()
plot_weights(support, lst_sq.weights, ['-3', '0', '3'], [-3, 0, 3]);

#### Ramsay's Ea

help(norms.RamsayE.weights)

a = .3
support = np.linspace(-3*a, 3*a, 1000)
ramsay = norms.RamsayE(a=a)
plot_weights(support, ramsay.weights, ['-3*a', '0', '3*a'], [-3*a, 0, 3*a]);

#### Trimmed Mean

help(norms.TrimmedMean.weights)

c = 2
support = np.linspace(-3*c, 3*c, 1000)
trimmed = norms.TrimmedMean(c=c)
plot_weights(support, trimmed.weights, ['-3*c', '0', '3*c'], [-3*c, 0, 3*c]);

#### Tukey's Biweight

help(norms.TukeyBiweight.weights)

c = 4.685
support = np.linspace(-3*c, 3*c, 1000)
tukey = norms.TukeyBiweight(c=c)
plot_weights(support, tukey.weights, ['-3*c', '0', '3*c'], [-3*c, 0, 3*c]);

#### Scale Estimators

# * Robust estimates of the location

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

# * The mean is not a robust estimator of location

x.mean()

# * The median, on the other hand, is a robust estimator with a breakdown point of 50%

np.median(x)

# * Analagously for the scale
# * The standard deviation is not robust

x.std()

# Median Absolute Deviation
#
# $$ median_i |X_i - median_j(X_j)|) $$

# Standardized Median Absolute Deviation is a consistent estimator for $\hat{\sigma}$
#
# $$\hat{\sigma}=K \cdot MAD$$
#
# where $K$ depends on the distribution. For the normal distribution for example,
#
# $$K = \Phi^{-1}(.75)$$

stats.norm.ppf(.75)

print(x)

sm.robust.scale.mad(x)

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

# * The default for Robust Linear Models is MAD
# * another popular choice is Huber's proposal 2

np.random.seed(12345)
fat_tails = stats.t(6).rvs(40)

kde = sm.nonparametric.KDE(fat_tails)
kde.fit()
fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111)
ax.plot(kde.support, kde.density);

print(fat_tails.mean(), fat_tails.std())

print(stats.norm.fit(fat_tails))

print(stats.t.fit(fat_tails, f0=6))

huber = sm.robust.scale.Huber()
loc, scale = huber(fat_tails)
print(loc, scale)

sm.robust.mad(fat_tails)

sm.robust.mad(fat_tails, c=stats.t(6).ppf(.75))

sm.robust.scale.mad(fat_tails)

#### Duncan's Occupational Prestige data - M-estimation for outliers

from statsmodels.graphics.api import abline_plot
from statsmodels.formula.api import ols, rlm

prestige = sm.datasets.get_rdataset("Duncan", "car", cache=True).data

print(prestige.head(10))

fig = plt.figure(figsize=(12,12))
ax1 = fig.add_subplot(211, xlabel='Income', ylabel='Prestige')
ax1.scatter(prestige.income, prestige.prestige)
xy_outlier = prestige.loc['minister'][['income','prestige']]
ax1.annotate('Minister', xy_outlier, xy_outlier+1, fontsize=16)
ax2 = fig.add_subplot(212, xlabel='Education',
                           ylabel='Prestige')
ax2.scatter(prestige.education, prestige.prestige);

ols_model = ols('prestige ~ income + education', prestige).fit()
print(ols_model.summary())

infl = ols_model.get_influence()
student = infl.summary_frame()['student_resid']
print(student)

print(student.loc[np.abs(student) > 2])

print(infl.summary_frame().loc['minister'])

sidak = ols_model.outlier_test('sidak')
sort_values(sidak, 'unadj_p', inplace=True)
print(sidak)

fdr = ols_model.outlier_test('fdr_bh')
sort_values(fdr, 'unadj_p', inplace=True)
print(fdr)

rlm_model = rlm('prestige ~ income + education', prestige).fit()
print(rlm_model.summary())

print(rlm_model.weights)

#### Hertzprung Russell data for Star Cluster CYG 0B1 - Leverage Points

# * Data is on the luminosity and temperature of 47 stars in the direction of Cygnus.

dta = sm.datasets.get_rdataset("starsCYG", "robustbase", cache=True).data

from matplotlib.patches import Ellipse
fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111, xlabel='log(Temp)', ylabel='log(Light)', title='Hertzsprung-Russell Diagram of Star Cluster CYG OB1')
ax.scatter(*dta.values.T)
# highlight outliers
e = Ellipse((3.5, 6), .2, 1, alpha=.25, color='r')
ax.add_patch(e);
ax.annotate('Red giants', xy=(3.6, 6), xytext=(3.8, 6),
            arrowprops=dict(facecolor='black', shrink=0.05, width=2),
            horizontalalignment='left', verticalalignment='bottom',
            clip_on=True, # clip to the axes bounding box
            fontsize=16,
     )
# annotate these with their index
for i,row in dta.loc[dta['log.Te'] < 3.8].iterrows():
    ax.annotate(i, row, row + .01, fontsize=14)
xlim, ylim = ax.get_xlim(), ax.get_ylim()

from IPython.display import Image
Image(filename='star_diagram.png')

y = dta['log.light']
X = sm.add_constant(dta['log.Te'], prepend=True)
ols_model = sm.OLS(y, X).fit()
abline_plot(model_results=ols_model, ax=ax)

rlm_mod = sm.RLM(y, X, sm.robust.norms.TrimmedMean(.5)).fit()
abline_plot(model_results=rlm_mod, ax=ax, color='red')

# * Why? Because M-estimators are not robust to leverage points.

infl = ols_model.get_influence()

h_bar = 2*(ols_model.df_model + 1 )/ols_model.nobs
hat_diag = infl.summary_frame()['hat_diag']
hat_diag.loc[hat_diag > h_bar]

sidak2 = ols_model.outlier_test('sidak')
sort_values(sidak2, 'unadj_p', inplace=True)
print(sidak2)

fdr2 = ols_model.outlier_test('fdr_bh')
sort_values(fdr2, 'unadj_p', inplace=True)
print(fdr2)

# * Let's delete that line

del ax.lines[-1]

weights = np.ones(len(X))
weights[X[X['log.Te'] < 3.8].index.values - 1] = 0
wls_model = sm.WLS(y, X, weights=weights).fit()
abline_plot(model_results=wls_model, ax=ax, color='green')

# * MM estimators are good for this type of problem, unfortunately, we don't yet have these yet.
# * It's being worked on, but it gives a good excuse to look at the R cell magics in the notebook.

yy = y.values[:,None]
xx = X['log.Te'].values[:,None]

get_ipython().magic(u'load_ext rmagic')

get_ipython().magic(u'R library(robustbase)')
get_ipython().magic(u'Rpush yy xx')
get_ipython().magic(u'R mod <- lmrob(yy ~ xx);')
get_ipython().magic(u'R params <- mod$coefficients;')
get_ipython().magic(u'Rpull params')

get_ipython().magic(u'R print(mod)')

print(params)

abline_plot(intercept=params[0], slope=params[1], ax=ax, color='green')

#### Exercise: Breakdown points of M-estimator

np.random.seed(12345)
nobs = 200
beta_true = np.array([3, 1, 2.5, 3, -4])
X = np.random.uniform(-20,20, size=(nobs, len(beta_true)-1))
# stack a constant in front
X = sm.add_constant(X, prepend=True) # np.c_[np.ones(nobs), X]
mc_iter = 500
contaminate = .25 # percentage of response variables to contaminate

all_betas = []
for i in range(mc_iter):
    y = np.dot(X, beta_true) + np.random.normal(size=200)
    random_idx = np.random.randint(0, nobs, size=int(contaminate * nobs))
    y[random_idx] = np.random.uniform(-750, 750)
    beta_hat = sm.RLM(y, X).fit().params
    all_betas.append(beta_hat)

all_betas = np.asarray(all_betas)
se_loss = lambda x : np.linalg.norm(x, ord=2)**2
se_beta = map(se_loss, all_betas - beta_true)

##### Squared error loss

np.array(se_beta).mean()

all_betas.mean(0)

beta_true

se_loss(all_betas.mean(0) - beta_true)

import numpy,from scipy,import statsmodels,from statsmodels


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

warnings.filterwarnings('ignore')

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

#Reading file
data = np.genfromtxt(path, delimiter=",", skip_header=1)
print(data.shape)
census=np.concatenate((data,new_record),axis=0)
print(census.shape)
#age
age=census[:,0]
max_age=age.max()
min_age=age.min()
age_mean=age.mean()
age_std=age.std()
print('Max Age=',max_age)
print('Min Age=',min_age)
print('Mean of ages=',age_mean)
print('Standard deviation of ages=',age_std)
#Race
race=census[:,2]
mask_0=race==0
race_0=np.array(race[mask_0])
len_0=len(race_0)
print('No. of Person in Race 0=',len_0)
mask_1=race==1
race_1=np.array(race[mask_1])
len_1=len(race_1)
print('No. of Person in Race 1=',len_1)
mask_2=race==2
race_2=np.array(race[mask_2])
len_2=len(race_2)
print('No. of Person in Race 2=',len_2)
mask_3=race==3
race_3=np.array(race[mask_3])
len_3=len(race_3)
print('No. of Person in Race 3=',len_3)
mask_4=race==4
race_4=np.array(race[mask_4])
len_4=len(race_4)
print('No. of Person in Race 4=',len_4)
len_of_each_race=np.array([len_0,len_1,len_2,len_3,len_4])
print(len_of_each_race)
minority_race=np.argmin(len_of_each_race, axis=0)
print('Minority race=',minority_race)
#senior_Citizens
senior_citizens=census[census[:,0]>60]
senior_citizens_len=len(senior_citizens)
working_hours_sum=sum(senior_citizens[:,6])
print('working hours sum=',working_hours_sum)
avg_working_hours=(working_hours_sum/senior_citizens_len)
print('average working hours',avg_working_hours)
#Income based on education: true or false
high=census[census[:,1]>10]
low=census[census[:,1]<=10]
avg_pay_high=np.mean(high[:,7])
avg_pay_low=np.mean(low[:,7])
print('Avg pay high=',avg_pay_high)
print('Avg pay low=',avg_pay_low)
compare=np.array_equal(avg_pay_high,avg_pay_low)
print(compare)


import math
import numpy as np

from metod_alg import objective_functions as mt_obj

def test_d_2():
    """Checks rotation matrix for d = 2."""
    rs = 10
    d = 2
    np.random.seed(rs)
    num = 3
    theta = np.random.uniform(0, 2 * math.pi)
    rotation = np.identity(d)

    rotation[0, 0] = math.cos(theta)
    rotation[0, 1] = - math.sin(theta)
    rotation[1, 0] = math.sin(theta)
    rotation[1, 1] = math.cos(theta)

    np.random.seed(rs)
    rotation_function = mt_obj.calculate_rotation_matrix(d, num)
    assert(np.all(rotation == rotation_function))

def test_d_3():
    """
    Checks rotation matrix for d = 3 and number of
    rotations = 3.
    """
    rs = 20
    d = 3
    np.random.seed(rs)
    number_rotations = 3

    theta_1 = np.random.uniform(0, 2 * math.pi)
    rotation_1 = np.identity(d)
    pos_1 = np.random.randint(0, d - 1)
    pos_2 = np.random.randint(pos_1 + 1, d)
    rotation_1[pos_1, pos_1] = math.cos(theta_1)
    rotation_1[pos_1, pos_2] = - math.sin(theta_1)
    rotation_1[pos_2, pos_1] = math.sin(theta_1)
    rotation_1[pos_2, pos_2] = math.cos(theta_1)

    theta_2 = np.random.uniform(0, 2 * math.pi)
    rotation_2 = np.identity(d)
    pos_3 = np.random.randint(0, d - 1)
    pos_4 = np.random.randint(pos_3 + 1, d)
    rotation_2[pos_3, pos_3] = math.cos(theta_2)
    rotation_2[pos_3, pos_4] = - math.sin(theta_2)
    rotation_2[pos_4, pos_3] = math.sin(theta_2)
    rotation_2[pos_4, pos_4] = math.cos(theta_2)

    theta_3 = np.random.uniform(0, 2 * math.pi)
    rotation_3 = np.identity(d)
    pos_5 = np.random.randint(0, d - 1)
    pos_6 = np.random.randint(pos_5 + 1, d)
    rotation_3[pos_5, pos_5] = math.cos(theta_3)
    rotation_3[pos_5, pos_6] = - math.sin(theta_3)
    rotation_3[pos_6, pos_5] = math.sin(theta_3)
    rotation_3[pos_6, pos_6] = math.cos(theta_3)

    final_rotation = rotation_1 @ rotation_2 @ rotation_3
    np.random.seed(rs)
    rotation_function = (mt_obj.calculate_rotation_matrix
                         (d, number_rotations))
    assert(np.all(final_rotation == rotation_function))


#
# Fourier Series for f(x) = abs(x) for -pi <= x <= pi
# 06_fou/Fourier_series.py
#
# (c) Dr. Yves J. Hilpisch
# Derivatives Analytics with Python
#
import numpy as np
import matplotlib.pyplot as plt

#
# Fourier series function
#

def fourier_series(x, n):
    ''' Generate Fourier Series from vector x for f(x) = abs(x)
    of order n.

    Parameters
    ==========
    x : float or array of floats
        input numbers
    n : int
        order of Fourier series

    Returns
    =======
    fourier_values : float or array of floats
        numbers according to Fourier series approximation
    '''
    fourier_values = np.pi / 2
    for i in range(1, n + 1):
        fourier_values += ((2 * ((-1) ** i - 1)) /
                           (np.pi * i ** 2) * np.cos(i * x))
    return fourier_values

def plot_fourier_series():
    # Data Generation
    x = np.linspace(-np.pi, np.pi, 100)
    y1 = fourier_series(x, 1)
    y2 = fourier_series(x, 5)

    # Data Plotting
    plt.figure(figsize=(10, 5))
    plt.subplot(121)
    plt.plot(x, abs(x), 'b', label='$f(x) = |x|$')
    plt.plot(x, y1, 'r-.', lw=3.0, label='Fourier series $n=1$')
    plt.legend(loc=9)
    plt.subplot(122)
    plt.plot(x, abs(x), 'b', label='$f(x) = |x|$')
    plt.plot(x, y2, 'r-.', lw=3.0, label='Fourier series $n=5$')
    plt.legend(loc=9)


#encoding: utf-8

import numpy as np

#exercice 01

s1=np.array((168, 398, 451, 337, 186, 232, 262, 349, 189, 204, 220, 220, 207, 239, 259, 258,
242, 331, 251, 323, 106, 1055, 170))
print(f"Serie 1 = {s1}")
s2=np.array((168, 400, 451, 300, 186, 200, 262, 349, 189, 204, 220, 220, 207, 239, 259, 258,
242, 331, 251, 180, 106, 1055, 200))
print(f"Serie 2 = {s2}")
#Euclidean Distance
dist=np.linalg.norm(s1-s2)
print(f"Euclidean Distance between S1 and S2 = {dist}")
#Mean
s_mean=np.mean(np.array([s1,s2]), axis=0)
print(f"Mean between S1 and S2 = {s_mean}")
#Max
s_max=np.fmax(s1,s2)
print(f"Maximum values per instant in S1 and S2 = {s_max}")
#Min
s_min=np.fmin(s1,s2)
print(f"Minimum values per instant in S1 and S2 = {s_min}")


#! /usr/bin/python
# -*- coding: utf-8 -*-
u"""
Finite Horizon Optimal Control

author Atsushi Sakai
"""

import numpy as np
import scipy.linalg as la

def CalcFiniteHorizonOptimalInput(A,B,Q,R,P,N,x0):
    u"""
    Calc Finite Horizon Optimal Input

    # TODO optimize
    in: see below

    min x'Px+sum(x'Qx+u'Ru)
    s.t xk+1=Axk+Bu

    out: uopt optimal input
    """
    #  print("CalcFiniteHorizonOptimalInput start")

    # data check
    if A.shape[1] is not x0.shape[0]:
        print("Data Error: A's col == x0's row")
        print("A shape:")
        print(A.shape)
        print("x0 shape:")
        print(x0.shape)
        return None
    elif B.shape[1] is not R.shape[1]:
        print("Data Error: B's col == R's row")
        print("B shape:")
        print(B.shape)
        print("R's shape:")
        print(R.shape)
        return None

    sx=np.eye(A.ndim)
    su=np.zeros((A.ndim,B.shape[1]*N))

    #calc sx,su
    for i in range(N):
        #generate sx
        An=np.linalg.matrix_power(A, i+1)
        sx=np.r_[sx,An]

        #generate su
        tmp=None
        for ii in range(i+1):
            tm=np.linalg.matrix_power(A, ii)*B
            if tmp is None:
                tmp=tm
            else:
                tmp =np.c_[tm,tmp]

        for ii in np.arange(i,N-1):
            tm=np.zeros(B.shape)
            if tmp is None:
                tmp=tm
            else:
                tmp =np.c_[tmp,tm]

        su=np.r_[su,tmp]

    tm1=np.eye(N+1)
    tm1[N,N]=0
    tm2=np.zeros((N+1,N+1))
    tm2[N,N]=1
    Qbar=np.kron(tm1,Q)+np.kron(tm2,P)
    Rbar=np.kron(np.eye(N),R)

    uopt=-(su.T*Qbar*su+Rbar).I*su.T*Qbar*sx*x0
    #  print(uBa)
    costBa=x0.T*(sx.T*Qbar*sx-sx.T*Qbar*su*(su.T*Qbar*su+Rbar).I*su.T*Qbar*sx)*x0
    #  print(costBa)

    return uopt

if __name__ == '__main__':
    import matplotlib.pyplot as plt
    A=np.matrix([[0.77,-0.35],[0.49,0.91]])
    print("A:")
    print(A)
    B=np.matrix([0.04,0.15]).T
    print("B:")
    print(B)
    x0=np.matrix([1,-1]).T
    print("x0")
    print(x0)
    Q=np.matrix([[500,0.0],[0.0,100]])
    print("Q")
    print(Q)
    R=np.matrix([1.0])
    print("R")
    print(R)
    P=np.matrix([[1500,0.0],[0.0,100]])
    print("P")
    print(P)
    N=20#Number of horizon

    uopt=CalcFiniteHorizonOptimalInput(A,B,Q,R,P,N,x0)

    #simulation
    u_history=[]
    x1_history=[]
    x2_history=[]
    x=x0
    for u in uopt:
        u_history.append(float(u[0]))
        x=A*x+B*u
        x1_history.append(float(x[0]))
        x2_history.append(float(x[1]))

    plt.plot(u_history,"-r",label="input")
    plt.plot(x1_history,"-g",label="x1")
    plt.plot(x2_history,"-b",label="x2")
    plt.grid(True)
    plt.legend()
    plt.show()


"""Valuation of European call options
in Black-Scholes-Merton model
incl. vega function and implied volatility estimation
"""

#
# Author: Yehui He <yehui.he@hotmail.com>
# License: Apache-2.0 License

def bsm_call_value(S0, K, T, r, sigma):
    """Valuation of European call option in BSM model.
    Analytical formula.
    Parameters
    ==========
    S0 : float
        initial stock/index level
    K : float
        strike price
    T : float
    maturity date (in year fractions)
    r : float
        constant risk-free short rate
    sigma : float
        volatility factor in diffusion term

    Returns
    =======
    value : float
        present value of the European call option
    """
    from math import log, sqrt, exp
    from scipy import stats

    S0 = float(S0)
    d1 = (log(S0 / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * sqrt(T))
    d2 = (log(S0 / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * sqrt(T))
    # stats.norm.cdf --> cumulative distribution function
    # for normal distribution
    value = (S0 * stats.norm.cdf(d1, 0.0, 1.0) -
             K * exp(-r * T) * stats.norm.cdf(d2, 0.0, 1.0))
    return value

def bsm_vega(S0, K, T, r, sigma):
    """Vega of European option in BSM model.

    Parameters
    ----------
    S0 : float
        initial stock/index level

    K : float
        Strick price

    T : float
        maturity date (in year fractions)

    r : float
        constant risk-free short rate

    sigma : float
        volatility factor in diffusion term

    Returns
    -------
    vega : float
        partial derivative of BSM formula with respect
        to sigma, i.e. vega
    """
    from math import log, sqrt
    from scipy import stats

    S0 = float(S0)

    d1 = (log(S0 / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * sqrt(T))
    vega = S0 * stats.norm.pdf(d1, 0.0, 1.0) * sqrt(T)
    return vega

def bsm_call_imp_vol(S0, K, T, r, C0, sigma_est, it=100):
    """Implied volatility of European call option in BSM model.

    Parameters
    ==========
    S0: float
        initial stock/index level
    K: float
        strike price
    T: float
        maturity date (in year fractions)
    r: float
        constant risk-free short rate
    sigma_est: float
        estimate of impl. volatility
    it: integer
        number of iterations
    Returns
    =======
    simga_est: float
        numerically estimated implied volatility
    """
    for i in range(it):
        sigma_est -= ((bsm_call_value(S0, K, T, r, sigma_est) - C0) /
                      bsm_vega(S0, K, T, r, sigma_est))
    return sigma_est


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

np.random.seed(3)
x = np.linspace(-np.pi, np.pi, 201)
y = np.sin(x)

'''
y_predicted = slope * x_input + intercept
slope = sum(
			(x(i) - mean(x)) * (y(i) - mean(y))
		)
		/
		sum(
			(x(i) - mean(x))^2
		)
intercept = mean(y) - slope * mean(x)
'''

print x.shape

mean_x = x.mean()
mean_y = y.mean()

print mean_x, mean_y

slope_num = 0.0
slope_den = 0.0
for i in range(x.shape[0]):
	slope_num += (x[i] - mean_x) * (y[i] - mean_y)
	slope_den += (x[i] - mean_x) * (x[i] - mean_x)

slope = slope_num/slope_den

intercept = mean_y - slope * mean_x

print slope, intercept

plt.plot(x, y, 'o', label='original data')
plt.plot(x, intercept + slope*x, 'r', label='fitted line')
plt.legend()
plt.show()


import numpy as np
from scipy import stats
from typing import Tuple, Union
from warnings import warn

def pearson_with_confidence(
    x: np.ndarray, y: np.ndarray, α: float
) -> Tuple[float, float, float]:
    """
    Calculate the Pearson r coefficient and confidence intervals.

    Parameters
    ----------
    x - array of the first dataset
    y - array of the second dataset
    α - 1 - α is the confidence level.
        E.g. for 95% confidence, alpha = 0.05

    Returns
    -------
    Pearson r, r-95%, r+95%

    """
    r, p = stats.pearsonr(x, y)
    n = x.size
    # two-tailed significance
    t_statistic = stats.t.ppf(1.0 - α / 2.0, n - 1)
    # Fisher transform
    F = np.arctanh(r)
    F_min = F - (t_statistic / np.sqrt(n - 3))
    F_plus = F + (t_statistic / np.sqrt(n - 3))
    # Inverse Fisher transform
    r_min = np.tanh(F_min)
    r_plus = np.tanh(F_plus)

    return r, r_min, r_plus

def array_rmse(x1: np.ndarray, x2: np.ndarray) -> float:
    """Returns the root mean squared error between two arrays."""
    return np.sqrt(((x1 - x2) ** 2).mean())

def array_mae(x1: np.ndarray, x2: np.ndarray) -> float:
    """Returns the mean_absolute error between two arrays."""
    return np.asscalar((np.abs(x1 - x2)).mean())

def wrap_pearsonr(x1: np.ndarray, x2: np.ndarray) -> float:
    """Return only pearson r, not the probability."""
    return stats.pearsonr(x1, x2)[0]

def msd(x1: float, x2: float) -> float:
    """Returns the mean squared deviation between two numbers."""
    return np.mean((x1 - x2) ** 2)

def array_median_error(x1: np.ndarray, x2: np.ndarray) -> float:
    """Return the median deviation between numbers in the array."""
    return np.asscalar((np.abs(x1 - x2)).median())

def absolute_loss(x1: float, x2: float):
    """Returns the absolute difference between two numbers."""
    return np.abs(x1 - x2)

def squared_loss(x1: float, x2: float):
    """Returns the squared difference between two numbers"""
    return (x1 - x2) ** 2

def rmsd_curve(curve1: np.ndarray, curve2: np.ndarray, *args) -> float:
    """Calculate the RMSD between two curves."""
    return np.linalg.norm(curve2 - curve1) / np.sqrt(curve2.size)

def msd_curve(curve1: np.ndarray, curve2: np.ndarray) -> float:
    """Calculate the MSD between two curves."""
    return np.power(array_rmse(curve2, curve1), 2)

def area_between_curves(curve1: np.ndarray, curve2: np.ndarray, dx=0.1):
    """Calculate area between curves using chunks of size dx."""
    diff = np.abs(curve1 - curve2)
    area = diff * dx

    return np.sum(area)

def area_curve_vectorized(curve1, curve2, dx, pHdim=1):
    diff = np.abs(curve1 - curve2)
    if len(curve1.shape) < 2:
        return np.trapz(diff, dx=dx, axis=0)
    else:
        return np.trapz(diff, dx=dx, axis=pHdim)

def rmsd_curve_vectorized(
    curve1: np.ndarray, curve2: np.ndarray, *args, pHdim=1
) -> float:
    """Calculate the RMSD between two sets curves."""
    if len(curve1.shape) < 2:
        return np.linalg.norm(curve2 - curve1, axis=0) / np.sqrt(curve2.shape[0])
    else:
        return np.linalg.norm(curve2 - curve1, axis=pHdim) / np.sqrt(
            curve2.shape[pHdim]
        )

def sum_of_squares(curve1: np.ndarray, curve2: np.ndarray, *args):
    """Sum of the squared differences between two curves. Ignore extra arguments"""
    diff = np.square(curve1 - curve2)
    return np.sum(diff)

def maximum_deviation(curve1: np.ndarray, curve2: np.ndarray, *args):
    """Calculate the largest deviation for any two curves. Ignores extra arguments"""
    diff = curve1 - curve2
    # Return the largest deviation in absolute terms (without losing sign)
    return max(diff.min(), diff.max(), key=abs)

def median_absolute_deviation(curve1: np.ndarray, curve2: np.ndarray, *args):
    """Calculate the median deviation."""
    diff = np.abs(curve1 - curve2)
    return np.median(diff)

def mean_absolute_deviation(curve1: np.ndarray, curve2: np.ndarray, *args):
    """Calculate the mean deviation."""
    diff = np.abs(curve1 - curve2)
    return np.mean(diff)

def gaussian_bootstrap_sample(
    mean: Union[np.ndarray, float], sd: float, bias: float
) -> Union[np.ndarray, float]:
    """Return a sample from a Gaussian bootstrap distribution.

    Parameters
    ----------
    mean - average value of the bootstrap distribution
    sd - standard deviation of the boostrap distribution
    bias - bias of the bootstrap distribution.
    """
    return np.random.normal(mean, sd)

class BootstrapDistribution:
    """Represents a bootstrap distribution, and allows calculation of useful statistics."""

    def __init__(self, sample_estimate: float, bootstrap_estimates: np.array) -> None:
        """
        Parameters
        ----------
        sample_estimate - estimated value from original sample
        bootstrap_estimates - estimated values from bootstrap samples
        """
        self._sample = sample_estimate
        self._bootstrap = bootstrap_estimates
        # approximation of δ = X - μ
        # denoted as δ* = X* - X
        self._delta = bootstrap_estimates - sample_estimate
        self._significance: int = 16
        return

    def __float__(self):
        return float(self._sample)

    def empirical_bootstrap_confidence_intervals(
        self, percent: float
    ) -> Tuple[float, float, float]:
        """Return % confidence intervals.

        Uses the approximation that the variation around the center of the
        bootstrap distribution is the same as the variation around the
        center of the true distribution. E.g. not sensitive to a bootstrap
        distribution is biased in the median.

        Note
        ----
        Estimates are rounded to the nearest significant digit.
        """
        if not 0.0 < percent < 100.0:
            raise ValueError("Percentage should be between 0.0 and 100.0")
        elif 0.0 < percent < 1.0:
            warn("Received a fraction but expected a percentile.", UserWarning)

        a = (100.0 - percent) / 2
        upper = np.percentile(self._delta, a)
        lower = np.percentile(self._delta, 100 - a)
        return self._sig_figures(
            self._sample, self._sample - lower, self._sample - upper
        )

    def bootstrap_percentiles(self, percent: float) -> Tuple[float, float, float]:
        """Return percentiles of the bootstrap distribution.

        This assumes that the bootstrap distribution is similar to the real
        distribution. This breaks down when the median of the bootstrap
        distribution is very different from the sample/true variable median.

        Note
        ----
        Estimates are rounded to the nearest significant digit.
        """
        if not 0.0 < percent < 100.0:
            raise ValueError("Percentage should be between 0.0 and 100.0")
        elif 0.0 < percent < 1.0:
            raise UserWarning("Received a fraction but expected a percentage.")

        a = (100.0 - percent) / 2
        lower = np.percentile(self._bootstrap, a)
        upper = np.percentile(self._bootstrap, 100 - a)
        return self._sig_figures(self._sample, lower, upper)

    def standard_error(self) -> float:
        """Return the standard error for the bootstrap estimate."""
        # Is calculated by taking the standard deviation of the bootstrap distribution
        return self._bootstrap.std()

    def _sig_figures(
        self, mean: float, lower: float, upper: float, max_sig: int = 16
    ) -> Tuple[float, float, float]:
        """Find the lowest number of significant figures that distinguishes
        the mean from the lower and upper bound.
        """
        i = 16
        for i in range(1, max_sig):
            if (round(mean, i) != round(lower, i)) and (
                round(mean, i) != round(upper, i)
            ):
                break
        self._significance = i
        return round(mean, i), round(lower, i), round(upper, i)

    def __repr__(self) -> str:
        try:
            return "{0:.{3}f} [{1:.{3}f}, {2:.{3}f}]".format(
                *self.bootstrap_percentiles(95), self._significance
            )
        except:
            return str(self.__dict__)

    def _round_float(self, flt):
        return (flt * pow(10, self._significance)) / pow(10, self._significance)

    def to_tuple(self, percent=95):
        """Return the mean, lower and upper percentiles rounded to significant digits"""
        mean, lower, upper = self.bootstrap_percentiles(percent)
        mean = self._round_float(mean)
        lower = self._round_float(lower)
        upper = self._round_float(upper)
        return mean, lower, upper

class PearsonRBootstrapDistribution:
    """Represents a bootstrap distribution, and allows calculation of useful statistics."""

    def __init__(self, sample_estimate: float, bootstrap_estimates: np.array) -> None:
        """
        Parameters
        ----------
        sample_estimate - estimated value from original sample
        bootstrap_estimates - estimated values from bootstrap samples
        """
        self._sample = sample_estimate
        self._bootstrap = bootstrap_estimates
        # approximation of δ = X - μ
        # denoted as δ* = X* - X
        self._delta = bootstrap_estimates - sample_estimate
        self._significance: int = 16
        return

    def empirical_bootstrap_confidence_intervals(
        self, percent: float
    ) -> Tuple[float, float, float]:
        """Return % confidence intervals.

        Uses the approximation that the variation around the center of the
        bootstrap distribution is the same as the variation around the
        center of the true distribution. E.g. not sensitive to a bootstrap
        distribution is biased in the median.

        Note
        ----
        Estimates are rounded to the nearest significant digit.
        """
        if not 0.0 < percent < 100.0:
            raise ValueError("Percentage should be between 0.0 and 100.0")
        elif 0.0 < percent < 1.0:
            warn("Received a fraction but expected a percentile.", UserWarning)

        a = (100.0 - percent) / 2
        upper = np.percentile(self._delta, a)
        lower = np.percentile(self._delta, 100 - a)
        new_upper = min(1.00, self._sample - upper)
        return self._sig_figures(self._sample, self._sample - lower, new_upper)

    def bootstrap_percentiles(self, percent: float) -> Tuple[float, float, float]:
        """Return percentiles of the bootstrap distribution.

        This assumes that the bootstrap distribution is similar to the real
        distribution. This breaks down when the median of the bootstrap
        distribution is very different from the sample/true variable median.

        Note
        ----
        Estimates are rounded to the nearest significant digit.
        """
        if not 0.0 < percent < 100.0:
            raise ValueError("Percentage should be between 0.0 and 100.0")
        elif 0.0 < percent < 1.0:
            raise UserWarning("Received a fraction but expected a percentage.")

        a = (100.0 - percent) / 2
        lower = np.percentile(self._bootstrap, a)
        upper = np.percentile(self._bootstrap, 100 - a)
        return self._sig_figures(self._sample, lower, min(1.00, upper))

    def standard_error(self) -> float:
        """Return the standard error for the bootstrap estimate."""
        # Is calculated by taking the standard deviation of the bootstrap distribution
        return self._bootstrap.std()

    def _sig_figures(
        self, mean: float, lower: float, upper: float, max_sig: int = 16
    ) -> Tuple[float, float, float]:
        """Find the lowest number of significant figures that distinguishes
        the mean from the lower and upper bound.
        """
        i: int = 1
        for i in range(1, max_sig):
            if (round(mean, i) != round(lower, i)) and (
                round(mean, i) != round(upper, i)
            ):
                break
        self._significance = i
        return round(mean, i), round(lower, i), round(upper, i)

    def __repr__(self) -> str:
        return "{0:.{3}f}; [{1:.{3}f}, {2:.{3}f}]".format(
            *self.bootstrap_percentiles(95), self._significance
        )

def bootstrapped_func(values: np.ndarray, nbootstrap_samples=10000, func=np.mean):
    """Perform a non-parametric bootstrap over values to estimate a function such as the mean."""
    # Draw random array indices to resample data points with replacement
    samples = np.random.randint(0, values.size, values.size * nbootstrap_samples)
    # Get the right output shape
    samples = samples.reshape(values.size, nbootstrap_samples)
    # Allow 2D indexing by adding empty axis
    value_2d = values[:, np.newaxis]
    return BootstrapDistribution(func(values), func(value_2d[samples], axis=0))


from __future__ import division
import scipy as sp
from scipy import linalg as la
from scipy.linalg import hessenberg
import numpy as np
from numpy.linalg import matrix_power

def qr_solver(A, niter=1000, tol=1e-3):
    '''
    Calculate the eigenvalues of a matrix A using QR iteration.
    Inputs:
        A -- real square matrix
        niter -- number of QR iterations to run
        tol -- real number. All real numbers with magnitude below we treat as 0
    Returns:
        eigs -- list of real or complex numbers, the eigenvalues of A.
    Note: this code is far from optimized, but considering that the algorithm itself is
          inherently limited in robustness, any extra optimization short of chaning the
          algorithm seems wasted effort.
    '''
    # first calculate the upper hessenberg form of A
    H = la.hessenberg(A)

    # perform the QR iterations
    for i in xrange(niter):
        Q, R = la.qr(H)
        H = R.dot(Q)

    # populate the list of eigenvalues
    eigs = []
    i = 0
    while i < H.shape[0]:
        if i == H.shape[0]-1: #if we are at the last diagonal entry, must be eigenvalue
            eigs.append(H[i,i])
            i += 1
        elif abs(H[i+1,i]) < tol: #if subdiagonal zero, diagonal must be e'value
            eigs.append(H[i,i])
            i += 1
        else: #subdiagonal nonzero, so find complex e'values of 2x2 block
            a, b, c, d = H[i:i+2,i:i+2].flatten()
            T = a + d
            D = a*d - b*c
            eigs.append(T/2 + math.sqrt(abs(T**2/4 - D))*1j)
            eigs.append(T/2 - math.sqrt(abs(T**2/4 - D))*1j)
            i += 2
    return eigs

def eig(A, normal = False, iter = 100):
	'''Finds eigenvalues of an nxn array A. If A is normal, QRalg.eig
	may also return eigenvectors.

	Parameters
	----------
	A :  nxn array
	     May be real or complex
	normal : bool, optional
		     Set to True if A is normal and you want to calculate
		     the eigenvectors.
	iter : positive integer, optional

	Returns
	-------
	v : 1xn array of eigenvectors, may be real or complex
	Q : (only returned if normal = True)
		nxn array whose columns are eigenvectors, s.t. A*Q = Q*diag(v)
		real if A is real, complex if A is complex

	For more on the QR algorithm, see Eigenvalue Solvers lab.
	'''
	def getSchurEig(A):
		#Find the eigenvalues of a Schur form matrix. These are the
		#elements on the main diagonal, except where there's a 2x2
		#block on the main diagonal. Then we have to find the
		#eigenvalues of that block.
		D = sp.diag(A).astype(complex)
		#Find all the 2x2 blocks:
		LD = sp.diag(A,-1)
		index = sp.nonzero(abs(LD)>.01)[0] #is this a good tolerance?
		#Find the eigenvalues of those blocks:
		a = 1
		b = -D[index]-D[index+1]
		c = D[index]*D[index+1] - A[index,index+1]*LD[index]
		discr = sp.sqrt(b**2-4*a*c)
		#Fill in vector D with those eigenvalues
		D[index] = (-b + discr)/(2*a)
		D[index+1] = (-b - discr)/(2*a)
		return D

	n,n = A.shape
	I = sp.eye(n)
	A,Q = hessenberg(A,True)
	if normal == False:
		for i in sp.arange(iter):
			s = A[n-1,n-1].copy()
			Qi,R = la.qr(A-s*I)
			A = sp.dot(R,Qi) + s*I
		v = getSchurEig(A)
		return v

	elif normal == True:
		for i in sp.arange(iter):
			s = A[n-1,n-1].copy()
			Qi,R = la.qr(A-s*I)
			A = sp.dot(R,Qi) + s*I
			Q = sp.dot(Q,Qi)
		v = sp.diag(A)
		return v,Q

def markov_freethrow():
    '''
    Compute the answers to problem 1 in the lab.
    Initialize the given Markov matrix, and perform all
    calculations within the function.
    Returns:
        n1 -- n1 is the answer to part 1
        n2 -- n2 is the answer to part 2
    '''
    A = np.array([[.75, .5], [.25, .5]])
    n1 = A.dot(A)[0,0]
    n2 = matrix_power(A, 20)[0,0]
    return n1, n2

def markov_stablept():
    '''
    Calculate the answers to problem 2 in the lab.
    Hint: to see if there is a stable fixed point, raise the
    matrix to some high powers (like powers of 15-20), and see
    if the columns are converging to some common array. If
    they are, return the common array, and if not, return None.
    Returns:
        n1 -- transition matrix asked for in part 1
        n2 -- probability of being in state 2 after 2
              transitions (starting from state 1)
        n3 -- array giving the stable fixed point if exists, or None
    '''
    A = np.array([[1./4, 1./3, 1./2], [1./4, 1./3, 1./3], [1./2, 1./3, 1./6]])
    n2 = A.dot(A)[1,0]
    n3 = matrix_power(A, 20)[:,0]
    return A, n2, n3

import numpy,from numpy,import scipy,from scipy


from scipy import random
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

def ellipsoid_plot(a, b, c,grid_count = 35):
    '''
    a,b,c are the values for the x,y and z axis multipliers
    grid_count is the relative amount of grid lines, 35 works best
    returns a 3d plot of an ellipsoid with radius in x,y,z directions of a,b,c
    '''

    # it is recommended to not eneter a very large number for the grid count as it can me very performance intensive stick to 100 as a max value

    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')

    u = np.linspace(0, 2 * np.pi, 100) #array for u
    v = np.linspace(0, np.pi, 100) #array for v

    #parametres for an elipsoid in polar coordinates

    x = a * np.outer(np.cos(u), np.sin(v))
    y = b * np.outer(np.sin(u), np.sin(v))
    z = c * np.outer(np.ones(np.size(u)), np.cos(v))

    # Surface plot
    ax.plot_surface(x, y, z,rcount=grid_count,ccount=grid_count,shade=True,color='green', edgecolors='k', lw=0.4)
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')

    max_radius = max(a, b, c) #limits of plot
    for axis in 'xyz':
        getattr(ax, 'set_{}lim'.format(axis))((-max_radius, max_radius))

    return plt.show()

def ellipsoid_integration(a, b, c, accuracy=5 * (10 ** (-3))):
    '''
    a,b,c are values for x,y and z axis multipliers
    accuracy is the difference of the monte carlo integration with the volume of a given ellipsoid (volume of ellipsoid is 4/3*pi*a*b*c
    returns a value for the value for the volume of the desired ellipsoid with radii a,b,c and an error of this abs(volume - 4/3*pi*abc)
    '''

    N = 10000000 # Number of points used in space

    volume_of_box = 2*a * 2*b * 2*c # Formula for box that surrounds the ellipsoid
    volume_of_ellipsoid = (4/3)*np.pi*a*b*c # Formula that is the true value of the volume of the ellipsoid

    x_rand = random.uniform(-a, a, size=(N, 1))# These are arrays generated by the scipy random function (which is the essentialy sampe as the numpy random function.)
    y_rand = random.uniform(-b, b, size=(N, 1))
    z_rand = random.uniform(-c, c, size=(N, 1))

    x = (x_rand**2)/a**2 # Note the equation of an ellipsoid is x^2/a^2 + y^2/b2 +z^2/c^2 = 1
    y = (y_rand**2)/b**2 # The purpose of these variables x,y,z is to make it easier to read
    z = (z_rand**2)/c**2

    final_array = (x+y+z) # the final array will give values between 0 and a maximum of the boxes max coordinate ie (2a,2b,2c) and add them (2a+2b+2c)

    final_array_bool = final_array <= 1
    # From the equation of the ellipsoid we know that if x+y+z = 1 the point is on the surface of the ellipsoid.
    # This means that any value greater than 1 is therefore outside the ellipsoid and as we are interest in points inside or surface points of the ellipsoid
    # We can discard the values that are above 1 and replace them with a value of "False" and less than 1 is set to "True"

    final_array_int = final_array_bool.astype(int)
    # This converts all the bool values ("True" and "False") to 1 or 0 (1 == True, 0 == false)

    points_inside_ellipsoid = sum(final_array_int)
    # Simple sum of the array

    final_result = volume_of_box * (points_inside_ellipsoid/N)
    # Volume will be the volume of the box times the proportion of points insede the ellipsoid i.e points inside/total points

    while np.abs(final_result-volume_of_ellipsoid) > accuracy:
    # This while loop will break when the required accuracy is met or beaten.
    # The absolute difference bbetween the real volume and the MC prediction is regarded as the accuracy measurement as the equation is the true value.

        x_rand = random.uniform(-a, a, size=(N, 1))
        y_rand = random.uniform(-b, b, size=(N, 1))
        z_rand = random.uniform(-c, c, size=(N, 1))

        x = (x_rand ** 2) / a ** 2
        y = (y_rand ** 2) / b ** 2
        z = (z_rand ** 2) / c ** 2

        #This is just recalculating the value of the volume until the condtion is fulfilled at which point is prints the volume

        point_array = (x + y + z)
        final_array_bool = point_array <= 1
        final_array_int = final_array_bool.astype(int)
        points_inside_ellipsoid = sum(final_array_int)
        final_result = volume_of_box * (points_inside_ellipsoid / N)

    print(final_result,'error in volume = ',np.abs(final_result-volume_of_ellipsoid))

code/Python/Fun programming and data poblems/ellipsoid.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/4/14 19:45
# @Author  : duanhaobin
# @File    : metrics.py
# @Software: PyCharm
# @Desc    : MSE,RMSE,MAE算法封装

import numpy as np
from math import sqrt

def mean_squared_error(y_true, y_predict):
    """根据真值和预测值计算均方误差"""
    assert len(y_true) == len(y_predict),\
        "the size of y_true must be equal to the size of y_predict"
    return np.sum((y_true - y_predict) ** 2) / len(y_true)

def root_mean_squraed_error(y_true, y_predict):
    """根据真值和预测值计算均方根误差"""
    return sqrt(mean_squared_error(y_true, y_predict))

def mean_absolute_error(y_true, y_predict):
    """根据真值和预测值计算平均绝对误差"""
    return np.sum(np.absolute(y_true - y_predict)) / len(y_true)


import numpy as np
import random as rm

# The statespace
states = ["Sleep","Icecream","Run"]

# Possible sequences of events
transitionName = [["SS","SR","SI"],["RS","RR","RI"],["IS","IR","II"]]

# Probabilities matrix (transition matrix)
transitionMatrix = [[0.2,0.6,0.2],[0.1,0.6,0.3],[0.2,0.7,0.1]]

def activity_forecast(days):
    # Choose the starting state
    activityToday = "Sleep"
    activityList = [activityToday]
    i = 0
    prob = 1
    while i != days:
        if activityToday == "Sleep":
            change = np.random.choice(transitionName[0],replace=True,p=transitionMatrix[0])
            if change == "SS":
                prob = prob * 0.2
                activityList.append("Sleep")
                pass
            elif change == "SR":
                prob = prob * 0.6
                activityToday = "Run"
                activityList.append("Run")
            else:
                prob = prob * 0.2
                activityToday = "Icecream"
                activityList.append("Icecream")
        elif activityToday == "Run":
            change = np.random.choice(transitionName[1],replace=True,p=transitionMatrix[1])
            if change == "RR":
                prob = prob * 0.5
                activityList.append("Run")
                pass
            elif change == "RS":
                prob = prob * 0.2
                activityToday = "Sleep"
                activityList.append("Sleep")
            else:
                prob = prob * 0.3
                activityToday = "Icecream"
                activityList.append("Icecream")
        elif activityToday == "Icecream":
            change = np.random.choice(transitionName[2],replace=True,p=transitionMatrix[2])
            if change == "II":
                prob = prob * 0.1
                activityList.append("Icecream")
                pass
            elif change == "IS":
                prob = prob * 0.2
                activityToday = "Sleep"
                activityList.append("Sleep")
            else:
                prob = prob * 0.7
                activityToday = "Run"
                activityList.append("Run")
        i += 1
    return activityList

# To save every activityList
list_activity = []
count = 0

# `Range` starts from the first count up until but excluding the last count
for iterations in range(1,10000):
        list_activity.append(activity_forecast(2))

# Check out all the `activityList` we collected
#print(list_activity)

# Iterate through the list to get a count of all activities ending in state:'Run'
for smaller_list in list_activity:
    if(smaller_list[2] == "Run"):
        count += 1

# Calculate the probability of starting from state:'Sleep' and ending at state:'Run'
percentage = (count/10000) * 100
print("The probability of starting at state:'Sleep' and ending at state:'Run'= " + str(percentage) + "%")


import numpy as np

def vector_2norm(x):
    """

    :param x:
    :return:
    """
    return np.sqrt(np.sum(np.dot(x.T, x)))

def vector_1norm(x):
    """

    :param x:
    :return:
    """
    return np.max(np.abs(x))

def matrix_1norm(a):
    """
    max_{j} sum_{i} |a_{ij}|
    :param a:
    :return:
    """
    return np.max(np.sum(np.abs(a), axis=0))

def matrix_inftynorm(a):
    """
    max_{i} sum_{j} |a_{ij}|
    :param a:
    :return:
    """
    return np.max(np.sum(np.abs(a), axis=1))


# -*- coding: utf-8 -*-
import numpy as np
from scipy.ndimage.filters import gaussian_filter

'''
- can be imported by algorithms for 2d inversion as an input distribution
- define a density function e.g. f(T1,T2) = Gaussian peak + ridge
- e.g. dim(F(T1,T2)) = 100x100
'''

#def centered_gaussian(sigma, Nx, Ny):
#    trueF = np.zeros((Nx, Ny))
#    for i in range(Nx):
#        for j in range(Ny):
#            trueF[i, j] = gaussian(sigma, 50, 50, i, j)
#    trueF /= trueF.sum()
#    return trueF

def gaussian(sigma, T1, T2, tau1, tau2):
    px = 1/np.sqrt(2*np.pi*sigma**2)*np.exp(-(tau1-T1)**2/(2*sigma**2))
    py = 1/np.sqrt(2*np.pi*sigma**2)*np.exp(-(tau2-T2)**2/(2*sigma**2))
    return px*py

def single_gauss(Nx=100, Ny=100, T1=0.7, T2=0.2, sigmaGauss=3.0):
    T1min = 1e-3
    T1max = 10.0
    T2min = 1e-3
    T2max = 10.0
    T1Arr = np.logspace(np.log10(T1min),
                        np.log10(T1max),
                        Nx, endpoint=True,
                        base=10.0)
    T2Arr = np.logspace(np.log10(T2min),
                        np.log10(T2max),
                        Ny,
                        endpoint=True,
                        base=10.0)
    print("T1 = %.2f s" % T1)
    print("T2 = %.2f s" % T2)
    T1_index = np.where(T1Arr > T1)[0][0]
    T2_index = np.where(T2Arr > T2)[0][0]
    trueF = np.zeros([Nx, Ny])
    for i in range(Nx):
        for j in range(Ny):
            trueF[i, j] = gaussian(sigmaGauss, T1_index, T2_index, i, j)
    trueF /= trueF.sum()
    return trueF, T1Arr, T2Arr

def ridge_gauss(Nx=100, Ny=100, sigmaGauss=3.0, sigmaRidge=2):
    # sigmas are given in pixels
    T1min = 1e-3
    T1max = 10.0
    T2min = 1e-3
    T2max = 10.0
    T1Arr = np.logspace(np.log10(T1min),
                        np.log10(T1max),
                        Nx, endpoint=True,
                        base=10.0)
    T2Arr = np.logspace(np.log10(T2min),
                        np.log10(T2max),
                        Ny,
                        endpoint=True,
                        base=10.0)
    T1 = 0.7  # seconds #T1Arr[50]
    T2 = 0.2  # seconds #T2Arr[40]
    print("T1 = %.2f s" % T1)
    print("T2 = %.2f s" % T2)
    T1_index = np.where(T1Arr > T1)[0][0]
    T2_index = np.where(T2Arr > T2)[0][0]
    trueF = np.zeros([Nx, Ny])
    for i in range(Nx):
        for j in range(Ny):
            trueF[i, j] = gaussian(sigmaGauss, T1_index, T2_index, i, j)
    xUpper = 50
    xLower = 17
    m = 0.5
    n = 30
    F = np.zeros([Nx, Ny])
    for i in range(xLower, xUpper, 1):
        j = int(m * i + n)
        F[i, j] = 1.0
    Ridge = gaussian_filter(F, sigma=sigmaRidge)
    Ridge = Ridge/max(Ridge.ravel())
    trueF = trueF/max(trueF.ravel())
    trueF = trueF + Ridge.T
    trueF = trueF/np.sum(trueF.ravel())
    return trueF, T1Arr, T2Arr

if __name__ == "__main__":
    import matplotlib.pyplot as plt
    trueF, T1Arr, T2Arr = ridge_gauss(Nx=100,
                                      Ny=100,
                                      sigmaGauss=3,
                                      sigmaRidge=2)
    fig = plt.figure()
    ax = fig.add_axes([.1, .1, .8, .8])
    ax.pcolor(T2Arr,
              T1Arr,
              trueF,
              vmin=0.0,
              vmax=max(trueF.ravel()))
    ax.set_yscale('log')
    ax.set_xscale('log')
    ax.plot(T1Arr, T2Arr, 'w--')
    ax.set_xlabel(r'$T_{2}\,/\, \mathrm{s}$')
    ax.set_ylabel(r'$T_{1}\,/\,\mathrm{s}$')
    plt.show()


import numpy as np

# pytrahn export relu(float32[:,:])
def relu(x):
    return np.maximum(x, 0)

# Numerically-stable version of softmax
# pythran export softmax(float32[:,:])
def softmax(x):
    # tmp_max = np.max(x, axis=-1, keepdims=True)
    tmp_max = np.max(x, axis=-1)[:, :, np.newaxis]
    tmp_out = np.exp(x - tmp_max)
    # tmp_sum = np.sum(tmp_out, axis=-1, keepdims=True)
    tmp_sum = np.sum(tmp_out, axis=-1)[:, :, np.newaxis]
    return tmp_out / tmp_sum

# 3-layer MLP
# pythran export mlp(float32[:,:], float32[:,:], float32[:], float32[:,:],
#                    float32[:], float32[:,:], float32[:])
def mlp(input, w1, b1, w2, b2, w3, b3):
    x = relu(input @ w1 + b1)
    x = relu(x @ w2 + b2)
    x = softmax(x @ w3 + b3)  # Softmax call can be omitted if necessary
    return x


import numpy as np

class SingleIntegration:
    def __init__(self, f, a, b):
        """
        Initialize integration solver.
        Params:
            - f     name of the function to be integrated which must have a signature 'def f(x):...return f_x'
            - a     start point x=a of integration interval
            - b     end point x=b of integration interval
        """
        self.f = f
        self.a = a
        self.b = b

    def _trap_rule(self, x, h):
        """
        Trapezoidal rule.
        Calculate the area of the strip bounded by the interval ['x', 'x'+'h'] and [f('x'), f('x' + 'h')].
        Note: the function f between 'x' and 'x + h' is approximated by a straight line.
        Params:
            - x   start point of the interval
            - h   width of the interval
        Return value:
            - area under the strip
        """
        return (self.f(x) + self.f(x + h)) * (h / 2.0)

    def _recursive_trap_rule(self, I_old, k):
        """
        Recursive trapezoidal rule.
        Params:
            - I_old     previous solution of the integral dividing the integration interval [a, b] into 2^(k-2) strips
            - k         set the number of strips to 2^(k-1) for the new solution of the integral
        Return value:
            - new solution for the integral with the number of strips doubled
        """
        if k == 1:
            I_new = self._trap_rule(self.a, self.b - self.a)
        else:
            n = 2**(k - 2)
            h = (self.b - self.a) / n
            x = self.a + h / 2.0
            sum_ = 0.0
            for i in range(n):
                sum_ = sum_ + self.f(x)
                x += h
            I_new = (I_old + h * sum_) / 2.0
        return I_new

    @staticmethod
    def _richardson(r, k):
        """
        Richardson extrapolation. Helper method of '_romberg'.
        """
        for j in range(k - 1, 0, -1):
            const = 4.0 ** (k - j)
            r[j] = (const * r[j + 1] - r[j]) / (const - 1.0)
        return r

    def _romberg(self, tol=1.0e-6):
        """
        Romberg quadrature.
        Combines the recursive trapezoidal rule with Richardson extrapolation.
        """
        r = np.zeros(21)
        r[1] = self._recursive_trap_rule(0.0, 1)
        r_old = r[1]
        for k in range(2, 21):
            r[k] = self._recursive_trap_rule(r[k - 1], k)
            r = self._richardson(r, k)
            if abs(r[1] - r_old) < tol * max(abs(r[1]), 1.0):
                return r[1], 2 ** (k - 1)
            r_old = r[1]
        raise OverflowError("Romberg quadrature did not converge")

    def solve(self, tol=1.0e-6):
        """
        Solve the integral using Romberg quadrature.
        Params:
            - tol   accuracy in decimal places of the solution (the calculation is repeated until the difference between
                    the new solution and the old solution is smaller than 'tol')
        Return value:
            - the integral of f(x) between x=a and x=b
            - the number of strips used to calculate the integral
        """
        return self._romberg(tol)


import math
import numpy as np
import pandas as pd
from pandas import DataFrame
from sklearn import preprocessing
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from numpy import loadtxt, where
from pylab import scatter, show, legend, xlabel, ylabel

##implementation of sigmoid function
def Sigmoid(x):
	g = float(1.0 / float((1.0 + math.exp(-1.0*x))))
	return g

##Prediction function
def Prediction(theta, x):
	z = 0
	for i in xrange(len(theta)):
		z += x[i]*theta[i]
	return Sigmoid(z)

# implementation of cost functions
def Cost_Function(X,Y,theta,m):
	sumOfErrors = 0
	for i in xrange(m):
		xi = X[i]
		est_yi = Prediction(theta,xi)
		if Y[i] == 1:
			error = Y[i] * math.log(est_yi)
		elif Y[i] == 0:
			error = (1-Y[i]) * math.log(1-est_yi)
		sumOfErrors += error
	const = -1/m
	J = const * sumOfErrors
	#print 'cost is ', J
	return J

# gradient components called by Gradient_Descent()

def Cost_Function_Derivative(X,Y,theta,j,m,alpha):
	sumErrors = 0
	for i in xrange(m):
		xi = X[i]
		xij = xi[j]
		hi = Prediction(theta,X[i])
		error = (hi - Y[i])*xij
		sumErrors += error
	m = len(Y)
	constant = float(alpha)/float(m)
	J = constant * sumErrors
	return J

# execute gradient updates over thetas
def Gradient_Descent(X,Y,theta,m,alpha):
	new_theta = []
	constant = alpha/m
	for j in xrange(len(theta)):
		deltaF = Cost_Function_Derivative(X,Y,theta,j,m,alpha)
		new_theta_value = theta[j] - deltaF
		new_theta.append(new_theta_value)
	return new_theta


import numpy as np
from scipy.sparse import csc_matrix, diags, vstack, hstack
from scipy.sparse.linalg import inv, spsolve

def simplex(A, c, b):
    nr = len(b)
    nv = len(c)
    I = diags(np.ones(nr))

    bi = b.copy()

    # form tableau blocks
    M = hstack((A, I))

    x = np.r_[np.zeros(nv), b]

    fx = np.r_[c, np.zeros(nr)]

    # pick the most negative of the variables in fx
    var_idx = np.argmin(fx)
    xj = fx[var_idx]

    bi = bi / xj

    return 0

def interior_point(A, c, x0, tol=1e-6, max_iter=100):
    """
    Interior point solver for linear systems
    Source: Computational methods for electric power systems (3rd Ed.) - Mariesa L- Crow  (CRC Press)
    Args:
        A: Restrictions matrix
        c: Objective function coefficients
        x0: Feasible solution
        tol: Tolerance
        max_iter: Maximum number of iterations
    Returns: Optimal solution x
    """
    n = len(c)

    e = np.ones(n)

    I = diags(e)

    x = x0.copy()

    x_prev = x0.copy()

    converged = False

    iterations = 0

    last_f = 1e20

    while not converged and iterations < max_iter:

        D = diags(x)

        Ap = A * D

        cp = D * c

        # Pp = I - Ap.transpose() * inv(Ap * Ap.transpose()) * Ap

        Pp = I - Ap.transpose() * spsolve(Ap * Ap.transpose(), Ap)  # avoid using matrix inversions...

        p0 = - Pp * cp

        alpha = 0.9

        theta = - p0.min()

        xp = e + (alpha / theta) * p0

        x = D * xp

        f = c.dot(x)

        # back track
        b_iter = 0
        while f > last_f and b_iter < 10:
            alpha *= 0.25

            xp = e + (alpha / theta) * p0

            x = D * xp

            f = c.dot(x)

            b_iter += 1

            print('\talpha:', alpha)

        error = np.linalg.norm(x - x_prev, np.inf)

        converged = error < tol

        x_prev = x.copy()

        last_f = f

        iterations += 1

        print('f:', f, '\terror:', error)

    return x

if __name__ == '__main__':
    """
    Problem:
    min: -6x1 - 14x2

    s.t:
    2x1 + 1x2 <= 12
    2x1 + 3x2 <= 15
    1x1 + 7x2 <= 21

    x1 >=0, x2>=0
    """

    c_ = np.array([-6, -14])

    A_ = csc_matrix([[2, 1],
                     [2, 3],
                     [1, 7]])

    b_ = np.array([12, 15, 21])

    # solve
    x = simplex(A=A_, c=c_, b=b_)

    print()
    print('Solution:', x)
    print('Constraints mismatch:', A_ * x - b_)


import numpy as np

def reduce_by_max(x, n=2):
    out = x.copy()
    out[np.argsort(x)[:-n]] = 0
    return out

# Gaussian-Kernel
# https://en.wikipedia.org/wiki/Kernel_smoother
def gauss_kernel(x, x_i, rho=0.1, alpha=1.0, n_reduce=-1, point_to_flatten=1):
    """
    Parameters
    ----------
    x : array-like
        points required to compute kernel weight
    x_i : array-like
        reference points location used to compute correspondent distance of each entry points
    rho : float
        smoothing parameter known as "length-scale" in gaussian process
    alpha : float
        marginal standard deviation parameter in gaussian process; one should use 1 in kernel regression
    n_reduce : int
        if greater 0 (default=-1), reduce number of positive weights to such input
    point_to_flatten : float
        the time point starting to flatten the weights; default is 1 for normalized time points

    Returns
    -------
    np.ndarray
        2D array with size N x M such that
        N as the number of entry points
        M as the number of reference points
        matrix entries hold the value of weight of each element

    See Also
    --------
    1. https://mc-stan.org/docs/2_24/stan-users-guide/gaussian-process-regression.html
    2. https://en.wikipedia.org/wiki/Local_regression
    """
    N = len(x)
    M = len(x_i)
    k = np.zeros((N, M), np.double)
    alpha_sq = alpha ** 2
    rho_sq_t2 = 2 * rho ** 2
    for n in range(N):
        if x[n] <= point_to_flatten:
            k[n, :] = alpha_sq * np.exp(-1 * (x[n] - x_i) ** 2 / rho_sq_t2)
        else:
            # last weights carried forward for future time points
            k[n, :] = alpha_sq * np.exp(-1 * (point_to_flatten - x_i) ** 2 / rho_sq_t2)

    if n_reduce > 0:
       k = np.apply_along_axis(reduce_by_max, axis=1, arr=k, n=n_reduce)

    k = k / np.sum(k, axis=1, keepdims=True)

    return k

def sandwich_kernel(x, x_i):
    """
    Parameters
    ----------
    x : array-like
        points required to compute kernel weight
    x_i : array-like
        reference points location used to compute correspondent distance of each entry points

    Returns
    -------
    np.ndarray :
        2D array with size N x M such that
        N as the number of entry points
        M as the number of reference points
        matrix entries hold the value of weight of each element

    See Also
    --------
    1. https://mc-stan.org/docs/2_24/stan-users-guide/gaussian-process-regression.html
    2. https://en.wikipedia.org/wiki/Local_regression
    """
    N = len(x)
    M = len(x_i)
    k = np.zeros((N, M), dtype=np.double)

    np_idx = np.where(x < x_i[0])
    k[np_idx, 0] = 1

    for m in range(M - 1):
        np_idx = np.where(np.logical_and(x >= x_i[m], x < x_i[m + 1]))
        total_dist = x_i[m + 1] - x_i[m]
        backward_dist = x[np_idx] - x_i[m]
        forward_dist = x_i[m + 1] - x[np_idx]
        k[np_idx, m] = forward_dist / total_dist
        k[np_idx, m + 1] = backward_dist / total_dist

    np_idx = np.where(x >= x_i[M - 1])
    k[np_idx, M - 1] = 1

    # TODO: it is probably not needed
    k = k / np.sum(k, axis=1, keepdims=True)

    return k

def parabolic_kernel(x, x_i):
    # TODO: docstring
    N = len(x)
    M = len(x_i)
    k = np.zeros((N, M), dtype=np.double)

    # boundary case
    np_idx = np.where(x < x_i[0])
    if len(np_idx) > 0:
        k[np_idx, 0] = 1

    for m in range(M - 1):
        np_idx = np.where(np.logical_and(x >= x_i[m], x < x_i[m + 1]))
        total_dist = x_i[m + 1] - x_i[m]
        backward_dist = x[np_idx] - x_i[m]
        forward_dist = x_i[m + 1] - x[np_idx]
        k[np_idx, m] = 0.75 * (1 - (backward_dist / total_dist) ** 2)
        k[np_idx, m + 1] = 0.75 * (1 - (forward_dist / total_dist) ** 2)

    # boundary case
    np_idx = np.where(x >= x_i[M - 1])
    if len(np_idx) > 0:
        k[np_idx, M - 1] = 1

    # TODO: it is probably not needed
    k = k / np.sum(k, axis=1, keepdims=True)

    return k


from typing import Optional
import numpy as np

from ..misc.utils import isType

def chebyshevNodes(n: int = 10) -> Optional[np.ndarray]:
    """Creates a vector of Chebyshev nodes in the shape of (n+1, )

    :param n: amount of Chebyshev nodes, a positive integer

    :returns: the vector of chebyshev nodes
    :rtype: np.ndarray
    """

    if not isType(n, int) or n < 0:
        return None

    # return np.cos(np.linspace(1, n, n) * np.pi / n)
    return np.array([np.cos(i * np.pi / n) for i in range(0, n + 1)])


import matplotlib.pyplot as plt
import numpy as np

################################################################################
def lp(X, Y=None, p=2):

    if Y==None:
        Y = np.zeros(X.shape)

    return np.sum((X-Y)**p, axis=1)**(1/p)
################################################################################
def arccos_metric(X, y, origin='1...0'):

    if origin=='1...0':
        # For this case, I set the origin in:
        # y = np.zeros(X.shape[1])
        # y[0] = 1, therefore

        return np.arccos(X[:, 0])

    return np.arccos(np.sum(X*y, axis=1))
################################################################################
def Q(X):
    return X[:, 0]**2 - np.sum(X[:, 1:]**2, axis=1)

def hyp_dist(X, y, origin='minima'):
    ## https://en.wikipedia.org/wiki/Hyperbolic_space#:~:text=Hyperbolic%20space
    ## %20is%20a%20space,also%20called%20the%20hyperbolic%20plane.

    if origin=='minima':
        # y = np.zeros(X.shape[1])
        # y[0] = 1. # reference point
        X[:, 0] += 1 # --> cuase B_xy = (Q(x+y)-Q(x)-Q(y))/2
        B_Xy = 0.5*( Q(X) - 2)

        return np.arccosh(B_Xy)

    B_Xy = 0.5*( Q(X+y) -2 )

    return np.arccosh(B_Xy)
################################################################################

def plot(x, y, fname, path, title, metric, euclidean=False, p=None, figsize=(10,5)):

    if euclidean:

        fig, ax = plt.subplots(figsize=figsize)
        ax.set_title(f'{title}\n {metric} $ \\to p=$ {p:.1f}', fontsize='xx-large')
        ax.set_xlabel(f'Number of Diemnsions', fontsize='xx-large')
        ax.set_ylabel(f'Contrast', fontsize='xx-large')

        ax.scatter(x, y)
        plt.tight_layout()
        fig.savefig(f'{path}/{fname}.png')
        fig.savefig(f'{path}/{fname}.pdf')
        plt.close()
    else:

        fig, ax = plt.subplots(figsize=figsize)
        ax.set_title(f'{title}\n {metric}', fontsize='xx-large')
        ax.set_xlabel(f'Number of Diemnsions', fontsize='xx-large')
        ax.set_ylabel(f'Contrast', fontsize='xx-large')

        ax.scatter(x, y)
        plt.tight_layout()
        fig.savefig(f'{path}/{fname}.png')
        fig.savefig(f'{path}/{fname}.pdf')
        plt.close()
################################################################################


import numpy as np
import matplotlib.pyplot as plt

TOL = np.finfo(float).resolution

# Set up our constants
Lx = 10 * 0.01   # [m]
Ly = 7.5 * 0.01  # [m]

rho = 7860  # [kg/m^3]
c_p = 490   # [J/kg.K]
k   = 54    # [W/m.K]

alpha = k / (c_p * rho)  # [m^2/s]

dx = 2.5 * 0.01  # [m]
dy = 2.5 * 0.01  # [m]
dt = 100

sigma_x = alpha * dt / dx**2
sigma_y = alpha * dt / dy**2

# Create out arrays
nx = int((Lx+TOL) // dx) + 1
ny = int((Ly+TOL) // dy) + 1  # NOTE: Tolerance for floating point error

# Dividing small floating point numbers sometimes doesn't give the expected
# answer. For example, 0.075 / 0.025 = 2.9999999999999996
# Without the tolerance, this gives ny = 3 rather than the expected 4.

# Configure initial conditions
current_temperature = (50+273.15) * np.ones(ny*nx)

# Configure boundary conditions
bottom_edge = np.array([110, 100, 90, 80, 70]) + 273.15
top_edge    = np.array([0, 10, 20, 30, 40]) + 273.15

left_edge  = np.array([65, 25]) + 273.15
right_edge = np.array([60, 50]) + 273.15

current_temperature[:nx] = bottom_edge
current_temperature[nx*(ny-1):] = top_edge

current_temperature[nx:3*nx:nx] = left_edge
current_temperature[2*nx-1:4*nx-1:nx] = right_edge

recording = []

implicit_matrix = np.zeros((nx*ny, nx*ny))

for i in range(ny):
    for j in range(nx):
        s = i*nx + j

        # Skip updating boundary nodes
        if i == 0 or i == ny-1:
            implicit_matrix[s, s] = 1
            continue
        if j == 0 or j == nx-1:
            implicit_matrix[s, s] = 1
            continue

        implicit_matrix[s, s]    = (1 + 2*sigma_x + 2*sigma_y)
        implicit_matrix[s, s-1]  = -sigma_x
        implicit_matrix[s, s+1]  = -sigma_x
        implicit_matrix[s, s-nx] = -sigma_y
        implicit_matrix[s, s+nx] = -sigma_y

recording.append(current_temperature)

for _ in range(100):
    next_temperature = np.linalg.solve(implicit_matrix, current_temperature)
    current_temperature = next_temperature.copy()

    recording.append(current_temperature)

# plt.plot([t[12] for t in recording])
# plt.show()


import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from matplotlib.widgets import Button

TRAJ_STEPS = 4096

class Oscillator:

    def __init__(self, eta=0.07674, gamma=1.21, epsilon=12.3):
        self.limit = (-5, 5), (-5, 5)
        self.eta = eta
        self.gamma = gamma
        self.epsilon = epsilon

    def dfun(self, state_variables, *args, **kwargs):
        psi1, psi2 = state_variables

        dpsi1 = self.eta * (psi2 - self.gamma * psi1 - psi1**3)
        dpsi2 = self.eta* (- self.epsilon * psi1)

        return [dpsi1, dpsi2]

class PhasePlaneInteractive:
    def __init__(self, model):
        self.model = model

    def plot_trajectory(self,x0):
        tspan = np.linspace(0, 200, TRAJ_STEPS)
        ys = odeint(self.model.dfun, x0, tspan)
        self.ax.plot(ys[:,0], ys[:,1], 'b-') # path
        self.ax.plot([ys[0,0]], [ys[0,1]], 'o') # start
        self.ax.plot([ys[-1,0]], [ys[-1,1]], 's') # end

    def onclick(self, event):
        self.plot_trajectory([event.xdata,event.ydata])
        plt.draw()

    def __call__(self):
        y1 = np.linspace(-2.0, 2.0, 20)
        y2 = np.linspace(-2.0, 2.0, 20)

        Y1, Y2 = np.meshgrid(y1, y2)

        u, v = np.zeros(Y1.shape), np.zeros(Y2.shape)

        NI, NJ = Y1.shape

        for i in range(NI):
            for j in range(NJ):
                x = Y1[i, j]
                y = Y2[i, j]
                yprime = self.model.dfun([x, y])
                u[i,j] = yprime[0]
                v[i,j] = yprime[1]

        fig, self.ax = plt.subplots()
        plt.subplots_adjust(bottom=0.2)

        def clear(event):
            self.ax.clear()
            Q = self.ax.quiver(Y1, Y2, u, v, color='r')
            self.ax.set_xlabel('$y_1$')
            self.ax.set_ylabel('$y_2$')
            self.ax.set_xlim(-2.0,2.0)
            self.ax.set_ylim(-2.0,2.0)
            plt.draw()

        clear([0.0, 0.0])
        cid = fig.canvas.mpl_connect('button_press_event', self.onclick)

        plt.xlabel('$y_1$')
        plt.ylabel('$y_2$')
        plt.xlim([-2, 2])
        plt.ylim([-2, 2])

        axclear = plt.axes([0.8, 0.02, 0.1, 0.075])
        bclear = Button(axclear, 'Clear')
        bclear.on_clicked(clear)

        plt.show()

if __name__ == '__main__':
    model = Oscillator()
    ppi = PhasePlaneInteractive(model)
    ppi()


import numpy
from math import sqrt

def compute_gradient_RSS_W(H, W, y):
    '''
    This function computes the gradient of RSS(W).
    Args:
        H: |NxD| Matrix of N observations with D features each
        W: |D| Vector of features
        y: |N| vector of true labels

    Returns:
        |D| Vector, the gradient of W
    '''
    if type(H) != numpy.matrix:
        H = numpy.matrix(H)
        if H.shape[0] == 1:  # In case there was one feature
            H = H.T
    if type(W) != numpy.matrix:
        W = numpy.matrix(W).T  # column vector
    elif W.shape[0] == 1:  # creating a column vector
        W = W.T
    if type(y) != numpy.matrix:
        y = numpy.matrix(y).T  # column vector
    elif y.shape[0] == 1:  # creating a column vector
        y = y.T
    delta_W = -2 * H.T * (y - H * W)
    return delta_W

def magnitude(W):
    '''
    Computes the magnitude of the vector W
    Args:
        W: an arbitrary sized vector

    Returns:
        magnitude of W
    '''
    if type(W) != numpy.matrix:
        W = numpy.matrix(W).T
    elif W.shape[0] == 1:  # creating a column vector
        W = W.T
    return sqrt(float(W.T * W))

def add_bias_feature(H):
    '''
    Adds an all 1 feature to serve as the bias feature for W[0]

    Args:
        H: |NxD| Matrix of N observations with D features each

    Returns:
        H: |Nx(D+1)| numpy matrix
    '''
    if not type(H) == numpy.matrix:
        H = numpy.matrix(H)
        if H.shape[0] == 1:  # In case there was one feature
            H = H.T
    return numpy.hstack((numpy.ones((H.shape[0], 1)), H))

def graident_descent(H, W, y, step_size, tolerance):
    '''
    Conducts the gradient descent and returns the minimum of the function RSS(W)
    Args:
        H: |NxD| Matrix of N observations with D features each
        W: |D| Vector of features
        y: |N| vector of true labels
        step_size: step size of the gradient
        tolerance: error tolerance

    Returns:
        |D| Vector minimizing the RSS
    '''
    if type(W) != numpy.matrix:
        W = numpy.matrix(W).T
    elif W.shape[0] == 1:  # creating a column vector
        W = W.T
    H = add_bias_feature(H)
    delta_W = compute_gradient_RSS_W(H, W, y)
    M = magnitude(delta_W)
    iteration = 1
    while M > tolerance:
        if iteration % 500 == 0:
            print('Iteration {0} with Magnitude of {1} for gradiant(RSS(W))'.format(iteration, M))
        W = W - step_size * delta_W
        delta_W = compute_gradient_RSS_W(H, W, y)
        M = magnitude(delta_W)
        iteration += 1
    return W


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

def main(n,l):
	#setup domain
	#number of points
	try:
		n=int(n)
	#time length in secs
		l= int(l)
	except ValueError as e:
		return
	#angular frequency
	omg=2*np.pi/l

	#creating signals
	x=np.linspace(0,l,n);
	y1=1*np.cos(5*omg*x)
	y2=1*np.cos(10*omg*x)
	y3=0.5*np.cos(20*omg*x)

	y=y1+y2+y3

	freq=fftfreq(n)

	mask=freq>0

	fft_vals=fft(y)

	fft_theo=2*np.abs(fft_vals/n)

	plt.figure(1)
	plt.title('Original Image')
	plt.plot(x,y,color='xkcd:salmon',label='Original')
	plt.legend()

	plt.figure(2)
	plt.title('FFT')
	#plt.plot(freq,fft_vals,label='fft')
	#plt.title('True FFT')
	plt.plot(freq[mask],fft_theo[mask],label='true fft values')
	plt.show()


"""
.. module:: distances

distances
*************

:Description: distances

    Distances and divergence functions for probability matrices and vectors

:Authors: bejar

:Version:

:Created on: 17/11/2014 13:01

"""

__author__ = 'bejar'

import numpy as np

def simetrized_kullback_leibler_divergence(m1, m2):
    """
    Simetrized Kullback-Leibler divergence between two probability matrices/vectors
    :param m1:
    :param m2:
    :return:
    """
    lm1 = np.log(m1)
    lm2 = np.log(m2)
    lquot12 = np.log(m1 / m2)
    lquot21 = np.log(m2 / m1)
    dkl12 = lm1 * lquot12
    dkl21 = lm2 * lquot21
    return dkl12.sum() + dkl21.sum()

def kullback_leibler_divergence(m1, m2):
    """
    Kullback-Leibler divergence between two probability matrices/vectors
    :param m1:
    :param m2:
    :return:
    """
    lm1 = np.log(m1)
    lm2 = np.log(m2)
    lquot12 = np.log(m1 / m2)
    lquot21 = np.log(m2 / m1)
    dkl12 = lm1 * lquot12

    return dkl12.sum()

def jensen_shannon_divergence(m1, m2):
    """
    Jensen Shannon Divergence between two probability matrices/vectors

    :param m1:
    :param m2:
    :return:
    """
    m = 0.5*(m1+m2)

    return (0.5 * kullback_leibler_divergence(m1, m)) + (0.5 * kullback_leibler_divergence(m2, m))

def renyi_half_divergence(m1, m2):
    """
    Renyi divergence for parameter 1/2 between two probability matrices/vectors
    :param m1:
    :param m2:
    :return:
    """

    pm = m1 * m2
    spm = np.sqrt(pm)

    return -2 * np.log(spm.sum())

def square_frobenius_distance(m1, m2):
    """
    Square frobenius distance between two probability matrices/vectors
    :param m1:
    :param m2:
    :return:
    """
    c = m1 - m2
    c = c * c
    return c.sum()

def bhattacharyya_distance(m1, m2):
    """
    Bhattacharyya distance between two probability matrices/vectors
    :param m1:
    :param m2:
    :return:
    """
    sum = 0.0
    for a, b in zip(m1, m2):
        sum += np.sum(np.sqrt(a*b))
    return - np.log(sum)

def hellinger_distance(m1, m2):
    """
    Bhattacharyya distance between two probability matrices/vectors
    :param m1:
    :param m2:
    :return:
    """
    sum = 0.0
    for a, b in zip(m1, m2):
        sum += np.sum((np.sqrt(a) - np.sqrt(b)) ** 2)
    return (1/np.log(2)) * np.sqrt(sum)


import numpy as np
from numpy.random import rand
import matplotlib
matplotlib.rcParams = matplotlib.rc_params_from_file('../../matplotlibrc')
from matplotlib import pyplot as plt

ax = plt.subplot(1,1,1)
X = np.linspace(-5, 30, 17501)
Y = np.log(10**(-X) + 1) / 10**(-X)
plt.plot(X, Y, label="$10^x \\log(10^{-x}+1)$")
X = np.linspace(1, 30, 291)
poly = np.poly1d([(-1.)**(i+1)/i for i in xrange(1,30)][::-1])
Y = poly(10**(-X))
plt.plot(X, Y, label="Series Approximation")
handles, labels = ax.get_legend_handles_labels()
plt.legend(handles, labels, loc="upper left")
plt.savefig("lnseries.pdf")
plt.cla()

def pnorm(x, p):
    P = p.reshape((1, -1))
    X = x.reshape((-1, 1))
    return ((X**P).sum(axis=0)**(1./P)).ravel()

ax = plt.subplot(1,1,1)
powers = np.linspace(1, 7, 701)
X = rand(100)+1
N = pnorm(X, 10**powers)
plt.plot([1,7], [X.max()]*2, label="$\\|x\\|_{\\infty}$")
plt.plot(powers, N, label="p-norms of $x$")
handles, labels = ax.get_legend_handles_labels()
plt.legend(handles, labels, loc="upper right")
plt.xlabel("$\\log_{10} p$")
plt.ylabel("$\\| x \\|_p$")
plt.savefig("pnorm_convergence.pdf")
plt.cla()


# Copyright 2021 BlackRock, Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#     http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import cast

import numpy as np
import numpy.typing as npt

def levy_13(x1: float, x2: float) -> float:
    """https://www.sfu.ca/~ssurjano/levy13.html."""
    term_1 = np.sin(3 * np.pi * x1) ** 2
    term_2 = (x1 - 1) ** 2 * (1 + np.sin(3 * np.pi * x2) ** 2)
    term_3 = (x2 - 1) ** 2 * (1 + np.sin(2 * np.pi * x1) ** 2)
    return cast(float, term_1 + term_2 + term_3)

def levy_13_np(x: npt.NDArray[np.floating]) -> float:
    if len(x) != 2:
        raise AssertionError("Exactly 2 items expected")
    return levy_13(x[0], x[1])