"""Module responsible for the kernels"""
from __future__ import absolute_import, division, print_function, unicode_literals
import numpy as np

def poly_kernel(x: np.ndarray, y: np.ndarray, degree: int=1, gamma: float=1.0, coef0: float=0.0):
    """
    Compute the polynomial kernel between x and y::
        K(x, y) = (gamma * <x, y> + coef0)^degree

    :param x: ndarray of shape (n_samples_1, n_features)
    :param y: ndarray of shape (n_samples_2, n_features)
    :param degree: see formula
    :param gamma: see formula
    :param coef0: see formula
    :return: Gram matrix : array of shape (n_samples_1, n_samples_2)
    """

    K = np.dot(x, y.T)
    K *= gamma
    K += coef0
    K **= degree
    return K

def rbf(a: np.ndarray, b: np.ndarray, length: float, sigma_f: float):
    """
    Radial basis kernel: Gaussian distance kernel

    :param a: design matrix of shape (nexamples, nfeatures)
    :param b: design matrix of shape (nexamples, nfeatures)
    :param length: Kernel parameter: vertical length
    :param sigma_f: Kernel parameter: horizontal length
    :return: Gram Matrix of shape (nexamples, nexamples)
    """
    sqdist = np.sum(a**2, 1).reshape(-1, 1) + np.sum(b**2, 1) - 2 * np.dot(a, b.T)
    return np.exp(-0.5 * (1 / length) * sqdist) * sigma_f


import tools
import log
import copy

import numpy as np

def gauss(B, c, use_np = True):
    if use_np:
        return np.linalg.solve(B, c)
    A = copy.copy(B)
    b = copy.copy(c)

    log.debug(f'Gauss started {tools.print_matrix(A)}')
    assert A.shape[0] == A.shape[1] == len(b)
    n = len(b)
    assert n > 0

    current_line = np.array([i for i in range(n)]).reshape(n)
    line_max = np.array([max([abs(A[i][j]) for j in range(n)]) for i in range(n)]).reshape(n)

    for i in range(n - 1):

        index = i + np.argmax([abs(A[current_line[j]][i]) / line_max[current_line[j]] for j in range(i, n)])
        current_line[i], current_line[index] = current_line[index], current_line[i]

        for j in range(i + 1, n):
            factor = A[current_line[j]][i] / A[current_line[i]][i]
            b[current_line[j]] = b[current_line[j]] - factor * b[current_line[i]]
            for k in range(i, n):
                A[current_line[j]][k] = A[current_line[j]][k] - factor * A[current_line[i]][k]

    x = np.zeros(n)
    x[n - 1] = b[current_line[n - 1]] / A[current_line[n - 1]][n - 1]

    for i in range(n - 2, -1, -1):
        summa = sum([A[current_line[i]][j] * x[j] for j in range(i + 1, n)])
        x[i] = (b[current_line[i]] - summa) / A[current_line[i]][i]

    log.debug('Gauss ended')
    return x


import numpy as _np

__all__=['calc_phase',
        'linear_frequency',
        'symetric_linear_frequency',
        'poly_frequency',
        'sin_frequency',
        'sin_quart_frequency',
        'sin_half_frequency',
        'sin_phase_frequency'
        ]

#-------------------------------
def calc_phase(frequencies, init_phases, length = None, fs=None):
    '''
    Utilite to calculte the phase to time relation
      based on frequency to time relation.
      ..math::
      phi(n) = 2pi*integral(*f(n)*n/fs)

    Paramters
    -----------
    frequencies: float or 1d ndarray,
      could be either carier frequency (float),
      or frequency to time relation (frequency modulation).
    init_phases: float or 1d ndarray,
      could be either initial phase (float),
      or additional phase to time relation (phase modulation).
    length: int or None,
      length or required signal,
      if None, length = max of lengths
      between frequencies, amplitudes, init_phases
    fs: float or None,
      sampling frequency, if None, fs = length

    Returns
    --------------
    full_phase: 1d ndarray.

    Note
    ----------
    If some of the parameters (freq, amp, phase) have a size,
      smaller than the required size, it will be extended,
      with the last value. In the opposite case,
      it will be cut up to the required size.

    '''
    frequencies = _np.asarray(frequencies, dtype = float)
    init_phases = _np.asarray(init_phases, dtype = float)

    if length is None:
        length = max(frequencies.size,
                     init_phases.size)

    frequencies = _check_size(frequencies, length)
    init_phases = _check_size(init_phases, length)

    if fs is None:
        fs = length

    dt = 1/fs

    return 2*_np.pi*_np.cumsum(frequencies)*dt+init_phases

#-------------------------------------
def _check_size(array, size=None):

    array = _np.asarray(array, dtype = float)

    if size is None:
        return array

    size = int(size)

    if array.size==1:
        return _np.ones(size, dtype=float)*array
    else:
        if array.size>=size:
            return array[:size]

        else:
            last  = _np.ones(size-array.size,
                            dtype=float)*array[-1]
            return _np.concatenate((array,last))

#-------------------------------
def linear_frequency(f0, delta_f, length, fs):
    '''
    Linear frequency to time relation.
      ..math::
      f(n) = f0 + delta_f*(n/fs)/Tm,
      Tm = N/fs, n=0,...,N-1

    Paramteres
    ------------
    f0: float,
      carried frequency.
    delta_f: float,
      frequency bandwidth.
    length: int,
      length of relation.
    fs: float,
      sampling frequency.

    Return
    ----------
    freq: 1d ndarray.
    '''
    length = int(length)
    t = _np.arange(length)/fs
    return f0+delta_f*t/((length/fs))
#-------------------------------
def symetric_linear_frequency(f0, delta_f, length, fs):
    '''
    Linear frequency to time relation.
      ..math::
      f(n) = [f0 + delta_f*(n/fs)/Tm,
      f0+delta_f - delta_f*(n/fs)/Tm]
      Tm = N/2fs, n=0,...,N-1

    Paramteres
    ------------
    f0: float,
      carried frequency.
    delta_f: float,
      frequency bandwidth.
    length: int,
      length of relation.
    fs: float,
      sampling frequency.

    Return
    ----------
    freq: 1d ndarray.
    '''
    length = int(length)
    t = _np.arange(length)/(2*fs)
    tm = length/fs/2
    return _np.concatenate((f0+delta_f*t/tm,
                           f0+delta_f-delta_f*t/tm))
#-------------------------------
def poly_frequency(f0, delta_f, degree, length, fs):
    '''
    Polynomial frequency to time relation.
      ..math::
      f(n) = f0 + delta_f*(fm/max(fm)),
      fm = (n/fs)^d/Tm
      Tm = N/fs, n=0,...,N-1

    Paramteres
    ------------
    f0: float,
      carried frequency.
    delta_f: float,
      frequency bandwidth.
    degree: float,
      degree of Polynomial relation.
    length: int,
      length of relation.
    fs: float,
      sampling frequency.

    Return
    ----------
    freq: 1d ndarray.
    '''
    t = _np.arange(length)/fs
    freq = _np.power(t,degree)/((length/fs))
    return f0+delta_f*freq/_np.max(freq)
#-------------------------------
def sin_frequency(f0, delta_f, length, fs):
    '''
    Sinus frequency to time relation.
      ..math::
      f(n) = f0+delta_f/2+delta_f*sin(2pi*n/(Tmfs))/2,
      Tm = N/fs, n=0,...,N-1

    Paramteres
    ------------
    f0: float,
      carried frequency.
    delta_f: float,
      frequency bandwidth.
    length: int,
      length of relation.
    fs: float,
      sampling frequency.

    Return
    ----------
    freq: 1d ndarray.
    '''
    t = _np.arange(length)/fs
    tm = length/fs
    return (f0+delta_f/2)+delta_f*_np.sin(2*_np.pi*t/tm)/2
#-------------------------------
def sin_quart_frequency(f0, delta_f, length, fs):
    '''
    Sinus quarter (first quadrant) frequency to time relation.
      ..math::
      f(n) = f0+delta_f*sin(2pi*n/(4Tmfs)),
      Tm = N/fs, n=0,...,N-1

    Paramteres
    ------------
    f0: float,
      carried frequency.
    delta_f: float,
      frequency bandwidth.
    length: int,
      length of relation.
    fs: float,
      sampling frequency.

    Return
    ----------
    freq: 1d ndarray.
    '''
    t = _np.arange(length)/fs
    tm = length/fs
    return (f0)+delta_f*_np.sin((2*_np.pi*t/tm)/4)

#-------------------------------
def sin_half_frequency(f0, delta_f, length, fs):
    '''
    Sinus half (first 2 quadrants) frequency to time relation.
      ..math::
      f(n) = f0+delta_f*sin(2pi*n/(2Tmfs)),
      Tm = N/fs, n=0,...,N-1

    Paramteres
    ------------
    f0: float,
      carried frequency.
    delta_f: float,
      frequency bandwidth.
    length: int,
      length of relation.
    fs: float,
      sampling frequency.

    Return
    ----------
    freq: 1d ndarray.
    '''
    t = _np.arange(length)/fs
    tm = length/fs
    return (f0)+delta_f*_np.sin((2*_np.pi*t/tm)/2)

#-------------------------------
def sin_phase_frequency(f0, delta_f, length, fs, phi0=0, phiN=_np.pi/4):
    '''
    Arbitarry sinus frequency to time relation.
      ..math::
      f(n) = f0+delta_f*sin(2pi*n/(Tm*fs*pi/phiN)+phi0),
      Tm = N/fs, n=0,...,N-1

    Paramteres
    ------------
    f0: float,
      carried frequency.
    delta_f: float,
      frequency bandwidth.
    length: int,
      length of relation.
    fs: float,
      sampling frequency.

    Return
    ----------
    freq: 1d ndarray.
    '''
    t = _np.arange(length)/fs
    tm = length/fs
    divider = _np.pi/phiN
    freqm = _np.sin(2*_np.pi*t/(tm*divider)+phi0)
    return (f0)+delta_f*(freqm-min(freqm))/(max(freqm)-min(freqm))

#---------------------------------------
def to_beatsignal(sig_ref, sig_delayed,
                  reduced_ratio=None, hilbert = False):
    '''
    Mixing reference and delayed (received)
        signals to create the beat one.

    Parameters
    -------------
    sig_ref: 1d ndarray,
        reference signal
    sig_delayed: 1d ndarray,
        dealyed signal
    reduced_ratio: float,
        pooling (or downsampling) ratio as fs_old/fs_new,
        where fs is the sampling frequency,
    hilbert: bool,
        If ture, hilbert transform will be carried out additionally.

    Returns
    -------------
    sig_beat: 1d ndarray,
        beat signal.
    '''
    sig_beat = sig_ref*_np.conj(sig_delayed);
    if reduced_ratio is not None:

        len_reduce = int(len(sig_ref)/reduced_ratio)

        sp = _np.fft.fft(sig_beat)

        if hilbert is False:
            sp = _np.concatenate((sp[:len_reduce//2],
                                 [sp[len(sp)//2]],
                                 sp[len(sp) - len_reduce//2 +1:]))
        else:
            sp = _np.concatenate((sp[:len_reduce//2],
                                 [sp[len(sp)//2]],
                                 _np.zeros(len_reduce//2 +1,
                                          dtype=complex)))

        sig_beat = _np.fft.ifft(sp)
    else:
        if hilbert:
            sp = _np.fft.fft(sig_beat)
            sp[len(sp)//2:] = 0
            sig_beat = _np.fft.ifft(sp)

    #TODO: add pooling
    return sig_beat


import numpy as np
import math

def FitLinearGaussianParameters(X, U):
    '''
    :param X:
    :param U:
    :return:
    '''

    M = U.shape[0]
    N = U.shape[1]
    assert(N == 3)
    assert(M == X.shape[0])

    Beta = np.zeros((N+1, ))
    sigma = 1

    A = np.ones((N + 1, N + 1))
    mean_U = np.mean(U, axis=0)
    last_col = np.concatenate(([1], mean_U))
    first_row = np.concatenate((mean_U, [1]))
    A[0, :] = first_row
    A[:, -1] = last_col

    for i in range(N):
        for j in range(N):
            prod_ij = np.dot(U[:, i], U[:, j])
            E_ij = prod_ij / M
            A[i + 1, j] = E_ij

    B = np.ones((N + 1, ))
    first_row_B = np.mean(X)
    B[0] = first_row_B
    for k in range(N):
        prod_X_U_k = np.dot(X, U[:, k])
        E_X_U_k = prod_X_U_k / M
        B[k + 1] = E_X_U_k

    Beta = np.linalg.solve(A, B)

    cov_X_X = np.dot(X, X) / M - (np.mean(X)) ** 2
    cov_U = np.cov(U, rowvar=False, bias=True)

    beta_vec = Beta[0 : -1]
    beta_mat = np.matmul(np.matmul(beta_vec, cov_U), beta_vec.transpose())

    first_term = cov_X_X
    second_term = np.matmul(np.matmul(beta_vec, cov_U), beta_vec.transpose())
    sigma = math.sqrt(first_term - second_term)

    return Beta, sigma


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

import numpy, math

def gain(X_partition, y_partition):
    """Calcula medida de ganho de informação."""
    info_partition = info(y_partition)
    info_attr, partitions, values = info_attribute(X_partition, y_partition)
    return (info_partition - info_attr), partitions, values

def info(y_partition):
    """Calcula medida de informação para o conjunto de dados."""
    total = 0
    partition_size = y_partition.size
    values, indices = numpy.unique(y_partition, return_inverse=True)
    counts = numpy.bincount(indices)
    if len(values) > 1:
        for value, count in zip(values, counts):
            prob = count / float(partition_size)
            total -= prob * math.log(prob, len(values))
    return total

def info_attribute(X_partition, y_partition):
    """Calcula medida de informação para um atributo do conjunto de dados."""
    total = 0
    partition_size = y_partition.size
    values, indices = numpy.unique(X_partition, return_inverse=True)
    counts = numpy.bincount(indices)
    partitions = []
    for value, count in zip(values, counts):
        prob = count / float(partition_size)
        partition = numpy.where(X_partition==value)
        partitions.append(partition)
        partition_info = info(y_partition[partition])
        total += prob * partition_info
    return total, partitions, values


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Aug 19 2020

@author: daniel
"""

# swish function
# https://en.wikipedia.org/wiki/Swish_function
from numpy import arange
def swish(x, beta):
    return x/(1+exp(-beta*x))

x_sample_space = arange(-5, 5.01, 0.01)
beta = 1 # 0.5
y = swish(x_sample_space, beta)
plt.plot(x_sample_space, y)
plt.show()


from math import floor
from numpy import arange, exp, pi, flipud, append, conj, real
from numpy.fft import ifft
from numpy.random import randn, rand

def powernoise(alpha, N, randpower=False, normalize=False):
	"""
	Generate samples of power law noise. The power spectrum
	of the signal scales as f^(-alpha).

	Usage:
		x = powernoise(alpha, N)
		x = powernoise(alpha, N, randpower=True, normalize=True)

	Inputs:
		alpha - power law scaling exponent
		N     - number of samples to generate

	Output:
		x     - N x 1 vector of power law samples

	By default, the power spectrum is deterministic, and the phases are
	uniformly distributed in the range -pi to +pi. The power law extends
	all the way down to 0Hz (DC) component. By specifying randpower=True
	the power spectrum will be stochastic with Chi-square distribution.
	With normalize=True the output is scaled to the range [-1, 1], and
	consequently the power law will not necessarily extend right down to 0Hz.

	Original Matlab code by Max Little:
	Little MA et al. (2007), "Exploiting nonlinear recurrence and fractal
	scaling properties for voice disorder detection", Biomed Eng Online, 6:23
	See http://www.maxlittle.net/software/
	"""

	N2 = floor(N/2)-1
	f = arange(2, N2+2)
	A2 = 1./(f**(alpha/2))

	if (randpower):
		p2 = (rand(N2)-0.5)*2.*pi
		d2 = A2 * exp(1j*p2)
	else:
		# 20080323
		p2 = randn(N2) + 1j * randn(N2)
		d2 = A2 * p2

	d = append( append( append([1.], d2), [1/((N2+2)**alpha)] ), flipud(conj(d2)) )
	x = real(ifft(d))

	if (normalize):
		x = ((x - min(x))/(max(x) - min(x)) - 0.5) * 2

	return x


from scipy.integrate import odeint
import matplotlib.pyplot as plt

class SIR:
    def __init__(self, N, I0, beta, gamma, days):
        """
        N - Total population
        I0 - Initial number of infected individuals,
        S0 - Everyone else is susceptible to infection initially
        Contact rate, beta, and mean recovery rate, gamma, (in 1/days)
        """
        self.N = N
        self.I0 = I0
        self.beta = beta
        self.gamma = gamma
        self.S0 = N - I0
        self.days = days

    @staticmethod
    def _deriv(y, t, N, beta, gamma):
        """
        The SIR model differential equations
        """
        S, I, R = y
        #print(t)
        dSdt = -beta[int(t)] * S * I / N
        dIdt = beta[int(t)] * S * I / N - gamma * I
        dRdt = gamma * I
        return dSdt, dIdt, dRdt

    def run(self):
        # Initial conditions vector
        y0 = self.S0, self.I0, 0
        # Integrating the SIR equations over the time grid, t
        t = list(range(0, self.days))
        # Getting results
        result = odeint(self._deriv, y0, t, args=(self.N, self.beta, self.gamma))
        S, I, R = result.T
        return S, I, R

    @staticmethod
    def plot_results(S, I, R):
        fig = plt.figure(facecolor='w')
        ax = fig.add_subplot(111, axisbelow=True)
        ax.plot(S/1000, 'b', alpha=0.5, lw=2, label='Susceptible')
        ax.plot(I/1000, 'r', alpha=0.5, lw=2, label='Infected')
        ax.plot(R/1000, 'g', alpha=0.5, lw=2, label='Recovered')
        ax.set_xlabel('Time /days')
        ax.set_ylabel('Number (1000s)')
        #ax.set_ylim(0,1.2)
        ax.yaxis.set_tick_params(length=0)
        ax.xaxis.set_tick_params(length=0)
        ax.grid(b=True, which='major', c='w', lw=2, ls='-')
        legend = ax.legend()
        legend.get_frame().set_alpha(0.5)
        for spine in ('top', 'right', 'bottom', 'left'):
            ax.spines[spine].set_visible(False)
        plt.show()


import numpy as np

def mse(y,t):
    result = 0.5 * np.sum((y-t)**2)    #예측값 - 참값
    print(result)
    return result

#출력층 활성함수에 의해 출력된 결과  (소프트맥스)   -----> 예측값
y3 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]  # 1일 확률이 0.1, 2일 확률이 0.05 등..
#원핫 인코딩   ----->  참값
t3 = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]  #np.argmax(y3)을 통해서 가장 확률이 높은 값을 표현하는 원핫인코딩

# 분류가 3일 확률이 0.6으로 가장 높은 경우 실제 3라는 결과의 손실 함수 값
mse(np.array(y3), np.array(t3)) #0.0975

# 분류가 7일 확률이 가장 높으나 실제 3이라는 결과의 손실 함수 값

y7 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
mse(np.array(y7), np.array(t3)) #0.5975

#코스트가 줄지 않았다..?
#그러니까, 모든 케이스를 봤을 때, 손실함수 값이 가장 작았던 값을 첫 추정결과로 판단하게 되는 근거가 된다.
#그게 바로 MSE! 손실함수! cost !!

def cross_entropy_error(y,t):  # y와 t는 넘파이 배열이다.
    delta = 1e-7
    result = -np.sum(t* np.log(y+delta)) #np.log계산할때 아주 작은 값인 delta를 더했다.
                                          #0을 함수에 입력하면 -inf가 되버리기 때문에, 작은 값을 더해 무한대가 발생하지 않도록 하는 것.
    print(result)
    return result

cross_entropy_error(np.array(y3), np.array(t3))  #0.510825457099
cross_entropy_error(np.array(y7), np.array(t3))  #2.30258409299


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

"""
def pend(y, t, b, c):
    theta, omega = y
    dydt = [omega, -b*omega - c*np.sin(theta)]
    return dydt

b = 0.025
c = 5.0
y0 = [np.pi - 0.1, 0.0]
t = np.linspace(0, 100, 1001)
sol = odeint(pend, y0, t, args=(b, c))

x, p = sol.T[0], sol.T[1]
plt.plot(x, p, ".", markersize=4)
plt.pause(3)
plt.savefig('plot_xp.png', dpi=60)
plt.close()

plt.plot(t, sol[:, 0], 'b', label='theta(t)')
plt.xlabel('t')
plt.grid()
plt.legend(loc='best')
plt.pause(3)
plt.plot(t, sol[:, 1], 'g', label='omega(t)')
plt.legend(loc='best')
plt.pause(3)
plt.savefig('plot_thomegavst.png', dpi=60)
plt.close()
"""

def dualPendulum(y, t, L, omegaJ,M,M1):
    theta1, omega1,theta2, omega2 = y
    dydt = [omega1,
            (-omegaJ*(np.sin(theta1)+M*np.sin(theta1-2*theta2))-2*np.sin(theta1-theta2)*M*(omega2*omega2*L+omega1*omega1*np.cos(theta1-theta2)))/(1*(1-M*np.cos(2*(theta1-theta2)))),
            omega2,
            (2*np.sin(theta1-theta2)*(omega1*omega1*M1+omegaJ*M1*np.cos(theta1)+omega2*omega2*L*M1*np.cos(theta1-theta2)))/(L*(1 - M*np.cos(2*(theta1-theta2))))]
    return dydt

def doublePendulum(y, t, L, omegaJ,M):
    theta1, omega1,theta2, omega2 = y
    theta12=theta1 -theta2
    dydt = [omega1,
            (omegaJ*(-np.sin(theta1)+M*np.cos(theta12)*np.sin(theta2))-M*(omega1*omega1*np.cos(theta12)+L*omega2*omega2)*np.sin(theta12))/(1-M*np.cos(theta12)*np.cos(theta12)),
            omega2,
            (omegaJ*(-np.sin(theta2)+np.cos(theta12)*np.sin(theta1))+(M*L*omega2*omega2*np.cos(theta12)+omega1*omega1)*np.sin(theta12))/(L-M*L*np.cos(theta12)*np.cos(theta12))]
    return dydt

def doublePendulum2(y, t, L, omegaJ,M,M1):
    theta1, omega1,theta2, omega2 = y
    theta12=theta1 -theta2
    dydt = [omega1,
            (omegaJ*(-M1*np.sin(theta1)+M*np.cos(theta12)*np.sin(theta2))-M*(2*omega1*omega1*np.cos(theta12)+L*omega2*omega2)*np.sin(theta12))/(1-2*M*np.cos(theta12)*np.cos(theta12)),
            omega2,
            (omegaJ*(-np.sin(theta2)+2*M1*np.cos(theta12)*np.sin(theta1))+(2*M*L*omega2*omega2*np.cos(theta12)+2*omega1*omega1)*np.sin(theta12))/(L-2*M*L*np.cos(theta12)*np.cos(theta12))]
    return dydt

L1=7
L2=1
g=9.8
m1=100
m2=20
y01=0.5
for i in range(0,10,1):
    y01=(2.1115*0.0001)*np.exp(-i)  #3.14*np.exp(i)/np.exp(10)
    M=m2/(2*m1+m2)
    M1=(m1+m2)/(2*m1+m2)
    omegaJ=g/L1
    L=L2/L1
    y0 = [y01, 0.0,0, 0.0]
    t = np.linspace(0, 1000, 4001)
    sol = odeint(dualPendulum, y0, t, args=(L, omegaJ,M,M1))

    x1, p1,x2,p2 = sol.T[0],sol.T[1], sol.T[2], sol.T[3]
    plt.plot(x1, p1, ".", markersize=4)
    plt.pause(3)
    plt.savefig('plot_xp1dual_L1{}L2{}m1{}m2{}y01{}.png'.format(L1, L2,m1,m2,y01), dpi=180)
    plt.close()
    plt.plot(x2, p2, ".", markersize=4)
    plt.pause(3)
    plt.savefig('plot_xp2dual_L1{}L2{}m1{}m2{}y01{}.png'.format(L1, L2,m1,m2,y01),dpi=180)
    plt.close()
    """
    plt.plot(t, sol[:, 0], 'b', label='theta1(t)')
    plt.xlabel('t')
    plt.xlim(0,100)
    #plt.ylim(-0.5,0.5)
    plt.grid()
    plt.legend(loc='best')
    plt.pause(3)
    plt.plot(t, sol[:, 2], 'g', label='theta2(t)')
    plt.legend(loc='best')
    plt.pause(3)
    plt.savefig('plot_theta2vstdual_L1{}L2{}m1{}m2{}y01{}.png'.format(L1, L2,m1,m2,y01), dpi=180)
    plt.close()

    plt.plot(t, sol[:, 1], 'b', label='omega1(t)')
    plt.xlabel('t')
    plt.xlim(0,100)
    #plt.ylim(-1,1)
    plt.grid()
    plt.legend(loc='best')
    plt.pause(3)
    plt.plot(t, sol[:, 3], 'g', label='omega2(t)')
    plt.legend(loc='best')
    plt.pause(3)
    plt.savefig('plot_omega2vstdual_L1{}L2{}m1{}m2{}y01{}.png'.format(L1, L2,m1,m2,y01), dpi=180)
    plt.close()
    """

    M=m2/(m1+m2)
    L=L2/L1
    omegaJ=g/L1
    #y01=0.0020
    y0 = [y01, 0.0,0, 0.0]
    t = np.linspace(0, 1000, 4001)
    #sol = odeint(dualPendulum, y0, t, args=(L1, L2,g,m1,m2))
    #sol = odeint(doublePendulum, y0, t, args=(L1, L2,g,m1,m2))
    sol = odeint(doublePendulum, y0, t, args=(L, omegaJ,M))

    x1, p1,x2,p2 = sol.T[0],sol.T[1], sol.T[2], sol.T[3]
    plt.plot(x1, p1, ".", markersize=4)
    plt.pause(3)
    #plt.savefig('plot_xp1pen_L{}M{}omegaJ{}y01{}n.png'.format(L, omegaJ,M,y01), dpi=180)
    plt.savefig('plot_xp1pen_L1{}L2{}m1{}m2{}y01{}n.png'.format(L1, L2,m1,m2,y01), dpi=180)
    plt.close()
    plt.plot(x2, p2, ".", markersize=4)
    plt.pause(3)
    plt.savefig('plot_xp2pen_L{}M{}omegaJ{}y01{}n.png'.format(L, omegaJ,M,y01),dpi=180)
    plt.close()
    """
    plt.plot(t, sol[:, 0], 'b', label='theta1(t)')
    plt.xlabel('t')
    plt.xlim(0,100)
    #plt.ylim(-0.5,0.5)
    plt.grid()
    plt.legend(loc='best')
    plt.pause(3)
    plt.plot(t, sol[:, 2], 'g', label='theta2(t)')
    plt.legend(loc='best')
    plt.pause(3)
    plt.savefig('plot_theta2vstpen_L1{}L2{}m1{}m2{}y01{}n.png'.format(L1, L2,m1,m2,y01), dpi=180)
    plt.close()

    plt.plot(t, sol[:, 1], 'b', label='omega1(t)')
    plt.xlabel('t')
    plt.xlim(0,100)
    #plt.ylim(-1,1)
    plt.grid()
    plt.legend(loc='best')
    plt.pause(3)
    plt.plot(t, sol[:, 3], 'g', label='omega2(t)')
    plt.legend(loc='best')
    plt.pause(3)
    plt.savefig('plot_omega2vstpen_L1{}L2{}m1{}m2{}y01{}n.png'.format(L1, L2,m1,m2,y01), dpi=180)
    plt.close()
    """

    L1=L1
    L2=L2
    g=9.8
    m1=m1
    m2=m2
    M=2*m2/(m1+4*m2)
    M1=(m1+2*m2)/(m1+4*m2)
    L=L2/L1
    omegaJ=g/L1
    y01=y01
    y0 = [y01, 0.0,0, 0.0]
    t = np.linspace(0, 1000, 4001)
    #sol = odeint(dualPendulum, y0, t, args=(L1, L2,g,m1,m2))
    #sol = odeint(doublePendulum, y0, t, args=(L1, L2,g,m1,m2))
    sol = odeint(doublePendulum2, y0, t, args=(L, omegaJ,M,M1))

    x1, p1,x2,p2 = sol.T[0],sol.T[1], sol.T[2], sol.T[3]
    plt.plot(x1, p1, ".", markersize=4)
    plt.pause(3)
    #plt.savefig('plot_xp1Pen2_L{}M{}omegaJ{}y01{}n.png'.format(L, omegaJ,M,M1,y01), dpi=180)
    plt.savefig('plot_xp1Pen2_L1{}L2{}m1{}m2{}y01{}n.png'.format(L1, L2,m1,m2,y01), dpi=180)
    plt.close()
    plt.plot(x2, p2, ".", markersize=4)
    plt.pause(3)
    plt.savefig('plot_xp2Pen2_L{}M{}omegaJ{}y01{}n.png'.format(L, omegaJ,M,y01),dpi=180)
    plt.close()
    """
    plt.plot(t, sol[:, 0], 'b', label='theta1(t)')
    plt.xlabel('t')
    plt.xlim(0,100)
    #plt.ylim(-0.5,0.5)
    plt.grid()
    plt.legend(loc='best')
    plt.pause(3)
    plt.plot(t, sol[:, 2], 'g', label='theta2(t)')
    plt.legend(loc='best')
    plt.pause(3)
    plt.savefig('plot_theta2vstPen2_L{}M{}omegaJ{}y01{}n.png'.format(L, omegaJ,M,y01), dpi=180)
    plt.close()

    plt.plot(t, sol[:, 1], 'b', label='omega1(t)')
    plt.xlabel('t')
    plt.xlim(0,100)
    #plt.ylim(-1,1)
    plt.grid()
    plt.legend(loc='best')
    plt.pause(3)
    plt.plot(t, sol[:, 3], 'g', label='omega2(t)')
    plt.legend(loc='best')
    plt.pause(3)
    plt.savefig('plot_omega2vstPen2_L{}M{}omegaJ{}y01{}n.png'.format(L, omegaJ,M,y01), dpi=180)
    plt.close()
    """


# 2D Newton's method
import numpy as np

def f(x):
    x0,x1 = x[0,0],x[1,0]
    return np.array([[4*x0-2*x0*x1],[2*x1+x0*x1-2*x1**2]])

def JI(x):
    x0,x1 = x[0,0],x[1,0]
    d = (4-2*x1)*(2-x0-4*x1)+2*x0*x1
    return (1/d)*np.array([[2-x0-4*x1,2*x0],[-x1,4-2*x0]])

x0 = float(input("x0: "))
x1 = float(input("x1: "))
x = np.array([[x0],[x1]])

N = 20
for i in range(N):
    x = x - JI(x) @ f(x)
    if (i > (N-10)):
        print("%4d: (%0.8f, %0.8f)" % (i, x[0,0],x[1,0]))


import numpy as np

def minmax_scale(x):
    """Scale data so it is in the range (0, 1)"""
    data_min = np.min(x)
    data_max = np.max(x)
    data_range = data_max - data_min

    # don't divide by zero
    if data_range == 0.:
        data_range = 1.

    x -= data_min
    x /= data_range


import numpy as np

def normalize(X):
    mean = np.mean(X, axis=0)
    std_deviation = np.std(X, axis=0)
    return (X - mean) / (std_deviation), mean, std_deviation


import numpy as np

def convert_meter_to_latlon_deg(lat_deg):
    # Scaling factor is 1 / 111.32 km, hence approximating a spherical Earth
    # See https://en.wikipedia.org/wiki/Decimal_degrees#Precision
    m_to_deg_lat = 1 / 111320.
    m_to_deg_lon = 1 / (111320. * np.cos(np.deg2rad(lat_deg)))
    return m_to_deg_lat, m_to_deg_lon

def convert_resolution_from_meters_to_deg(position_lat, gsd_metric):
    m_to_deg_lat, m_to_deg_lon = convert_meter_to_latlon_deg(position_lat)
    gsd_deg_lat = gsd_metric * m_to_deg_lat
    gsd_deg_lon = gsd_metric * m_to_deg_lon
    return gsd_deg_lon, gsd_deg_lat


from math import sqrt
from pprint import pprint
import numpy as np

#Cholesky
def cholesky(A):
    rows = len(A)
    columns = len(A[0])
    Z = np.zeros((rows,1), float)
    X = np.zeros((rows, 1), float)
    #X = np.array([[1],[1],[1],[1]])
    #Z = np.array([[1,1,1,1],[1,1,1,1],[1,1,1,1],[1,1,1,1]])
    L = np.zeros((rows,columns), float)
    U = np.zeros((rows,columns), float)

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

    #L = np.zeros((rows,columns), float)
    #print(L)

    for k in range(0, rows):
        suma = 0.0
        for p in range(0, k):
            suma = suma + L[k][p]*U[p][k]
        L[k][k] = sqrt(A[k][k] - suma)
        U[k][k] = L[k][k]

        for i in range(k, rows):
            suma = 0
            for p in range(0, k):
                suma = suma + L[i][p]*U[p][k]
            L[i][k] = (A[i][k] - suma)/L[k][k]

        for j in range(k, rows):
            suma = 0
            for p in range(0, k):
                suma = suma + L[k][p]*U[p][j]
            U[k][j] = (A[k][j] - suma)/L[k][k]

    Lb = np.concatenate([L, b], axis=1)

    for i in range(0, rows):
        suma = 0
        for p in range(0, i):
            suma = suma + Lb[i][p]*Z[p][0]
        Z[i][0] = (Lb[i][rows] - suma)/Lb[i][i]

    Lu = np.concatenate([U, Z], axis=1)

    for i in range(rows-1,-1, -1):
        suma = 0
        for p in range(i, rows):
            suma = suma + Lu[i][p]*X[p]
        X[i] = (Lu[i][rows] - suma)/Lu[i][i]

    return L, U, Z, X

if __name__ == "__main__":
    A = [[4, -1, 0, 3], [1, 15.5, 3, 8], [0, -1.3, -4, 1.1],[14, 5, -2, 30]]
    C = [[5,4,3,2], [2,4,1,1], [3,4,5,1],[2,3,3,7]]
    #[4, -1, 0, 3; 1, 15.5, 3, 8; 0, -1.3, -4, 1.1; 14, 5, -2, 30]
    if((np.all(np.linalg.eigvals(C) > 0) == True)):
        L,U, Z, X = cholesky(C)
        print ("A:")
        pprint(C)

        print ("L:")
        pprint(L)
        print("U: ")
        pprint(U)
        print("X: ")
        print(X)
        print("Z: ")
        print(Z)
    else:
        print("La matriz no se puede operar, pues no esta definida positivamente.")


import numpy as np

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

def derivated_sigmoid(x):
    return x*(1-x)

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

assert np.shape(x)[0] == np.shape(y)[0]

w = 2*np.random.random((np.shape(x)[1], 1))-1
b =1
lr = 0.0001
epoc = 100000
for i in range(epoc):
    #forward propogation
    layer_1 = x
    y_hat = sigmoid((np.dot(layer_1, w) + b))

    #backpropogation
    error = y - y_hat
    weight_updates = lr*error*derivated_sigmoid(y_hat)
    w += np.dot(x.T, weight_updates)
    b += np.dot(lr,error)

print("--Output--")
print(y_hat)


import numpy as np
from scipy.stats import chi2

def chi_square(Ns, Ni):
    """ Return $\chi^2_{\text stat}$ value and the associate p-value"""

    NsNi = np.ndarray((len(Ns), 2))
    NsNi[:, 0] = Ns
    NsNi[:, 1] = Ni

    length = len(Ns)
    Ns = sum(Ns)
    Ni = sum(Ni)

    X2 = 0.
    for Nsj, Nij in NsNi:
        X2 += (Nsj*Ni - Nij*Ns)**2 / (Nsj + Nij)

    X2 *= 1.0/(Ns*Ni)
    rv = chi2(length - 1)
    return 1.0 - rv.cdf(X2)

def calculate_central_age(Ns, Ni, zeta, seZeta, rhod, Nd, sigma=0.15):
    """Function to calculate central age."""

    Ns = np.array(Ns)
    Ni = np.array(Ni)

    # We just replace 0 counts with a low value, the age will be rounded to
    # 2 decimals. That should take care of the zero count issue.
    Ns = np.where(Ns == 0, 1e-10, Ns) # Do this to account for 0 track counts
    Ni = np.where(Ni == 0, 1e-10, Ni) # Do this to account for 0 track counts

    # Calculate mj
    LAMBDA = 1.55125e-4
    G = 0.5
    m = Ns + Ni
    p = Ns / m

    theta = np.sum(Ns) / np.sum(m)

    for i in range(0, 30):
        w = m / (theta * (1 - theta) + (m - 1) * theta**2 * (1 - theta)**2 * sigma**2)
        sigma = sigma * np.sqrt(np.sum(w**2 * (p - theta)**2) / np.sum(w))
        theta = np.sum(w * p) / np.sum(w)

    t = (1.0 / LAMBDA) * np.log( 1.0 + G * LAMBDA * zeta * rhod * (theta) / (1.0 - theta))
    se = np.sqrt(1 / (theta**2 * (1.0 - theta)**2 * np.sum(w)) + 1.0 / Nd + (seZeta / zeta)**2) * t

    return {"Central": np.round(t, 2), "se": np.round(se, 2), "sigma": np.round(sigma, 2)}

def calculate_pooled_age(Ns, Ni, zeta, seZeta, rhod, Nd):

    # We just replace 0 counts with a low value, the age will be rounded to
    # 2 decimals. That should take care of the zero count issue.
    Ns = np.where(Ns == 0, 1e-10, Ns) # Do this to account for 0 track counts
    Ni = np.where(Ni == 0, 1e-10, Ni) # Do this to account for 0 track counts

    Ns = np.sum(Ns)
    Ni = np.sum(Ni)

    LAMBDA = 1.55125e-4
    G = 0.5
    t = 1.0 / LAMBDA * np.log(1.0 + G * LAMBDA * zeta * rhod * Ns / Ni)
    se = t * (1.0 / Ns + 1.0 / Ni + 1 / Nd + seZeta**2)**0.5

    return {"Pooled Age": np.round(t, 2), "se": np.round(se, 2)}

def calculate_ages(Ns, Ni, zeta, seZeta, rhod, Nd):

    # We just replace 0 counts with a low value, the age will be rounded to
    # 2 decimals. That should take care of the zero count issue.
    Ns = np.where(Ns == 0, 1e-10, Ns) # Do this to account for 0 track counts
    Ni = np.where(Ni == 0, 1e-10, Ni) # Do this to account for 0 track counts

    Ns = np.array(Ns)
    Ni = np.array(Ni)
    Nd = np.array(Nd)

    def true_divide(val):
        with np.errstate(divide='ignore', invalid='ignore'):
            val = np.true_divide(1.0, val)
            val[val == np.inf] = 0
            return np.nan_to_num(val)

    # Calculate mj
    LAMBDA = 1.55125e-4
    G = 0.5
    t = 1.0 / LAMBDA * np.log(1.0 + G * LAMBDA * zeta * rhod * Ns / Ni)

    se = (true_divide(Ns) + true_divide(Ni) + 1.0 / Nd + seZeta**2)**0.5
    se *= t

    return {"Age(s)": np.round(t, 2), "se(s)": np.round(se, 2)}


# This problem involves predicting the number of car sales per month.
# lstm for time series forecasting
from numpy import sqrt
from numpy import asarray
from pandas import read_csv
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import LSTM

# split a univariate sequence into samples
# what this function does is convert a stream of data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  to
#Input 				Output
# 1, 2, 3, 4, 5 		6
# 2, 3, 4, 5, 6 		7
# 3, 4, 5, 6, 7 		8
# ...
def split_sequence(sequence, n_steps):
	X, y = list(), list()
	for i in range(len(sequence)):
		# find the end of this pattern
		end_ix = i + n_steps
		# check if we are beyond the sequence
		if end_ix > len(sequence)-1:
			break
		# gather input and output parts of the pattern
		seq_x, seq_y = sequence[i:end_ix], sequence[end_ix]
		X.append(seq_x)
		y.append(seq_y)
	return asarray(X), asarray(y)

# load the dataset
path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/monthly-car-sales.csv'
df = read_csv(path, header=0, index_col=0, squeeze=True)
# retrieve the values
values = df.values.astype('float32')
# specify the window size
n_steps = 5
# split into samples
X, y = split_sequence(values, n_steps)
# reshape into [samples, timesteps, features]
X = X.reshape((X.shape[0], X.shape[1], 1))
# split into train/test
n_test = 12
X_train, X_test, y_train, y_test = X[:-n_test], X[-n_test:], y[:-n_test], y[-n_test:]
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
# define model
model = Sequential()
model.add(LSTM(100, activation='relu', kernel_initializer='he_normal', input_shape=(n_steps,1)))
model.add(Dense(50, activation='relu', kernel_initializer='he_normal'))
model.add(Dense(50, activation='relu', kernel_initializer='he_normal'))
model.add(Dense(1))
# compile the model
model.compile(optimizer='adam', loss='mse', metrics=['mae'])
# fit the model
model.fit(X_train, y_train, epochs=350, batch_size=32, verbose=2, validation_data=(X_test, y_test))
# evaluate the model
mse, mae = model.evaluate(X_test, y_test, verbose=0)
print('MSE: %.3f, RMSE: %.3f, MAE: %.3f' % (mse, sqrt(mse), mae))
# make a prediction
row = asarray([18024.0, 16722.0, 14385.0, 21342.0, 17180.0]).reshape((1, n_steps, 1))
yhat = model.predict(row)
print('Predicted: %.3f' % (yhat))


### Calculate Integrals ###
import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate

#_______________________________ QUAD INT ____________________________________#
from scipy.integrate import quad # También podemos usar trapz, simps

## Define function ##
def fun(x):
    return x * np.sin(x)

## Plot graph ##
x = np.linspace(0,10,100)
y = fun(x)
with plt.style.context('seaborn-notebook'):
    # título
    plt.title('$y = x sin(x)$', fontsize = 25)

    # pintando la línea
    plt.plot(x,y, linewidth = 2)

    # pintando el relleno
    x_fill = np.linspace(2,9,100)
    y_fill = fun(x_fill)
    plt.fill_between(x_fill, y_fill, color='gray', alpha=0.5)

    # poniendo la cuadrícula
    plt.grid()

## Integrate with quad ##
# Integremos la función en el intervalo [2,9]. Recuerda que esto te calcula la integral, no el area:

value, err = quad(fun, 2, 9)
print("El resultado es: ", value, "con un error de: ", err)

#___________________________SIMPSONS & TRAPEZOID______________________________#
x = np.linspace(2,9,100)

value = integrate.trapz(fun(x), x)

print("El resultado es: ", value)

x = np.linspace(2,9,100)

value = integrate.simps(fun(x), x)

print("El resultado es: ", value)


#Basic Libraries Import
import numpy as np
import scipy as sc
import matplotlib.pyplot as plt

from sklearn.datasets import make_circles

#Dataset
print("Original Dataset")

n = 500
p = 2

X, Y = make_circles(n_samples=n, factor=0.5, noise=0.05)

Y = Y[:, np.newaxis]

plt.scatter(X[Y[:, 0] == 0, 0], X[Y[:, 0] == 0, 1], c="blue")
plt.scatter(X[Y[:, 0] == 1, 0], X[Y[:, 0] == 1, 1], c="red")
plt.axis("equal")
plt.show()

#Neural Network
  #Neural Layers
  class neural_layer():
  def __init__(self, n_conn, n_neur, act_f):
    self.act_f = act_f
    self.b = np.random.rand(1, n_neur) * 2 - 1
    self.W = np.random.rand(n_conn, n_neur) * 2 - 1

  #Activation Function
    #Sigmoid Function
      #Function
      sigm = (
        lambda x: 1 / (1 + np.e ** (-x)),
        lambda x: x * (1 - x)
        )

      #Variables
      rang = np.linspace(-5, 5, 100)
      sigm_func = sigm[0](rang)
      sigm_derv = sigm[1](rang)

      #Graph Plotting
      fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(15,5))
      axes[0].plot(rang, sigm_func)
      axes[1].plot(rang, sigm_derv)
      fig.tight_layout()

    #ReLu Function
      #Function
      def relu_derivate(x):
        x[x<=0] = 0
        x[x>0] = 1
        return x

      relu = (
        lambda x: x * (x > 0),
        lambda x: relu_derivate(x)
        )

      #Variables
      rang = np.linspace(-5, 5, 100)
      relu_func = relu[0](rang)
      relu_derv = relu[1](rang)

      # Graph Plotting
      fig, axes = plt.subplots(nrows=1, ncols=2, figsize =(15,5))
      axes[0].plot(rang, relu_func)
      axes[1].plot(rang, relu_derv)
      plt.show()

  #Neural Network
    #Creation
    def create_nn(topology, act_f):

      nn = []

      for l, layer in enumerate(topology[:-1]):
        nn.append(neural_layer(topology[l], topology[l+1], act_f))

      return nn

    topology = [p, 4, 8, 4, 1]

    neural_network = create_nn(topology, sigm)

    print(neural_network)

    #Training
      #Cost Function
      l2_cost = (
        lambda Yp, Yr: np.mean((Yp - Yr) ** 2),
        lambda Yp, Yr: (Yp - Yr)
      )

      #Training Process
      def train(neural_network, X, Y, l2_cost, lr=0.5, train=True):

        out = [(None, X)]

        #Forward Pass
        for l, layer in enumerate(neural_network):
          z = out[-1][1] @ neural_network[l].W + neural_network[l].b
          a = neural_network[l].act_f[0](z)

          out.append((z, a))

        if train:

          #Backward Pass
          deltas = []

          for l in reversed(range(0, len(neural_network))):

            z = out[l+1][0]
            a = out[l+1][1]

            if l == len (neural_network) -1:
              deltas.insert(0, l2_cost[1](a, Y) * neural_network[l].act_f[1](a))

            else:
              deltas.insert(0, deltas[0] @ _W.T * neural_network[l].act_f[1](a))

            _W = neural_network[l].W

            #Gradient Descent
            neural_network[l].b = neural_network[l].b - np.mean(deltas[0], axis=0, keepdims=True) * lr
            neural_network[l].W = neural_network[l].W - out[l][1].T @ deltas[0] * lr

        return out[-1][1]

      train(neural_network, X, Y, l2_cost, 0.5)

#Runing The Neuronal Network
import time
from IPython.display import clear_output

neural_n = create_nn(topology, sigm)

loss = []

for i in range (2500):

  #Training
  pY = train(neural_n, X, Y, l2_cost, lr=0.051)

  if i % 25 == 0:

    print (pY)

    loss.append (l2_cost[0](pY, Y))

    res = 50

    _x0 = np.linspace(-1.5, 1.5, res)
    _x1 = np.linspace(-1.5, 1.5, res)

    _Y = np.zeros((res, res))

    for i0, x0 in enumerate(_x0):
      for i1, x1 in enumerate(_x1):
        _Y[i0, i1] = train(neural_n, np.array([[x0, x1]]), Y, l2_cost, train=False)[0][0]

    plt.pcolormesh(_x0, _x1, _Y, cmap="coolwarm")
    plt.axis("equal")

    plt.scatter(X[Y[:, 0] == 0, 0], X[Y[:, 0] == 0, 1], c="blue")
    plt.scatter(X[Y[:, 0] == 1, 0], X[Y[:, 0] == 1, 1], c="red")

    clear_output(wait=True)
    plt.show()
    plt.plot(range(len(loss)), loss)
    plt.show()
    time.sleep(0.5)


# heights and positions are available as lists
positions = ['GK', 'M', 'A', 'D', 'M', 'D', 'M', 'M', 'M', 'GK']
heights = [191, 184, 185, 180, 181, 187, 170, 179, 183, 186]

# Import numpy
import numpy as np

# Convert positions and heights to numpy arrays: np_positions, np_heights
np_positions = np.array(positions)
np_heights = np.array(heights)

# Heights of the goalkeepers: gk_heights
gk_heights = np_heights[np_positions == 'GK']

# Heights of the other players: other_heights
other_heights = np_heights[np_positions != 'GK']

# Print out the median height of goalkeepers. Replace 'None'
print("Median height of goalkeepers: " + str(np.median(gk_heights)))

# Print out the median height of other players. Replace 'None'
print("Median height of other players: " + str(np.median(other_heights)))


import numpy as np
import matplotlib.pyplot as plt

def _lchirp(N, tmin=0, tmax=1, fmin=0, fmax=None):
    fmax = fmax if fmax is not None else N / 2
    t = np.linspace(tmin, tmax, N, endpoint=True)

    a = (fmin - fmax) / (tmin - tmax)
    b = (fmin*tmax - fmax*tmin) / (tmax - tmin)

    phi = (a/2)*(t**2 - tmin**2) + b*(t - tmin)
    phi *= (2*np.pi)
    return phi

def lchirp(N, tmin=0, tmax=1, fmin=0, fmax=None, zero_phase_tmin=True, cos=True):
    phi = _lchirp(N, tmin, tmax, fmin, fmax)
    if zero_phase_tmin:
        phi *= ( (phi[-1] - phi[-1] % (2*np.pi)) / phi[-1] )
    else:
        phi -= (phi[-1] % (2*np.pi))
    fn = np.cos if cos else np.sin
    return fn(phi)

f0 = 7000
f1 = 17000
samplerate = 192000
T = .004

N = int(samplerate * T)
tmin = 0
tmax = T

t = np.linspace(tmin, tmax, N, endpoint=True)
for zero_phase_min in (True, False):
    for cos in (True, False):
        x = lchirp(N=int(samplerate * T), tmin=tmin, tmax=tmax, fmin=f0, fmax=f1,
                   zero_phase_tmin=zero_phase_min, cos=cos)
        plt.plot(t, x)
        plt.title("cos={}, zero_phase_tmin={}".format(cos, zero_phase_min),
                  weight='bold', fontsize=17, loc='left')
        plt.show()


import numpy as np

def lambdas(i):
    import sympy as sm

    # Parâmetros para o sistema
    a = 1
    b = 3
    c = 1
    d = 5
    r = 0.006
    s = 4
    xr = - 1.56

    x, y, z = sm.symbols('x, y, z')

    # O sistema dinâmico a ser simulado
    fx = y - a * x ** 3 + b * x ** 2 - z + i
    fy = c - d * x ** 2 - y
    fz = r * (s * (x - xr) - z)

    # Igualar as equações do sistema a zero
    eqx = sm.Eq(fx, 0)
    eqy = sm.Eq(fy, 0)
    eqz = sm.Eq(fz, 0)

    # Resolver o sistema
    pf1, pf2, pf3 = sm.solve([eqx, eqy, eqz])

    sistema = sm.Matrix([fx, fy, fz])                # Sistema de matrizes
    jacobiano_sistema = sistema.jacobian((x, y, z))  # Jacobiano das matrizes   |A*I - lambda| = 0

    # Substituir os pontos de equilibrio no sistema das matrizes jacobianas
    jacobiano_pf1 = jacobiano_sistema.subs([(x, pf1.get(x)), (y, pf1.get(y)), (z, pf1.get(z))])
    jacobiano_pf2 = jacobiano_sistema.subs([(x, pf2.get(x)), (y, pf2.get(y)), (z, pf2.get(z))])
    jacobiano_pf3 = jacobiano_sistema.subs([(x, pf3.get(x)), (y, pf3.get(y)), (z, pf3.get(z))])

    # Printar as soluções para os lambdas de cada função em cada intensidade I
    print(f'\n', f'*'*25, f'Lambdas para I = {i}', f'*'*25)
    print(f'Lambdas para o ponto fixo 1:')
    for x in jacobiano_pf1.eigenvals():
        print(f'{x}')
    print(f'\nLambdas para o ponto fixo 2:')
    for y in jacobiano_pf2.eigenvals():
        print(f'{y}')
    print(f'\nLambdas para o ponto fixo 3:')
    for z in jacobiano_pf3.eigenvals():
        print(f'{z}')

def sist_EDO(edo, t, i):
    # Função para nos retornar a matriz do sistema a ser resolvida pela função odeint

    # Parâmetros para o sistema
    a = 1
    b = 3
    c = 1
    d = 5
    r = 0.006
    s = 4
    xr = - 1.56

    # Retorna a matriz que representa o sistema de equações
    return np.array([edo[1] - a * edo[0] ** 3 + b * edo[0] ** 2 - edo[2] + i,  # x' = y - a*x^3 + b*x^2 - z + I
                     c - d * edo[0] ** 2 - edo[1],                             # y' = c - d*x^2 - y
                     r * (s * (edo[0] - xr) - edo[2])])                        # z' = r*[s*(x - xr) - z]

def sol_EDO(i):
    # Função para resolver o sistema dinâmico que é retornado pela função sist_EDO

    from scipy.integrate import odeint
    import matplotlib.pyplot as plt
    from matplotlib.pyplot import figure

    plt.style.use('seaborn-poster')     # Estilo do plot
    tempo = np.arange(0, 1500, 0.01)    # Matriz para a iteração de tempo
    cond_inicial = np.array([0, 0, 0])  # Condições iniciais para o sistema

    # Usamos a função odeint para resolver o sistema de equações retornado pela função
    # sist_EDO utilizando o tempo e as condições iniciais e diferentes intensidades I
    solucao_edo = odeint(sist_EDO, cond_inicial, tempo, args=(i,))
    x = solucao_edo[:, 0]
    y = solucao_edo[:, 1]
    z = solucao_edo[:, 2]

    # Plot para as funções x, y e z em função do tempo
    figure(figsize=(15, 8), dpi=80)
    plt.title(f'I = {i:.2f}')
    plt.xlabel('Tempo [s]')
    plt.ylabel('Variável')
    plt.xlim(0, 1000)
    plt.ylim(-12, 4)
    plt.plot(tempo, x, label='x', linewidth=0.75)
    plt.plot(tempo, y, label='y', linewidth=0.75)
    plt.plot(tempo, z, label='z', linewidth=0.75)
    plt.legend(loc=4)
    plt.savefig(f'graficos-var-tempo/var_tempo-{i:.2f}.png')

    # # Plot para o plano de fase de y vs. x
    # figure(figsize=(15, 8), dpi=80)
    # plt.xlabel('x')
    # plt.ylabel('y')
    # plt.plot(x[36000:], y[36000:], linewidth=0.75)
    # plt.show()
    #
    # # Plot para o plano de fase de z vs. x
    # figure(figsize=(15, 8), dpi=80)
    # plt.xlabel('x')
    # plt.ylabel('z')
    # plt.plot(x[36000:], z[36000:], linewidth=0.75)
    # plt.show()
    #
    # # Plot para o plano de fase de z vs. y
    # figure(figsize=(15, 8), dpi=80)
    # plt.xlabel('z')
    # plt.ylabel('y')
    # plt.plot(y[36000:], z[36000:], linewidth=0.75)
    # plt.show()
    #
    # # Plot para o plano de fase 3D
    # figure(figsize=(15, 8), dpi=80)
    # fig = plt.figure()
    # ax = fig.gca(projection='3d')
    # ax.plot(x[36000:], y[36000:], z[36000:])
    # ax.set_xlabel("Eixo x")
    # ax.set_ylabel("Eixo y")
    # ax.set_zlabel("Eixo z")
    # ax.set_title("Atrator de Lorenz")
    # plt.show()

if __name__ == '__main__':
    # Encontrar os autovalores lambdas para diferentes intensidades I
    # lambdas(1.1)
    # lambdas(1.2)
    # lambdas(3.0)

    # Simular o sistema dinâmico para diferentes intensidades I
    # sol_EDO(1.1)
    # sol_EDO(1.2)
    # sol_EDO(3.0)

    i_range = np.arange(0, 3.1, 0.025)

    for intensidade in i_range:
        sol_EDO(intensidade)


#%%
#Importing packages
import matplotlib.pyplot as plt
import matplotlib.patches as ptch
import numpy as np
import math
from scipy.spatial.distance import euclidean
from scipy.optimize import minimize

#%%
#test dataget to make diagrams
#p,r,0 = passer, reciever, opponent
p,r,o = (2.8747200000000035, -6.010519999999998), (0.5851199999999968, -10.46928), (35.43791999999999, -2.485399999999998)
#p = (1, 1)
#r = (4, 1)
#o = (3, 0)
all_points = [p,r,o]
labels = ['p', 'r', 'o']

#%%
#function to calculate points of intersection of two circles
#source of function
#https://stackoverflow.com/questions/55816902/finding-the-intersection-of-two-circles
def get_intersections(x0, y0, r0, x1, y1, r1):
    """
    circle 1: center (x0, y0), radius r0
    circle 2: center (x1, y1), radius r1
    """
    d = math.sqrt((x1-x0)**2 + (y1-y0)**2)

    # non intersecting circles
    if d > r0 + r1 :
        raise Exception('non intersecting')
    # One circle within other
    if d < abs(r0-r1):
        raise Exception('one inside another')
    # coincident circles
    if d == 0 and r0 == r1:
        raise Exception('coincident')
    else:
        a=(r0**2-r1**2+d**2)/(2*d)
        h=math.sqrt(r0**2-a**2)
        x2=x0+a*(x1-x0)/d
        y2=y0+a*(y1-y0)/d
        x3=x2+h*(y1-y0)/d
        y3=y2-h*(x1-x0)/d

        x4=x2-h*(y1-y0)/d
        y4=y2+h*(x1-x0)/d

        return (x3, y3, x4, y4)

#%%
#Function to evaluate accuracy of gamma calculation
def obj_func(gamma, p, r, o):
    """
    gamma: value of ɣ
    p, r, o: (x,y) coordinates of pas, rec, opp
    """
    t = 0.25
    c = 4
    d = euclidean(p,r)

    R_p = gamma*d*t
    R_r = gamma*d*(1-t)
    R_a = c*d/gamma

    #get the center of the circles that form the arcs
    inters = get_intersections(p[0],p[1],(R_a-R_p),
                                r[0],r[1],(R_a-R_r))
    C_a1x, C_a1y, C_a2x, C_a2y = inters

    dist_Ca1_o = euclidean((C_a1x, C_a1y), o)
    dist_Ca2_o = euclidean((C_a2x, C_a2y), o)
    return abs(max(dist_Ca1_o, dist_Ca2_o) - R_a)

#%%
#using scipy.optimize to calculate gamma
def calc(p, r, o):
    return minimize(obj_func, args=(p,r,o), x0 = 0.5).x[0]

#%%
#Drawing diagrams
#testing gamma
t = 0.25 #scaling factor
d = euclidean(p,r) #dist btw p,r
c = 4 #other scaling factor

R_a_store = []
plot = True

#Loop to make plots for different values of gamma
for ind, gamma in enumerate(np.linspace(0.0001, 3, 5)):
    print(gamma)

    R_p = gamma*d*t
    R_r = gamma*d*(1-t)
    R_a = c*d/gamma
    R_a_store.append(R_a)

    C_a1x, C_a1y, C_a2x, C_a2y = get_intersections(p[0],p[1],(R_a-R_p), r[0],r[1],(R_a-R_r))

    dist_Ca1_o = euclidean((C_a1x, C_a1y), o)
    dist_Ca2_o = euclidean((C_a2x, C_a2y), o)

    print(abs(max(dist_Ca1_o, dist_Ca2_o) - R_a))

    if plot:
        fig, ax = plt.subplots()
        ax.set_aspect('equal')
        x = [x[0] for x in all_points]
        y = [y[1] for y in all_points]

        ax.scatter(x,y)
        C_p = plt.Circle((x[0], y[0]), R_p, fill = False)
        C_r = plt.Circle((x[1], y[1]), R_r, fill = False)
        C_a1 = plt.Circle((C_a1x, C_a1y), R_a, fill = False, color = 'red')
        C_a2 = plt.Circle((C_a2x, C_a2y), R_a, fill = False, color = 'orange')
        print(dist_Ca1_o, dist_Ca2_o, R_a)

        ax.add_patch(C_p)
        ax.add_patch(C_r)
        ax.add_patch(C_a1)
        ax.add_patch(C_a2)
        ax.text(-1,4,f'ɣ = {gamma:.2f}')
        plt.ylim(-35,35)
        plt.xlim(-20,20)

        #plt.savefig(f'C:/Users/Ayoola_PC/Documents/cap2/LaurieOnTracking/gifims/img{ind}.png')
        plt.show()

# %%


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

t = np.linspace(0, 100, 1000, endpoint=False)
sig=[]
for t1 in t:
    if t1<20:
        sig1 = np.cos(2 * np.pi * 0.5 * t1)
        print("5",t1)
    elif t1<40:
        sig1 = np.cos(2 * np.pi * 1 * t1)
        print("10",t1)
    elif t1<60:
        sig1 = np.cos(2 * np.pi * 1.5 * t1)
        print("20",t1)
    elif t1<80:
        sig1 = np.cos(2 * np.pi * 2 * t1)
        print("30",t1)
    else:
        sig1 = np.cos(2 * np.pi * 2.5 * t1)
        print(t1)
    sig.append(sig1)

plt.plot(t, sig)
plt.axis([0, 100, -2, 2])
plt.show()

freq =fft(sig,1024)
Pyy = np.sqrt(freq*freq.conj())/1025 #np.abs(freq)/1025    #freq*freq.conj(freq)/1025
f = np.arange(1024)
plt.plot(f,Pyy)
plt.axis([0, 512, 0,0.2])
plt.show()

t1=np.linspace(0, 100, 1024, endpoint=False)
sig1=ifft(freq)
plt.plot(t1, sig1)
plt.axis([0, 100, -2, 2])
plt.show()


import numpy as np
from dissimilarity__utils import *

def test_euclidean():
    eucl = lambda x, y: np.sum((x - y)**2, axis=1)**0.5
    x = np.array([0, 0])
    dA = eucl(x, yA)
    dB = eucl(x, yB).reshape(s.shape)
    plotDist(x, dA, dB, 'euclidean_distance', save=True)

def test_manhattan():
    manh = lambda x, y: np.sum(np.absolute(x - y), axis=1)
    x = np.array([0, 0])
    dA = manh(x, yA)
    dB = manh(x, yB).reshape(s.shape)
    plotDist(x, dA, dB, 'manhattan_distance', save=True)

def test_chebyshev():
    cheb = lambda x, y: np.max(np.absolute(x - y), axis=1)
    x = np.array([0, 0])
    dA = cheb(x, yA)
    dB = cheb(x, yB).reshape(s.shape)
    plotDist(x, dA, dB, 'chebyshev_distance', save=True)

def test_minkowski():
    mink = lambda x, y, p: np.sum(np.absolute(x - y) ** p, axis=1) ** (1 / p)
    x = np.array([0, 0])
    p = 2 ** -1
    dA = mink(x, yA, p)
    dB = mink(x, yB, p).reshape(s.shape)
    plotDist(x, dA, dB, 'minkowski_distance_A', ctitle=r'$p=2^{0}{2}{1}={3}$'.format('{', '}', -1, p), save=True)

def test_minkowski_multi():
    mink = lambda x, y, p: np.sum(np.absolute(x - y) ** p, axis=1) ** (1 / p)
    x = np.array([0, 0])
    fig, axes = plt.subplots(2, 4, sharex=True, sharey=True)
    for j, axs in enumerate(axes):
        for i, ax in enumerate(axs):
            index = i + 4 * j
            exp = index - 3
            pi = 2 ** exp
            d = mink(x, yB, pi).reshape(s.shape)
            plotContour(ax, d,
                        r'$p=2^{0}{2}{1}={3}$'.format('{', '}', exp, pi),
                        fsize=8)
    figname = 'minkowski_distance_B'
    fig.suptitle(' '.join([e.capitalize() for e in figname.split('_')]))
    fig.savefig('_output/similarity_{}.png'.format(figname), bbox_inches='tight')

def canb(x, y):
    num = np.absolute(x - y)
    den = np.absolute(x) + np.absolute(y)
    return np.sum(num/den, axis = 1)

def test_canberra():
    x = np.array([0.25, 0.25])
    dA = canb(x, yA)
    dB = canb(x, yB).reshape(s.shape)
    plotDist(x, dA, dB, 'canberra_distance', save=True)

def coss(x, y):
    if x.ndim == 1:
        x = x[np.newaxis]
    num = np.sum(x*y, axis=1)
    den = np.sum(x**2, axis = 1)**0.5
    den = den*np.sum(y**2, axis = 1)**0.5
    return 1 - num/den

def test_cosine():
    x = np.array([1e-7, 1e-7])
    dA = coss(x, yA)
    dB = coss(x, yB).reshape(s.shape)
    plotDist(x, dA, dB, 'cosine_distance', save=True)

if __name__ == "__main__":
    test_euclidean()
    test_manhattan()
    test_chebyshev()
    test_minkowski()
    test_minkowski_multi()
    test_canberra()
    test_cosine()


'''
Benchmarks for testing / comparisons
'''

import numpy as np
from freelunch.util import ZeroLengthSolutionError

# %%

class benchmark:
    '''
    base class for benchmarking functions
    '''
    default_bounds = lambda n:None
    rtm_optimum = lambda n:None

    def __init__(self, n=None):
        if n is None:
            self.n = 2
        else:
            self.n = n
        self.bounds = self.default_bounds()
        self.optimum = self.rtn_optimum()

    def __call__(self, dna):
        if len(dna) == 0:
            raise ZeroLengthSolutionError('An empty trial solution was passed')
        return self.obj(dna)

# %%

class ackley(benchmark):
    '''
    ackely function in n dimensions
    '''

    default_bounds = lambda self:np.array([[-10, 10]]*self.n)
    rtn_optimum = lambda self:np.array([0]*self.n)
    f0 = 0
    tol = 10**-2

    a,b,c = 20, 0.2, 2*np.pi
    def obj(self, dna):
        t1 = -self.a * np.exp(-self.b * (1/len(dna)) * np.sum(dna**2))
        t2 = - np.exp(1/len(dna) * np.sum(np.cos(self.c * dna)))
        t3 = self.a + np.exp(1)
        return t1 + t2 + t3

class exponential(benchmark):
    '''
    exponential function in n dimensions
    '''

    default_bounds = lambda self:np.array([[-10, 10]]*self.n)
    rtn_optimum = lambda self:np.array([0]*self.n)
    f0 = -1
    tol = 10**-3

    a = -0.5
    def obj(self, dna):
        t1 = - np.exp(self.a * np.sum(dna**2))
        return t1

class happycat(benchmark):
    '''
    happycat function in n dimensions
    '''

    default_bounds = lambda self:np.array([[-2, 2]]*self.n)
    rtn_optimum = lambda self:np.array([-1]*self.n)
    f0 = 0
    tol = None

    a = 1/8
    def obj(self, dna):
        norm = np.sum(dna**2)
        t1 = ((norm - self.n)**2)**(self.a)
        t2 = (1/self.n)*(0.5*norm + np.sum(dna)) + 0.5
        return t1 + t2

class periodic(benchmark):
    '''
    periodic function in n dimensions
    '''

    default_bounds = lambda self:np.array([[-10, 10]]*self.n)
    rtn_optimum = lambda self:np.array([0]*self.n)
    f0 = 0.9
    tol = None

    def obj(self, dna):
        t1 = np.sum(np.sin(dna)**2) +1
        t2 = - 0.1 * np.exp(-np.sum(dna**2))
        return t1 + t2


import numpy as np
import math
from scipy.special import gamma,factorial,beta
from scipy import integrate
from distributions import *

def derivative(f,x,h=0.0001): #one parameter fuction derivative
    return (f(x+h)-f(x))/h

def derivative2(f,x,h=0.0001): #Second Derivative
    return (derivative(f,x+h,h) - derivative(f,x,h))/h

def normalDistribution(x):
    return 1/np.sqrt(2*np.pi) * np.exp(-0.5*x**2)

def softmaxFuc(x):
    softmax = np.exp(x)/np.sum(np.exp(x))
    #print(softmax)
    #print(np.sum(softmax))
    return softmax

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

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

def entropy(x):
    return -1*x*np.log(x)

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

def circle(x):
    return np.sqrt(1-x**2)*randomSymbol(len(x))

def heart(x): #heart equation: x**2+ (5*y/4 - sqrt(abs(x)))**2 = 1
    a = np.sqrt(1-x**2)*randomSymbol(len(x)) + np.sqrt(abs(x))
    return a*4/5

def sawtoothWave(x): # y = t-floor(t) or y = t%1
    #return x%1
    #return x%1 + x
    #return x%1 + np.sin(x)*x
    a = 10 #perid
    return 2*(x/a - np.floor(0.5+x/a))

def powerX(x):
    #return np.power(x,x)
    return powerAX(x,x)

def powerAX(a,x):
    return np.power(a,x)

def logisticMap2(r=1.5,x0=0.8,N=10): #x:= r*x(1-x)
    maps=[]
    a = x0
    while N>0:
        #print(a,' ',end='')
        maps.append(a)
        a = r*a*(1-a)**3
        N -= 1

    return maps

def logisticMap(r=1.5,x0=0.8,N=10): #x:= r*x(1-x)
    maps=[]
    a = x0
    while N>0:
        #print(a,' ',end='')
        maps.append(a)
        a = r*a*(1-a)
        N -= 1

    return maps

def randomSymbol(length): #-1,1,1,-1,1,-1...
    f = np.zeros(length)+np.where(np.random.random(length)>0.5,1.0,-1.0)
    return f

def Divisorfunction(param): #https://en.wikipedia.org/wiki/Divisor_function#Definition
    def getDivsorList(N):
        for i in range(1,N+1):
            #print('i=',i)
            if N%i == 0:
                yield i

    N = param[0]
    p = param[1]
    def powerF(x):
        #print('x=',x,np.power(x,p))
        return np.power(x,p)

    l = list(map(powerF, list(getDivsorList(N))))
    return np.sum(l)

def EulerTotients(N=10):#https://en.wikipedia.org/wiki/Euler%27s_totient_function
    def gcd(p,q): # Create the gcd of two positive integers.
        while q != 0:
            p, q = q, p%q
        return p

    def is_coprime(x, y):
        return gcd(x, y) == 1

    def Totients(x):
        if x == 1:
            return 1
        n = [y for y in range(1,x) if is_coprime(x,y)]
        #print('n=',n)
        return len(n)

    return Totients(N)

def PrimeNumbers(N=10): #https://en.wikipedia.org/wiki/Prime-counting_function
    def isPrime(num):
        if num>1:
            for n in range(2, num):
                if (num % n) == 0:
                    return False
            return True
        return False

    def getPrime():
        for i in range(2,N+1):
            if isPrime(i):
                yield i

    l = list(getPrime())
    print('l=', len(l), l)
    return len(l)

def Mobiusfunction(N=10): #https://en.wikipedia.org/wiki/M%C3%B6bius_function
    def IsSquareFreeIntegers(x):
        for n in range(2, int(np.sqrt(x)+1)):
            if (x % n**2) == 0:
                return False
        return True

    def SquareFreeIntegers2():
        squareFreeNumbers=[]
        for val in range(1, N + 1):
            if IsSquareFreeIntegers(val):
                squareFreeNumbers.append(val)
        return squareFreeNumbers

    def SquareFreeIntegers():
        bSqure=False
        for val in range(1, N + 1):
            for n in range(2, int(np.sqrt(N)+1)):
                bSqure=False
                if (val % n**2) == 0:
                    bSqure=True
                    break
            if not bSqure:
                yield val

    def Mobius(x):
        if IsSquareFreeIntegers(x):
            nPrime = PrimeNumbers(x)
            print('x,nPrime=',x,nPrime)
            if nPrime % 2 ==0:
                return 1
            return -1
        return 0

    #squareFreeNumbers = SquareFreeIntegers2() #[i for i in SquareFreeIntegers()]
    #print('squareFreeNumbers=',len(squareFreeNumbers),squareFreeNumbers)
    #l = list(map(Mobius, [i for i in range(N)]))
    #print('l=',len(l),l)
    return Mobius(N)

def LegendreFunction(x,n=0): #https://en.wikipedia.org/wiki/Legendre_function
    if n == 0:
        return 0.5*np.log((1+x)/(1-x))
    elif n == 1:
        return x*LegendreFunction(x,0) -1 #P1(x) = x
    return ((2*n-1)/n)*x*LegendreFunction(x,n-1) - ((n-1)/n)*LegendreFunction(x,n-2)

def ScorersFunctionGi(x): #https://en.wikipedia.org/wiki/Scorer%27s_function
    def gi(t):
        return (1/np.pi)*np.sin((1/3)*t**3 + x*t)
    # return integrate.quad(gi, 0, 1)[0]
    def hi(t):
        return (1/np.pi)*np.exp((-1/3)*t**3 + x*t)

    # rGi = integrate.quad(gi, 0, np.inf,epsabs=1.49e-8,
    #                epsrel=1.49e-8, maxp1=50, limit=50)[0]
    # rHi = integrate.quad(hi, 0, np.inf,epsabs=1.49e-8,
    #                epsrel=1.49e-8, maxp1=50, limit=50)[0]
    # return rGi,rHi
    return integrate.quad(gi, 0, np.inf)[0], integrate.quad(hi, 0, np.inf)[0]

def Logarithmic_integral(x): #https://en.wikipedia.org/wiki/Logarithmic_integral_function
    def Li(t):
        return 1/np.log(t)

    return integrate.quad(Li, 0, x)[0]

def Exponential_integral(x): #https://en.wikipedia.org/wiki/Exponential_integral
    def exp_in(t):
        return -1*np.exp(-1*t)/t

    return integrate.quad(exp_in, -1*x, np.inf)[0]

def Trigonometric_integral(x): #https://en.wikipedia.org/wiki/Trigonometric_integral
    def Si(t):
        return np.sin(t)/t
    def Ci(t):
        return -1*np.cos(t)/t

    si = integrate.quad(Si, 0, x)[0]
    ci = integrate.quad(Ci, x, np.inf)[0]
    return si,ci

def KL_divergence(x):#https://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence
    p = NormalDistribution(x)
    q = NormalDistribution(x,u=1)

    def KL_integratePQ(t):
        return p*np.log(p/q)

    def KL_integrateQP(t):
        return q*np.log(q/p)

    return KL_integratePQ(x),KL_integrateQP(x)
    #return integrate.quad(KL_integrate, -100, x)[0]
    #return integrate.quad(KL_integrate, -1*np.inf, np.inf)[0]
    #return integrate.quad(KL_integrate, -3, 4)[0]


# python 3 version 1/16 - frt
import numpy as np
import matplotlib.pyplot as plt
"""
interp - Program to interpolate data using Lagrange
polynomial to fit quadratic to three data points
clear all; help interp;  % Clear memory and print header
Initialize the data points to be fit by quadratic
"""
def intrpf(xi,x,y):
    """
    Function to interpolate between data points
    using Lagrange polynomial (quadratic)
    Inputs
       x    Vector of x coordinates of data points (3 values)
       y    Vector of y coordinates of data points (3 values)
       xi   The x value where interpolation is computed
    Output
      yi   The interpolation polynomial evaluated at xi
    """

# Calculate yi = p(xi) using Lagrange polynomial
    yi = (xi-x[1])*(xi-x[2])/((x[0]-x[1])*(x[0]-x[2]))*y[0]\
    + (xi-x[0])*(xi-x[2])/((x[1]-x[0])*(x[1]-x[2]))*y[1] \
    + (xi-x[0])*(xi-x[1])/((x[2]-x[0])*(x[2]-x[1]))*y[2];
    return (yi);

x = [0.,0.,0.];
y = [0.,0.,0.]
print ('Enter data points as x,y pairs (e.g., 1,2)');
for i in range(0,3):
  temp1,temp2 =  input("Enter data points: ").split(',');
  x[i] = float(temp1);
  y[i] = float(temp2);

# Establish the range of interpolation (from x_min, x_max)
temp1,temp2 = input("Enter range of x values as x_min, x_max: ").split(',');

xr=np.array([float(temp1),float(temp2)]);
# Find yi for the desired interpolation values xi using
# the function intrpf
nplot = 100;     #% Number of points for interpolation curve
xi= np.linspace(xr[0], xr[1], nplot,endpoint=True)
yi= np.linspace(0, 0, nplot,endpoint=True)
for i in range(0,nplot):
  xi[i] = xr[0] + (xr[1]-xr[0])*(i-1)/(nplot-1);
  yi[i] = intrpf(xi[i],x,y);  #% Use intrpf function to interpolate

# Plot the curve given by (xi,yi) and mark original data points
plt.figure(1);plt.clf() # open a window and clear it
plt.plot(x,y,'*',label="Data points")
plt.plot(xi,yi,'-',label="Interpolation");
plt.xlabel('x');
plt.ylabel('y');
plt.title('Three point interpolation');
plt.legend()
plt.show()


import numpy as np
import pytest

from fdtd.waveforms import GaussianWaveform, SineWaveform, StepWaveform

def test_sinewaveform():
    """
    Test a SineWaveform object.

    Ensure that the object is callable with the correct sine waveform.
    """
    t = np.random.rand(1000)
    freq, offset, amp = 1e9, 1, 2
    wf = SineWaveform(frequency=freq, offset=offset, amplitude=amp)
    y = amp * np.sin(2 * np.pi * freq * t - offset)

    assert y == pytest.approx(wf(t), rel=0.01)

def test_stepwaveform():
    """
    Test a StepWaveform object.

    Ensure that the object is callable with the correct step waveform.
    """
    t = np.random.uniform(0, 5, 1000)
    t_0, amp = 3, 2
    wf = StepWaveform(t_0=t_0, amplitude=amp)
    y = amp * np.heaviside(t - t_0, 1)
    assert y == pytest.approx(wf(t), rel=0.01)

def test_gaussianwaveform():
    """
    Test a GaussianWaveform object.

    Ensure that the object is callable with the correct gaussian waveform.
    """
    t = np.random.uniform(0, 5, 1000)
    t_0, tau, amp = 3, 4, 2
    wf = GaussianWaveform(t_0=t_0, tau=tau, amplitude=amp)
    y = amp * np.exp(-(((t-t_0) / tau)**2))
    assert y == pytest.approx(wf(t), rel=0.01)


import numpy as np

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

def sigmoid_derivative(x):
    return x * (1 - x)

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

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

np.random.seed(1)

synaptic_weights = 2 * np.random.random((3,1)) - 1

print("Random synaptic weights: ")
print(synaptic_weights)

for iteration in range(100000):
    input_layer = training_inputs
    output = sigmoid(np.dot(input_layer, synaptic_weights))
    error = training_outputs - output
    adjustments = error * sigmoid_derivative(output)
    synaptic_weights += np.dot(input_layer.T, adjustments)

print("Synaptic weights after training: ")
print(synaptic_weights)
print("Outputs after training: ")
print(output)


import numpy as np

def sphere(d):
    return np.sum([x**2 for x in d])

def sphereFn(d):
    def fn(*args):
        return sum([args[i]**2 for i in range(len(args))])
    return fn

def ackley(d, *, a=20, b=0.2, c=2 * np.pi):
    sum_part1 = np.sum([x**2 for x in d])
    part1 = -1.0 * a * np.exp(-1.0 * b * np.sqrt((1.0 / len(d)) * sum_part1))

    sum_part2 = np.sum([np.cos(c * x) for x in d])
    part2 = -1.0 * np.exp((1.0 / len(d)) * sum_part2)

    return a + np.exp(1) + part1 + part2

def ackleyFn(d, *, a=20, b=0.2, c=2 * np.pi):
    def fn(*args):
        sum_part1 = sum([args[i]**2 for i in range(len(args))])
        part1 = -1.0 * a * np.exp(-1.0 * b * np.sqrt((1.0 / d) * sum_part1))

        sum_part2 = sum([np.cos(c * args[i]) for i in range(len(args))])
        part2 = -1.0 * np.exp((1.0 / d) * sum_part2)

        return a + np.exp(1) + part1 + part2
    return fn

def rastrigin(d):
    sum_i = np.sum([x**2 - 10 * np.cos(2 * np.pi * x) for x in d])
    return 10 * len(d) + sum_i

def rastriginFn(d):
    def fn(*args):
        sum_i = sum([args[i]**2 - 10 * np.cos(2 * np.pi * args[i])
                     for i in range(len(args))])
        return 10 * d + sum_i

    return fn


#plot Bayesian updates to beta function with prior 1.4, 2.3
from scipy.stats import beta
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 1, num = 100)
plt.plot(x, beta(1.4, 2.3).pdf(x), label = "Prior = beta(1.4,2.3)")
for i in range(1,11,2):
    plt.plot(x, beta(1.4+i,2.3).pdf(x), label = "After {} heads".format(i))
for i in range(1,6,2):
    plt.plot(x, beta(1.4+i*5+10,2.3).pdf(x), label = "After {} heads".format(i*5+10))
plt.legend()
plt.title("Updates to prior distribution")
plt.show()


import silence_tensorflow.auto
import numpy as np
import tensorflow as tf
import tensorflow_probability as tfp
from scipy.special import logsumexp
import matplotlib.pyplot as plt

from tqdm import tqdm # progress-meter

# def em(dataset, n_classes, n_iterations, random_seed):
#     n_samples = dataset.shape[0]

#     np.random.seed(random_seed)

#     # Initial guesses for the parameters
#     mus = np.random.rand(n_classes)
#     sigmas = np.random.rand(n_classes)
#     class_probs = np.random.dirichlet(np.ones(n_classes))

#     for em_iter in tqdm(range(n_iterations)):
#         # E-Step
#         responsibilities = tfp.distributions.Normal(loc=mus, scale=sigmas).prob(
#             dataset.reshape(-1, 1)
#         ).numpy() * class_probs

#         responsibilities /= np.linalg.norm(responsibilities, axis=1, ord=1, keepdims=True)

#         class_responsibilities = np.sum(responsibilities, axis=0)

#         # M-Step
#         for c in range(n_classes):
#             class_probs[c] = class_responsibilities[c] / n_samples
#             mus[c] = np.sum(responsibilities[:, c] * dataset) / class_responsibilities[c]
#             sigmas[c] = np.sqrt(
#                 np.sum(responsibilities[:, c] * (dataset - mus[c])**2) / class_responsibilities[c]
#             )

#         # Calculate the marginal log likelihood
#         log_likelihood = np.sum(
#             logsumexp(
#                 np.log(class_probs)
#                 +
#                 tfp.distributions.Normal(loc=mus, scale=sigmas).log_prob(
#                     dataset.reshape(-1, 1)
#                 ).numpy()
#                 ,
#                 axis=1
#             )
#             ,
#             axis=0
#         )
#         print(log_likelihood)

#     return class_probs, mus, sigmas

def em_with_guesses(
    dataset,
    n_iterations,
    class_probs_initial,
    mus_initial,
    sigmas_initial,
):
    n_classes = class_probs_initial.shape[0]
    n_samples = dataset.shape[0]

    class_probs = class_probs_initial.copy()
    mus = mus_initial.copy()
    sigmas = sigmas_initial.copy()

    log_likelihood_history = []

    for em_iter in tqdm(range(n_iterations)):
        # E-Step
        responsibilities = tfp.distributions.Normal(loc=mus, scale=sigmas).prob(
            dataset.reshape(-1, 1)
        ).numpy() * class_probs

        responsibilities /= np.linalg.norm(responsibilities, axis=1, ord=1, keepdims=True)

        class_responsibilities = np.sum(responsibilities, axis=0)

        # M-Step
        for c in range(n_classes):
            class_probs[c] = class_responsibilities[c] / n_samples
            mus[c] = np.sum(responsibilities[:, c] * dataset) / class_responsibilities[c]
            sigmas[c] = np.sqrt(
                np.sum(responsibilities[:, c] * (dataset - mus[c])**2) / class_responsibilities[c]
            )

        # Calculate the marginal log likelihood
        log_likelihood = np.sum(
            logsumexp(
                np.log(class_probs)
                +
                tfp.distributions.Normal(loc=mus, scale=sigmas).log_prob(
                    dataset.reshape(-1, 1)
                ).numpy()
                ,
                axis=1
            )
            ,
            axis=0
        )
        log_likelihood_history.append(log_likelihood)

    return class_probs, mus, sigmas, log_likelihood_history

def em_sieved(
    dataset,
    n_classes,
    n_iterations_pre_sieving,
    n_candidates,
    n_iterations_post_sieving,
    n_chosen_ones,
    random_seed,
):

    # (1) Pre-Sieving

    mus_list = []
    sigmas_list = []
    class_probs_list = []
    log_likelihood_history_list = []

    for candidate_id in range(n_candidates):
        np.random.seed(random_seed + candidate_id)

        mus = np.random.rand(n_classes)
        sigmas = np.random.rand(n_classes)
        class_probs = np.random.dirichlet(np.ones(n_classes))

        class_probs, mus, sigmas, log_likelihood_history = em_with_guesses(
            dataset,
            n_iterations_pre_sieving,
            class_probs,
            mus,
            sigmas,
        )
        mus_list.append(mus)
        sigmas_list.append(sigmas)
        class_probs_list.append(class_probs)
        log_likelihood_history_list.append(log_likelihood_history)

    # (2) Sieving, select the best candidates
    log_likelihood_history_array = np.array(log_likelihood_history_list)

    # Sort in descending order
    ordered_candidate_ids = np.argsort( - log_likelihood_history_array[:, -1])
    chosen_ones_ids = ordered_candidate_ids[:n_chosen_ones]

    # (3) Post-Sieving
    mus_chosen_ones_list = []
    sigmas_chosen_ones_list = []
    class_probs_chosen_ones_list = []
    log_likelihood_history_chosen_ones_list = []
    for chosen_one_id in chosen_ones_ids:
        class_probs, mus, sigmas, log_likelihood_history = em_with_guesses(
            dataset,
            n_iterations_post_sieving,
            class_probs_list[chosen_one_id],
            mus_list[chosen_one_id],
            sigmas_list[chosen_one_id],
        )

        mus_chosen_ones_list.append(mus)
        sigmas_chosen_ones_list.append(sigmas)
        class_probs_chosen_ones_list.append(class_probs)
        log_likelihood_history_chosen_ones_list.append(log_likelihood_history)

    # (4) Select the very best candidate
    log_likelihood_history_chosen_ones_array = np.array(log_likelihood_history_chosen_ones_list)

    # Sort in descending order
    ordered_chosen_ones_ids = np.argsort( - log_likelihood_history_chosen_ones_array[:, -1])

    best_chosen_one_id = ordered_chosen_ones_ids[0]
    best_mus = mus_chosen_ones_list[best_chosen_one_id]
    best_sigmas = sigmas_chosen_ones_list[best_chosen_one_id]
    best_class_probs = class_probs_chosen_ones_list[best_chosen_one_id]

    return best_class_probs, best_mus, best_sigmas, log_likelihood_history_chosen_ones_array

def main():
    class_probs_true = [0.6, 0.4]
    mus_true = [2.5, 4.8]
    sigmas_true = [0.6, 0.3]
    random_seed = 42 # for reproducability
    n_samples = 1000
    n_iterations_pre_sieving = 5
    n_candidates = 100
    n_iterations_post_sieving = 100
    n_chosen_ones = 5
    n_classes = 2

    # generate the data
    univariate_gmm = tfp.distributions.MixtureSameFamily(
        mixture_distribution=tfp.distributions.Categorical(probs=class_probs_true),
        components_distribution=tfp.distributions.Normal(
            loc=mus_true,
            scale=sigmas_true,
        )
    )

    dataset = univariate_gmm.sample(n_samples, seed=random_seed).numpy()

    class_probs, mus, sigmas, log_likelihood_histories = em_sieved(
        dataset,
        n_classes,
        n_iterations_pre_sieving,
        n_candidates,
        n_iterations_post_sieving,
        n_chosen_ones,
        random_seed,
    )

    print(class_probs)
    print(mus)
    print(sigmas)

    plt.figure()
    for log_likelihood_history in log_likelihood_histories:
        plt.plot(log_likelihood_history)
    plt.xlabel("Iteration")
    plt.ylabel("Log Likelihood")
    plt.show()

if __name__ == "__main__":
    main()


import scipy.optimize as opt
import numpy as np
import pylab as plt

#define model function and pass independant variables x and y as a list
def twoD_Gaussian(xy, amplitude, xo, yo, sigma_x, sigma_y, theta, offset):
    x = xy[0]
    y = xy[1]
    xo = float(xo)
    yo = float(yo)
    a = (np.cos(theta)**2)/(2*sigma_x**2) + (np.sin(theta)**2)/(2*sigma_y**2)
    b = -(np.sin(2*theta))/(4*sigma_x**2) + (np.sin(2*theta))/(4*sigma_y**2)
    c = (np.sin(theta)**2)/(2*sigma_x**2) + (np.cos(theta)**2)/(2*sigma_y**2)
    g = offset + amplitude*np.exp( - (a*((x-xo)**2) + 2*b*(x-xo)*(y-yo) + c*((y-yo)**2)))
    return g.ravel()

# Create x and y indices
x = np.linspace(0, 200, 201)
y = np.linspace(0, 200, 201)
x, y = np.meshgrid(x, y)

#create data
data = twoD_Gaussian((x, y), amplitude=3, xo=100, yo=100, sigma_x=20, sigma_y=40, theta=0, offset=10)

# plot twoD_Gaussian data generated above
plt.figure()
plt.imshow(np.reshape(data, (201, 201)))
plt.colorbar()
plt.show()

# add some noise to the data and try to fit the data generated beforehand
initial_guess = (3,100,100,20,40,0,10)

data_noisy = data + 0.2*np.random.normal(size=data.shape)

popt, pcov = opt.curve_fit(twoD_Gaussian, (x, y), data_noisy, p0=initial_guess)

data_fitted = twoD_Gaussian((x, y), *popt)

fig, ax = plt.subplots(1, 1)
ax.hold(True)
ax.imshow(data_noisy.reshape(201, 201), cmap=plt.cm.jet, origin='bottom',
    extent=(x.min(), x.max(), y.min(), y.max()))
ax.contour(x, y, data_fitted.reshape(201, 201), 8, colors='w')
plt.show()


## Storing Kernels :
import numpy as np

def lin(x, y):
    print "Computing linear Kernel"
    return np.dot(x,y.T)
# Defining Gaussian Kernel
def rbf(x, y, sigma= 0.2):
    print "Computing RBF Kernel"
    z = d(x, y)
    return np.exp(-z**2/(2*(sigma**2)))

def d(x, y):
    ## Compute the matrix distance between two matrices of features
    gram_matrix = np.dot(x, y.T)

    x_norm = np.sum( np.abs(x) ** 2 , axis=1, keepdims=True)
    y_norm = np.sum( np.abs(y) ** 2 , axis=1, keepdims=True)

    d_mat = x_norm + y_norm.T - 2 * gram_matrix

    d_mat= np.sqrt(np.maximum(d_mat,0))

    return d_mat


#!/usr/bin/python3.4

import numpy as np
from numpy import *
import matplotlib.pyplot as plt
import math as m
import os
from partie1 import *

from matplotlib.pyplot import figure, show

M = np.matrix([[11,21,5,12],[48,548,16,887],[47,88,91,45],[17,32,68,17]])

def extraireVect_Col(M,n,m,i):
    #Function that extract the column vector with index i from the matrix M
    Y = np.zeros(shape=(n,1))
    for j in range(i,n): #i
        Y[j] = M[j,i]
    return Y

def extraireVect_Lig(M,n,m,i):
    #Function that extract the line vector with index i from the matrix M
    Y = np.zeros(shape=(m,1))
    for j in range(i+1,m): #i+1
        Y[j] = M[i,j]
    return Y

def genererVect(X):
    Y = np.zeros(shape=np.shape(X))
    i = 0
    while (i < np.shape(X)[0] and X[i] == 0):
        i += 1
    if (i < np.shape(X)[0]):
        Y[i] = np.linalg.norm(X)
    return Y

def BD(A):
    #Function that transforms the matrix A to a bidiagonal matrix BD and two others Qleft and Qright
    #The matrix provide A = Qleft x BD x Qright
    n,m = np.shape(A)
    Qleft = np.eye(n)
    Qright = np.eye(m)
    BD = A
    for i in range(n-1):
        X = extraireVect_Col(BD,n,m,i)
        Y = genererVect(X)
        if (np.linalg.norm(X) == 0 and np.linalg.norm(Y) == 0):
            Q1 = np.eye(X.size)
        else:
            Q1 = householder(X,Y)
        Qleft = np.dot(Qleft, Q1)
        BD = np.dot(Q1, BD)
        if (i < (m-2)):
            X2 = extraireVect_Lig(BD,n,m,i)
            Y2 = genererVect(X2)
            if (np.linalg.norm(X2) == 0 and np.linalg.norm(Y2) == 0):
                Q2 = np.eye(X2.size)
            else:
                Q2 = householder(X2,Y2)
            Qright = np.dot(Q2, Qright)
            BD = np.dot(BD, Q2)
    return (Qleft, BD, Qright)
'''
Qleft, BD2, Qright = BD(M)

A = np.dot(np.dot(Qleft,BD2), Qright)

ec_rel = np.linalg.norm(A-M)/np.linalg.norm(M)

print(A)

print(ec_rel)
'''


"""
Objective
In this challenge, we go further with Poisson distributions.

Task
The manager of a industrial plant is planning to buy a machine of either type A or type B. For each day’s operation:

The number of repairs, X, that machine A needs is a Poisson random variable with mean 0.88.
The daily cost of operating A is C_A = 160+40X^2.
The number of repairs, Y, that machine B needs is a Poisson random variable with mean 1.55.
The daily cost of operating B is C_B = 128+40Y^2.
Assume that the repairs take a negligible amount of time and the machines are maintained nightly to ensure that
they operate like new at the start of each day.
Find and print the expected daily cost for each machine.
"""

import numpy as np

def daily_cost(lam=0.88, intercept=160):
    """
    Return the expected daily cost for machine with lam and intercept
    """
    # for a poisson distribution, E(X) = lam, Var(X) = lam,
    # since E(X-E(X))^2 = E(X^2) - (EX)^2,
    # then E(X^2) = Var(X) + (EX)^2
    return intercept + 40*(lam + lam**2)

# print the expected daily cost for machine A
print(np.round(daily_cost(), 3))
# print the expected daily cost for machine B
print(np.round(daily_cost(lam=1.55, intercept=128), 3))


import numpy as np
import matplotlib.pyplot as plt
from numpy.core.multiarray import ndarray
from typing import Optional, Union, Tuple

"""
1	Topic Introduction
--------------------------
Find the depth of the water tank to be filled so it holds 30 m^3

2	Topic Theory/Approach
--------------------------
Manipulate the given function based off of the given variables and solve for the roots
when V = 30 using false position and midpoint root functions with the lower limit of 0
and upper limit as R.

3	Problems
--------------------------
    (a)	Problem Statement
You are designing a spherical tank to hold water for a small village in a developing country. The
volume of liquid it can hold can be computed as
V =          3R - h
    pi*h^2*___________
                3
Where V =volume (m3), h=depth of water in tank(m), and R=the tank radius(m). If R=3 m, to
what depth must the tank be lled so that it holds 30 m3? Calculate the answer using both the
false position and midpoint approaches. Employ a lower limit of xl = 0 and xu = R.

    (b)	Problem Approach
Enter the given variables in the function, rearrange the function to set equal to 0 and V = 30.
Graph the function to visually see how many roots there are.
Determine the solution through false position and midpoint approaches.

    (c)	Problem Results
False Position Root Estimate:	-1.64081, -0.0
False Position Root Estimate:	2.02691, 0.0
False Position Root Estimate:	8.61391, 0.0

Midpoint Root Estimate:	-1.64081, 0.0
Midpoint Root Estimate:	2.02691, 0.0
Midpoint Root Estimate:	8.61391, -0.0

    (d)	Problem Discussion of Results
I set the ranges to check:
    [-2.5, 0]
    [0, 3]
    [7.5, 10]

These results returned the roots between the lower and upper limits.
These roots demonstrate where the depth can maintain 30 m^2

"""

def false_position(f, xa, xb):
    x_lp = xa
    x_up = xb

    for i in range(1, 21, 1):
        x_rp = x_up - ((f(x_up) * (x_lp - x_up)) / (f(x_lp) - f(x_up)))
        if f(x_lp) * f(x_rp) < 0:
            x_up = x_rp
        else:
            x_lp = x_rp
    plt.plot(x_rp, f(x_rp), 'y*')
    print('False Position Root Estimate:\t' + str(round(x_rp, 5)) + ', ' + str(round(f(x_rp), 5)))

def midpoint(f, xa, xb):
    x_lower = xa
    x_upper = xb
    x_r = x_lower
    for i in range(1, 100, 1):
        x_r = ((x_upper + x_lower) / 2)
        if (f(x_lower) * f(x_r) < 0):
            x_upper = x_r
        else:
            x_lower = x_r
    plt.plot(x_r, f(x_r), 'b*')
    print('Midpoint Root Estimate:\t' + str(round(x_r, 5)) + ', ' + str(round(f(x_r), 5)))

if __name__ == "__main__":
    h: Union[ndarray, Tuple[ndarray, Optional[float]]] = np.linspace(-10, 10)

    V = lambda R, h: np.pi * h ** 2 * ((3 * R - h) / 3.0)
    V_new = lambda h: 9 * np.pi * h ** 2 - np.pi * h ** 3 - 90

    line, = plt.plot(h, V_new(h), 'r')

    false_position(V_new, -2.5, 0)
    false_position(V_new, 0, 3)
    false_position(V_new, 7.5, 10)

    midpoint(V_new, -2.5, 0)
    midpoint(V_new, 0, 3)
    midpoint(V_new, 7.5, 10)

    line.set_antialiased(False)  # turn off antialising

    plt.setp(line, 'linewidth', 2.0)
    plt.legend((line, ), ('V = pi * h ^ 2 * (3R-h/3)',))
    plt.grid(True)
    plt.show()


import numpy
from scipy.integrate import solve_ivp

def fhn(t,y, c1, c2):
    a = -0.12
    b = 0.011
    c3 = 0.55

    v = y[0]
    w = y[1]

    f0 = c1*v*(v-a)*(1-v) - c2*w
    f1 =  b*(v-c3*w)

    return [f0, f1]

# Initial parameter at the Hopf point
c1 = 0.050417
c2 = 0.05

# Initial parameter far from the Hopf point
c1 = 0.15
c2 = 0.05

# Final parameter at the Hopf point
c1 = 0.050417
c2 = 0.025736

# Final parameter far from the Hopf point
c1 = 0.15
c2 = 0.025736

# initial condition for FHN
y0 = [0.01, 0.0]  # Off into orbit
T = 2000
t = numpy.linspace(0, T, T+1)

sol = solve_ivp(fhn, [0,T], y0, args=(c1,c2), t_eval=t)
print("min_t v = ", min(sol.y[0]))
print("max_t v = ", max(sol.y[0]))

S = numpy.array([[sol.t[i], sol.y[0,i], sol.y[1,i]] for i in range(len(sol.t))])
numpy.savetxt("sol_%.3f_%.3f.csv" %(c1,c2), S, delimiter=',')

# # Plot solutions
import pylab
pylab.figure()
pylab.plot(sol.t, sol.y[0])

pylab.ylabel("v (mV)")
pylab.xlabel("t (s)")
pylab.savefig("fhn_v.png")


import numpy as np

def get_haversine(lon1, lat1, lon2, lat2, d2r):

    dlat = d2r * (lat2 - lat1)
    dlon = d2r * (lon2 - lon1)
    lt1 = d2r * lat1
    lt2 = d2r * lat2

#    a = np.sin(0.5 * dlon) * np.sin(0.5 * dlon)
#    a = a * np.cos(lt1) * np.cos(lt2)
#    a = a + (np.sin(0.5 * dlat) * np.sin(0.5 * dlat))
#    thedist = 2.0 * np.arctan2(np.sqrt(a), np.sqrt(1.0 - a))

    a = np.sin(0.5 * dlon) * np.sin(0.5 * dlon) * \
            np.cos(lt1) * np.cos(lt2) + \
            (np.sin(0.5 * dlat) * np.sin(0.5 * dlat))
    thedist = 2.0 * np.arctan2(np.sqrt(a), np.sqrt(1.0 - a))

    return thedist

def distance_vector(lon1, lat1, lon2, lat2):

    erad = 6371315.0
    d2r = np.arctan2(0.,-1.)/ 180. # atan2(0.,-1.) == pi

    m = np.shape(lon1)[0]

    dist = np.zeros((m))
    for i in range(m):
        dist[i] = get_haversine(lon1[i], lat1[i], lon2[i], lat2[i], d2r)

    dist = dist * erad

    return dist

def distance_matrix(xa, xb):

    erad = 6371315.0
    d2r = np.arctan2(0.,-1.)/ 180. # atan2(0.,-1.) == pi

    m = np.shape(xa)[1] #changed by Ben, used to be 0
    n = np.shape(xb)[1] #changed by Ben, used to be 0

    dist = np.zeros((m,n))

    for j in range(m):
        #for i in range(n):
            #dist[j,i] = get_haversine(xa[j,0], xa[j,1], xb[i,0], xb[i,1],d2r)  #fiona probably had xa and xb zipped
            #dist[j,i] = get_haversine(xa[0,j], xa[1,j], xb[0,i], xb[1,i], d2r)  #first edit by Ben
        dist[j,:] = get_haversine(xa[0,j], xa[1,j], xb[0,:], xb[1,:], d2r)  #Ben's attempt to do entire row at once

    dist = dist * erad

    return dist

def distance(lon1, lat1, lon2, lat2):

    erad = 6371315.0
    d2r = np.arctan2(0.,-1.)/ 180. # atan2(0.,-1.) == pi

    thedist = get_haversine(lon1, lat1, lon2, lat2, d2r)
    thedist = thedist * erad

    return thedist


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

train_X = np.linspace(-1, 1, 100);

train_Y = 2 * train_X + np.random.randn(*train_X.shape) * 0.3

plt.plot(train_X, train_Y, 'ro', label='Original data')
plt.legend()
plt.show()

X = tf.placeholder("float")
Y = tf.placeholder("float")

W = tf.Variable(tf.random_normal([1]), name='weight')
b = tf.Variable(tf.zeros([1]), name='bias')

z = tf.multiply(X, W) + b

cost = tf.reduce_mean(tf.square(Y - z))
learning_rate = 0.01
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)

init = tf.global_variables_initializer()

training_epochs = 20
display_step = 2

with tf.Session() as sess:
	sess.run(init)
	plotdata={"batchsize":[],"loss":[]}

	for epoch in range(training_epochs):
		for (x, y) in zip(train_X, train_Y):
			sess.run(optimizer, feed_dict={X:x, Y:y})

		if epoch % display_step == 0:
			loss = sess.run(cost, feed_dict={X:train_X, Y:train_Y})
			print ("Epoch:", epoch+1, "cost=", loss, "W=", sess.run(W), "b=", sess.run(b))

			if not (loss == 'NA'):
				plotdata['batchsize'].append(epoch)
				plotdata['loss'].append(loss)

	print ("Finished!")
	print ("cost=", sess.run(cost, feed_dict={X:train_X, Y:train_Y}),
	"W=", sess.run(W), "b=", sess.run(b))


# -*- coding:UTF8 -*-
import numpy as np
import sys,os
import math

from tools.loadData import load_array
from tools import ulti

path = os.getcwd()

# Housholder reduction
def Housholder_reduction(mat, m, n):
    p_factor = 1.
    P = np.identity(m)
    mat_A = mat.copy()
    for diag_idx in range(min(m,n)):
        A = mat_A[diag_idx:, diag_idx:].copy()
        if A.shape==(1,1):
            break
        # ulti.print_array(A,m-diag_idx,n-diag_idx)
        # 计算 u,R,和R的系数
        x = A[0:,0].copy()
        a1_norm =round(math.sqrt(np.sum(np.square(x))),4)
        e1 = np.zeros(m-diag_idx)
        e1[0] = 1
        I = np.identity(m-diag_idx)
        u = np.matrix(x - a1_norm * e1)
        r1_factor = 2/ np.matmul(u, u.T)[0,0]
        r1 = np.matmul(u,u.T)[0,0] * I / 2 - np.matmul(u.T, u)
        # ulti.print_array(r1, m-diag_idx,m-diag_idx)

        # 当前P矩阵，p_factor是其系数
        P_helper = np.round(np.identity(m) * np.matmul(u,u.T)[0,0] /2, 3)
        P_helper[diag_idx:, diag_idx:] = np.round(r1,3)
        p_factor *= round(r1_factor,3)
        P = np.round(np.matmul(P_helper,P),3)
        # print("P=")
        # ulti.print_array(p_factor*  P,m,m)

        # 矩阵mat_A = P*mat_A
        # A_factor = r1_factor
        A = np.round(np.matmul(r1_factor* r1, A),3)
        # print("A=")
        # ulti.print_array(A, m-diag_idx,n-diag_idx)

        # 把A复制到mat_A相应的位置
        # mat_A_factor *= A_factor
        # mat_A = np.matmul(u,u.T)[0,0] *mat_A /2
        mat_A[diag_idx:, diag_idx:] = A
        # print("mat_A=")
        # ulti.print_array(mat_A,m,n)
    P = np.round(p_factor *P, 3)
    T = mat_A #* mat_A_factor
    return P.T,T

if __name__ == "__main__":
    input_file=path+'/data/example2.txt'
    # output_file=''
    matrix, m, n = load_array(input_file,"HR")
    # ulti.print_array(matrix, m, n )
    if matrix.size ==0:
        print("input Error!")
        sys.exit()
    Q,R = Housholder_reduction(matrix,m,n)
    print("Q=")
    ulti.print_array(Q,m,m)
    print("R=")
    ulti.print_array(R,m,n)


import numpy as np
import cv2
# Reference : https://marcin-chwedczuk.github.io/iterative-algorithm-for-drawing-hilbert-curve

#estimate the last 2 digit's "binary AND" with 3(Binary: 11)
def LastTwoDigit(D):
    return D & 3
'''
my basic 2X2 unit
01 10
00 11   input : 00, output : 11
'''
def X_Coordinate_Hilbert(x):
    if x & 2 == 0:      #x binary and 10 == 00
        return 0
    elif x & 2 == 2:    #x binary and 10 == 10
        return 1

def y_Coordinate_Hilbert(y):
    if y & 2 == 0:      #y binary and 10 == 00
        return y & 1    #y binary and 01
    elif y & 2 == 2:    #y binary and 10 == 10
        return y ^ 3    #y binary XOR 11
'''
Hilbert function gives the corresponding coordinate of Index , N is the size of Hilbert curve
'''
def Hilbert(Index, N):
    count = Index
    '''
    Old version, if use this code, i should begin with value 4
    x = X_Coordinate_Hilbert(LastTwoDigit(Index))
    y = y_Coordinate_Hilbert(LastTwoDigit(Index))
    Index = Index >> 2
    '''
    x, y = (0, 0)
    i = 2
    while(i <= N):
        Half_Of_N = i / 2
        Case = LastTwoDigit(Index)
        if Case == 0:
            t = x
            x = y
            y = t
        elif Case == 1:
            y = y + Half_Of_N
        elif Case == 2:
            x = x + Half_Of_N
            y = y + Half_Of_N
        elif Case == 3:
            t = x
            x = -y + (Half_Of_N - 1) + Half_Of_N
            y = -t + (Half_Of_N - 1)
        Index = Index >> 2
        i *= 2
    #print("node", count,"x:", x,"y:", y)
    x, y = map(int, (x, y))
    return y, x
'''
Hilbert_Coordinate_to_Index function gives the corresponding Index of coordinate, N is the size of Hilbert curve
'''
def Hilbert_Coordinate_to_Index(x, y, N):
    Index = 0
    while(N >= 2):
        Half_Of_N = N / 2
        Cur_corr_x = 2 ** (2 * np.log2(N) - 1)
        Cur_corr_y = 2 ** (2 * np.log2(N) - 2)
        if x < Half_Of_N:
            if y < Half_Of_N:
                Index = Index + Cur_corr_x * 0 + Cur_corr_y * 0
                t = x
                x = y
                y = t
                N /= 2
                continue
            elif y >= Half_Of_N and y <= N - 1:
                Index = Index + Cur_corr_x * 0 + Cur_corr_y * 1
                y = y - Half_Of_N
                N /= 2
                continue
        elif x >= Half_Of_N and x <= N-1:
            if y >= Half_Of_N and y <= N - 1:
                Index = Index + Cur_corr_x * 1 + Cur_corr_y * 0
                x = x - Half_Of_N
                y = y - Half_Of_N
                N /= 2
                continue
            elif y < Half_Of_N:
                Index = Index + Cur_corr_x * 1 + Cur_corr_y * 1
                t = y
                y = -x + (Half_Of_N - 1) + Half_Of_N
                x = -t + (Half_Of_N - 1)
                N /= 2
                continue
    return int(Index)

'''
Main function begins
'''
N = 32
img = np.zeros((900, 900, 3), np.uint8) + 255   #make an empty image, the part "+255" is to make it white (original one is black)
Siz_Fix = int(900/N)                            #let the Hilbert curve fit the image size 900 * 900
for j in range(N*N-1):
    print('node', j, 'x:', Hilbert(j, N)[0], 'y:', Hilbert(j, N)[1])
    Start_x, Start_y = map(lambda x : x * Siz_Fix, Hilbert(j, N))
    End_x, End_y = map(lambda x : x * Siz_Fix, Hilbert(j + 1, N))
    cv2.line(img, (Start_x, 900 - Start_y), (End_x, 900 - End_y), (0, 140, 255), 3)
    cv2.imshow('Hilbert', img)
    cv2.waitKey(1)
cv2.waitKey(0)


"""
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
from tqdm import tqdm
import os

# Comment this if you want a white backround
plt.style.use("dark_background")

N = 15000
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")
cont_index = 0
for i in tqdm(range(3, N, 50)):
    plt.scatter(x[cont_index:i], y[cont_index:i], c=c[cont_index:i], s=5)
    cont_index = i
    plt.savefig(f"images/Sierpinsky{str((i-3)//50).zfill(4)}.png")

# Note : Inorder to work this, You need to setup ffmpeg.
# Or, you can take images from images folder and make animation.
fps = 20
os.system(f'ffmpeg -r {fps} -s 1920x1080 -i "images/Sierpinsky%04d.png"\
 -vcodec libx264 -crf 20 -pix_fmt yuv420p "video/Sierpinsky.mp4"')


import numpy as np
import matplotlib.pyplot as plt

rates = [0.4, 1, 3]
ns = [1, 10, 100, 1000, 10000]

fig, axs = plt.subplots(len(rates), len(ns), sharex="col", dpi=700)
plt.tight_layout()

for i in range(0, len(rates)):
    for j in range(0, len(ns)):
        data = np.random.exponential(rates[i], ns[j])
        axs[i, j].hist(data, bins=20)

for j in range(0, len(ns)):
    axs[len(rates) - 1][j].set_xlabel("n = " + str(ns[j]))

for i in range(0, len(rates)):
    axs[i][0].set_ylabel("rate = " + str(rates[i]))

plt.show()
# plt.savefig('plot.pdf', dpi=200)


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

def main():
    x1 = np.random.uniform(low=-2, high=10, size=12)
    x_train = get_x_train(x1)
    y_train = get_y_train(x1)

    print_training_data(x1, y_train)

    w = linear_regression(x_train, y_train)
    best_r = determine_reg_param(x_train, y_train)
    w_reg = ridge_regression(x_train, y_train, regularizer=best_r)

    print_regression_eq('without reg', w, round(calculate_error(w, x_train, y_train), 2))
    print()
    print_regression_eq('with reg', w_reg, round(calculate_error(w_reg, x_train, y_train), 2))

    plot_exp(x1, y_train, w, w_reg)

def determine_reg_param(x_train, y_train):
    regularizers = np.array([0.1, 1, 10, 100])
    cv_error = np.zeros_like(regularizers)
    ein = np.zeros_like(regularizers)

    for i, r in enumerate(regularizers):
        w = ridge_regression(x_train, y_train, regularizer=r)
        ein[i] = calculate_error(w, x_train, y_train)
        cv_error[i] = cross_validation(x_train, y_train, 3, r)

    print_cross_validation_results(regularizers, ein, cv_error)

    return regularizers[np.argmin(cv_error)]

def print_cross_validation_results(regularizers, ein, cv_error):
    cv_summary = np.round(np.column_stack((regularizers, ein, cv_error)), 2)
    df = pd.DataFrame(cv_summary, columns=['lambda', 'in-sample error', 'cv error'])
    print(str(df))
    print('choose lambda = ' + str(regularizers[np.argmin(cv_error)]) + '\n')

def cross_validation(x_train, y_train, num_splits, regularizer):
    d = np.column_stack((x_train, y_train))
    cv_error = np.zeros(num_splits)

    for i, this_d in enumerate(np.split(d, num_splits)):
        x_train, y_train = this_d[:, :-1], this_d[:, -1]
        w = ridge_regression(x_train, y_train, regularizer)
        cv_error[i] = calculate_error(w, x_train, y_train)

    return np.average(cv_error)

def calculate_error(w, x_train, y_train):
    y = np.dot(x_train, w)
    return np.average(np.square(np.subtract(y, y_train)))

def ridge_regression(x_train, y_train, regularizer):
    I = np.identity(x_train.shape[1])
    xTx = np.dot(x_train.T, x_train)
    xTy = np.dot(x_train.T, y_train)
    return np.dot(np.linalg.pinv(np.add(xTx, regularizer * I)), xTy)

def linear_regression(x_train, y_train):
    return np.dot(np.linalg.pinv(x_train), y_train)

def get_x_train(x1):
    bias = np.ones_like(x1)
    return np.column_stack((bias, x1))

def get_y_train(x1):
    return np.square(x1) + 10

def print_training_data(x1, y_train):
    d = np.column_stack((x1, y_train))
    d_sorted = d[np.argsort(d[:, 0])]
    df = pd.DataFrame(np.round(d_sorted, 2), columns=['x', 'y'])
    print(str(df) + '\n')

def print_regression_eq(label, w, error):
    print('{0:12}: y = {1}x + {2}'.format(label, round(w[1], 2), round(w[0], 2)))
    print('{0:12}: {1}'.format('error', error))

def plot_exp(x1, y_train, w, w_reg):
    plt.style.use('seaborn-whitegrid')
    fig, ax = plt.subplots()

    ax.set(title='Ridge Regression')
    ax.scatter(x1, y_train, color='b', marker='x', label='training data')
    ax.plot(x1, line(w[1], x1, w[0]), color='g', label='regression line')
    ax.plot(x1, line(w_reg[1], x1, w_reg[0]), color='r', label='ridge regression line')

    ax.legend(facecolor='w', fancybox=True, frameon=True, edgecolor='black', borderpad=1)
    plt.show()

def line(m, x, b):
    return m * x + b

if __name__ == '__main__':
    main()


import numpy as np
import vg

def test_principal_components():
    # Example from http://www.iro.umontreal.ca/~pift6080/H09/documents/papers/pca_tutorial.pdf
    coords = np.array(
        [
            [2.5, 2.4],
            [0.5, 0.7],
            [2.2, 2.9],
            [1.9, 2.2],
            [3.1, 3.0],
            [2.3, 2.7],
            [2, 1.6],
            [1, 1.1],
            [1.5, 1.6],
            [1.1, 0.9],
        ]
    )

    pcs = vg.principal_components(coords)

    assert pcs.shape == (2, 2)
    np.testing.assert_array_almost_equal(pcs[0], np.array([-0.677873, -0.735179]))

    first_pc = vg.major_axis(coords)

    np.testing.assert_array_almost_equal(first_pc, np.array([-0.677873, -0.735179]))