'''
SMOOTHING A 1D SPECTRUM
-----------------------
The original code for this comes from
https://scipy-cookbook.readthedocs.io/items/SignalSmooth.html

I've modified it to use scipy & allow for a gaussian shape.

'''

import numpy as np
import matplotlib.pyplot as plt
import scipy.signal.windows as w

def smooth(x,window_len=11,window='hann',sigma=2):
    '''
    Window options:
    'flat','gaussian','hann','hamming','bartlett','blackman'

    To access them, use w.[window](window_len)
    '''
    if window_len < 3: # too small, doesn't smooth
        return x

    # np.r_ turns a list into an array, in this case it works like np.concatenate
    # s will be longer than x based on the window_len (will need to crop it)
    s = np.r_[x[window_len-1:0:-1],x,x[-2:-window_len-1:-1]]

    if window == 'flat': # generates a moving average
        w = np.ones(window_len)
    elif window == 'gaussian': # requires sigma input
        w = eval('w.' + window + '(window_len,sigma)')
    else:
        w = eval('w.' + window + '(window_len)')

    # the actual smoothing line
    y = np.convolve(w/w.sum(), s, mode='valid')

    # y will be larger than x based upon the window_len size
    # for now, I've written in a return that slices out the original section
    h = int(window_len/2)
    y = y[h:-h] # removing the increase in array size due to window_len
    return y

def see_smoothing():
    '''
    Just a function that can be used to plot what this can look
    like for the different filters.  Feel free to change it up.
    '''
    window_len = 7
    x = np.linspace(2,4,50)
    y = 3*np.cos(x)**3
    yn = y + np.random.normal(0,0.5,len(x))

    plt.figure(figsize=(8,4.5)); plt.axis('off')
    plt.plot(x,y,label='true',lw=2,ls=':')
    plt.plot(x,yn,label='w/noise')
    plt.text(0.4,0.8,f'window size: {window_len}',transform=plt.gca().transAxes,fontsize=16)

    for f in ['flat','gaussian','hann','hamming','bartlett','blackman']:
        s = smooth(yn,window_len,window=f)
        plt.plot(x,s,label=f,lw=1)

    plt.legend(ncol=3,loc=3,bbox_to_anchor=(0.1,-0.5))
    plt.tight_layout()
    plt.show()
    plt.close()

def see_windows():
    '''
    Just a function that can be used to visualize the different
    smoothing windows.
    '''
    window_len = 19
    filts = ['flat', 'gaussian', 'hann', 'hamming', 'bartlett', 'blackman']

    plt.figure(figsize=(7,4.5)); plt.axis('off')
    plt.text(0.7,0.82,f'window size: {window_len}',transform=plt.gca().transAxes,fontsize=13.5)

    i = 0
    for f in ['flat', 'gaussian', 'hann', 'hamming', 'bartlett', 'blackman']:
        label = f # assigning it so I can add the sigma for gaussian

        if f == 'flat':
            wfilt = np.ones(window_len)
        elif f == 'gaussian':
            wfilt = eval('w.'+f+'(window_len,2)')
            label = f'{f}\n$\sigma$=2' # adding note about sigma
        else:
            wfilt = eval('w.'+f+'(window_len)')

        plt.plot(wfilt,label=label,color=f'C{i+2}') # so the color matches the other plot
        i += 1

    plt.legend(ncol=3,loc=3,bbox_to_anchor=(0.02,-0.5))
    plt.tight_layout()
    plt.show()
    plt.close()

def double_smooth(x,window_len=5,width=11,sigma=2):
    '''
    This function smooths a spectrum using a double gaussian with a
    specified window size & sigma, separated by a width.
    '''
    if window_len < 3: # too small, doesn't smooth
        return x

    # making double gaussian
    window = 'gaussian' # requires sigma input
    w_one = eval('w.' + window + '(window_len,sigma)')

    if width % 2 == 0: w = np.concatenate((w_one,np.zeros(width),w_one,[0]))
    else: w = np.concatenate((w_one,np.zeros(width),w_one))

    # np.r_ turns a list into an array, in this case it works like np.concatenate
    # s will be longer than x based on the window_len (will need to crop it)
    full_window_len = len(w)
    s = np.r_[x[full_window_len-1:0:-1],x,x[-2:-full_window_len-1:-1]]

    # the actual smoothing line
    y = np.convolve(w/w.sum(), s, mode='valid')

    # y will be larger than x based upon the window_len size
    # for now, I've written in a return that slices out the original section
    h0 = int(window_len/2)
    h = int(full_window_len/2)
    y = y[h0:-(h+(h-h0))] # removing the increase in array size due to window_len+width
    return y

def rebin_spec(wave, specin, wavnew):
	'''
	Given wavelength, a spectrum, and new wavelength array, this
    function resamples the spectrum to match new array.
	'''
	import numpy as np
	from pysynphot import observation
	from pysynphot import spectrum

	spec = spectrum.ArraySourceSpectrum(wave=wave, flux=specin,keepneg=True)
	f = np.ones(len(wave))
	filt = spectrum.ArraySpectralElement(wave, f, waveunits='angstrom')
	obs = observation.Observation(spec, filt, binset=wavnew, force='taper')
	return obs.binflux


## philvals.py
## This is my implementation of phivals.m
## Computation of scaling function and wavelet by recursion
## using Python libraries numpy, scipy
##
## The main reference that I'll use is
## Gilbert Strang, and Kevin Amaratunga. 18.327 Wavelets, Filter Banks and Applications, Spring 2003. (Massachusetts Institute of Technology: MIT OpenCourseWare), http://ocw.mit.edu (Accessed 19 Jun, 2015). License: Creative Commons BY-NC-SA
##
##
##
#####################################################################################
## Copyleft 2015, Ernest Yeung <ernestyalumni@gmail.com>
##
## 20150621
##
## This program, along with all its code, is free software;
## you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You can have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software Foundation, Inc.,
## S1 Franklin Street, Fifth Floor, Boston, MA
## 02110-1301, USA
##
## Governing the ethics of using this program, I default to the Caltech Honor Code:
## ``No member of the Caltech community shall take unfair advantage of
## any other member of the Caltech community.''
##
## If you like what I'm doing and would like to help and contribute support,
## please take a look at my crowdfunding campaign at ernestyalumni.tilt.com
## and subscription-based Patreon
## read my mission statement and give your financial support,
## no matter how small or large,
## if you can
## and to keep checking my ernestyalumni.wordpress.com blog and
## various social media channels
## for updates as I try to keep putting out great stuff.
##
## Fund Science! Help my physics education outreach and research efforts at
## Open/Tilt or subscription Patreon - Ernest Yeung
##
## ernestyalumni.tilt.com
##
## Facebook     : ernestyalumni
## gmail        : ernestyalumni
## google       : ernestyalumni
## linkedin     : ernestyalumni
## Patreon      : ernestyalumni
## Tilt/Open    : ernestyalumni
## tumblr       : ernestyalumni
## twitter      : ernestyalumni
## youtube      : ernestyalumni
## wordpress    : ernestyalumni
##
##
################################################################################
##
##
##
##
## EY : 20150621 on the MIT OCW website for 18.327, and in the download, phivals.m isn't even a text file; it's in html for some reason.  However, on the web.mit.edu website, the formating is correct, although it's still a html file.

import numpy as np
import scipy
from scipy.linalg import toeplitz

def phivals(h,i):
    """
    phivals = phivals(h,i)
    Generate a scaling function and its associated wavelet
    using the given filter coefficients

    Matlab original version (but it was a html file!) by Kevin Amaratunga 5 March 1993
    INPUTS:
    h = filter coefficients (sum(h)=2)
    i = discretization parameter. The number of points per integer
    step is 2^i.  Thus, setting i = 0 gives the scaling function
    and wavelet values at integer points

    OUTPUTS: x,phi,psi
    """

    assert i>=0, "phivals: i must be non-negative"

    m,n = h.shape
    assert n==1, "input h is not a column vector"

    g = np.multiply( np.array( [(-1)**i for i in range(0,m)]), h[::-1,0] )

    # The Haar filter produces a singular matrix, but since we know the solution
    # already we treat this as a special case.

    if m == 2 and h == np.vstack( np.array([1,1])):
        phi = np.vstack( np.append(np.ones(2**i), np.zeros(1) ) )

        if i > 0:
            psi = np.vstack( np.append( np.append(np.ones(2**(i-1)),-np.ones(2**(i-1))), np.zeros(1) ))

        elif i==0:
            psi = np.vstack( np.array([1,0]) )
    else:
        ch = np.vstack( (h,np.zeros((m,1)) ))
        rh = np.append( np.array([h[0,0]]), np.zeros(m-1))
        tmp = toeplitz(ch,rh)

        M = tmp.flatten('F')[0:-1:2].reshape((m,m)).T - np.identity(m)

        M[-1,:] = np.ones(m)
        tmp = np.vstack( np.append(np.zeros(m-1),np.identity(1)) )
        phi = np.linalg.solve( M,tmp)

        # Integer values of phi
        if i > 0:
            for k in range(0,i):
                p = 2**(k+1)*(m-1)+1   # No of rows in toeplitz matrix
                q = 2**k *(m-1)+1      # No of columns toeplitz matrix
                if k==0:
                    ch0 = np.vstack( np.append( h, np.zeros(p-1-m)) )
                    ch  = np.vstack( ( ch0, np.zeros(1) ))
                    cg0 = np.vstack( np.append(g, np.zeros(p-1-m)))
                else:
                    ch =  np.vstack( np.append( np.identity(1), np.zeros(2**k-1))).dot(ch0.T)
                    ch = np.vstack( np.append( ch.flatten('F'), np.zeros(1) ) )
                rh = np.append( ch[0], np.zeros(q-1) )
                Th = toeplitz(ch,rh)
                if k == i-1:
                    cg = (np.vstack(np.append(np.identity(1),np.zeros(2**k-1)))).dot( cg0.T)
                    cg = cg.flatten('F') # flatten
                    cg = np.vstack( np.append(cg,np.zeros(1)))
                    rg = np.append( cg[0], np.zeros(q-1) )
                    Tg = toeplitz(cg,rg)
                    psi = Tg.dot(phi)
                phi = Th.dot(phi)
        elif i==0:
            cg0 = np.vstack( np.append( g, np.zeros(m-1) ) )
            cg = np.vstack((cg0, np.zeros(1) ) )
            rg = np.append(cg[0],np.zeros(m-1))
            Tg = toeplitz(cg,rg)
            psi = Tg.dot(phi)
            psi=psi[::2]

    a,b = phi.shape
    x = np.vstack( np.arange(0,a)/2.**i )

    return x,phi,psi

#################
## test values
#################
h_test = np.random.rand(3,1)


# Università di Bologna
# Corso di laurea in Informatica
# 02023 - Calcolo numerico
# 17/11/2021
#
# Stefano Volpe #969766
# lab4.py

import numpy as np
import matplotlib.pyplot as plt

def es0():
    '''
    Esercizio 1: Calcolare lo zero di una funzione
    Scrivere una function che implementi il metodo delle approssimazioni
    successive per il calcolo dello zero di una funzione f(x) per x \\in R^n
    prendendo come input una funzione per l'aggiornamento:
    - g(x) = x - f(x) e ^ (x / 2)
    - g(x) = x - f(x) e ^ (- x / 2)
    - g(x) = x - f(x) / f'(x)
    Testare il risolutore per risolvere f(x) = e ^ x - x ^ 2 = 0, la cui
    soluzione è x* = -0.7034674 ca. In particolare:
    - disegnare il grafico della funzione f nell’intervallo I = [−1,1] e
    verificare che x* sia lo zero di f in [-1, 1];
    - calcolare lo zero della funzione utilizzando entrambe le funzioni
    precedentemente scritte;
    - confrontare l'accuratezza delle soluzioni trovate e il numero di
    iterazioni effettuate dai solutori;
    - modificare le due funzioni in modo da calcolare l'errore ad ogni
    iterazione k-esima e graficare.
    '''
    def succ_app(f, g, tolf, tolx, maxit, xTrue, x0 = 0):
        i = 0
        err = np.zeros(maxit + 1, dtype = np.float64)
        err[0] = tolx + 1 # errori relativi rispetto all'iterato precedente
        vecErrore = np.zeros(maxit + 1, dtype = np.float64) # err. ass. da sol.
        vecErrore[0] = np.abs(x0 - xTrue)
        x = x0
        # scarto assoluto tra iterati
        while (i < maxit and (err[i] > tolx or abs(f(x)) > tolf)):
            x_new = g(x)
            err[i + 1] = abs((x_new - x) / x_new)
            vecErrore[i + 1] = x - xTrue
            i = i + 1
            x = x_new
        err = err[0 : i]
        vecErrore = vecErrore[0 : i]
        return (x, i, err, vecErrore)

    f = lambda x: np.exp(x) - x ** 2
    df = lambda x: np.exp(x) - 2 * x

    g1 = lambda x: x - f(x) * np.exp(x / 2)
    g2 = lambda x: x - f(x) * np.exp(- x / 2)
    g3 = lambda x: x - f(x) / df(x)

    xTrue = -0.7034674
    fTrue = f(xTrue)
    print(fTrue)

    tolx= 10**(-10)
    tolf = 10**(-6)
    maxit = 100
    x0 = 0

    [sol_n, iter_n, err_n, vecErrore_g1] = \
        succ_app(f, g1, tolf, tolx, maxit, xTrue, x0)
    print('Metodo approssimazioni successive g1 \n x =', sol_n, '\n iter_new=',
        iter_n, '\n err_new=', err_n)

    [sol_n, iter_n, err_n, vecErrore_g2] = \
        succ_app(f, g2, tolf, tolx, maxit, xTrue, x0)
    print('Metodo approssimazioni successive g2 \n x =', sol_n, '\n iter_new=',
        iter_n, '\n err_new=', err_n)

    [sol_n, iter_n, err_n, vecErrore_g3] = \
        succ_app(f, g3, tolf, tolx, maxit, xTrue, x0)
    print('Metodo approssimazioni successive g2 \n x =', sol_n, '\n iter_new=',
        iter_n, '\n err_new=', err_n)

    # GRAFICO Errore vs Iterazioni

    # g1
    plt.plot(vecErrore_g1, '.-', color='blue')
    # g2
    plt.plot(vecErrore_g2[ : 3], '.-', color='green')
    # g3
    plt.plot(vecErrore_g3, '.-', color='red')

    plt.legend( ("g1", "g2", "g3"))
    plt.xlabel('iter')
    plt.ylabel('errore')
    plt.title('Errore vs Iterazioni')
    plt.grid()

def es1():
    '''
    Esercizio 2: metodo del gradiente per l'ottimizzazione in R^n
    Scrivere una funzione che implementi il metodo del gradiente rispettivamente
    con step size \\alpha_k variabile, calcolato secondo la procedura di
    backtracking ad ogni iterazione k-esima.
    Testare la function per minimizzare f(x) definita come:
        f(x) = 10 (x - 1)^2 + (y - 2)^2
    In particolare:
    - plotta la superficie f(x) con plt.plot_surface() e le curve di livello con
    plt.contour().
    - plotta, al variare delle iterazioni, la funzione obiettivo, l'errore e la
    norma del gradiente.
    '''
    def f(x, y):
        return (x - 1) ** 2 - (y - 2) ** 2

    x = np.linspace(-1.5, 3.5, 100)
    y = np.linspace(-1, 5, 100)
    X, Y = np.meshgrid(x, y)
    Z=f(X, Y)

    plt.figure(figsize = (15, 8))

    ax1 = plt.subplot(1, 2, 1, projection = '3d')
    ax1.plot_surface(X, Y, Z, cmap = 'viridis')
    ax1.set_title('Surface plot')
    ax1.view_init(elev = 20)

    ax2 = plt.subplot(1, 2, 2, projection = '3d')
    ax2.plot_surface(X, Y, Z, cmap = 'viridis')
    ax2.set_title('Surface plot from a different view')
    ax2.view_init(elev = 5)
    plt.show()

    # plt.figure(figsize=(8, 5))

    contours = plt.contour(X, Y, Z, levels = 10)
    plt.title('Contour plot')
    plt.show()

    # backtracking procedure for the choice of the steplength
    def next_step(x, grad):
        alpha = 1.1
        rho = 0.5
        c1 = 0.25
        p = -grad
        j = 0
        jmax = 10
        while f(x[0] + alpha * p[0], x[1] + alpha * p[1]) > f(x[0], x[1]) + c1 \
            * alpha * grad.T @ p and j < jmax:
            alpha = rho * alpha
            j += 1
        if (j>jmax):
            return -1
        else:
            # print('alpha = ',alpha)
            return alpha

    # funzione che implementa il metodo del gradiente
    def minimize(x0, b, mode, step, MAXITERATION, ABSOLUTE_STOP):
        # declare x_k and gradient_k vectors
        if mode == 'plot_history':
            x = np.zeros((2, MAXITERATION))

        norm_grad_list = np.zeros((1, MAXITERATION))
        function_eval_list = np.zeros((1, MAXITERATION))
        error_list = np.zeros((1, MAXITERATION))

        #initialize first values
        x_last = np.array([x0[0], x0[1]])

        if mode == 'plot_history':
            x[:, 0] = x_last

        k = 0

        function_eval_list[:, k] = f(x_last[0], x_last[1])
        error_list[:, k] = np.linalg.norm(x_last - b)
        norm_grad_list[:, k] = np.linalg.norm(grad_f(x_last))

        while np.linalg.norm(grad_f(x_last)) > ABSOLUTE_STOP \
            and k < MAXITERATION:
            k = k + 1
            # direction is given by gradient of the last iteration
            grad = grad_f(x_last)

            # backtracking step
            step = next_step(x_last, grad)
            # Fixed step
            # step = 0.1

            if(step == -1):
                print('non convergente')
                return k # no convergence

            x_last = x_last - step * grad
            if mode == 'plot_history':
                x[:, k] = x_last

        function_eval_list[:, k] = f(x_last[0], x_last[1])
        error_list[:, k] = np.linalg.norm(x_last - b)
        norm_grad_list[:, k] = np.linalg.norm(grad_f(x_last))

        function_eval_list = function_eval_list[:, :k + 1]
        error_list = error_list[:, :k + 1]
        norm_grad_list = norm_grad_list[:, :k + 1]

        print('iterations = ',k)
        print('last guess: x = (%f, %f)' % (x[0, k], x[1, k]))

        # plots
        if mode == 'plot_history':
            v_x0 = np.linspace(-5, 5, 500)
            v_x1 = np.linspace(-5, 5, 500)
            x0v, x1v = np.meshgrid(v_x0, v_x1)
            z = f(x0v, x1v)

            plt.figure()
            ax = plt.axes(projection = '3d')
            ax.plot_surface(v_x0, v_x1, z, cmap = 'viridis')
            ax.set_title('Surface plot')
            plt.show()

            # plt.figure(figsize=(8, 5))
            contours = plt.contour(x0v, x1v, z, levels = 100)
            plt.plot(x[0, 0:k],x[1, 0:k], '*')
            # plt.axis([-5,5,-5,5])
            plt.axis('equal')
            plt.show()
        return x_last, norm_grad_list, function_eval_list, error_list, k

    b = np.array([1,2])

    def f(x1, x2):
      res = 10 * (x1 - b[0]) ** 2 + (x2 - b[1]) ** 2
      return res

    def grad_f(x):
        return np.array([20 * (x[0] - b[0]), 2 * (x[1] - b[1])])

    step = 0.1
    MAXITERATIONS = 1000
    ABSOLUTE_STOP = 1.e-5
    mode = 'plot_history'
    x0 = np.array((3, -5))
    x_last, norm_grad_list, function_eval_list, error_list, k = \
        minimize(x0, b, mode, step, MAXITERATIONS, ABSOLUTE_STOP)

    plt.plot(norm_grad_list.T, 'o-')
    plt.xlabel('iter')
    plt.ylabel('Norma Gradiente')
    plt.title('Iterazioni vs Norma Gradiente')
    plt.grid()

    plt.plot(error_list.T, 'o-')
    plt.xlabel('iter')
    plt.ylabel('Errore')
    plt.title('Errore vs Iterazioni')
    plt.grid()

    plt.plot(function_eval_list.T, 'o-')
    plt.xlabel('iter')
    plt.ylabel('Funzione Obiettivo')
    plt.title('Iterazioni vs Funzione Obiettivo')
    plt.grid()


"""
Implement simple polynomial interpolation to help draw smooth curves
on the merge trees
"""
import numpy as np
import matplotlib.pyplot as plt

def polyFit(X, xs, doPlot = False):
    """
    Given a Nx2 array X of 2D coordinates, fit an N^th order polynomial
    and evaluate it at the coordinates in xs.
    This function assumes that all of the points have a unique X position
    """
    x = X[:, 0]
    y = X[:, 1]
    N = X.shape[0]
    A = np.zeros((N, N))
    for i in range(N):
        A[:, i] = x**i
    AInv = np.linalg.inv(A)
    b = AInv.dot(y[:, None])

    M = xs.size
    Y = np.zeros((M, 2))
    Y[:, 0] = xs
    for i in range(N):
        Y[:, 1] += b[i]*(xs**i)
    if doPlot:
        plt.plot(Y[:, 0], Y[:, 1], 'b')
        plt.hold(True)
        plt.scatter(X[:, 0], X[:, 1], 20, 'r')
        plt.show()
    return Y

if __name__ == '__main__':
    [x1, y1, x3, y3] = [100, 100, 101, 104]
    x2 = 0.5*(x1 + x3)
    y2 = 0.25*y1 + 0.75*y3
    xs = np.linspace(x1, x3, 50)
    X = np.array([[x1, y1], [x2, y2], [x3, y3]])
    Y = polyFit(X, xs, doPlot = False)
    plt.plot(Y[:, 0], Y[:, 1], 'k')
    plt.hold(True)
    plt.scatter(X[:, 0], X[:, 1], 20)
    plt.axis('equal')
    plt.show()


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

"""
Programa 4: Fórmula de Simpson compuesta
"""

"""
Datos de entrada
"""

# Función cuya integral queremos aproximar
import scipy as sp
import numpy as np
from numpy.polynomial import polynomial as P

import math
import scipy.integrate as integrate
import scipy.special as special
def f(x):
	return (math.exp(3*x)*math.sin(3*x))/(x**4+1)

a = 0
b = 2
n = 20

"""
Implementación
"""

# Fórmula de Simpson compuesta
def SimpsonCompuesto(f, a, b, n):
	m = 2 * n
	h = float((b - a)) / float(m)

	nodos = []
	for i in range(m+1):
		nodos.append(a + i * h)

	sum1 = 0
	for i in range(1,n+1):
		sum1 += 4 * f(nodos[2 * i - 1])

	sum2 = 0
	for i in range(2,n+1):
		sum2 += 2 * f(nodos[2 * i - 2])

	return (h / 3) * (f(nodos[0]) + sum1 + sum2 + f(nodos[m]))

"""
Programa principal
"""

i = 0
result = integrate.quad(f, 0, 2)
print("Valor de la integral", result[0])

print("Método de Simpson Compuesto:")
# Ejemplo de ejecución
for i in range(1, n+1):
        print("n =", i, "Error obtenido: ", SimpsonCompuesto(f, a, b, i)-result[0])

def intTrapecio( f, a, b, n ):
     h = float((b-a))/float(n)
     x=[ a+h*i for i in range(n+1)]

     if(n<1):
          resultado=0
     elif(n==1):
          resultado = (f(b) + f(a))*(b-a)/2
     else:
          resultado = ( h *( ( f(x[0]) + f(x[n]) )/2 + sum([f(x[i+1]) for i in range(n-1)]) ) )

     return resultado

a=0
b=2

print("Método del trapecio compuesto")
for i in range(439, 441):
        resultado = intTrapecio( f, a, b, i )
        print("El valor aproximado es:",resultado, "la diferencia con el valor exacto es: ", resultado-result[0], "con n = ", i)


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

import numpy as np, pandas as pd, seaborn as sns, pandas_datareader.data as web
from cmdstanpy import CmdStanModel
from matplotlib import pyplot as plt, ticker as mtick

#%% load data

stock_names = ["GOOG", "AAPL", "AMZN", "TSLA"]
stock_df = pd.DataFrame()
for stock in stock_names:
	stock_data = web.DataReader(stock, 'yahoo', "2015-09-01", "2018-04-27")
	stock_df[stock] = stock_data["Open"]
stock_df.index = stock_data.index
stock_returns = stock_df.pct_change()[1:]

pd.DataFrame({
	"mu": [-.03, .05, .03, -.02],
	"sigma": [.04, .03, .02, .01]
}, index = stock_names)

stock_returns.mean()
stock_returns.cov()

#%% some plot

cum_returns = np.cumprod(1 + stock_returns) - 1
cum_returns.index = stock_returns.index
cum_returns.plot()
plt.legend(loc = "upper left")
plt.ylabel("Return of $1 on first date")
plt.gca().yaxis.set_major_formatter(mtick.PercentFormatter(xmax = 1))

meltt = stock_returns.melt(var_name = "column")
sns.displot(meltt, x = 'value', hue = 'column', bins = "sqrt", kde = True)
g = sns.FacetGrid(meltt, col = 'column', col_wrap = 2)
g.map(sns.histplot, 'value', bins = "sqrt", kde = True)

#%% model

mdl_data = {"N": len(stock_returns), "N_stocks": len(stock_names), "observations": stock_returns.values}
modelfile = "stocks.stan"
with open(modelfile, "w") as file: file.write("""
	data { // avoid putting data in matrix except for linear algebra
		int<lower=0> N;
		int<lower=0> N_stocks;
		row_vector[N_stocks] observations[N];
	}

	transformed data {
		int<lower=2+N_stocks> df = 10;
		row_vector[N_stocks] expert_mus = [-.03, .05, .03, -.02];
		matrix<lower=0>[N_stocks, N_stocks] expert_sigmas = diag_matrix(square([.04, .03, .02, .01]'));
	}

	parameters { // discrete parameters impossible
		row_vector[N_stocks] locs;
		cov_matrix[N_stocks] covs;
	}

	transformed parameters { // Cholesky form, more numerically stabilized
		cholesky_factor_cov[N_stocks] L = cholesky_decompose(covs);
	}

	model {
		locs ~ normal(expert_mus, 1);
		covs ~ wishart(df, expert_sigmas);
		observations ~ multi_normal_cholesky(locs, L); // failed to initialize if not use Cholesky
	}
""")

sm = CmdStanModel(stan_file = modelfile)

#%% reparameterization for more efficient computation: Bartlett decomposition

modelfile_repar = "stocks_repar.stan"
with open(modelfile_repar, "w") as file: file.write("""
	data { // avoid putting data in matrix except for linear algebra
		int<lower=0> N;
		int<lower=0> N_stocks;
		row_vector[N_stocks] observations[N];
	}

	transformed data {
		int<lower=2+N_stocks> df = 10;
		row_vector[N_stocks] expert_mus = [-.03, .05, .03, -.02];
		matrix<lower=0>[N_stocks, N_stocks] expert_sigmas = diag_matrix(square([.04, .03, .02, .01]'));
		cholesky_factor_cov[N_stocks] L = cholesky_decompose(expert_sigmas);
	}

	parameters { // discrete parameters impossible
		row_vector[N_stocks] locs;
		vector[N_stocks] c;
		vector[N_stocks * (N_stocks - 1) / 2] z;
	}

	transformed parameters {
		matrix[N_stocks, N_stocks] A;
		{ // extra layer of brackes let us define a local int for the loop
			int count = 1;
			for (j in 1:(N_stocks-1)) {
				for (i in (j+1):N_stocks) {
					A[i,j] = z[count];
					count += 1;
				}
				for (i in 1:(j-1)) A[i,j] = 0;
				A[j, N_stocks] = 0;
				A[j,j] = sqrt(c[j]);
			}
			A[N_stocks, N_stocks] = sqrt(c[N_stocks]);
		}
	}

	model {
		for (i in 1:N_stocks) c[i] ~ chi_square(df - i + 1);
		z ~ std_normal();
		locs ~ normal(expert_mus, 1);
		observations ~ multi_normal_cholesky(locs, L*A);
	}
""")

Xrange = range(1, 5)
var_name_repar_array = [f"locs[{i}]" for i in Xrange] + [f"A[{i},{i}]" for i in Xrange]
var_name_repar_combi = ["locs", "A"]

sm_repar = CmdStanModel(stan_file = modelfile_repar)

# maximum likelihood estimation
optim_repar = sm_repar.optimize(data = mdl_data).optimized_params_pd
optim_repar[var_name_repar_array]

# variational inference
vb_repar = sm_repar.variational(data = mdl_data)
vb_repar.variational_sample.columns = vb_repar.variational_params_dict.keys()
vb_name_repar = vb_repar.variational_params_pd.columns[~vb_repar.variational_params_pd.columns.str.startswith(("lp", "log_"))]
vb_repar.variational_params_pd[var_name_repar_array]
vb_repar.variational_sample[var_name_repar_array]

# Markov chain Monte Carlo
fit_repar = sm_repar.sample(
	data = mdl_data, show_progress = True, chains = 4,
	iter_sampling = 50000, iter_warmup = 10000, thin = 5
)

fit_repar.draws().shape # iterations, chains, parameters
fit_repar.summary().loc[var_name_repar_array] # pandas DataFrame
print(fit_repar.diagnose())

posterior_repar = {k: fit_repar.stan_variable(k) for k in var_name_repar_combi}

# re-compose the covariance matrix
L_repar = np.linalg.cholesky(np.diag([.04, .03, .02, .01]))
f = lambda a: L_repar @ a @ a.T @ L_repar.T
posterior_repar["covs"] = np.array([f(a) for a in posterior_repar["A"]])

colors = ['#5DA5DA', '#F15854', '#B276B2', '#60BD68']
fig = plt.figure(figsize = (16, 9))
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
for i in range(len(stock_names)):
	sns.kdeplot(posterior_repar["locs"][:,i], color = colors[i], ax = ax1)
	sns.kdeplot(posterior_repar["covs"][:,i,i], color = colors[i], ax = ax2)
ax1.legend(labels = stock_names)
ax1.set_title(r"$ \mu $")
ax2.legend(labels = stock_names)
ax2.set_title(r"$ \sigma $")


import numpy as np

from bootstrap import create_normal_ci, create_percentile_ci, create_pivotal_ci

def sample_corr_plugin(ys, zs):
    ys_mean = ys.mean()
    zs_mean = zs.mean()
    numerator = np.sum((ys - ys_mean) * (zs - zs_mean))
    denominator = np.sqrt(
        np.sum((ys - ys_mean) ** 2) * np.sum((zs - zs_mean) ** 2)
    )
    return numerator / denominator

rng = np.random.default_rng(42)

b = 5000
lsat = np.array(
    [576, 635, 558, 578, 666, 580, 555, 661, 651, 605, 653, 575, 545, 572, 594]
)
gpa = np.array(
    [3.39, 3.30, 2.81, 3.03, 3.44, 3.07, 3.00, 3.43, 3.36, 3.13]
    + [3.12, 2.74, 2.76, 2.88, 2.95]
)
n = len(lsat)
idxs = np.arange(0, n)

est_corr = sample_corr_plugin(lsat, gpa)

bootstrap_corrs = np.zeros(b)
for i in range(b):
    random_idxs = rng.choice(idxs, size=n, replace=True)
    lsat_sample = lsat[random_idxs]
    gpa_sample = gpa[random_idxs]

    bootstrap_corrs[i] = sample_corr_plugin(lsat_sample, gpa_sample)

est_corr_se = bootstrap_corrs.std()

print(f"The plug-in estimate for the correlation is {est_corr:.5}.")
print(f"Bootstrap approximation for standard error is {est_corr_se:.4}.")
normal_ci = create_normal_ci(est_corr, bootstrap_corrs)
print(f"95% CI by normal method is [{normal_ci[0]:.4}, {normal_ci[1]:.4}]")
pivotal_ci = create_pivotal_ci(est_corr, bootstrap_corrs)
print(f"95% CI by pivotal method is [{pivotal_ci[0]:.4}, {pivotal_ci[1]:.4}]")
percent_ci = create_percentile_ci(bootstrap_corrs)
print(
    f"95% CI by percentile method is [{percent_ci[0]:.4}, {percent_ci[1]:.4}]"
)


import numpy as np
import matplotlib.pyplot as plt

N_samples = 10000

mu1 = 100.
mu2 = 100.
sigma1 = 20.
sigma2 = 10.
h = 2

def volume(a1, a2, h):
  return h*(a1 + a2 + np.sqrt(a1*a2))/3

def compute_mu(mu1, mu2, h):
  return volume(mu1, mu2, h)

def compute_sigma(sigma1, sigma2, h):
  return h*np.sqrt(sigma1**2+sigma2**2)/3

def compute_sigma_orig(sigma1, sigma2, h):
  return h*(sigma1+sigma2)/3

# sample X and Y
s1 = np.random.normal(mu1, sigma1, N_samples)
s2 = np.random.normal(mu2, sigma2, N_samples)

# Compute Z
v = volume(s1, s2, h)

# Plot hist of Z
count, bins, ignored = plt.hist(v, 100, normed=True)

# Compute and plot approx of Z
mu = compute_mu(mu1, mu2, h)
sigma = compute_sigma(sigma1, sigma2, h)
sigma_orig = compute_sigma_orig(sigma1, sigma2, h)

plt.plot(
    bins,
    1/(sigma * np.sqrt(2 * np.pi)) * np.exp( - (bins - mu)**2 / (2 * sigma**2) ),
    linewidth=2, color='r')

plt.plot(
    bins,
    1/(sigma_orig * np.sqrt(2 * np.pi)) * np.exp( - (bins - mu)**2 / (2 * sigma_orig**2) ),
    linewidth=2, color='g')
plt.show()


import sys
import numpy as np
from numpy import linalg as LA

def fib(n):
    A = np.matrix([[1, 1], [1, 0]], dtype='object')
    R = LA.matrix_power(A, n - 1)
    return R.item((0, 0))

n = int(sys.argv[1])
print("res = ", fib(n))


# -*- coding: utf-8 -*-
import numpy as np
from matplotlib.mlab import find
from svm_kernels import kernel_svm_rbf
from optim.optimizer import qp_optimizer

def svm_train(X, y, sigma, C):
    """SVM training for a 2 label classification problem. Label -1 and 1 are
    used to distinguise between the two classes.

    Args:
        X (ndarray): Input training data set.\n
        y (ndarray): Label for the training set.\n
        sigma (float): The variance of the RBF kernel.\n
        C (float): Upper bound optimization value.

    Yields:
        SVM (dict): A container of the trained values (support vectors etc.).

    Example:
        Train the synthetic SVM data set

        >>> SVM = svm_train(Train, target, 1, 1000)
    """
    # Scale data set (other scaling can be used instead)
    shift = np.mean(X, axis=0)
    stdiv = np.std(X, axis=0)
    scale = 1/stdiv

    # Apply scaling
    for c in range(len(X[0])):
        X[:, c] = scale[c] * (X[:, c] + shift[c])

    # Generate kernel
    kernel = kernel_svm_rbf(X.T, X.T, sigma)

    # Make kernel symmetric
    kernel = (kernel + kernel.T)/2  # + np.diag(1 / (np.ones((len(y),1)) * C))

    # Formulate as QP as the problem  min:  1/2*x'*H*x + f'*x

    # Construct H: Represents the Hessian matrix
    H = y.dot(y.T) * kernel

    # Make H symmetric
    # H = (H+H.T)/2

    # Construct f: Represents the linear term
    f = -np.ones(len(X))

    # Construct Aeq: Represents the linear coefficients in Aeq*x = beq
    Aeq = y.T

    # Construct beq: Represents the constant vector in Aeq*x = beq
    beq = 0

    # Construct lb: Represents the lower bounds elementwise in lb
    lb = np.zeros(len(y))

    # Construct ub: Represents the upper bounds elemetwise in ub
    ub = C*np.ones(len(y))

    # QP solver
    res = qp_optimizer(H, f, Aeq, beq, lb, ub)

    # The support vectors are non-zero of res.x
    reference = np.sqrt(np.spacing(1))
    support_vector_index = find(res.x > reference)
    support_vector = X[support_vector_index, :]

    # Hat
    alpha_hat = y[support_vector_index].T * res.x[support_vector_index]

    # Find the bias (several possibilities)
    max_pos = np.argmax(res.x)
    bias = y[max_pos] - np.sum(alpha_hat * kernel[support_vector_index, max_pos])

    # Rescale data
    for c in range(len(support_vector[0])):
        support_vector[:, c] = (support_vector[:, c]/scale[c]) - shift[c]

    # Construct a dictonary of the trained values
    SVM = {}
    SVM['support_vector'] = support_vector
    SVM['support_vector_index'] = support_vector_index
    SVM['sigma'] = sigma
    SVM['C'] = C
    SVM['alpha_hat'] = alpha_hat
    SVM['shift'] = shift
    SVM['scale'] = scale
    SVM['bias'] = bias

    return(SVM)


# -*- coding: utf-8 -*-
"""
computes the MFCCs from the magnitude spectrum (see Slaney)

  Args:
    X: spectrogram (dimension FFTLength X Observations)
    f_s: sample rate of audio data

  Returns:
    v_mfcc mel frequency cepstral coefficients
"""

import numpy as np
from ToolMfccFb import ToolMfccFb

def FeatureSpectralMfccs(X,f_s, iNumCoeffs = 13):

    # allocate memory
    v_mfcc = np.zeros ([iNumCoeffs, X.shape[1]])

    # generate filter matrix
    H = ToolMfccFb(X.shape[0], f_s)
    T = generateDctMatrix (H.shape[0], iNumCoeffs)

    for n in range(0,X.shape[1]):
        # compute the mel spectrum
        X_Mel = np.log10(np.dot(H, X[:,n] + 1e-20))

        # calculate the mfccs
        v_mfcc[:,n] = np.dot(T, X_Mel)

    return (v_mfcc)

# see function mfcc.m from Slaneys Auditory Toolbox
def generateDctMatrix (iNumBands, iNumCepstralCoeffs):
    T = np.cos(np.outer(np.arange(0,iNumCepstralCoeffs), (2*np.arange(0,iNumBands)+1)) * np.pi/2/iNumBands)

    T = T / np.sqrt(iNumBands/2)
    T[0,:] = T[0,:] / np.sqrt(2)

    return (T)


import numpy as np
import numpy.linalg as LA
import math as m

def gaussianKernel(x1, x2, sigma):
    """returns a gaussian kernel between x1 and x2
    and returns the value in sim
    """
    # RBF Kernel
    return m.exp(-(LA.norm(x1.ravel() - x2.ravel())**2)/(2*sigma**2))


import os
import numpy as np

def get_lrt_folder():
    user_location = os.path.expanduser('~/.pylrtrc')
    try:
        with open(user_location, 'r') as f:
            return f.read().strip()
    except FileNotFoundError:
        raise FileNotFoundError('No default location for LibRadTran found. Place the path in ~/.pylrtrc.')

def planck_function(temperature, wavelength=None, frequency=None, wavenumber=None):
    '''Supply one of wavelength in m, frequency in Hz, wavenumber in m-1'''
    import scipy.constants
    h = scipy.constants.h
    c = scipy.constants.c
    kb = scipy.constants.Boltzmann
    if wavelength is not None:
        return ((2*h*c**2)/(wavelength**5))*(1/(np.exp(h*c/(kb*temperature*wavelength))-1))
    elif frequency is not None:
        return ((2*h*frequency**3)/(c**2))*(1/(np.exp(h*frequency/(kb*temperature))-1))
    elif wavenumber is not None:
        return ((2*h*c**2*wavenumber**3))*(1/(np.exp(h*c*wavenumber/(kb*temperature))-1))


from sympy import *
x = Symbol('x')
# y = solve(x**4 - 4*x -1, x)
# print(N(y[1])*(-1)**0.5)
# print((-1)**0.5)

ns =1.5
zeta = 0.15
famp = 7
fmean = 11
sse = 56861.6
sut = 284306.60
d = 0.0915
# temp = ns*2*(1+zeta)*(famp/se  + fmean/sy)
# eqn  = 4*(x**2)*temp + 2*temp*x-4*x+3
eqn = (((4*x+2)*8*(1+zeta)*x*ns)/(pi*d*d))*(famp/sse+fmean/sut)+3-4*x

c = solve(eqn, x)
for tt in c:
  print(N(tt))


import numpy as np
import matplotlib.pyplot as plt
import math
from BSplineBasis import CoxDeBoorRecursion, BasisGraph
from KnotVectors import OpenUniformKnotVector
from BSpline import BSpline

def CoxDeBoorFirstDerivative(i, order, Knots, t):
    if order == 1:
        return 0.
    else:
        ftt = CoxDeBoorRecursion(i, order - 1, Knots, t) + (t - Knots[i]) * CoxDeBoorFirstDerivative(i, order - 1, Knots, t)
        ftb = Knots[i + order - 1] - Knots[i]
        stt = (Knots[i + order] - t) * CoxDeBoorFirstDerivative(i + 1, order - 1, Knots, t) - CoxDeBoorRecursion(i + 1, order - 1, Knots, t)
        stb = Knots[i + order] - Knots[i + 1]

        first = ftt / ftb
        if math.isnan(first):
            first = 0.

        second = stt / stb
        if math.isnan(second):
            second = 0.

        return first + second

def CoxDeBoorSecondDerivative(i, order, Knots, t):
    if order <= 2:
        return 0.
    else:
        ftt = 2 * CoxDeBoorFirstDerivative(i, order - 1, Knots, t) + (t - Knots[i]) * CoxDeBoorSecondDerivative(i, order - 1, Knots, t)
        ftb = Knots[i + order - 1] - Knots[i]
        stt = (Knots[i + order] - t) * CoxDeBoorSecondDerivative(i + 1, order - 1, Knots, t) - 2 * CoxDeBoorFirstDerivative(i + 1, order - 1, Knots, t)
        stb = Knots[i + order] - Knots[i + 1]

        first = ftt / ftb
        if math.isnan(first):
            first = 0.

        second = stt / stb
        if math.isnan(second):
            second = 0.

        return first + second

def BasisFirstDerivativeGraph(Knots, order, i, T):
    values = []
    for t in T:
        values.append(CoxDeBoorFirstDerivative(i, order, Knots, t))
    return np.asarray(values)

def BasisSecondDerivativeGraph(Knots, order, i, T):
    values = []
    for t in T:
        values.append(CoxDeBoorSecondDerivative(i, order, Knots, t))
    return np.asarray(values)

def BSplineFirstDerivative(Points, order, Knots, T):
    countPoints = np.size(Points, 0)
    n = countPoints - 1
    dimension = np.size(Points, 1)
    rVal = []
    for t in T:
        point = np.zeros(dimension)
        for i in range(0, n+1):
            point += Points[i] * CoxDeBoorFirstDerivative(i, order, Knots, t)
        rVal.append(point)
    return np.array(rVal)

def BSplineSecondDerivative(Points, order, Knots, T):
    countPoints = np.size(Points, 0)
    n = countPoints - 1
    dimension = np.size(Points, 1)
    rVal = []
    for t in T:
        point = np.zeros(dimension)
        for i in range(0, n+1):
            point += Points[i] * CoxDeBoorSecondDerivative(i, order, Knots, t)
        rVal.append(point)
    return np.array(rVal)

def BSplineTangent(Points, order, Knots, t):
    deriv = BSplineFirstDerivative(Points, order, Knots, [t])[0]
    point = BSpline(Points, order, Knots, [t])[0]
    norm = deriv / np.linalg.norm(deriv)
    points = []
    points.append(point + norm)
    points.append(point - norm)
    points = np.asarray(points)
    return points

if __name__ == "__main__":
    order = 4
    countPoints = 6
    Knots = OpenUniformKnotVector(order, countPoints, False)

    maxKnot = np.max(Knots)

    T = np.arange(0., maxKnot, 0.01)

    for i in range(countPoints):
        plt.plot(T, BasisGraph(Knots, order, i, T))

    plt.show()

    for i in range(countPoints):
        plt.plot(T, BasisFirstDerivativeGraph(Knots, order, i, T))

    plt.show()

    for i in range(countPoints):
        plt.plot(T, BasisSecondDerivativeGraph(Knots, order, i, T))

    plt.show()

    BoxOrder = 3
    BoxPoints = np.array([[2, 0], [4, 0], [4, 2], [4, 4], [2, 4], [0, 4], [0, 2], [0, 0], [2, 0]])
    BoxKnots = OpenUniformKnotVector(BoxOrder, np.size(BoxPoints, 0), True)
    BoxT = np.arange(0., 1., 0.01)

    BoxSpline = BSpline(BoxPoints, BoxOrder, BoxKnots, BoxT)
    BoxFirstDerivative = BSplineFirstDerivative(BoxPoints, BoxOrder, BoxKnots, BoxT)
    BoxSecondDerivative = BSplineSecondDerivative(BoxPoints, BoxOrder, BoxKnots, BoxT)

    plt.plot(BoxPoints[:, 0], BoxPoints[:, 1])
    plt.plot(BoxSpline[:, 0], BoxSpline[:, 1])
    plt.plot(BoxFirstDerivative[:, 0], BoxFirstDerivative[:, 1])
    plt.plot(BoxSecondDerivative[:, 0], BoxSecondDerivative[:, 1])

    plt.show()

    BoxTangent = BSplineTangent(BoxPoints, BoxOrder, BoxKnots, 0.4)
    plt.plot(BoxPoints[:, 0], BoxPoints[:, 1])
    plt.plot(BoxSpline[:, 0], BoxSpline[:, 1])
    plt.plot(BoxTangent[:, 0], BoxTangent[:, 1])

    plt.show()


import math
import numpy as np

# https://cs.brown.edu/research/pubs/pdfs/1999/Moller-1999-EBA.pdf
def get_rotation_matrix(f, t):
    """Get rotation matrix from one vector (f) to another (t)"""
    v = np.cross(f, t)
    u = v / np.linalg.norm(v)
    c = np.dot(f, t)
    h = (1 - c) / (1 - (c ** 2))
    vx, vy, vz = v
    rotation_matrix = [
            [c + h*vx**2, h*vx*vy - vz, h*vx*vz + vy],
            [h*vx*vy+vz, c+h*vy**2, h*vy*vz-vx],
            [h*vx*vz - vy, h*vy*vz + vx, c+h*vz**2]
    ]
    return np.array(rotation_matrix)

# https://www.learnopencv.com/rotation-matrix-to-euler-angles/
def rotation_matrix_to_euler(R):
    """Convert rotation matrix (R) to euler [x, y, z] format"""
    sy = math.sqrt(R[0,0] * R[0,0] +  R[1,0] * R[1,0])

    singular = sy < 1e-6

    if  not singular :
        x = math.atan2(R[2,1] , R[2,2])
        y = math.atan2(-R[2,0], sy)
        z = math.atan2(R[1,0], R[0,0])
    else :
        x = math.atan2(-R[1,2], R[1,1])
        y = math.atan2(-R[2,0], sy)
        z = 0

    return np.array([x, y, z])


# Fast modulo exponentiation of numbers using Euler
# Rafał Lal 10/06/2021
import sys
from sympy.ntheory import isprime
from math import gcd

def euler_function(num):
    if isprime(num):
        return num - 1
    result = 1
    for i in range(2, num):
        if gcd(i, num) == 1:
            result += 1
    return result

def euler_theorem(a, n, m):
    eul = euler_function(m)
    n1 = n % eul
    n2 = pow(a, n1)
    return eul, n2 % m

def main():
    try:
        a = int(input('Base: '))
        n = int(input('Power: '))
        m = int(input('Mod: '))
        if n < 1 or m < 1 or gcd(a, m) != 1:
            raise ValueError
    except ValueError:
        print('Numbers does not fulfil requirements')
        sys.exit()

    e, r = euler_theorem(a, n, m)
    print('Euler({}) = {}'.format(m, e), "Result = {} <{}>".format(r, m), sep='\n')

if __name__ == '__main__':
    main()


from numpy import array as ary; from numpy import log as ln
from numpy import cos, sin, pi, sqrt, exp, arccos, e
tau = 2*pi
import numpy as np;
from matplotlib import pyplot as plt

def plot_complex(*lines_data, **kwargs):
    for line in lines_data:
        plt.plot(np.real(line), np.imag(line), **kwargs)
    return

def expo(base, exponent):
    mag = ln(np.absolute(base))
    arg = np.angle(base)
    x = np.real(exponent)
    y = np.imag(exponent)
    return exp(x*mag-y*arg) * exp(1j* (x*arg + y*mag))

if __name__=='__main__':
    #make a cartesian grid
    # x0 = np.arange(-0,9)
    x0 = np.arange(-pi, pi, 0.2)
    y0 = np.arange(-pi, pi, 0.2)
    x_ = 0
    y_ = 1
    z_ = x_ + y_*1j
    # z_ = exp(1j*np.linspace(0, pi))

    vert_lines = ary(np.meshgrid(x0, y0*1j)).T.sum(axis=2)
    horiz_lines = ary(np.meshgrid(y0*1j, x0)).T.sum(axis=2)
    plt.style.use('dark_background')
    plot_complex(*horiz_lines, color='C0')
    plot_complex(*vert_lines, color='C0')

    plot_complex(*( expo(horiz_lines, z_) ))
    plot_complex(*( expo(vert_lines, z_) ))
    plt.show()


# -*- coding: utf-8 -*-
"""
Created on Mon Mar 25 15:31:35 2019

INSTITUTO FEDERAL DE EDUCAÇÃO, CIÊNCIA E TECNOLOGIA DO PÁRA - IFPA ANANINDEUA

@author:
        Prof. Dr. Denis C. L. Costa

        Discentes:
            Heictor Alves de Oliveira Costa
            Lucas Pompeu Neves

Grupo de Pesquisa:
                 Gradiente de Modelagem Matemática e
                 Simulação Computacional - GM²SC

Assunto:
        Representação de Gráfica de Funções com duas variáveis independentes

Nome do sript: graficos_3d

Disponível em:
    https://github.com/GM2SC/DEVELOPMENT-OF-MATHEMATICAL-METHODS-IN-
    COMPUTATIONAL-ENVIRONMENT/blob/master/SINEPEM_2019/graficos_3d.py

"""
# Bibliotecas

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

# Comandos para plotar Gráficos em 3D
fig = plt.figure(1)
ax = Axes3D(fig)

# Intervalos de Análises: (x1, x2) e (y1, y2)
x1 = -5; x2 = 5
y1 = -5; y2 = 5
# Elemento de discretização: d
d = 0.25
x = np.arange(x1, x2, d)
# Valores de y:
y = np.arange(y1, y2, d)
print('')
print('=======================================')
print('Intervalos de Análises:')
print('(x1, x2), (y1, y2):', (x1, x2), (y1, y2))
print('=======================================')

# Função de duas Variáveis: z(x,y)
x, y = np.meshgrid(x, y)
z = x**2 + y**2

# Títulos do Gráfico 3D
ax.set_xlabel('Valores de x')
ax.set_ylabel('Valores de y')
ax.set_zlabel('Valores de z')
ax.set_title('Superfície de z = f(x,y)')

# Layout do Gráfico 3D:
# Opções de cores: cmap --> escolha a letra correspondente
a =  'Spectral'
b =  'seismic'
c =  'coolwarm'
d =  'PRGn'
e = 'RdYlBu'
f = 'RdGy'
g = 'RdYlGn'

ax.plot_surface(x, y, z, cmap = b)
print('')
print(' **** Gráficos gerados pelo Programa graficos_3d ****')

# Gráfico de Contornos
fig = plt.figure()
# n --> Número de linhas de contorno
n = 25
plt.contour(x, y, z, n)
plt.xlabel('Valores de x')
plt.ylabel('Valores de y')
plt.title('Curvas de Nível de z = f(x,y)')
plt.show()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
__author__ = 'cnheider'

import math

import numpy as np
import torch

def entropy(prob):
  return -torch.sum(prob * torch.log(prob), 1)

def log_entropy(log_prob):
  return -torch.sum(torch.exp(log_prob) * log_prob, 1)

def kl_log_probs(log_prob1, log_prob2):
  return -torch.sum(torch.exp(log_prob1) * (log_prob2 - log_prob1), 1)

def kl_probs(prob1, prob2):
  return -torch.sum(prob1 * torch.log(prob2 / prob1), 1)

def to_tensor(obj, dtype=torch.float, device='cpu'):
  if not torch.is_tensor(obj):
    return torch.tensor(obj, device=device, dtype=dtype)
  else:
    return obj.type(dtype).to(device)

def pi_torch(device='cpu'):
  return to_tensor([np.math.pi], device=device)

def normal(x, mu, sigma_sq, device='cpu'):
  a = (-1 * (to_tensor(x, device=device) - mu).pow(2) / (2 * sigma_sq)).exp()
  b = 1 / (2 * sigma_sq * pi_torch(device=device).expand_as(sigma_sq)).sqrt()
  return a * b

def normal_entropy(std):
  var = std.pow(2)
  ent = 0.5 + 0.5 * torch.log(2 * var * math.pi)
  return ent.sum(1, keepdim=True)

def normal_log_density(x, mean, log_std, std):
  var = std.pow(2)
  log_density = -(x - mean).pow(2) / (2 * var) - 0.5 * math.log(2 * math.pi) - log_std
  return log_density.sum(1, keepdim=True)


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

from numpy import *
from random import *
import matplotlib.pyplot as plt

'''
最小二乘法（又称最小平方法）:
    通过最小化误差的平方和寻找数据的最佳函数匹配。
    利用最小二乘法可以简便地求得未知的数据，并使得这些求得的数据与实际数据之间误差的平方和为最小。
    最小二乘法还可用于曲线拟合。其他一些优化问题也可通过最小化能量或最大化熵用最小二乘法来表达。

matplotlib： python 的2D 绘图库
'''

class LeastSquares:
    def __init__(self):
        pass

    '''
    一元线性回归
    x**y : x 的 y 次方
    sum(list) 表示 list 中算素相加的和
    // 表示整数除法
    / 表示浮点数除法
    '''
    def OneLeastSquares(self):
        x = [1, 2, 3, 5, 6, 12, 11, 13]
        y = [4, 5, 8, 13, 12, 23, 20, 22]
        # 求平均数（list所有元素的和/元素的个数）
        average_x = float(sum(x)) // len(x)
        average_y = float(sum(y)) / len(y)
        # 求残差
        x_sub = list(map((lambda x: x - average_x), x))
        y_sub = list(map((lambda x: x - average_y), y))
        # 残差平方
        x_sub_pow2 = list(map((lambda x: x ** 2), x_sub))
        y_sub_pow2 = list(map((lambda x: x ** 2), y_sub))
        # 残差成积
        x_y = list(map((lambda x, y: x * y), x_sub, y_sub))

        # 获取 最小残差平方和
        min_sub_pow2 = minimum(sum(x_sub_pow2), sum(y_sub_pow2))

        # 残差成积和/x方向的残差平方和
        a = float(sum(x_y)) / min_sub_pow2
        b = average_y - a * average_x
        plt.xlabel('X')
        plt.ylabel('Y')
        plt.plot(x, y, '*')
        plt.plot([0, 15], [0 * a + b, 15 * a + b])
        plt.grid()
        plt.show()

    def MoreLeastSquares(self):
        x, y, xr, yr = self.Data()
        X, Y = self.MAT(x, y, 9)
        XT = X.transpose()
        B = dot(dot(linalg.inv(dot(XT, X)), XT), Y)
        myY = dot(X, B)
        self.fig(x, myY, xr, yr)

    def Data(self):
        x = arange(-1, 1, 0.02)
        y = ((x * x - 1) ** 2 + 2) * (sin(x * 3) + 0.7 * cos(x * 1.2))
        xr = []
        yr = []
        i = 0
        for xx in x:
            yy = y[i]
            d = float(randint(80, 120)) / 100
            i += 1
            xr.append(xx * d)
            yr.append(yy * d)
        return x, y, xr, yr

    def MAT(self, x, y, order):
        X = []
        for i in range(order + 1):
            X.append(x ** i)
        X = mat(X).T
        Y = array(y).reshape((len(y), 1))
        return X, Y

    def fig(self, x1, y1, x2, y2):
        plt.xlabel('X')
        plt.ylabel('Y')
        plt.plot(x1, y1, color='g', linestyle='-', marker='')
        plt.plot(x2, y2, color='m', linestyle='', marker='.')
        plt.grid()
        plt.show()

LeastSquares().OneLeastSquares()
LeastSquares().MoreLeastSquares()


from RandomConcentration import fake_data
import numpy as np
import numpy.linalg as la

def generate_A(r, t):
    m = len(r)
    n = len(t)
    A = np.zeros((n, m))
    for j in range(n):
        for i in range(m):
            A[j][i] = np.exp(-1*r[i]*t[j])
    return A

def Cholesky(A, b):
    b = np.transpose(A)@b
    A = np.transpose(A)@A
    L = la.cholesky(A)
    y = la.lstsq(L, b, rcond=None)[0]
    x = la.lstsq(np.transpose(L), y, rcond=None)[0]
    return x

def QR(A, b):
    Q, R = la.qr(A)
    y = la.lstsq(Q, b, rcond=None)[0]
    x = la.lstsq(R, y, rcond=None)[0]
    return x

def SVD(A, b):
    U, S, Vh = la.svd(A)
    y = la.lstsq(U, b, rcond=None)[0]
    x = la.lstsq(np.diag(S)@Vh, y, rcond=None)[0]
    cond = max(S)/min(S)
    return x, cond

#easy problem
m = 5
n = 5
A_seed = 3
A_mu = 20.
A_sig = 1
r_seed = 19
r_mu = 20.
r_sig = 1
xi_seed = 2
xi_mu = 0
xi_sig = 0
r, t, F = fake_data(m, n, A_seed, A_mu, A_sig, r_seed, r_mu, r_sig, xi_seed, \
    xi_mu, xi_sig)
A = generate_A(r, t)
x_cho = Cholesky(A, F)
x_qr = QR(A, F)
x_svd, cond = SVD(A, F)

print("\nRMS differences between resulting solution vectors\n")
dim_info = "Dimension: m = {m:3d}, n = {n:3d}\n"
dim_info = dim_info.format(m = m, n = n)
print(dim_info)
A_info = "A:  seed = {A_seed:3d}, entry mean = {A_mu:8.1f}, sd = {A_sig:8.2f}"
A_info = A_info.format( A_seed = A_seed, A_mu = A_mu, A_sig = A_sig)
print(A_info)
r_info = "r:  seed = {r_seed:3d}, entry mean = {r_mu:8.1f}, sd = {r_sig:8.2f}"
r_info = r_info.format( r_seed = r_seed, r_mu = r_mu, r_sig = r_sig)
print(r_info)
xi_info = "xi: seed = {xi_seed:3d}, entry mean = {xi_mu:8.1f}, sd = {xi_sig:8.2f}\n"
xi_info = xi_info.format( xi_seed = xi_seed, xi_mu = xi_mu, xi_sig = xi_sig)
print(xi_info)
cq_info = "Cholesky vs. QR: {cq:14.6e}"
cs_info = "Cholesky vs SVD: {cs:14.6e}, condition number = {cond:14.6e}"
qs_info = "QR vs SVD:       {qs:14.6e}"
cq_info = cq_info.format( cq = la.norm(x_cho-x_qr))
cs_info = cs_info.format( cs = la.norm(x_cho-x_svd), cond = cond)
qs_info = qs_info.format( qs = la.norm(x_qr-x_svd))
print(cq_info)
print(cs_info)
print(qs_info)

Scientific Computing Projects (Code Parts)/3/Problem 2/LeastSquare.py


def verify_1a(answer):

    import sympy

    S = sympy.Symbol('S', positive=True)
    return answer == 2*S/9

def solve_1b():

    import sympy

    m = sympy.Symbol('m', positive=True) # Particle mass
    h = sympy.Symbol('h', positive=True) # Planck constant
    E = sympy.Symbol('E', positive=True) # Particle energy
    V_0 = sympy.Symbol('V_0', positive=True) # Potential step
    R = sympy.Symbol('R') # Reflection coefficient
    T = sympy.Symbol('T') # Transmission coefficient
    x = sympy.Symbol('x',real=True) # Position
    left_wave = sympy.exp(sympy.I*x*sympy.sqrt(2*m*E)/h) + R*sympy.exp(-sympy.I*x*sympy.sqrt(2*m*E)/h)
    right_wave = T*sympy.exp(sympy.I*x*sympy.sqrt(2*m*(E-V_0))/h)

    continuity = sympy.Eq(left_wave.subs(x,0), right_wave.subs(x,0))
    differentiability = sympy.Eq(left_wave.diff(x).subs(x,0), right_wave.diff(x).subs(x,0))
    sol = sympy.solve([continuity,differentiability],[R,T])
    return sol

def verify_1bI(answer):

    import sympy

    sol = solve_1b()
    return sol[sympy.Symbol('R')]==answer

def verify_1bII(answer):

    import sympy

    sol = solve_1b()
    return sol[sympy.Symbol('T')]==answer

def verify_2a(answer):

    import sympy

    G = sympy.Symbol('G', positive=True) # Gravitation constant
    M = sympy.Symbol('M', positive=True) # Mass
    t = sympy.Symbol('t', positive=True) # Time
    b = sympy.Symbol('b', positive=True) # Impact parameter
    v = sympy.Symbol('v', positive=True) # Particle velocity

    acceleration = G*M*b/(v**2*t**2+b**2)**sympy.Rational(3,2)

    solution = sympy.integrate(acceleration,(t,-sympy.oo,sympy.oo))

    return solution == answer

def verify_3a(answer):

    import sympy

    s = sympy.Symbol('s', positive=True) # Separation
    Q = sympy.Symbol('Q', positive=True) # Charge
    r = sympy.Symbol('r', positive=True) # Radius
    q = sympy.Symbol('theta', positive=True) # Angle

    potential = 2*Q/r-Q/sympy.sqrt(r**2+s**2+2*s*r*sympy.cos(q))-Q/sympy.sqrt(r**2+s**2-2*s*r*sympy.cos(q))

    temp = sympy.series(potential,s,0,3).removeO().simplify()

    return (temp/answer).simplify() == 1

def verify_4a(answer):

    return answer==1

def verify_5a(answer):

    import sympy

    x = sympy.Symbol('x', real=True)
    k = sympy.Symbol('k', real=True)
    func = sympy.exp(-x**2)

    solution = sympy.fourier_transform(func,x,k)
    return answer == solution

def verify_6a(answer):

    import sympy

    x = sympy.Function('x', real=True)
    t = sympy.Symbol('t', real=True)

    eqn = sympy.Eq(x(t).diff(t,2), -x(t)+sympy.sin(2*t))
    init_cond = {x(0):0,
                x(t).diff(t).subs(t,0):0}
    sol = sympy.dsolve(eqn,x(t),ics=init_cond)
    if not type(sol)==type(answer):
        print('wrong type')
        return False
    return sol == answer


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

import numpy as np
import matplotlib.pyplot as plt

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

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

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

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

# print(x)
# print(y)
# print(c)
fig = plt.figure(figsize = (12, 12))
plt.axis("off")
plt.scatter(x, y, c=c, s=0.5)
plt.show()


import math
import sympy
import collections
import time
from operator import mul
from functools import reduce
from itertools import product

# ordered_partitions...
def partitions_with_count(k):
    """
    return all possible partitions of a set with n elements grouped by the number of elements in each partition

    for example, paritions_with_count(3) returns {(1, 2): 3, (3,): 1, (1, 1, 1): 1}
    (1, 2)      -> [1],[2,3];  [2],[1,3];  [3],[1,2]    -> total of 3 ways
    (3,)        -> [1,2,3]                              -> total of 1 way
    (1, 1, 1)   -> [1],[2],[3]                          -> total of 1 way
    """
    if len(k) == 1 and k[0] == 1:
        return {((1,),): 1}  # the only way to partition set with one element

    unordered_len = []
    for i in sympy.utilities.iterables.multiset_partitions(
            [(group, j) for group, tot in enumerate(k) for j in range(tot)]):
        count_len = []
        for j in i:
            # print(j)
            ans = [0] * len(k)
            for kk in j:
                ans[kk[0]] += 1
            count_len.append(tuple(ans))
        unordered_len.append(tuple(sorted(count_len)))
    # all_partitions = sympy.utilities.iterables.multiset_partitions(range(k[0]))
    # all_partitions = sympy.utilities.iterables.multiset_partitions([(group, j) for group, tot in enumerate(k) for j in range(tot)])
    # unordered_len = [tuple(sorted([len(j) for j in i])) for i in all_partitions]
    return collections.Counter(unordered_len)

def integer_partitions(target, nb_ele):
    """
    return all possible ways to sum to target using nb_ele, allowing 0 to be one of the element

    for example, integer_partitions(4, 2) returns
    ([0,4], [4,0], [1,3], [3,1], [2,2])
    """
    if target == 0:
        return [[0] * nb_ele]

    ans = []
    for i in range(nb_ele):
        for part in sympy.utilities.iterables.ordered_partitions(target, m=i+1):
            arr = [0] * (nb_ele - (i + 1)) + part
            for j in sympy.utilities.iterables.multiset_permutations(arr):
                ans.append(j)
    return ans

def fdb_1d(k):
    """
    faa di bruno formula for 1 dimension

    for example, fdb_1d(k) return a list of size m x 3 such that
    d^k f(g(x)) = sum_{i=0}^{m-1} ans[i].coeff x f[ans[i].lamb]
                    x prod_{j=0}^{ans[i].s - 1} g[ans[i].l[j]]^[ans[i].k[j]],
    where f[n] means differentiate f n times
    ans[i].coeff is the index 0 of ans[i]
    ans[i].lamb is the index 1 of ans[i]
    ans[i].l is the key of the dictionary at index 2 of ans[i]
    ans[i].k is the value of the dictionary at index 2 of ans[i]
    ans[i].s is the size of the dictionary at index 2 of ans[i]
    """
    fdb = collections.namedtuple('fdb', 'coeff lamb l_and_k')
    return [fdb(count, len(par), collections.Counter(par))
            for par, count in partitions_with_count(k).items()]

def fdb_nd(n, ks):
    """
    the main function, multivariate faa di bruno formula for
    d^k1/dx1 d^k2/dx2 ... d^kd/dxd f(g1(x), g2(x), ..., gn(x))

    this implementation is derived from the R package kStatistics::MFB
    """
    fdb = collections.namedtuple('fdb', 'coeff lamb l_and_k')
    ans = []

    for par in product(*[integer_partitions(k, n) for k in ks]):
        # transpose par without numpy
        par = list(zip(*par))
        # k! / (par0! par1! par2! ...)
        p = reduce(mul, [math.factorial(ele) for ele in ks]) // reduce(mul, [math.factorial(ele) for group in par for ele in group])
        for cartesian in product(*[fdb_1d(ele) for ele in par]):
            coeff, lamb, l_and_k = p, [], {}
            for idx, ele in enumerate(cartesian):
                coeff *= ele.coeff
                lamb.append(ele.lamb)
                for l, k_arr in ele.l_and_k.items():
                    if l not in l_and_k:
                        # if the dictionary does not have the key of l, initialize one using zero list
                        l_and_k[l] = [0] * len(cartesian)
                    l_and_k[l][idx] = k_arr
            ans.append(fdb(coeff, tuple(lamb), l_and_k))
    return ans

if __name__ == "__main__":
    print(fdb_nd(2, (0, 0, 0)))
    # print(fdb_nd(3, (1, 2)))
    # print(len(fdb_nd(2, (1, 2))))
    # print(fdb_1d([1]))
    # print(fdb_1d(2))
    # print(fdb_1d([1, 2]))
    # print(list(integer_partitions(4, 2)))
    # print(partitions_with_count([1, 2]))
    # start = time.time()
    # print({k: fdb_nd(5, k) for k in range(1, 10)})
    # for k in range(1, 10):
    #     # print(fdb_nd(1, k))
    #     print(len(fdb_nd(1, k)))
    # print(f"Time taken: {time.time() - start} seconds.")
    # # print(len(fdb_nd(2,5)))
    # for i in integer_partitions(2, 3):
    #     print(i)
    # print(list(integer_partitions(5, 6)))
    # print(partitions_with_count(5))


import math

__author__ = 'paoolo'

import mpmath

from nsh_app.tools import function

def linear(a=1.0, b=0.0):
    """
    Return linear activation function.

    f(x) = a * x + b

    Keyword arguments:
    a -- linear factor (default 1.0)
    b -- linear shift (default 0.0)
    """
    return function.Function(lambda x: a * x + b,
                             'activation.linear',
                             'Linear activation function')

def linear_cut():
    """
    Return partially linear activation function.

    f(x) = -1.0, x \in (-inf, -1.0)
    f(x) =    x, x \in [-1.0, +1.0)
    f(x) =  1.0, x \in [+1.0, +inf)

    """
    return function.Function(lambda x: -1.0 if x < -1.0 else (1.0 if x > 1.0 else x),
                             'activation.linear_cut',
                             'Partially linear activation function')

def threshold_unipolar(a=0.0):
    """
    Return threshold unipolar activation function.

    f(x) = 0.0, x \in (-inf, a)
    f(x) = 1.0, x \in [a, +inf)

    Keyword arguments:
    a -- threshold value (default 0.0)
    """
    return function.Function(lambda x: 0.0 if x < a else 1.0,
                             'activation.threshold_unipolar',
                             'Threshold unipolar activation function')

def threshold_bipolar(a=0.0):
    """
    Return threshold bipolar activation function.

    f(x) = -1.0, x \in (-inf, a)
    f(x) = +1.0, x \in [a, +inf)

    Keyword arguments:
    a -- threshold value (default 0.0)
    """
    return function.Function(lambda x: -1.0 if x < a else 1.0,
                             'activation.threshold_bipolar',
                             'Threshold bipolar activation function')

def sigmoid_unipolar(beta=1.0):
    """
    Return sigmoid unipolar activation function.

    f(x) = 1.0 / (1.0 + exp(-beta * x) )

    Keyword arguments:
    beta -- epsilon factor value, mostly in range (0, 1] (default 1.0)
    """
    return function.Function(lambda x: 1.0 / (1.0 + mpmath.exp(-beta * x)),
                             'activation.sigmoid_unipolar',
                             'Sigmoid unipolar activation function')

def sigmoid_bipolar(beta=1.0):
    """
    Return sigmoid bipolar activation function.

    f(x) = (1.0 - exp(-beta * x)) / (1.0 + exp(-beta * x))

    Keyword arguments:
    beta -- epsilon factor value, mostly in range (0, 1] (default 1.0)
    """

    def f(x):
        val = mpmath.exp(-beta * x)
        return (1.0 - val) / (1.0 + val)

    return function.Function(f,
                             'activation.sigmoid_bipolar',
                             'Sigmoid bipolar activation function')

def gauss(a=1.0, b=1.0, c=1.0):
    """
    Return Gauss activation function. Arguments must be greater than zero.

    f(x) = a * Epsilon - ((x-b)^2 / (2.0 * c^2))

    Keyword arguments:
    a -- Euler linear factor
    b -- linear shift
    c -- divided part
    """
    div = 2.0 * (c ** 2.0)
    return function.Function(lambda x: a * mpmath.e - (((x - b) ** 2) / div),
                             'activation.gauss',
                             'Gauss activation function')

def tanh():
    """
    Return tanh activation function.

    f(x) = tanh(x)
    """
    return function.Function(lambda x: math.tanh(x),
                             'activation.tanh',
                             'Tanh activation function')


__author__ = 'Dmitry Patashov'

import myFunctions as mf
import numpy as np
import cv2
from matplotlib import pyplot as plt
import logicFunctions as lf

img1 = cv2.imread('img1.jpg')
img3 = cv2.imread(('BlurryImage1.jpg'))

# Assignment 1:

GaussMask = 1.0/273 * np.array([[1, 4, 7, 4, 1],
                                [4, 16, 26, 16, 4],
                                [7, 26, 41, 26, 7],
                                [4, 16, 26, 16, 4],
                                [1, 4, 7, 4, 1]])

LaplacianMask = np.array([[0, -1, 0],
                          [-1, 4, -1],
                          [0, -1, 0]])

GFmat = mf.myMasking(lf.myExtendedPadding(img1.copy()), GaussMask)
LFmat = mf.myMasking(lf.myExtendedPadding(img1.copy()), LaplacianMask)

GFmat2 = GFmat - np.min(GFmat)
GFimg = np.uint8(np.round(GFmat2 * 255 / np.max(GFmat2)))

LFmat2 = np.abs(LFmat)
LFmat2 = LFmat2 - np.min(LFmat2)
LFimg = np.uint8(np.round(LFmat2 * 255 / np.max(LFmat2)))

plt.figure()
plt.subplot(221)
plt.axis('off')
plt.title('Original image')
plt.imshow(img1[:,:,::-1])

plt.subplot(222)
plt.axis('off')
plt.title('Gaussian filtered image')
plt.imshow(GFimg[:,:,::-1])

plt.subplot(223)
plt.axis('off')
plt.title('Laplacian filtered image')
plt.imshow(LFimg[:,:,::-1])

plt.subplot(224)
plt.axis('off')
plt.title('Laplacian filtered image')
plt.imshow(np.max(LFimg, axis=2), cmap='gray')

plt.show()

# Assignment 2:

myMask = np.array([[-1, -1, -1],
                   [-1, 10, -1],
                   [-1, -1, -1]])

Mimg = np.uint8(np.round(np.abs(mf.myMasking(lf.myExtendedPadding(img3.copy()), myMask))))

plt.figure()
plt.subplot(121)
plt.axis('off')
plt.title('Original image')
plt.imshow(img3[:,:,::-1])

plt.subplot(122)
plt.axis('off')
plt.title('Masked image')
plt.imshow(Mimg[:,:,::-1])

plt.show()

# Assignment 3:

img3g = cv2.cvtColor(img3, cv2.COLOR_BGR2GRAY)
Mimgg = cv2.cvtColor(Mimg, cv2.COLOR_BGR2GRAY)

hist1 = mf.myHistPlotUint8(img3g)
hist2 = mf.myHistPlotUint8(Mimgg)

plt.figure()
plt.subplot(121)
plt.title('Original image')
plt.bar(range(256), hist1)

plt.subplot(122)
plt.title('Masked image')
plt.bar(range(256), hist2)

plt.figure()
plt.subplot(121)
plt.title('Original image')
plt.bar(range(256), hist1)
plt.ylim((0, np.max(hist1) / 20))

plt.subplot(122)
plt.title('Masked image')
plt.bar(range(256), hist2)
plt.ylim((0, np.max(hist2) / 20))

plt.show()


from sympy import *
import math

def secant_method(f, x0, x1, eps=0, eta=0, max_steps=20, verbose=False):
    """两点弦截法（割线法）

    Args:
        f: function, 迭代函数
        x0, x1: float, 初值
        eps: float, 根的容许误差, default 0.
        eta: float, abs(f(x)) 的容许误差, default 0.

        max_steps: int, 最大迭代次数, default 20.
        verbose: bool, 打印出每一步的值, default False.

    Returns:
        x_final: float, 最终的近似根 x
    """
    for i in range(max_steps):
        if verbose:
            print(i, x1)

        x2 = x1 - f(x1) * (x1 - x0) / (f(x1) - f(x0))
        x0, x1 = x1, x2

        if abs(x1 - x0) <= eps or abs(f(x1)) <= eta:
            break

    return x1


import math
import numpy as np
from Point import R2_Point
import copy
from Utils import *
# 0.046
#valTol = 0.76#0.0015#0.25#0.073
percentualTol = 0.1#0.081#0.05#0.012
# 0.03512794452
def simpleRatio(A, B, C):
	AC = A.euclideanDistance(C)
	BC = B.euclideanDistance(C)
	return AC/BC

def crossRatio(A, B, C, D):
	AC = A.euclideanDistance(C)
	BC = B.euclideanDistance(C)
	AD = A.euclideanDistance(D)
	BD = B.euclideanDistance(D)

	if BC == 0 or BD == 0 or AD == 0:
		# print("cross ratio value = 0")
		# print("points: ", [A, B, C, D])
		return 0

	# if (AC/BC)*(BD/AD) > 10:
	# 	print("cross ratio value = ", (AC/BC)*(BD/AD))
	# 	print("points: ", [A, B, C, D])

	return (AC/BC)*(BD/AD)

def det3(P1, P2, P3):
	(x1, y1, z1) = unpackPoint(P1)
	(x2, y2, z2) = unpackPoint(P2)
	(x3, y3, z3) = unpackPoint(P3)

	return x1*y2*z3 + x3*y1*z2 + x2*y3*z1 - (x3*y2*z1 + x2*y1*z3 + x1*y3*z2)

def crossRatio5(A1, B1, A2, B2, O):
	det_A1_A2_O = det3(A1, A2, O)
	det_A1_B2_B1 = det3(A1, B2, B1)

	if det_A1_A2_O == 0 or det_A1_B2_B1 == 0:
		return 0

	cp1 = det3(A1, A2, B1)*det3(A1, B2, O)/(det_A1_A2_O*det_A1_B2_B1)
	#cp2 = det3(A2, A1, B1)*det3(A2, O, B2)/(det3(A2, A1, B2)*det3(A2, O, B1))
	#O = P2_Point(0, 0, 1)

	# print(det3(A1, A2, O))
	# print(det3(A1, A2, B2))
	# print(det3(A2, B1, O))
	# print(det3(A2, B1, B2))

	#cp1 = (det3(A1, A2, O)/det3(A1, A2, B2))/(det3(A2, B1, O)/det3(A2, B1, B2))
	return (cp1)#, cp2)

def fiveCrossRatio(P1, P2, P3, P4, P5):
	det124 = det3(P1, P2, P4)
	det135 = det3(P1, P3, P5)
	deno = det124*det135
	if deno == 0:
		return 0

	return det3(P1, P2, P3)*det3(P1, P4, P5)/deno

def suitable5CR(P1, P2, P3, P4, P5):
	q = fiveCrossRatio(P1, P2, P3, P4, P5)
	return 2*q/(q*q + 1)

def invariant5CrossRatio(P1, P2, P3, P4, P5):
	r = suitable5CR(P1, P2, P3, P4, P5)*suitable5CR(P1, P2, P3, P5, P4)*suitable5CR(P1, P2, P4, P5, P3)
	return r

def crossRatioFilter(points=[]):
	crossRatioValues = []
	calcCrossRatioTolerances = []
	nPoints = len(points)
	if nPoints >= 4:
		nSlideComb = nPoints - 2 #3
		for i in range(1, nSlideComb):
			#crossRatioValues.append(crossRatio(points[i], points[i+1], points[i+2], points[i+3]))
			crossRatioValues.append(crossRatio(points[0], points[i], points[i+1], points[-1]))
			#calcCrossRatioTolerances.append(calcCrossRatioTolerance(points[i], points[i+1], points[i+2], points[i+3]))

	else:
		return [0]
	return 	crossRatioValues#, calcCrossRatioTolerances)

def crossRatioFilter5(points=[], junctionPoint=None):
	crossRatioValues = []
	O = junctionPoint
	calcCrossRatioTolerances = []
	nPoints = len(points)
	if nPoints >= 4:
		nSlideComb = nPoints - 3
		for i in range(0, nSlideComb):
			crossRatioValues.append(crossRatio5(points[i], points[i+1], points[i+2], points[i+3], O))
			#calcCrossRatioTolerances.append(calcCrossRatioTolerance(points[i], points[i+1], points[i+2], points[i+3]))

	else:
		return ([0],[0])
	return 	crossRatioValues#, calcCrossRatioTolerances)

def invariant5CrossRatioFilter(points, vertice=None):
	crossRatioValues = []
	calcCrossRatioTolerances = []
	nPoints = len(points)

	factor = 0
	if vertice != None:
		factor = 1

	if nPoints >= 5 - factor:
		nSlideComb = nPoints - (4 - factor)
		for i in range(0, nSlideComb):

			if vertice != None:
				p0 = vertice
			else:
				p0 = points[i]

			crossRatioValues.append(crossRatio5(p0, points[i+1-factor], points[i+2-factor], points[i+3-factor], points[i+4-factor]))
	return crossRatioValues

def calcCrossRatioTolerance(p1, p2, p3, p4):
	# d12 = p1.euclideanDistance(p2)
	# d23 = p2.euclideanDistance(p3)
	# d34 = p3.euclideanDistance(p4)

	# d13 = d12 + d23
	# d24 = d23 + d34
	# d14 = d12 + d24

	# tol = (d13**2)*(d34**2)/((d14**2)*(d23**4)) + (d12**2)*(d13**2)/((d14**4)*(d23**2)) + (d12**2)*(d24**2)/((d14**2)*(d23**4)) + (d24**2)*(d34**2)/((d14**4)*(d23**2))

	# d14Pow2 = d14*d14
	# tol = 1/d14Pow2

	return valTol#math.sqrt(tol)

def calcDistanceTolerance(crossRatioVector):
	tol = percentualTol
	#print("crossRatioVector: ", crossRatioVector)
	seq = crossRatioVector
	return sum([r*tol for r in seq]) #math.sqrt(

def isEqualValues(val1, val2, valTol_):
	return (val2 - valTol_) <= val1 <= (val2 + valTol_)

# def isEqualVectors(crossValues1, crossValues2, tol, vectorTolerances):
# 	if len(crossValues1) == len(crossValues2):
# 		for i in range(0, len(crossValues1)):
# 			val1 = crossValues1[i]
# 			val2 = crossValues2[i]
# 			valTol_ = vectorTolerances[i]
# 			if not isEqualValues(val1, val2, valTol_):
# 				return False
# 		return True
# 	else:
# 		return False

def calcDistanceVector(vector1, vector2):
	lenVector = len(vector1)
	distance = 1000 # INF
	if lenVector == len(vector2):
		distance = 0
		for i in range(0, len(vector1)):
			val1 = vector1[i]
			val2 = vector2[i]
			diffVal = val2 - val1
			diffVal = diffVal*diffVal
			distance += diffVal
		distance = math.sqrt(distance)
	return distance

def compareCellPerCell(vector1, vector2, cell_tol):
	matchingCounter = 0
	lenVector = len(vector1)
	distance = 1000 # INF
	if lenVector == len(vector2):
		for i in range(0, len(vector1)):
			val1 = vector1[i]
			val2 = vector2[i]
			diffVal = abs(val2 - val1)
			if cell_tol*max(val1, val2) >= diffVal:
				matchingCounter += 1

	percentMatching = 0
	if lenVector > 0:
		percentMatching = matchingCounter/lenVector

	return percentMatching

def isEqualVectors(crossValues1, crossValues2, distanceTol):
	if len(crossValues1) == len(crossValues2):
		# for (val1, val2) in zip(crossValues1, crossValues2):
		# 	if not(abs(val2 - val1) <= val1*percentualTol):
		# 		return False
		# return True

		distance = calcDistanceVector(crossValues1, crossValues2)
		#if sumTol >= 2:
		#	print("size = ", len(crossValues1))
		#	print("distance = ", distance)
		#	print("sumTol = ", sumTol)
		#	print("sumTol*valTol = ", sumTol*valTol)
		#lenVector = len(crossValues1)
		#vectorTol = lenVector*valTol#sumTol#*valTol#lenVector*valTol
		# print("distance  = ", distance)
		# print("distanceTol = ", distanceTol)
		return (distance <= distanceTol)
	else:
		return False

'''
	lenVector = len(crossValues1)
	if lenVector == len(crossValues2):
		distance = 0
		for i in range(0, len(crossValues1)):
			val1 = crossValues1[i]
			val2 = crossValues2[i]
			diffVal = val2 - val1
			diffVal = diffVal*diffVal
			distance += diffVal
		distance = math.sqrt(distance)
		vectorTol = lenVector*valTol
		return (- vectorTol <= distance <= vectorTol)
'''

def compareCrossRatiosVectors(vector1, vector2, distanceTol):
	# print("vector1 = ", vector1)
	# print("vector2 = ", vector2)
	#sumTol = math.sqrt(sum([t*t for t in vectorTolerances])) #sum(tolerances2)
	if isEqualVectors(vector1, vector2, distanceTol):
		#print("compareCrossRatiosVectors: true,true")
		return (True, True)
	else:
		vector2_ = copy.deepcopy(vector2)
		vector2_.reverse()
		#print("compareCrossRatiosVectors: ", isEqualVectors(vector1, vector2_, sumTol))
		return (isEqualVectors(vector1, vector2_, distanceTol), False)

"""
A = R2_Point(0, 0)
B = R2_Point(0, 0.95)
C = R2_Point(0, 0.95+1.75)
D = R2_Point(0, 0.95+1.75+3.6)

E = R2_Point(0, 0.95+1.75+3.6 + 2.0)
F = R2_Point(0, 0.95+1.75+3.6 + 4.0)
G = R2_Point(0, 0.95+1.75+3.6 + 7.0)
H = R2_Point(0, 0.95+1.75+3.6 + 9.0)

edgePoints1 = [A, B, C, D, E, F, G, H]
edgePoints2 = [A, B, C, D, E, F, G, H]
edgePoints2.reverse()

crossRV1 = crossRatioFilter(edgePoints1)
crossRV2 = crossRatioFilter(edgePoints2)

print("cross ratio values1 = ", crossRV1)
print("cross ratio values2 = ", crossRV2)

print("compareCrossRatiosVectors = ", compareCrossRatiosVectors(crossRV1, crossRV2))
"""

# cr5vectorTemplate = [0.8993799740727911, 0.06552501293135299, 0.007481991191622515, 0.7269387781499284, 0.0034725190336924033, 0.06337601484562531, 0.9053433484125969]
# cr5vectorTest = [0.9539378247574579, 0.024929637360532646, 0.016669482399608818, 0.727639016927337, 0.0012661011136918786, 0.5976631136144654, 0.35658122903519274]

# cell_tol = 0.5
# print("compareCellPerCell: ", compareCellPerCell(cr5vectorTemplate, cr5vectorTest, cell_tol))


#!/usr/bin/env python

## make imports
import sys
import numpy as np
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
import scipy.stats as stats

class TwoComponentGaussianEM():

    def __init__(self, y, numIters, numRuns,verbose=False):
        self.y = y
        self.verbose = verbose
        self.maxLike, self.bestEst = self.run_em_algorithm(numIters, numRuns)

    ### make definations for initial guessing, expectation, and maximization
    def get_init_guesses(self,y):
        ## make intial guesses for the parameters (mu1, sig1, mu2, sig2 and pi)
        n    = len(self.y)
        mu1  = y[np.random.randint(0,n)]
        mu2  = y[np.random.randint(0,n)]
        sig1 = np.random.uniform(0.5,1.5) #y.var() or 0.5,3.0
        sig2 = np.random.uniform(0.5,1.5) #y.var() or 0.5,3.0
        pi   = 0.5

        return {'n':n, 'mu1':mu1, 'mu2':mu2, 'sig1':sig1, 'sig2':sig2, 'pi':pi}

    def perform_expectation(self, y, parms):
        gammaHat = np.zeros((parms['n']),'float')

        for i in range(parms['n']):
            phiTheta1 = stats.norm.pdf(y[i],loc=parms['mu1'],scale=np.sqrt(parms['sig1']))
            phiTheta2 = stats.norm.pdf(y[i],loc=parms['mu2'],scale=np.sqrt(parms['sig2']))
            numer = parms['pi'] * phiTheta2
            denom = ((1.0 - parms['pi']) * phiTheta1) + (parms['pi'] * phiTheta2)
            gammaHat[i] = numer / denom

        return gammaHat

    def perform_maximization(self,y,parms,gammaHat):
        ## use weighted maximum likelihood fits to get updated parameter estimates
        numerMuHat1 = 0
        denomHat1 = 0
        numerSigHat1 = 0
        numerMuHat2 = 0
        denomHat2 = 0
        numerSigHat2 = 0
        piHat = 0

        ## get numerators and denomanators for updating of parameter estimates
        for i in range(parms['n']):
            numerMuHat1 = numerMuHat1 + ((1.0 - gammaHat[i]) * y[i])
            numerSigHat1 = numerSigHat1 + ( (1.0 - gammaHat[i]) * ( y[i] - parms['mu1'] )**2 )
            denomHat1 = denomHat1 + (1.0 - gammaHat[i])

            numerMuHat2 = numerMuHat2 + (gammaHat[i] * y[i])
            numerSigHat2 = numerSigHat2 + (gammaHat[i] * ( y[i] - parms['mu2'] )**2)
            denomHat2 = denomHat2 + gammaHat[i]
            piHat = piHat + (gammaHat[i] / parms['n'])

        ## calculate estimates
        muHat1 = numerMuHat1 / denomHat1
        sigHat1 = numerSigHat1 / denomHat1
        muHat2 = numerMuHat2 / denomHat2
        sigHat2 = numerSigHat2 / denomHat2

        return {'mu1':muHat1, 'mu2':muHat2, 'sig1': sigHat1, 'sig2':sigHat2, 'pi':piHat, 'n':parms['n']}

    def get_likelihood(self,y,parms,gammaHat):
        part1 = 0
        part2 = 0

        for i in range(parms['n']):
            phiTheta1 = stats.norm.pdf(y[i],loc=parms['mu1'],scale=np.sqrt(parms['sig1'])) #r.dnorm(y[i], mean = parms['mu1'], sd = np.sqrt(parms['sig1']))
            phiTheta2 = stats.norm.pdf(y[i],loc=parms['mu2'],scale=np.sqrt(parms['sig2'])) #r.dnorm(y[i], mean = parms['mu2'], sd = np.sqrt(parms['sig2']))
            part1 = part1 + ( (1.0 - gammaHat[i]) * np.log(phiTheta1) + gammaHat[i] * np.log(phiTheta2) )
            part2 = part2 + ( (1.0 - gammaHat[i]) * np.log(parms['pi']) + gammaHat[i] * np.log(1.0 - parms['pi']) )

        return part1 + part2

    def run_em_algorithm(self, numIters, numRuns, verbose = True):
        '''
        main algorithm functions
        '''

        maxLike = -np.inf
        bestEstimates = None

        for j in range(numRuns):

            iterCount = 0
            parms = self.get_init_guesses(self.y)

            ## iterate between E-step and M-step
            while iterCount < numIters:
                iterCount += 1

                ## check to make sure the var estimates are > 0.5
                if parms['sig1'] < 0.0 or parms['sig2'] < 0.0:
                    #print "WARNING: negative variances starting with new intital guesses"
                    iterCount = 1
                    parms = get_init_guesses()

                ## E-step
                gammaHat = self.perform_expectation(self.y,parms)
                logLike = self.get_likelihood(self.y,parms,gammaHat)

                #if self.verbose == True:
                #    print 'iteration',iterCount,'mu1',round(parms['mu1'],2),'mu2',round(parms['mu2'],2),'sig1',round(parms['sig1'],2),
                #    print 'sig2',round(parms['sig2'],2),'pi',round(parms['pi'],2),'obs.data likelihood', round(logLike,4)

                ## M-step
                parms = self.perform_maximization(self.y,parms,gammaHat)

            if logLike > maxLike:
                maxLike = logLike
                bestEstimates = parms.copy()

            if self.verbose == True:
                print('runNum: ',j + 1,'mu1: ',round(parms['mu1'],2),'mu2: ',round(parms['mu2'],2),'sig1: ',round(parms['sig1'],2),)
                print('sig2: ',round(parms['sig2'],2),'pi: ',round(parms['pi'],2),'obs.data likelihood: ', round(logLike,4))

        return maxLike, bestEstimates

if __name__ == '__main__':

    y1 = np.array([-0.39,0.12,0.94,1.67,1.76,2.44,3.72,4.28,4.92,5.53])
    y2 = np.array([ 0.06,0.48,1.01,1.68,1.80,3.25,4.12,4.60,5.28,6.22])
    y  = np.hstack((y1,y2))

    numIters = 25
    numRuns = 20
    verbose = True
    makePlots = True
    tcg = TwoComponentGaussianEM(y, numIters, numRuns,verbose=verbose)

    print('maxLike', tcg.maxLike)
    print('bestEstimates', tcg.bestEst)

    if makePlots == True:
        n, bins, patches = plt.hist(y,15,normed=1,facecolor='gray',alpha=0.75)

        ## add a 'best fit' line (book results)
        mu1 = 4.62
        mu2 = 1.06
        sig1 = 0.87
        sig2 = 0.77

        p1 = mlab.normpdf( bins, mu1, np.sqrt(sig1))
        p2 = mlab.normpdf( bins, mu2, np.sqrt(sig2))
        l1 = plt.plot(bins, p1, 'r--', linewidth=1)
        l2 = plt.plot(bins, p2, 'r--', linewidth=1)

        ## add a 'best fit' line (results from here)
        p3 = mlab.normpdf( bins, tcg.bestEst['mu1'], np.sqrt(tcg.bestEst['sig1']))
        p4 = mlab.normpdf( bins, tcg.bestEst['mu2'], np.sqrt(tcg.bestEst['sig2']))
        l3 = plt.plot(bins, p3, 'k-', linewidth=1)
        l4 = plt.plot(bins, p4, 'k-', linewidth=1)

        plt.xlabel('y')
        plt.ylabel('freq')
        plt.ylim([0,0.8])

        plt.legend( (l1[0], l3[0]), ('Book Estimate', 'My Estimate') )

        plt.savefig('../TwoComponentGauss.png')
        plt.show()


import numpy as np
import sympy as sy

epsilon=0.0001
maxiteration=100

def main():
    n=10
    # prepare matrix a
    a=np.diag([5.]*n)
    a+=np.diagflat([2.]*(n-1),1)
    a+=np.diagflat([2.]*(n-1),-1)
    print(a)

    b=np.array([3,1,4,0,5,-1,6,-2,7,-15],dtype='f').T
    #initial value x
    x=np.ones(10).T

    D=np.diag(np.diag(a))
    L=np.tril(a,-1)
    U=np.triu(a,+1)

    M= -np.linalg.inv(D+L) @ U
    N=np.linalg.inv(D+L)
    for k in range(maxiteration):
        x_new=M @ x + N @ b
        if(np.linalg.norm(x_new-x) < epsilon):
            break
        x=x_new
    else:
        print("Gauss-Seidel method fail ...")
        exit(1)

    print("the sol of ax = b using Gauss-Seidel method is \n{}".format(x))
    print("iteration {} times".format(k))
    print("indeed ax-b is \n{}".format(a @ x -b))
    print("you can check sol x using sympy...")
    sy_a=sy.Matrix(a)
    sy_x=sy_a.solve(b)
    print(sy_x)

if __name__ == '__main__':
    main()


import numpy as np

__all__ = ['harmonic_tone', 'freq_to_pitch', 'pitch_to_freq']

def harmonic_tone(base_freqs, n_partials=1, profile='exp'):
    """
    Creates a harmonic tone out of one or more base frequencies.

    Input:
    base_freqs - single value, or an numpy array of base frequencies
    n_partials - number of partial in the harmonic tone

    Output:
    Tuple of (freqs, amplitudes).

    Freqs are a 2D array of the frequencies of partials
    of shape (len(freqs), n_partials)

    Amplitudes are of the same shape.

    The amplitude values for a single harmonic tone are going down
    inversely in this case.
    """
    idx = 1 + np.arange(n_partials)
    freqs = np.outer(np.atleast_2d(base_freqs), idx.reshape(1, -1))
    # eg. amplitudes inversely going down
    if profile == 'exp':
        # exponential fall-off
        amp_profile = 0.88 ** idx
    elif profile == 'inverse':
        amp_profile = 1 / idx
    elif profile == 'constant':
        amp_profile = np.ones(len(idx))
    else:
        raise ValueError("Amplitude profile can be ['exp', 'inverse', 'constant'], was", profile)

    amplitudes = np.tile(amp_profile, (len(base_freqs), 1))
    return freqs, amplitudes

def freq_to_pitch(freq, base_freq=440.0, steps_per_octave=12):
    return np.log2(np.array(freq) / base_freq) * steps_per_octave

def pitch_to_freq(pitch, base_freq=440.0, steps_per_octave=12):
    return (2 ** (np.array(pitch) / steps_per_octave)) * base_freq


"""Lineshapes."""

# --- import -------------------------------------------------------------

import numpy as np

from scipy.special import wofz

# --- define -------------------------------------------------------------

__all__ = ["gaussian", "lorentzian_complex", "lorentzian_real", "voigt"]

# --- functions ----------------------------------------------------------

def gaussian(x, x0, FWHM, norm="height"):
    """Calculate a normalized Gaussian lineshape

    Parameters
    ----------
    x : array_like or number
        Input array.
    x0 : array_like or number
        Center of lineshape.
    FHWM : array_like or number
        Full-width-at-half-maximum of lineshape.
    norm : string (optional):
        Type of normalization.
        height specifies that the maximum value is 1.
        area specifies that the lineshape integrates to 1.
        Default is height.

    Returns
    -------
    array_like or number
        Gaussian lineshape.
    """
    c = FWHM / (2 * np.sqrt(2 * np.log(2)))
    arr = np.exp(-1 * (x - x0) ** 2 / (2 * c**2))
    if norm == "height":
        return arr
    elif norm == "area":
        return arr / (c * np.sqrt(2 * np.pi))

def lorentzian_complex(x, x0, G, norm="height_imag"):
    """Calculate a normalized complex Lorentzian lineshape

    Parameters
    ----------
    x : array_like or number
        Input array.
    x0 : array_like or number
        Center of lineshape.
    G : array_like or number
        Half-width-at-half-maximum of lineshape.
    norm : string (optional):
        Type of normalization.
        height_imag specifies that the maximum value of the imaginary component is 1.
        area_int specifies that the square magnitude of the lineshape integrates to 1.
        Default is height_imag.

    Returns
    -------
    array_like or number
        Complex Lorentzian lineshape.
    """
    arr = 1 / (x0 - x - 1j * G)
    if norm == "height_imag":
        return arr * G
    elif norm == "area_int":
        return arr * np.sqrt(G / np.pi)

def lorentzian_real(x, x0, G, norm="height"):
    """Calculate a normalized Lorentzian lineshape

    Parameters
    ----------
    x : array_like or number
        Input array.
    x0 : array_like or number
        Center of lineshape.
    G : array_like or number
        Half-width-at-half-maximum of lineshape.
    norm : string (optional):
        Type of normalization.
        height specifies that the maximum value is 1.
        area specifies that the lineshape integrates to 1.
        Default is height.

    Returns
    -------
    array_like or number
        Lorentzian lineshape.
    """
    arr = G**2 / ((x - x0) ** 2 + G**2)
    if norm == "height":
        return arr
    if norm == "area":
        return arr / (G * np.pi)

def voigt(x, x0, FWHM, G):
    """Calculate an unnormalized Voigt lineshape using Scipy's Faddeeva function

    `Link to Voigt article on Wikipedia`__

    __ https://en.wikipedia.org/wiki/Voigt_profile

    Parameters
    ----------
    x : array_like or number
        Input array.
    x0 : array_like or number
        Center of lineshape.
    FHWM : array_like or number
        Full-width-at-half-maximum of Gaussian part of lineshape.
    G : array_like or number
        Half-width-at-half-maximum of Lorentzian part of lineshape.

    Returns
    -------
    array_like or number
        Voigt lineshape.
    """
    c = FWHM / (2 * np.sqrt(2 * np.log(2)))
    arr = (x - x0 + 1j * G) / (c * np.sqrt(2))
    w = wofz(arr)
    return np.real(w) / (c * np.sqrt(2 * np.pi))


# --------------
#Importing header files
import pandas as pd
import scipy.stats as stats
import math
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.stats.weightstats import ztest
from statsmodels.stats.weightstats import ztest
from scipy.stats import chi2_contingency

import warnings

warnings.filterwarnings('ignore')
#Sample_Size
sample_size=2000

#Z_Critical Score
z_critical = stats.norm.ppf(q = 0.95)

# Critical Value
critical_value = stats.chi2.ppf(q = 0.95, # Find the critical value for 95% confidence*
                      df = 6)   # Df = number of variable categories(in purpose) - 1

#Reading file
data=pd.read_csv(path)

#Code starts here

data_sample = data.sample(n=sample_size,random_state=0)
sample_mean = data_sample['installment'].mean()
sample_std = data_sample['installment'].std()
margin_of_error = z_critical*(sample_std/math.sqrt(sample_size))
confidence_interval = (sample_mean-margin_of_error,sample_mean+margin_of_error)
true_mean = data['installment'].mean()
#print(confidence_interval[0])

if (true_mean >= confidence_interval[0]) and(true_mean <=confidence_interval[1]):
   print( " is in the range")
else :
   print("is outside the given range.")

#Different sample sizes to take
sample_size1=np.array([20,50,100])
#Code starts here
fig ,axes = plt.subplots(nrows = 3 , ncols = 1)
for i in range(len(sample_size1)):
   m=[]
   for j in range(1000):
       a1=data['installment'].sample(n=sample_size1[i])
       m.append(a1.mean())
   mean_series= pd.Series(m)
   axes[i].plot(mean_series)

data['int.rate']=(data['int.rate'].str[:-1].astype(float))/100
#data.head(2)
z_statistic_1 , p_value_1 = ztest(data[data['purpose']=='small_business']['int.rate'],value=data['int.rate'].mean(),alternative='larger')
print(z_statistic_1,p_value_1)

if p_value_1<0.05:
   print("reject null hypothesis")
else:
   print("Accept null hypothesis")

z_statistic_2 , p_value_2 = ztest(data[data['paid.back.loan']=='No']['installment'],data[data['paid.back.loan']=='Yes']['installment'])
print(z_statistic_2,p_value_2)
if p_value_2<0.05:
  print("reject null hypothesis")
else:
  print("Accept null hypothesis")

#Critical value
critical_value = stats.chi2.ppf(q = 0.95, # Find the critical value for 95% confidence*
                     df = 6)   # Df = number of variable categories(in purpose) - 1

#Code starts here
yes= data[data['paid.back.loan']=='Yes']['purpose'].value_counts()
no = data[data['paid.back.loan']=='No']['purpose'].value_counts()
observed = pd.concat([yes.transpose(),no.transpose()],axis=1,keys= ['Yes','No'])
chi2, p, dof, ex = chi2_contingency(observed)
if chi2 > critical_value:
   print("reject the null hypothesis since the two distributions are the same")
else:
   print("null hypothesis cannot be rejected")

import numpy,import scipy,from scipy,from statsmodels


# Implements the power method without using any matrix multiplications, i.e. Monte Carlo approximation to the sum implied by v = Mv
# Author : Cleve Moler, Aleyna Kara
# This function is the Python implementation of  https://github.com/probml/pmtk3/blob/master/demos/pagerankpow.m

import numpy as np
from scipy.sparse import coo_matrix

'''
Returns the PageRank of the graph G and the number of iterations
Arguments:
    G : Adjacency matrix representing the link structure
    p : The probability of a link to be followed.
'''
def pagerank_power_method_sparse(G, p):
    # Link structure
    n, _ = G.shape

    # The fastest way to iterate columns of csc_matrix
    cg = coo_matrix(G)
    L = [[] for i in range(n)]
    for i, j in zip(cg.row, cg.col):
        L[j].append(i)
    c = [len(L[j]) for j in range(n)]

    # Power method
    delta, n_iterations = (1 - p) / n, 0
    x, z = np.ones((n, 1)) / n, np.zeros((n, 1))

    while np.max(np.abs(x - z)) > 1e-4:
        z = x
        x = np.zeros(n)
        for j in range(n):
            if not c[j]:
                x = x + z[j] / n
            else:
                x[L[j]] = x[L[j]] + z[j] / c[j]
        x = p * x + delta
        n_iterations += 1

    return x, n_iterations


import numpy as np

def entropy(y):
    # use numpy.unique to obtain sorted unique elements and their counts
    _, counts = # TODO
    # calculate the proportion of each class in the whole dataset
    # the return value should be an array of proportions
    p = # TODO
    # calculate and return entropy using the formula from the task
    # logarithm can be calculated using the numpy.log2 function
    return # TODO


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

import numpy as np

def calc_line(x_points, y_points):
    assert type(x_points) == list and type(y_points) == list, "x_points and y_points have to be lists"
    assert all([type(x) == int for x in x_points]), "elements of x_points have to be ints"
    assert all([type(y) == int for y in y_points]), "elements of y_points have to be ints"
    assert len(x_points) == len(y_points), "same x_points- and y_points-list length required"
    n_points = len(x_points)

    min_x = 100000
    max_x = 0
    sum_x = 0.0

    a = np.zeros([n_points, 2])
    y = np.zeros([n_points])

    for i in range(n_points):
        y[i] = y_points[i]

        px = x_points[i]
        a[i, 0] = 1.0
        a[i, 1] = px

        min_x = min(px, min_x)
        max_x = max(px, max_x)
        sum_x += px
    if max_x - min_x < 2:
        return sum_x / len(x_points), float("inf")

    return solve_lin(a, y)

def solve_lin(a, y):
    assert isinstance(a, np.ndarray), "a has to np.ndarray"
    assert isinstance(y, np.ndarray), "y has to np.ndarray"

    a_t = np.transpose(a)
    ls = np.matmul(a_t, a)
    rs = np.matmul(a_t, y)
    assert ls.shape == (2, 2)

    det = ls[0, 0] * ls[1, 1] - ls[0, 1] * ls[1, 0]
    if det < 1e-9:
        print("LinearRegression Error: Numerically unstable.")
        return a[0, 1], float("inf")
    else:
        d = 1.0 / det
        inv = np.empty_like(ls)
        inv[0, 0] = d * ls[1, 1]
        inv[1, 1] = d * ls[0, 0]
        inv[1, 0] = -d * ls[1, 0]
        inv[0, 1] = -d * ls[0, 1]

    return np.matmul(inv, rs)

# if __name__ == '__main__':
#     from scipy.stats import linregress
#
#     # (1,30) (10,25) (25, 22) (60,36)
#     xs = [1, 10, 25, 60]
#     ys = [30, 25, 22, 36]
#
#     # # (1,10) (2, 20) (3,15)
#     # x_points = [1, 2, 3]
#     # y_points = [10, 20, 15]
#
#     res = calc_line(xs, ys)
#     res2 = linregress(xs, ys)
#
#     print("res = \n", res)
#     print("res2 = \n", [res[0], res[1]])


"""Linear Regression
https://brohrer.mcknote.com/zh-Hant/how_machine_learning_works/how_linear_regression_works.html
"""

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

# Parameters
learning_rate = 0.2
training_epochs = 201
display_step = 20

# Create 100 training data
train_X = np.random.rand(100).astype(np.float32)
train_Y = train_X * 0.1 + 0.3

# Try to find values for W and b that compute train_Y = W * train_X + b
# TensorFlow will learns, and best fit is W: [0.1], b: [0.3]
W = tf.Variable(tf.random_uniform([1], -1.0, 1.0))
b = tf.Variable(tf.zeros([1]))
y = W * train_X + b

# Minimize the mean squared errors.
# MMSE reference:
# https://en.wikipedia.org/wiki/Minimum_mean_square_error
# http://allenluadvance.blogspot.tw/2014/01/sine-wave-estimation-mmse-estimator-ml.html
# https://www.khanacademy.org/math/statistics-probability/describing-relationships-quantitative-data/more-on-regression/v/proof-part-1-minimizing-squared-error-to-regression-line
loss = tf.reduce_sum(tf.pow(y-train_Y, 2))/train_X.shape[0]
# loss = tf.reduce_mean(tf.square(y - train_Y)) # Or use reduce_mean
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train = optimizer.minimize(loss)

# Initialize the variables (i.e. assign their default value)
init = tf.global_variables_initializer()

# Start training
with tf.Session() as sess:

    # Run the initializer
    sess.run(init)

    # Fit all training data
    for step in range(training_epochs):
        sess.run(train)
        if step % display_step == 0:
            stepStr = str(int(step/display_step) + 1) + '.'
            print(stepStr, sess.run(W), sess.run(b))
            plt.plot(train_X, train_Y, 'go', label='Original data')
            plt.plot(train_X, sess.run(W) * train_X + sess.run(b), label='Fitted line')
            plt.legend()
            plt.show()


'''
=====> The function is_prime(num) checks if an input number is a prime number.
=====> The function pirmeFactors(num) computes the prime factors of a given number.

Test number: 600851475143 ---> Required for project euler question 3.

Author: Harivinay V
Github: https://github.com/M87K452b
'''

import math
from numba import jit

@jit(nopython=True)
def is_prime(num):
    '''
    Function: To check if a number is prime
    '''
    if num < 2:
        return False
    if num % 2 == 0 and num > 2:
        return False
    for i in range(3, int(math.sqrt(num)) + 1, 2):
        if num % i == 0:
            return False
    return True

primes = []
factors = []

def primeFactors(num):
    '''
    Function to compute the primefactors of a given number
    '''
    i = 1
    while (num > 2 and i <= num):
        if is_prime(num):
            factors.append(num)
            break
        if is_prime(i):
            if num%i == 0:
                factors.append(i)
                num = num/i
                print(num,'|',i)
        i += 1
    return max(factors)

num=600851475143
largest_primeFactor = primeFactors(num)
print('The largest prime factor of {} is {}'.format(num,largest_primeFactor))


'''
Statistical Computing for Scientists and Engineers
Homework 2
Fall 2018
University of Notre Dame
'''
import numpy as np
import matplotlib.pyplot as plt
from scipy.special import gammaln
import pandas as pd
data = pd.read_csv('data.csv',header=None)
data = np.array(data)
y = data[:,0]
n = data[:,1]
print (y)
N = len(n)
#log-likelihood
def log_likelihood(alpha,beta,y,n):
    '''
    marginal posterior distribution-log_likelihood part
    @args: y = training data, parameters: alpha, beta and dataset:n
    @returns: log_likelihood
    '''
    log_likelihood = 0
    for Y,N in zip(y,n):
	##############################################################
	# INSERT CODE BELOW
	##############################################################
        log_likelihood+=
	##############################################################
	# INSERT CODE ABOVE
	##############################################################

    return log_likelihood

def log_prior(A,B):
    '''
    marginal posterior distribution-log_prior part
    @args: parameters: alpha, beta
    @returns: prior
    '''
    ##############################################################
    # INSERT CODE BELOW
    ##############################################################
    log_prior =
    ##############################################################
    # INSERT CODE ABOVE
    ##############################################################
    return log_prior

def to_beta(x,y):

    return np.exp(y)/(np.exp(x)+1)

def to_alpha(x,y):

    return np.exp(x)*trans_to_beta(x,y)

X,Y = np.meshgrid(np.arange(-2.3,-1.3,0.01),np.arange(1,5,0.01))
param_space = np.c_[X.ravel(), Y.ravel()]
df= pd.DataFrame(param_space, columns=['X','Y'])

df['alpha']= to_alpha(df.X,df.Y)
df['beta'] = to_beta(df.X,df.Y)

df['log_posterior'] = log_prior(df.alpha,df.beta) + log_likelihood(df.alpha,df.beta, y,n)
df['log_jacobian'] = np.log(df.alpha) + np.log(df.beta)

df['transformed'] = df.log_posterior+df.log_jacobian
df['exp_trans'] = np.exp(df.transformed - df.transformed.max())

surface = df.set_index(['X','Y']).exp_trans.unstack().values.T

fig, ax = plt.subplots(figsize = (8,8),facecolor='white')
ax.contourf(X,Y, surface)
ax.set_xlabel(r'$\log(\alpha/\beta)$', fontsize = 16)
ax.set_ylabel(r'$\log(\alpha+\beta)$', fontsize = 16)
ix_z,ix_x = np.unravel_index(np.argmax(surface, axis=None), surface.shape)
print ('x:co-ordinate_value:', np.round(X[0,ix_x],2))
print ('y:co-ordinate_value:', np.round(Y[ix_z,0],2))
ax.scatter([X[0,ix_x]], [Y[ix_z,0]], color = 'red')

text= r"$({a},{b})$".format(a = np.round(X[0,ix_x],2), b = np.round(Y[ix_z,0],2))

ax.annotate(text,xy = (X[0,ix_x],Y[ix_z,0]), xytext=(-1.6, 3.5),
            ha = 'center',
            fontsize = 16,
            color = 'white',
            arrowprops=dict(facecolor='black',));
plt.savefig('HW2-P1b.png', facecolor=fig.get_facecolor(), transparent=True)
plt.show()