""" 2)  RUN_prob-ode: The purpose of this code to demonstrate, how to simulate,
        solve and visualize differential equations, utilizing probabilistic models."""
#-----------------------------------------------------------------------------------------------------------------------------------
__author__ = "Christian Simonis"
__copyright__ = "Copyright 2021"
__version__ = "1.0"
__maintainer__ = "Christian Simonis"
__email__ = "christian.Simonis.1989@gmail.com"
__status__ = "work in progress"

# Approach: The class  ODE_Analysis enables the simulation of Lotka Volterra ODEs and applying additional observation noise and offsets.
# A domain-driven time integration approach is applied, which is combined with a probabilistic correction model.
# This model is optimized by tuning the data-driven part. The corresponding parameters are optimized via maximum marginal likelihood.
# Visualizations are provided to illustrate results.

#-----------------------------------------------------------------------------------------------------------------------------------
# Name                                Version                      License
# numpy                               1.19.5                       BSD,                                         Copyright (c) 2005-2020, NumPy Developers: https://numpy.org/doc/stable/license.html#:~:text=Copyright%20(c)%202005%2D2020%2C%20NumPy%20Developers.&text=THIS%20SOFTWARE%20IS%20PROVIDED%20BY,A%20PARTICULAR%20PURPOSE%20ARE%20DISCLAIMED.
# tensorflow-probability              0.12.2                       Apache Software License , Version 2.0,       Copyright 2018 The TensorFlow Probability Authors.  All rights reserved.https://github.com/tensorflow/probability/blob/master/LICENSE
# tensorflow                          2.5.0                        Apache Software License,                     Copyright 2019 The TensorFlow Authors.  All rights reserved.https://github.com/tensorflow/tensorflow/blob/master/LICENSE
# matplotlib                          3.4.2                        Python Software Foundation License,          Copyright (c) 2002 - 2012 John Hunter, Darren Dale, Eric Firing, Michael Droettboom and the Matplotlib development team; 2012 - 2021 The Matplotlib development team: https://matplotlib.org/stable/users/license.html
# seaborn                             0.11.1                       BSD 3-Clause "New" or "Revised" License,     Copyright (c) 2012-2021, Michael L. Waskom: https://github.com/mwaskom/seaborn/blob/master/LICENSE
# scipy                               1.5.2                        BSD 3-Clause "New" or "Revised" License,     Copyright (c) 2001-2002 Enthought, Inc.  2003-2019, SciPy Developers: https://github.com/scipy/scipy/blob/master/LICENSE.txt
# lmfit/lmfit-py                      1.0.2                        BSD-3                                        Copyright 2021 Matthew Newville, The University of Chicag, Renee Otten, Brandeis University, Till Stensitzki, Freie Universitat Berlin, A. R. J. Nelson, Australian Nuclear Science and Technology Organisation, Antonino Ingargiola, University of California, Los Angeles, Daniel B. Allen, Johns Hopkins University, Michal Rawlik, Eidgenossische Technische Hochschule, Zurich, https://github.com/lmfit/lmfit-py/blob/master/LICENSE
# app (Lotka Volterra simulation)       -                          MIT License,                                 Copyright (c) 2018 Mostapha Kalami Heris / Yarpiz Team, https://github.com/smkalami/lotka-volterra-in-python/blob/master/app.py
# scipy/scipy-cookbook                  -                          Copyright (c) 2001, 2002 Enthought, Inc.,    All rights reserved., Copyright (c) 2003-2017 SciPy Developers., All rights reserved., https://github.com/scipy/scipy-cookbook/blob/master/LICENSE.txt
#-----------------------------------------------------------------------------------------------------------------------------------
import numpy as np
import tensorflow_probability as tfp
import tensorflow.compat.v2 as tf
import matplotlib.pyplot as plt
import seaborn as sns
import scipy
import lmfit
import random                                                      # https://docs.python.org/3/library/random.html                                            # https://docs.python.org/3/library/datetime.html
#-----------------------------------------------------------------------------------------------------------------------------------
# '''
#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
#BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
#OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
#THE POSSIBILITY OF SUCH DAMAGE.
#"""
#-----------------------------------------------------------------------------------------------------------------------------------

# Defined Lotka-Volterra Model parameters for creating time series data
alpha = 1.0
beta = 0.55
gamma = 1.15
delta = 0.75

# Simulation Time
N = 800
till = 15
t = np.linspace(0,till,N)
dt = t[1] - t[0]

# Initial Values
x0 = 1.3
y0 = 0.5

#Observability, assuming a noisy signal
noise_factor_x = 0.2
noise_factor_y = 0.3
offset_x = 0.9 #Preys that do not take part in the game
offset_y = 1.2 #Predators that do not  not take part in the game

#Probabilistic analysis
sigma_eval = 3 #Evaluation at 3 sigma

#Visualization of trajectory samples
nr_samples = 10

#-----------------------------------------------------------------------------------------------------------------------------------
#import ODE_Analysis
from ODE_Analysis import ODE_Analysis
#-----------------------------------------------------------------------------------------------------------------------------------

#Random number generator for repeatabe results
random.seed(0)

#call class ODE_Analysis
Lotka_Volterra = ODE_Analysis()

#visualization of pure theoretic ODE part based on parameters
nb_points   = 20
Lotka_Volterra.visualize_ODE(t, alpha, beta, gamma, delta, nb_points)
plt.show()

#create data with noisy observations and apply term which ODE model cannot describe (offset)
data = Lotka_Volterra.create_time_series(alpha, beta, gamma, delta, t, x0, y0, noise_factor_x, noise_factor_y, offset_x, offset_y)
x_init = data[0,0]
y_init = data[0,1]

#optimization: Fit differential eqaution model
lim_min = 0
lim_max = 20
fitted_mdl_result, residuum_ode = Lotka_Volterra.fit_ODE(t, data, x_init, y_init, lim_min, lim_max)
x_res_ode = residuum_ode[:,0]
y_res_ode = residuum_ode[:,1]

# plot data and fitted curves
plt.plot(t, data, 'o',label='Noisy observations',alpha = 0.2)
plt.plot(t, fitted_mdl_result, '-.', linewidth=5 ,label='Model Fit')
plt.xlabel('Time', fontsize=16)
plt.ylabel('Population', fontsize=16)
plt.legend(loc = 'upper right')
plt.show()

# for X (Preys)
ODE_x = fitted_mdl_result[:,0]
observation_x = data[:,0]
Lotka_Volterra.evaluate_prob_mdl(t,x_res_ode,ODE_x, observation_x, sigma_eval)

# for Y (Predators)
ODE_y = fitted_mdl_result[:,1]
observation_y = data[:,1]
Lotka_Volterra.evaluate_prob_mdl(t,y_res_ode,ODE_y, observation_y, sigma_eval)

#Optimization input
observation_index_points = t.reshape(-1,1)
index_points = t.reshape(-1,1)

#Call function for X optimization
print("--------------Optimization for Prey class X--------------")
obs_X = -x_res_ode
observation_noise_variance_X = np.std(obs_X)
GP_opt_X, x_opt_mean, x_opt_up, x_opt_low = Lotka_Volterra.optimize_mdl_prm(index_points,observation_index_points, obs_X, observation_noise_variance_X, sigma_eval)

#probabilistic correction for X
x_opt = x_opt_mean + ODE_x
x_opt_up = x_opt_up + ODE_x
x_opt_low = x_opt_low + ODE_x

#Visualization
Lotka_Volterra.visualize_results(t, x_opt, ODE_x, observation_x)

#Call function for Y optimization
print("-----------Optimization for Predator class Y-------------")
obs_Y = -y_res_ode
observation_noise_variance_Y = np.std(obs_Y)
GP_opt_Y, y_opt_mean, y_opt_up, y_opt_low = Lotka_Volterra.optimize_mdl_prm(index_points,observation_index_points, obs_Y, observation_noise_variance_Y, sigma_eval)

#probabilistic correction for Y
y_opt = y_opt_mean + ODE_y
y_opt_up = y_opt_up + ODE_y
y_opt_low = y_opt_low + ODE_y

#Visualization
Lotka_Volterra.visualize_results(t, y_opt, ODE_y, observation_y)
print("-----------------Optimization finished-------------------")

#Time series plot
plt.plot(t, data, 'o',label='Noisy observations',alpha = 0.2)
plt.plot(t, x_opt, c='r', alpha=1, linewidth=3, label = 'Model for X (Prey class)')
plt.fill_between(t, x_opt_up, x_opt_low, color='r', alpha=.1)
plt.plot(t, y_opt, c='k', alpha=1, linewidth=3, label = 'Model for Y (Predator class)')
plt.fill_between(t, y_opt_up, y_opt_low, color='k', alpha=.1)
plt.legend(ncol=2)
plt.xlabel('Time', fontsize=16)
plt.ylim(0,8)
plt.ylabel('Population', fontsize=16)
plt.title('Optimized probabilistic model, combined with ODE model')
plt.show()

#Sampling from probabilistic model
samples_X = GP_opt_X.sample(nr_samples).numpy()
samples_Y = GP_opt_Y.sample(nr_samples).numpy()

#Diagram with trajectories
plt.plot(x_opt, y_opt, c='b', alpha=.5, linewidth=7, label = 'Model Mean')
plt.plot(samples_X[0,:]  + ODE_x, samples_Y[0,:]  + ODE_y, c='b', alpha=.1, label = 'Model samples') #for creating one legend entry
plt.plot(samples_X.T + ODE_x.reshape(-1,1), samples_Y.T + ODE_y.reshape(-1,1), c='b', alpha=.1, label = '_nolegend_') # no legend entrys hier
plt.legend(loc = 'upper right')
plt.xlabel('Preys', fontsize=16)
plt.ylabel('Predators', fontsize=16)
plt.title('Trajectory diagram w/ {} drawn samples from probabilistic model'.format(nr_samples))
plt.show()


import numpy as np

def gaussjordanInv(A):
    '''
    Inverse a matrix using elimination Gauss Jordan method

    This method takes a matrix as parameter, then it returns the inverse of the given matrix.

    Parameters
    -------

    A : matrix
        a numpy matrix (vector of vectors) of any dimension
    '''
    B = A.copy()
    n,m = len(B), len(B[0])
    I = np.eye(n)
    for i in range(n):
        for j in range(n):
            if i != j:
                ratio = B[j,i]/B[i,i]
                for k in range(m):
                    B[j,k] = B[j,k] - ratio * B[i,k]
                    I[j,k] = I[j,k] - ratio * I[i,k]
    for i in range(len(B)):
        divisor = B[i,i]
        for j in range(len(B)):
            B[i,j] = B[i,j]/divisor
            I[i,j] = I[i,j]/divisor
    return I

def linearGauss(A,b):
    '''
    Solve a linear system

    This method takes a matrix and a vector as parameter, then it returns the vector solution of the given matrix using gauss jordan method.

    Parameters
    -------

    A : matrix
        a numpy matrix (vector of vectors) of any dimension
    b : list
        a list or a numpy vector
    '''
    n=len(A)
    for i in range(n):
        for j in range(n):
            if i!=j:
                ratio =A[j,i]/A[i,i]
                for k in range(n):
                    A[j,k]=A[j,k]-ratio *A[i,k]
                b[j]=b[j]-ratio *b[i]
    x=b
    for i in range(n-1,-1,-1):
        x[i]=x[i]/A[i,i]
        A[i,i] /= A[i,i]
    return x

def _decompositionLU(A):
    n=len(A)
    L=np.identity(n)
    U=A
    for i in range(n):
        for j in range(n):
            s=0
            for k in range(i):
                s+=(L[i,k]*U[k,j])
            U[i,j]=A[i,j]-s
        for j in range(i,n):
            if i==j:
                L[i,i]=1
            else:
                s=0
                for k in range(i):
                    s+=(L[j,k]*U[k,i])
                L[j,i]=(A[j,i]-s)/U[i,i]
    return (L,U)

def _choleski(A):
    n=len(A)
    L=np.zeros((n,n))
    for i in range(n):
        for j in range(i+1):
            s=0
            if j==i:
                for k in range(j):
                    s+=pow(L[j,k],2)
                L[j,j]=np.sqrt(A[j,j]-s)
            else:
                for k in range(j):
                    s+=L[i,k]*L[j,k]
                L[i,j]=(A[i,j]-s)/L[j,j]
    return L

def LUdecomp(A,b):
    '''
    Solve a linear system

    This method takes a matrix and a vector as parameter, then it returns the vector solution of the given matrix using Choleski
    Parameters
    -------

    A : matrix
        a numpy matrix (vector of vectors) of any dimension
    b : list
        a list or a numpy vector
    '''
    L, U = _decompositionLU(A)
    y = linearGauss(L,b)
    x = linearGauss(U,y)
    return x
def cholsekidecomp(A,b):
    A = _choleski(A)
    B = A.T
    y = linearGauss(A,b)
    x = linearGauss(B,y)
    return x


'''
Busca binária iterativa
Exercício: Lista 1.1

Requerido: python 3+, pip install -r requirements.txt
Executar: python busca_binaria.py
'''

from numpy import integer
#import logging

#LOGGER = logging.getLogger(__name__)

def busca_binaria(lista, valor):
    '''
    Dada uma lista de números e um número, retorna o índice do número na lista
    ou -1 se o número não estiver na lista.

      :param lista: a lista que você deseja pesquisar
      :param valor: o valor que está procurando

      Issue:
      Return rightmost, not leftmost
      https://en.wikipedia.org/wiki/Binary_search_algorithm#Duplicate_elements

    Run: pytest busca_binaria.py --hypothesis-show-statistics
    '''
    tamanho = len(lista)
    fim = tamanho - 1
    inicio = 0
    #chute = tamanho // 2
    #print(chute)
    #print((inicio + fim) // 2)
    #while (fim - inicio) >= 0:
    while fim >= inicio:
        chute = (inicio + fim) // 2
        if valor == lista[chute]:
            return chute
        if valor > lista[chute]:
            inicio = chute + 1
        else:
            fim = chute - 1
        #chute = (inicio + fim) // 2
    return -1

if __name__ == "__main__":
    assert(busca_binaria([1, 2, 3, 4, 5, 6], 4) == 3)
    assert(busca_binaria([1, 2, 3, 4, 5, 6], 1) == 0)
    assert(busca_binaria([1, 2, 3, 4, 5, 6], 6) == 5)
    assert(busca_binaria([23, 32, 44, 45, 45, 60], 44) == 2)
    assert(busca_binaria([23, 32, 44, 45, 45, 60], 45) == 3)
    assert(busca_binaria([23, 32, 44, 45, 45, 60], 100) == -1)
    assert(busca_binaria([23, 32, 44, 45, 45, 60], 23) == 0)
    assert(busca_binaria([23, 32, 44, 45, 45, 60], 60) == 5)
    assert(busca_binaria([23, 32, 44, 45, 45, 60], 32) == 1)
    assert(busca_binaria([0, 0], 0) == 0)

# https://learning.oreilly.com/library/view/robust-python/9781098100650/ch23.html
from hypothesis import given, event, strategies as st
import random

@given(st.lists(st.integers(min_value=0, max_value=1000), min_size=1, unique=True).map(sorted))
def test_search(xs):
    #test_list = [23, 32, 44, 45, 45, 60]
    element_to_search = random.choice(xs)
    #LOGGER.warning(f'{xs}, {element_to_search}')
    event(f'{xs}, {element_to_search}')
    assert(busca_binaria(xs, element_to_search) == xs.index(element_to_search))


# -*- coding: utf-8 -*-
"""
Created on Sun Mar 31 18:54:17 2019

@author: RAJDEEP PAL
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
#%%
# Function to return gcd of a and b
def gcd(a, b):   # want a > b

    if (a == b):
        return a
    elif ( b == 0 ):
        return a
    elif (a < b):
        return gcd(b, a)
    return gcd(b, b%a)

#%%
def gcd(a, b):

    if (a == 0):
        return b
    return gcd(b % a, a)

#"""  Euler Totient Function  """
def phi(n):

    result = 1
    for i in range(2, n):
        if (gcd(i, n) == 1):
            result+=1
    return result

#%%
# Driver Code
totient_vals = np.zeros(1000)
x = np.zeros(1000)
for i in range(1, 1001): # i = 1 to 1000
    #print (i)
    x[i-1] = i
    totient_vals[i-1] = phi(i)
    print ( phi(i) )
#%%
y = totient_vals
temp = x-1
font = {
 #   'family' : 'Bitstream Vera Sans',
    'family' : 'DejaVu Sans',
    'weight' : 'bold',
    'size'   : 18
}
matplotlib.rc('font', **font)

plt.figure(figsize=(20, 20))

plt.plot(x, y, 'ro')

plt.title("Euler's Totient Function for the first 1000 positive integers")
#plt.legend(loc='upper right', shadow=True)
plt.ylabel('Totient values : phi(x)')
plt.xlabel('Integers : x')

plt.savefig("Totient Fuction")

# This code is contributed
# by Smitha


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Dec 22 10:54:50 2020

@author: Jane Hsieh (Hsing-Chuan, Hsieh)

@article:
    Generate random sample of dice (with Faif and Loaded dice used interchangeably)
"""
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#0. ================================================ Functions ===============================================

def InitialState(pi_0=0.5):
    '''
    function to generate initial state S_0 out of {F,L} of the dice with prob-p(S_0=F) = p(F)=pi_0 (0:F; 1:L)
    Input:
        pi_0: defaul= 0.5 which is the initial prob of hiddent state p(S_0 = 0)  [0: fair dice; 1: Loaded dice]
                (pi1 := p(S_0 = 1) = 1-pi_0)
    Output:
        S_0: initial generated hidden state
    '''
    S_0 = np.random.choice(2, 1, p=[pi_0, 1-pi_0])[0] #Default: replace=True
    return S_0

def EmitObs(S_t, Dice, pF, pL):
    '''
    function to generate observation O_t according to the mechanism of hidden state S_t --> Emit Observation
    Input:
        S_t: current hidden state
        Dice: face point of dice, e.g., [1,2,...,6]
        pF: distributions of Fair Dice, say, with point = [1,2,...,6]
        pL: distributions of Loaded Dice, say, with point = [1,2,...,6]
    '''
    if S_t == 0:
        #Fair dice state with prob = pF
        O_t = np.random.choice(Dice, 1, replace=True, p=pF)[0]
    if S_t == 1:
        #Loaded dice state with prob = pL
        O_t = np.random.choice(Dice, 1, replace=True, p=pL)[0]
    return O_t

def TransitState(S_t, p01, p10):
    '''
    function to generate the new hidden state S_t according to the mechanism of previous hidden state S_t
    Input:
        S_t: current hidden state
        p01: Transition prob from 0(F) to 1(L)); p00 =  1- p01
        p10: Transition prob from 1(L) to 0(F); p11 = 1-p10
    '''
    if S_t == 0:
        #Fair dice state with prob = pF
        S_new = np.random.choice(2, 1, replace=True, p=[1-p01, p01])[0]
    if S_t == 1:
        #Loaded dice state with prob = pL
        S_new = np.random.choice(2, 1, replace=True, p=[p10, 1-p10])[0]
    return S_new

def GenerateFLDice(N, p01, p10, pL, pF=[1/6 for i in range(6)], Dice = [i+1 for i in range(6)], pi_0=0.5, seed=None):
    '''
    Generate random sample of dice (with predefined Fair(R) and Loaded(L) dice used interchangeably)

    Input:
        N: sample size
        seed: random seed– None or int
        Dice: face point of the dice; default = [1,2,...,6]
        pF, pL: distributions of Fair vs Loaded Dice (length of pF, pL must be the same with Dice)
        pi_0: initial probability of hidden state S_0 – p(S_0 = 0)  [0: fair dice; 1: Loaded dice]
        p01, p10: Transition prob of hidden state from 0(F) to 1(L)) & from 1(L) to 0(F), respectively
    Output:
        Sample_S: sequence of hidden states {S_t} from t=0,...,N-1
        Sample_O: sequence of observations {O_t} from t=0,...,N-1

    '''
    np.random.seed(seed)
    Sample_S = []
    Sample_O = []

    t=0
    # Generate initial hidden state S_t & the Observed state O_t out of it
    S_t = InitialState(pi_0)
    O_t = EmitObs(S_t, Dice, pF, pL)

    Sample_S.append(S_t)
    Sample_O.append(O_t)

    t += 1

    while t < N:
        #Generate New S_t at next time (i.e., t+1) point according to previous mechanism of S_t;
        #and O_t out of New S_t
        S_t = TransitState(S_t, p01, p10)
        O_t = EmitObs(S_t, Dice, pF, pL)

        Sample_S.append(S_t)
        Sample_O.append(O_t)

        t += 1

    return Sample_S, Sample_O

Hidden Markov Model (HMM)/Dice Simulation Data/Step3. HMM Analysis/Generate_Dice_Sample.py


# -*- coding: utf-8 -*-
"""
Created on Wed May 29 09:11:47 2019

@author: Thiago
"""
'''
Modelos estocásticos
'''

import numpy as np
import pylab as pl
import sympy as sp

#%%

def fun(x):
    return x*x

a, b, M, N = 0, 1, 1, 500
k = 0
u = np.linspace(a, b, 100)
pl.plot(u, fun(u))

for i in range(N):
    x, y = np.random.rand(2)
    pl.scatter(x, y, c='b')
    if(y<fun(x)):
        k += 1
        pl.scatter(x, y, c='r')

pl.show()
I1 = M*(b-a)*k/N

x = sp.var('x')

I0 = sp.Integral(fun(x), (x,a,b))
display(I0, I0.evalf(), I1)

#%%

for N0 in [10, 100, 500, 1000, 5000, 50000, 100000]:
    I1=[]
    for j in range(10):
        k = 0
        for i in range(N0):
            x, y = np.random.rand(2)
            if(y<fun(x)):
                k += 1

        I1.append(M*(b-a)*k/N0)

    print(N0, np.mean(I1), np.std(I1))

#%%


# get the numerical gradient of multivariable function f(x1, x2, ...)
import sys
import os
sys.path.append(os.pardir)
import numpy as np
from ch04.numerical_diff import show
from ch04.numerical_gradient import numerical_gradient

def numerical_gradient_batch(f, x):
    """
    Returns the gradient of f at x[0], at x[1], ... .
    x is a matrix(including array).
    """
    h = 1e-4  # rule of thumb

    if x.ndim == 1: # if x is an array
        gradient = numerical_gradient(f, x)
    else: # if x is an matrix(not array)
        gradient = np.zeros_like(x)
        for index, x_i in enumerate(x):
            gradient[index] = numerical_gradient(f, x_i)
    return gradient

def get_unit_vector(dimension, index):
    vector = np.zeros(dimension)
    vector[index] = 1
    return vector

if __name__ == '__main__':
    print('z = x ** 2 + y ** 2')

    def f1(x): return x[0] ** 2 + x[1] ** 2
    show(f1, np.array([3.0, 4.0]), numerical_gradient,
         'numerical_gradient', np.array([6.0, 8.0]))
    show(f1, np.array([5.0, 0.0]), numerical_gradient,
         'numerical_gradient', np.array([10.0, 0.0]))
    show(f1, np.array([0.0, 0.0]), numerical_gradient,
         'numerical_gradient', np.array([0.0, 0.0]))

    def f2(x): return x[0] + x[1] ** 2 + x[2] ** 3
    show(f2, np.array([1.0, 2.0, 3.0]), numerical_gradient,
         'numerical_gradient', np.array([1.0, 4.0, 27.0]))

    # x can be a matrix
    print(numerical_gradient_batch(f1, np.array([[3.0, 4.0], [5.0, 0.0], [0.0, 0.0]])))


#!/usr/bin/env python3
#
# Script to test various ODE solvers for the test problem
#    u' = (u+t^2-2)/(t+1),   t in [0,5]
#    u(0) = 2.
#
# Daniel R. Reynolds
# SMU Mathematics
# Math 4315

# imports
import numpy
import matplotlib.pyplot as plt
from ivp_methods import *

# ODE RHS and Jacobian, initial condition, etc.
def f(t,u):
    return (u+t*t-2)/(t+1)
def f_u(t,u):
    return (1.0/(t+1))
def utrue(t):
    return (t**2 + 2*t + 2 - 2*(t+1)*numpy.log(t+1))
u0  = 2.0
t0  = 0.0
Tf  = 5.0
hvals = [0.5**2, 0.5**3, 0.5**4, 0.5**5, 0.5**6, 0.5**7, 0.5**8]

# initialize error storage arrays
err_fE     = numpy.zeros((len(hvals),1), dtype=float)
err_RK2    = numpy.zeros((len(hvals),1), dtype=float)
err_Heun   = numpy.zeros((len(hvals),1), dtype=float)
err_AB2    = numpy.zeros((len(hvals),1), dtype=float)
err_bE     = numpy.zeros((len(hvals),1), dtype=float)
err_trap   = numpy.zeros((len(hvals),1), dtype=float)

# iterate over our h values
for j, h in enumerate(hvals):

    # create time output array
    N = int((Tf-t0)/h)
    tvals = numpy.linspace(t0, Tf, N+1)

    # initialize solutions
    u_fE     = u0
    u_RK2    = u0
    u_Heun   = u0
    u_AB2    = u0
    u_bE     = u0
    u_trap   = u0

    # try out our methods
    for i in range(N):

        t = tvals[i]
        tnew = t + h

        u_fE = fwd_Euler_step(f, t, u_fE,  h)
        err_fE[j] = max(err_fE[j], abs(u_fE-utrue(tnew)))

        u_RK2 = RK2_step(f, t, u_RK2, h)
        err_RK2[j] = max(err_RK2[j], abs(u_RK2-utrue(tnew)))

        u_Heun = Heun_step(f, t, u_Heun, h)
        err_Heun[j] = max(err_Heun[j], abs(u_Heun-utrue(tnew)))

        # for first AB2 step, store fold and use RK2 for step; subsequently use AB2
        if (i == 0):
            fold_AB2 = f(t, u_AB2)
            u_AB2 = RK2_step(f, t, u_AB2, h)
        else:
            u_AB2, fold_AB2 = AB2_step(f, t, u_AB2, h, fold_AB2)
        err_AB2[j] = max(err_AB2[j], abs(u_AB2-utrue(tnew)))

        u_bE = bwd_Euler_step(f, f_u, t, u_bE,  h)
        err_bE[j] = max(err_bE[j], abs(u_bE-utrue(tnew)))

        u_trap = trap_step(f, f_u, t, u_trap,  h)
        err_trap[j] = max(err_trap[j], abs(u_trap-utrue(tnew)))

# output convergence results
print('Results for Fwd Euler:')
err = err_fE
print("   h = %10g,  err = %.2e" % (hvals[0], err[0]))
for i in range(1,len(hvals)):
    print("   h = %10g,  err = %.2e,  rate = %g" %
          (hvals[i], err[i], numpy.log(err[i]/err[i-1])/numpy.log(hvals[i]/hvals[i-1])) )

print('Results for RK2:')
err = err_RK2
print("   h = %10g,  err = %.2e" % (hvals[0], err[0]))
for i in range(1,len(hvals)):
    print("   h = %10g,  err = %.2e,  rate = %g" %
          (hvals[i], err[i], numpy.log(err[i]/err[i-1])/numpy.log(hvals[i]/hvals[i-1])) )

print('Results for Heun:')
err = err_Heun
print("   h = %10g,  err = %.2e" % (hvals[0], err[0]))
for i in range(1,len(hvals)):
    print("   h = %10g,  err = %.2e,  rate = %g" %
          (hvals[i], err[i], numpy.log(err[i]/err[i-1])/numpy.log(hvals[i]/hvals[i-1])) )

print('Results for AB2:')
err = err_AB2
print("   h = %10g,  err = %.2e" % (hvals[0], err[0]))
for i in range(1,len(hvals)):
    print("   h = %10g,  err = %.2e,  rate = %g" %
          (hvals[i], err[i], numpy.log(err[i]/err[i-1])/numpy.log(hvals[i]/hvals[i-1])) )

print('Results for Bwd Euler:')
err = err_bE
print("   h = %10g,  err = %.2e" % (hvals[0], err[0]))
for i in range(1,len(hvals)):
    print("   h = %10g,  err = %.2e,  rate = %g" %
          (hvals[i], err[i], numpy.log(err[i]/err[i-1])/numpy.log(hvals[i]/hvals[i-1])) )

print('Results for Trapezoidal:')
err = err_trap
print("   h = %10g,  err = %.2e" % (hvals[0], err[0]))
for i in range(1,len(hvals)):
    print("   h = %10g,  err = %.2e,  rate = %g" %
          (hvals[i], err[i], numpy.log(err[i]/err[i-1])/numpy.log(hvals[i]/hvals[i-1])) )

# display true solution
plt.figure()
plt.plot(tvals, utrue(tvals))
plt.xlabel('$t$')
plt.ylabel('$u(t)$')
plt.show()

# end of script


# -*- coding: utf-8 -*-
"""
Created on Fri May 24 09:02:39 2019

@author: Training28
"""

1. Write a Python code to import NumPy.

import numpy as np

2. Write a Python program to create 3x3 matrix with values ranging from 5 to 13.

ab=np.arange(5,14).reshape(3,3)
print(ab)

3. Write a Python program to create a null vector of size 10 and update sixth value to 11.

a=np.zeros(10)
a[5]=11
print(a)

4. Write a Python program to create a array with values ranging from 12 to 38.

ac=np.arange(12,39)
print(ac)

6. Write a Python program to reverse an array so that first element becomes last.

reversed=ac[::-1]
print(reversed)

7. Write a Python program to an array converted to a float type.

y=ac.astype(np.float)
type(y)
print(y)

8. Write a Python program to create a 2d array with 1 on the border and 0 inside.

border=np.zeros((5,5))
print(border)
inside=np.pad(border, pad_width=1, mode='constant', constant_values=1)
print(inside)

9. Write a Python program to create a 8x8 matrix and fill it with a checkerboard pattern.
x=np.ones((3,3))
x=np.zeros((8,8),dtype=int)
#odd rows even columns
x[1::2,::2]=1
#even rows odd columns
x[::2,1::2]=1
print(x)

10. Write a Python program to convert a list and tuple into arrays.

a=[1,2,3]
b=(1,2,3)
c=np.asarray(a)
print(c)
type(c)
d=np.asarray(b)
print(d)
type(d)

11. Write a Python program to append values to the end of an array.

a=np.append(a,[[2,3]])
print(a)

12. Write a Python program to create an empty and a full array.

a=np.empty((3,4))
print(a)
y=np.full((3,4),0)
print(y)

13. Write a Python program to convert the values of Centigrade degrees into Fahrenheit degrees. Centigrade values are stored into a NumPy array.
centigrate=[0, 12, 45.21, 34, 99.91]
values=np.array(centigrate)
print(values)
type(values)
print('The value in centigrade degrees:')
print(5*values/9 - 5*32/9)

14. Write a Python program to find the real and imaginary parts of an array of complex numbers.
x = np.sqrt([1+0j])
y = np.sqrt([0+1j])
print(x.real)
print(y.real)
print(x.imag)
print(y.imag)

15. Write a Python program to test whether each element of a 1-D array is also present in a second array.
a1=np.array([1,2,3,4,5])
a2=np.array([1,2,2])
print(np.isin(a1,a2))

16. Write a Python program to find common values between two arrays.
print(np.intersect1d(a1, a2))

17. Write a Python program to get the unique elements of an array.

print(np.unique(a2))

18. Write a Python program to test if all elements in an array evaluate to True.

# 0 evaluates to false in python
print(np.all([10, 20, 0, -50]))

19. Write a Python program to test whether any array element along a given axis evaluates to True.
#checks for all elements in an array to be same and then responds the value
print(np.any([10, 20, 0, -50]))

20. Write a Python program to repeat elements of an array.
a=np.repeat(3,4)
print(a)
ab=np.array([[1,0],[1,3]])
print(np.repeat(ab,3))

21. Write a Python program to find the indices of the maximum and minimum values along the given axis of an array.
check=np.array([1,2,3,5,6,7,8,9])
print('max indicies',np.argmax(check))
print('min indicies',np.argmin(check))

22. Write a Python program compare two arrays using numpy.

a=np.array([1,2,3,4,5])
b=np.array([1,2])
print(np.array_equal(a,b))
print(np.array_equiv(a,b))
print(np.allclose(a,b))

23. Write a Python program to save a NumPy array to a text file.
a=np.array([1,2,3,4,5])
b=np.arange(1.0,2.0,22.3)
np.savetxt('file.out',a,delimiter=',')
np.savetxt('text.csv',b,delimiter=',')

24. Write a Python program to create a contiguous flattened array.
a=np.array([[12,12,3],[23,232,23],[232,21,32]])
b=np.ravel(a)
print(b)

25.Write a program to perform addition,minimum and maximum values from a 3D array.
arr = np.arange(36).reshape(3, 4, 3)
print(arr)
print("\nSum of arr : ", np.sum(arr))
print("Sum of arr(axis = 0) : ", np.sum(arr, axis = 0))
print("Sum of arr(axis = 1) : ", np.sum(arr, axis = 1))
print("Sum of arr(axis = 1) : ", np.sum(arr, axis = 2))

print("\nSum of arr (keepdimension is True): \n",
      np.sum(arr, axis = 1, keepdims = True))

print('minimum',np.min(arr))
print('max value',np.max(arr))


import math
import numpy as np

def segmentLineIntersection(seg_start, seg_end, line_p1, line_p2):
    """
    Return None if there is no intersection between the line and the segment or
    if the lines are coincident, otherwise, return the intersection point
    """
    # Line-segment intersection from points
    # https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection#Given_two_points_on_each_line
    x1 = seg_start[0]
    y1 = seg_start[1]
    x2 = seg_end[0]
    y2 = seg_end[1]
    x3 = line_p1[0]
    y3 = line_p1[1]
    x4 = line_p2[0]
    y4 = line_p2[1]
    num = (x1-x3)*(y3-y4)-(y1-y3)*(x3-x4)
    den = (x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)
    if (den == 0):
        # Line + segment are parallel or coincident
        return None
    t = num / den
    if t < 0 or t > 1:
        return None
    return np.array([x1+t*(x2-x1), y1+t*(y2-y1)])

def segmentCircleIntersection(seg_start, seg_end, circle_center, circle_radius):
    """
    Return None if there is no intersection between the segment and the
    circle. If there is an interesection, return the first intersection with the
    circle.
    """
    # First intersect segment with the normal line passing through center of the circle
    seg_dir = seg_end - seg_start
    seg_dir = seg_dir / np.linalg.norm(seg_dir)
    normal_line_dir = np.array([-seg_dir[1], seg_dir[0]])
    normal_intersection = segmentLineIntersection(seg_start, seg_end,
                                                  circle_center, circle_center + normal_line_dir)
    # Intersection is outside of segment or too far from circle_center
    if normal_intersection is None:
        return None
    dist = np.linalg.norm(circle_center - normal_intersection)
    if dist > circle_radius:
        return None
    # Intersection is inside the circle, now going to the border in opposite direction of seg_dir
    offset_length = math.sqrt(circle_radius ** 2 - dist ** 2)  # Pythagore
    return normal_intersection - offset_length * seg_dir

def linePointProjection(seg_start, seg_end, p):
    e1 = seg_end - seg_start
    e2 = p - seg_start
    return seg_start + e1 * e1.dot(e2) / np.sum(e1**2)

def segmentPointProjection(seg_start, seg_end, p):
    # Step 1: checking that point is on the appropriate side
    e1 = seg_end - seg_start
    e2 = p - seg_start
    if e1.dot(e2) < 0:
        return seg_start
    # Step 2: projecting point on segment
    proj = seg_start + e1 * e1.dot(e2) / np.sum(e1**2)
    # Step 3: checking that point is closer
    if np.linalg.norm(e1) < np.linalg.norm(proj - seg_start):
        return seg_end
    return proj


#setup: import numpy as np ; np.random.seed(0); N = 100000 ; a = np.random.random(N); b = 0.1; c =1.1
#run: log_likelihood(a, b, c)
#from: http://arogozhnikov.github.io/2015/09/08/SpeedBenchmarks.html
import numpy

#pythran export log_likelihood(float64[], float64, float64)
def log_likelihood(data, mean, sigma):
    s = (data - mean) ** 2 / (2 * (sigma ** 2))
    pdfs = numpy.exp(- s)
    pdfs /= numpy.sqrt(2 * numpy.pi) * sigma
    return numpy.log(pdfs).sum()


import numpy as np

class LinearRegressionModel(object):
    """
    This class performs Linear regression on a set of input data
    """
    def __init__(self, featureCount) -> None:
        self.featureCount = featureCount
        self.thetas = np.random.randn(featureCount,1)

    def _hypothesis(self, X):
        """
        X: (m x n) matrix
        thetas: (n x 1) vector
        hypothesis(X) = X dot (theta's)
        """
        return np.dot(X, self.thetas)

    def _computeCost(self, y, prediction):
        """
        y: (m x 1) vector of true y values
        prediction: (m x 1) vector of predicted y values
        cost = (1/2m) * sum((prediction - y)^2)
        """
        m = y.shape[0]
        cost = np.sum(np.square(prediction - y))
        return cost / (2 * m)

    def _calculateNewThetas(self, X, y, prediction):
        """
        X: (m x n) matrix of feature data
        y: (m x 1) vector of true y values
        prediction: (m x 1) vector of predicted y values
        dTheta = sum((prediction-y)^T dot X) / m
        """
        m = y.shape[0]
        dTheta = np.sum(np.dot(np.transpose(prediction - y), X), axis=0) / m
        return dTheta

    def _updateThetas(self, dTheta, alpha):
        """
        dTheta: (n x 1) vector of updated theta values
        alpha: scalar learning rate to scale down value to update thetas
        newThetas = oldThetas - alpha(dTheta)
        """
        self.thetas = self.thetas - alpha * np.reshape(dTheta, (self.featureCount,1))

    def train(self, X_train, Y_train, alpha, iterations, display=1):
        """
        X_train: (m x n) matrix of feature data
        Y_train: (m x 1) vector of true y values
        alpha: scalar learning rate
        iterations: scalar number of iterations Gradient Decent should run
        repeat until converge:{
            1. Make a prediction
            2. Calculate new theta values
            3. Update current theta values
            4. Compute and save cost
                - Cost should decrease with every iteration
        }
        """
        costs = []
        cost = 1
        i = 0
        for i in range(iterations):
            prediction = self._hypothesis(X_train)
            dTheta = self._calculateNewThetas(X_train, Y_train, prediction)
            self._updateThetas(dTheta, alpha)
            cost = self._computeCost(Y_train, prediction)
            costs.append(cost)
            if display:
                if i % 100 == 0:
                    print('Iter: {}, Current loss: {:.4f}'.format(i, cost))
            i += 1
        return costs

    def test(self, X_test, Y_test, display=1):
        """
        X_test: (m x n) matrix of feature values
        Y_test: (m x 1) vector of true y values
        To test our Model{
            1. Make a prediction based off input X_test[i]
            2. Compare to corresponding input Y_test[i]
            3. Compute cost
                -Cost should be low
        }
        """
        prediction = np.apply_along_axis(self._hypothesis, axis=1, arr=X_test)
        for i in range(Y_test.shape[0]):
            cost = self._computeCost(Y_test[i], prediction[i])
            if display:
                print('Predicted: {:.4f} Actual: {:.4f} Cost: {:.4f}'.format(prediction[i,0], Y_test[i,0], cost))


import numpy as np
import matplotlib.pyplot as plt

##### Sigmoid
sigmoid = lambda x: 1 / (1 + np.exp(-x))

x=np.linspace(-10,10,10)

y=np.linspace(-10,10,100)

fig = plt.figure()
plt.plot(y,sigmoid(y),'b', label='linspace(-10,10,100)')

plt.grid(linestyle='--')

plt.xlabel('X Axis')

plt.ylabel('Y Axis')

plt.title('Sigmoid Function')

plt.xticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])
plt.yticks([-2, -1, 0, 1, 2])

plt.ylim(-2, 2)
plt.xlim(-4, 4)

plt.show()
#plt.savefig('sigmoid.png')

fig = plt.figure()

##### TanH
tanh = lambda x: 2*sigmoid(2*x)-1

x=np.linspace(-10,10,10)

y=np.linspace(-10,10,100)

plt.plot(y,tanh(y),'b', label='linspace(-10,10,100)')

plt.grid(linestyle='--')

plt.xlabel('X Axis')

plt.ylabel('Y Axis')

plt.title('TanH Function')

plt.xticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])
plt.yticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])

plt.ylim(-4, 4)
plt.xlim(-4, 4)

plt.show()
#plt.savefig('tanh.png')

fig = plt.figure()

##### ReLU
relu = lambda x: np.where(x>=0, x, 0)

x=np.linspace(-10,10,10)

y=np.linspace(-10,10,1000)

plt.plot(y,relu(y),'b', label='linspace(-10,10,100)')

plt.grid(linestyle='--')

plt.xlabel('X Axis')

plt.ylabel('Y Axis')

plt.title('ReLU')

plt.xticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])
plt.yticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])

plt.ylim(-4, 4)
plt.xlim(-4, 4)

plt.show()
#plt.savefig('relu.png')

fig = plt.figure()

##### Leaky ReLU
leakyrelu = lambda x: np.where(x>=0, x, 0.1*x)

x=np.linspace(-10,10,10)

y=np.linspace(-10,10,1000)

plt.plot(y,leakyrelu(y),'b', label='linspace(-10,10,100)')

plt.grid(linestyle='--')

plt.xlabel('X Axis')

plt.ylabel('Y Axis')

plt.title('Leaky ReLU')

plt.xticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])
plt.yticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])

plt.ylim(-4, 4)
plt.xlim(-4, 4)

plt.show()
#plt.savefig('lrelu.png')

fig = plt.figure()

##### Binary Step
bstep = lambda x: np.where(x>=0, 1, 0)

x=np.linspace(-10,10,10)

y=np.linspace(-10,10,1000)

plt.plot(y,bstep(y),'b', label='linspace(-10,10,100)')

plt.grid(linestyle='--')

plt.xlabel('X Axis')

plt.ylabel('Y Axis')

plt.title('Step Function')

plt.xticks([-4, -3, -2, -1, 0, 1, 2, 3, 4])
plt.yticks([-2, -1, 0, 1, 2])

plt.ylim(-2, 2)
plt.xlim(-4, 4)

plt.show()
#plt.savefig('step.png')

print('done')


import numpy as np

def fourier_series_coefficients(f, T, N, return_complex=True, sample_rate=1000):
    r"""Calculates the first 2*N+1 Fourier series coefficients of a periodic function.

    Given a periodic, function f(t) with period T, this function returns the
    complex coefficients {c0,c1,c2,...}
    such that:

    .. math:: f(t) ~= \sum_{k=-N}^N c_k \cdot e^{i2 \pi kt/T}

    where we define :math: `c_{-n}=\overline{c_n}`

    Refer to `wikipedia <http://en.wikipedia.org/wiki/Fourier_series>`_ for the relation between the real-valued and
    complex valued coeffs.

    Notes
    -----
    This function was copied from
    `stackoverflow <https://stackoverflow.com/questions/4258106/how-to-calculate-a-fourier-series-in-numpy>`_.

    Parameters
    ----------
    f : callable
        the periodic function, a callable like f(t)
    T : float
        the period of the function f, so that f(0)==f(T)
    N : int
        the function will return the first N+1 Fourier coeff.
    return_complex : bool, optional
        defaults to True
    sample_rate : int, optional
        used to tune fast Fourier transform (FFT) algorithm accuracy

    Returns
    -------
    ndarray
        numpy 1-dimensional complex-valued array of size N+1

    """
    # From Shanon theorem we must use a sampling freq. larger than the maximum
    # frequency you want to catch in the signal. (Minimum 1000*N required for sufficient accuracy.)
    f_sample = sample_rate * N

    t = np.linspace(-T/2, T/2, f_sample, endpoint=False)

    y = np.fft.rfft(f(t)) / t.size

    # multiply odd terms by -1 to match SageMath
    y[1::2] *= -1

    # only take the number of coefficients requested
    y = y[:N + 1]

    if return_complex:
        return y
    else:
        y *= 2
        return y[0].real, y[1:].real, -y[1:].imag


import numpy as np
import pickle

def sigmoid(x):
    """
    Applies the sigmoid transformation on a given 1d vector

    Parameters
    ----------
    x : ndarray
        1d Array to be sigmoided

    Returns
    -------
    ndarray
        1d Array of same shape as x containing sigmoided values of x

    Notes
    -----
    σ(x) = 1/(1 + e^-x) = (e^x)/(1 + e^x)
    where:
        σ = sigmoid function
        x = input
        e = Euler's number

    """
    return np.where(x >= 0, 1 / (1 + np.exp(-x)), np.exp(x) / (1 + np.exp(x)))

def softmax(x):
    """
    Applies the softmax transformation on a given 2d vector

    In order to make softmax more stable, x.max is subtracted from each value of x before performing softmax.

    Parameters
    ----------
    x : ndarray
        2d array to be softmaxed

    Returns
    -------
    ndarray
        2d Array of same shape as x containing softmaxed values of x

    Notes
    -----
    σ(x) = (e^x_i)/ Σ (e^x)
    where:
        σ = softmax function
        x_i = ith value of x
        x = input
        e = Euler's number

    """

    x = x - x.max(axis=1, keepdims=True)
    y = np.exp(x)
    return y / y.sum(axis=1, keepdims=True)

def one_hot(labels, categories):
    """
    One hot encodes the labels.

    Parameters
    ----------
    labels : ndarray
        1d array of ints containing labels.

    categories :  int
        the number of categories to encode the labels onto

    Returns
    -------
    ndarray
        2d Array of shape (len(x), categories) containing one hot encoded labels

    """
    y = np.zeros((labels.size, categories))
    y[np.arange(labels.size), labels] = 1
    return y

def batches(x, y, batch_size):
    """
    Yields successive batch_sized chunks of inputs and corresponding outputs from list.

    Parameters
    ----------
    x : list
        list of inputs
    y : list
        list of outputs
    batch_size :
        size of the batches to be yielded.

    Returns
    -------
    list
        batch of inputs of length (batch_size)
    list
        batch of outputs of length (batch_size)

    """

    for i in range(0, len(x), batch_size):
        yield x[i:i + batch_size], y[i:i + batch_size]

def save_model(model, filename='model'):
    """
    Saves an object to file

    Parameters
    ----------
    model : object
        any object to be stored on file
    filename : str
        name of the file the object needs to be stored on. Default: model

    """
    with open(filename, 'wb') as f:
        pickle.dump(model, f, protocol=-1)

def load_model(filename='model'):
    """
    Loads an object from file.

    Parameters
    ----------
    filename: str
        name of the file the object needs to be loaded from. Default: model

    Returns
    -------
        object that was stored on the file
    """
    with open(filename, 'rb') as f:
        return pickle.load(f)


import numpy as np

def makeMoffat(size , fwhm =3 , b = 2.5  , center = None):

    #x = np.arange(0, size, 1, float)
    #y = x[:,np.newaxis]
    x = np.linspace(0.5, size-.5 , size)
    y = x[:,np.newaxis]

    if center is None:
        x0 = y0 = size / 2.
    else:
        x0 = center[0]
        y0 = center[1]

    a = fwhm/(2.*(2**(1./b)-1)**.5)
    r = ((x-x0)**2./a**2. + (y-y0)**2./a**2.)**.5

    return ((b - 1.)*(1. + r**2.)**(-1.*b))/(np.pi*(a**2.))

def makeGaussian(size , FWHM  , e = 0 , center = None):

    f = FWHM/(2.35482)
    #f = FWHM/(2.*np.sqrt(2.*np.log(2.)))
    #x = np.arange(0, size, 1, float)
    #y = x[:,np.newaxis]
    x = np.linspace(0.5, size-.5 , size)
    y = x[:,np.newaxis]

    if center is None:
        x0 = y0 = size / 2.
    else:
        x0 = center[0]
        y0 = center[1]

    r = ((x-x0)**2. + ((y-y0)**2.)*(1. + np.abs(e))**2./(1. - np.abs(e))**2.)**.5
    factor = 1./(2.*np.pi*f**2.)
    return factor*np.exp((-1.*r**2.)/(2.*f**2.))

if __name__ == "__main__":
    print 'profile main'


import math
import numpy as np
from scipy import ndimage

def gauss2d(sigma, fsize):
  """
  Args:
    sigma: width of the Gaussian filter
    fsize: dimensions of the filter

  Returns:
    g: *normalized* Gaussian filter
  """

  g = np.zeros((fsize, 1))
  offset = fsize // 2
  for i in range(-offset, -offset + fsize):
     g[i + offset] = 1/(np.sqrt(2*np.pi) * sigma) * np.exp(-(i**2) / 2*sigma**2) \

  g = g / g.sum()

  return g

def createfilters():
  """
  Returns:
    fx, fy: filters as described in the problem assignment
  """

  g = gauss2d(0.9, 3)
  d_x = np.array([-1, 0, 1])
  d_x = d_x[np.newaxis, :]
  fx = g.dot(d_x)
  fy = d_x.T.dot(g.T)

  return fx, fy

def filterimage(I, fx, fy):
  """ Filter the image with the filters fx, fy.
  You may use the ndimage.convolve scipy-function.

  Args:
    I: a (H,W) numpy array storing image data
    fx, fy: filters

  Returns:
    Ix, Iy: images filtered by fx and fy respectively
  """

  Ix = ndimage.convolve(I, fx, mode='constant', cval=0.0)
  Iy = ndimage.convolve(I, fy, mode='constant', cval=0.0)

  return Ix, Iy

def detectedges(Ix, Iy, thr):
  """ Detects edges by applying a threshold on the image gradient magnitude.

  Args:
    Ix, Iy: filtered images
    thr: the threshold value

  Returns:
    edges: (H,W) array that contains the magnitude of the image gradient at edges and 0 otherwise
  """

  magitude = np.sqrt(Ix**2 + Iy**2)
  edges= np.where(magitude >= thr, magitude, 0)

  return edges

def nonmaxsupp(edges, Ix, Iy):
  """ Performs non-maximum suppression on an edge map.

  Args:
    edges: edge map containing the magnitude of the image gradient at edges and 0 otherwise
    Ix, Iy: filtered images

  Returns:
    edges2: edge map where non-maximum edges are suppressed
  """
  m, n = edges.shape
  edges2 = np.zeros((m, n))
  for i in range(1, m-1):
        for j in range(1, n-1):
            theta = np.arctan(Iy[i, j] / Ix[i, j]) * 180 / np.pi
  # handle top-to-bottom edges: theta in [-90, -67.5] or (67.5, 90]
            if (-90 <= theta <= -67.5) or (67.5 < theta <= 90):
                  q, r = edges[i-1, j], edges[i+1, j]
  # handle left-to-right edges: theta in (-22.5, 22.5]
            elif -22.5 < theta <= 22.5:
                  q, r = edges[i, j-1], edges[i, j+1]
  # handle bottomleft-to-topright edges: theta in (22.5, 67.5]
            elif 22.5 < theta <= 67.5:
                  q, r = edges[i+1, j-1], edges[i-1, j+1]
  # handle topleft-to-bottomright edges: theta in [-67.5, -22.5]
            elif -67.5 <= theta <= -22.5:
                  q, r = edges[i-1, j-1], edges[i+1, j+1]

            if (edges[i, j] >= q) and (edges[i, j] >= r):
                  edges2[i, j] = edges[i, j]
  return edges2


from numpy import array, zeros, diag, diagflat, dot
from sympy import Eq, Expr, Symbol

def jacobi(A, b, N=25, x=None):
    """Solves the equation Ax=b via the Jacobi iterative method."""
    # Create an initial guess if needed
    if x is None:
        x = zeros(len(A[0]))

    # Create a vector of the diagonal elements of A
    # and subtract them from A
    D = diag(A)
    R = A - diagflat(D)

    # Iterate for N times
    for i in range(N):
        x = (b - dot(R,x)) / D
    return x

def seidel(a, x, b):
    # Finding length of a(3)
    n = len(a)
    # for loop for 3 times as to calculate x, r , z
    for j in range(0, n):
        # temp variable d to store b[j]
        d = b[j]

        # to calculate respective xi, yi, zi
        for i in range(0, n):
            if (j != i):
                d -= a[j][i] * x[i]
        # updating the value of our solution
        x[j] = d / a[j][j]
    # returning our updated solution
    return x

def eulers_method(x0, xf, num, slope_equation: Expr, y_: Symbol, x_: Symbol, initial_slope: float):
    delta = (xf - x0) / num

    y_explicits = [slope_equation.subs({y_: initial_slope, x_: x0})]
    y_implicits = [slope_equation.subs({y_: initial_slope, x_: x0})]
    for i in range(num):
        slope_e = slope_equation.subs({
            y_: y_explicits[-1],
            x_: x0 + delta * i,
        })
        y_explicits.append(y_explicits[-1] + delta * slope_e)

    for i in range(num):
        y_implicits.append(y_implicits[-1] + delta * -1)

if __name__ == '__main__':
    # int(input())input as number of variable to be solved
    n = 3
    a = []
    b = []
    # initial solution depending on n(here n=3)
    x = [0, 0, 0]
    a = [[4, 1, 2], [3, 5, 1], [1, 1, 3]]
    b = [4, 7, 3]
    print(x)

    # loop run for m times depending on m the error value
    for i in range(0, 25):
        x = seidel(a, x, b)
        # print each time the updated solution
        print(x)

    A = array([[2.0, 1.0], [5.0, 7.0]])
    b = array([11.0, 13.0])
    guess = array([1.0, 1.0])

    sol = jacobi(A, b, N=25, x=guess)


import numpy as np

def flat_ind_so3(l, m, n):
    """
    The SO3 spectrum consists of matrices f_hat^l of size (2l+1, 2l+1) for l=0, ..., L_max.
    If we flatten these matrices and stack them, we get a big vector where the element f_hat^l_mn has a certain
     flat index. This function computes that index.

    The number of elements up to and including order L is
    N_L = sum_{l=0}^L (2l+1)^2 = 1/3 (2 L + 1) (2 L + 3) (L + 1)

    Element (l, m, n) has N_l elements before it from previous blocks, and in addition several elements in the current
    block. The number of elements in the current block, before (m, n) is determined as follows.
    First we associate with indices m and n (running from -l to l) with their zero-based index:
    m' = m + l
    n' = n + l
    The linear index of this pair (m', n') is
    i = m' * w + n'
    where w is the width of the matrix, i.e. w = 2l + 1

    The final index of (l, m, n) is N_L + i

    :param l, m, n: spectral indices
    :return: index of (l, m, n) in flat vector
    """
    assert np.abs(m) <= l
    assert np.abs(n) <= l

    if l == 0:
        return 0  # The N_L formula only works for l > 0, so we special case this

    L = l - 1
    N_L = ((2 * L + 1) * (2 * L + 3) * (L + 1)) // 3
    i = (m + l) * (2 * l + 1) + (n + l)
    return N_L + i

def flat_ind_zp_so3(l, m, n, b):
    """
    The SO3 spectrum consists of matrices f_hat^l of size (2l+1, 2l+1) for l=0, ..., L_max = b - 1.
    These can be stored in a zero-padded array A of shape (b, 2b, 2b) with axes l, m, n with zero padding around
     the center of the last two axes. If we flatten this array A we get a vector v of size 4b^3.
    This function gives the flat index in this array v corresponding to element (l, m, n)

    The zero-based 3D index of (l, m, n) in A is (l, b + m, b + n).
    The corresponding flat index is i = l * 4b^2 + (b + m) * 2b + b + n

    :param l, m, n: spectral indices
    :return: index of (l, m, n) in flat zero-padded vector
    """
    return l * 4 * (b ** 2) + (b + m) * 2 * b + b + n

def list_to_flat(f_hat_list):
    """
    A function on the SO(3) spectrum can be represented as:
     1. a list f_hat of matrices f_hat[l] of size (2l+1, 2l+1)
     2. a flat vector which is the concatenation of the flattened matrices
     3. a zero-padded tensor with axes l, m, n.

    This function converts 1 to 2.

    :param f_hat: a list of matrices
    :return: a flat vector
    """
    return np.hstack([a.flat for a in f_hat_list])

def num_spectral_coeffs_up_to_order(b):
    """
    The SO(3) spectrum consists of matrices of size (2l+1, 2l+1) for l=0, ..., b - 1.
    This function computes the number of elements in a spectrum up to (but excluding) b - 1.

    The number of elements up to and including order L is
    N_L = sum_{l=0}^L (2l+1)^2 = 1/3 (2 L + 1) (2 L + 3) (L + 1)

    :param b: bandwidth
    :return: the number of spectral coefficients
    """
    L_max = b - 1
    assert L_max >= 0
    return ((2 * L_max + 1) * (2 * L_max + 3) * (L_max + 1)) // 3

def flat_to_list(f_hat_flat, b):
    """
    A function on the SO(3) spectrum can be represented as:
     1. a list f_hat of matrices f_hat[l] of size (2l+1, 2l+1)
     2. a flat vector which is the concatenation of the flattened matrices
     3. a zero-padded tensor with axes l, m, n.

    This function converts 2 to 1.

    :param f_hat: a flat vector
    :return: a list of matrices
    """
    f_hat_list = []
    start = 0
    for l in range(b):
        f_hat_list.append(f_hat_flat[start:start + (2 * l + 1) ** 2].reshape(2 * l + 1, 2 * l + 1))
        start += (2 * l + 1) ** 2
    return f_hat_list


# coding:utf-8
#

import numpy as np
from scipy import stats

def calc_statistics(x):
    n = x.shape[0]  # 样本个数

    # 手动计算
    m = 0
    m2 = 0
    m3 = 0
    m4 = 0
    for t in x:
        m += t
        m2 += t*t
        m3 += t**3
        m4 += t**4
    m /= n
    m2 /= n
    m3 /= n
    m4 /= n

    mu = m
    sigma = np.sqrt(m2 - mu*mu)
    skew = (m3 - 3*mu*m2 + 2*mu**3) / sigma**3
    kurtosis = (m4 - 4*mu*m3 + 6*mu*mu*m2 - 4*mu**3*mu + mu**4) / sigma**4 - 3
    print('手动计算均值、标准差、偏度、峰度：', mu, sigma, skew, kurtosis)

def calc_statistics2(x):
    # 使用系统函数验证
    mu = np.mean(x, axis=0)
    sigma = np.std(x, axis=0)
    skew = stats.skew(x)
    kurtosis = stats.kurtosis(x)
    print('函数库计算均值、标准差、偏度、峰度：', mu, sigma, skew, kurtosis)

if __name__ == '__main__':
    d = np.random.randn(5)
    print(d)
    print(d.shape)
    calc_statistics(d)
    calc_statistics2(d)


#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function, division

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

# https://en.wikipedia.org/wiki/B%C3%A9zier_curve
# https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-837-computer-graphics-fall-2012/lecture-notes/MIT6_837F12_Lec01.pdf
# https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-837-computer-graphics-fall-2012/lecture-notes/MIT6_837F12_Lec02.pdf

def linear_bezier(p0, p1, ts):

    tsm = 1-ts

    pts = p0[None,:]*tsm[:,None] \
            + p1[None,:]*ts[:,None]

    return pts

def quadratic_bezier(p0, p1, p2, ts):

    pts = p0[None,:]*((1-ts)*(1-ts))[:,None] \
            + p1[None,:]*2*((1-ts)*ts)[:,None] \
            + p2[None,:]*(ts*ts)[:,None]

    return pts

def cubic_bezier(p0, p1, p2, p3, ts):

    pts = p0[None,:]*((1-ts)**3)[:,None] \
            + p1[None,:]*3*(((1-ts)**2)*ts)[:,None] \
            + p2[None,:]*3*((1-ts)*(ts**2))[:,None] \
            + p3[None,:]*(ts**3)[:,None]

    return pts

def cubic_bezier_in_matrix_form(ptc, ts):

    '''
    pt - n x dim
    ts - 1d - [0 ... 1]
    '''

    G = ptc.T                                               # Geometry (control points)
    B = np.array([
        [ 1,-3, 3,-1],
        [ 0, 3,-6, 3],
        [ 0, 0, 3,-3],
        [ 0, 0, 0, 1]])                                     # Spline Basis - Bernstein
    T = np.vstack( (np.ones_like(ts), ts, ts**2, ts**3) )   # Power basis

    Q = np.dot(G,np.dot(B,T))                               # Q = GBT

    return Q.T

def cubic_bspline(ptc, ts):

    '''
    pt - 4 x dim
    ts - 1d - [0 ... 1]
    '''

    G = ptc.T                                               # Geometry (control points)
    B = np.array([
        [ 1,-3, 3,-1],
        [ 4, 0,-6, 3],
        [ 1, 3, 3,-3],
        [ 0, 0, 0, 1]])/6.0                                 # Spline Basis - Bernstein
    T = np.vstack( (np.ones_like(ts), ts, ts**2, ts**3) )   # Power basis

    Q = np.dot(G,np.dot(B,T))                               # Q = GBT

    return Q.T

def cubic_bsplines(ptc, ts):

    '''
    pt - n x dim
    ts - 1d - [0 ... 1]
    '''

    n_dim = ptc.shape[1]
    n_ts  = len(ts)

    B = np.array([
        [ 1,-3, 3,-1],
        [ 4, 0,-6, 3],
        [ 1, 3, 3,-3],
        [ 0, 0, 0, 1]])/6.0                                 # Spline Basis - Bernstein
    T = np.vstack( (np.ones_like(ts), ts, ts**2, ts**3) )   # Power basis

    nw = len(ptc)-3
    # print(nw)
    ps = []
    for i in range(nw):
        Gi = ptc[i:i+4].T                  # Geometry (control points)
        # print(Gi)
        Qi = np.dot(Gi,np.dot(B,T))      # Q = GBT  [ dim x 4]x[4x4]x[4xlen(ts)] ==> [dim x len(ts)]
        ps.append(Qi.T)

    return np.vstack(ps)

if __name__=='__main__':

    ts = np.linspace(0,1,100)

    ps = np.array([[0,1], [1,0]])
    #
    ptbz = linear_bezier(ps[0], ps[1], ts)

    plt.figure()
    ax = plt.subplot(1,1,1)
    ax.plot(ps[:,0], ps[:,1], 's-', label='control points')
    ax.plot(ptbz[:,0], ptbz[:,1], label='bezier curve')
    ax.axis('equal')
    ax.grid()
    ax.legend()

    ps = np.array([[0,1], [0.2,0], [1,0]])
    #
    ptbz = quadratic_bezier(ps[0], ps[1], ps[2], ts)

    plt.figure()
    ax = plt.subplot(1,1,1)
    ax.plot(ps[:,0], ps[:,1], 's-', label='control points')
    ax.plot(ptbz[:,0], ptbz[:,1], label='bezier curve')
    ax.axis('equal')
    ax.grid()
    ax.legend()

    ps = np.array([[0,1], [0.5,1], [0.5,0], [1,0]])
    #
    ptbz = cubic_bezier(ps[0], ps[1], ps[2], ps[3], ts)

    plt.figure()
    ax = plt.subplot(1,1,1)
    ax.plot(ps[:,0], ps[:,1], 's-', label='control points')
    ax.plot(ptbz[:,0], ptbz[:,1], label='bezier curve')
    ax.axis('equal')
    ax.grid()
    ax.legend()

    ps = np.array([[0,1], [0.5,1], [0.5,0], [1,0]])
    #
    ptbz = cubic_bezier_in_matrix_form(ps, ts)
    ptbs = cubic_bspline(ps, ts)

    plt.figure()
    ax = plt.subplot(1,1,1)
    ax.plot(ps[:,0], ps[:,1], 's-', label='control points')
    ax.plot(ptbz[:,0], ptbz[:,1], label='bezier curve')
    ax.plot(ptbs[:,0], ptbs[:,1], label='b-spline curve')
    ax.axis('equal')
    ax.grid()
    ax.legend()

    ps = np.array([
        [0,1],
        [0,1],
        [0.5,1],
        [0.5,0],
        [1,0],
        [1,0],
        # [2,1],
        # [3,0],
        # [4,1],
        # [4,1],
        ])
    #
    ptbs = cubic_bsplines(ps, ts)
    # print(ptbs)

    plt.figure()
    ax = plt.subplot(1,1,1)
    ax.plot(ps[:,0], ps[:,1], 's-', label='control points')
    # ax.plot(ptbz[:,0], ptbz[:,1], label='bezier curve')
    ax.plot(ptbs[:,0], ptbs[:,1], label='b-spline curve')
    ax.axis('equal')
    ax.grid()
    ax.legend()

    ''' show and close all together '''
    for i in plt.get_fignums():
        plt.figure(i).canvas.mpl_connect('close_event', lambda event: plt.close('all') )
    plt.show()


# -*- coding: utf-8 -*-#
'''
# Name:         CrossEntropy
# Description:  CrossEntropy 交叉熵
# Author:       super
# Date:         2020/5/7
'''

import numpy as np
import matplotlib.pyplot as plt

def target_function2(a,y):
    p1 = y * np.log(a)
    p2 = (1-y) * np.log(1-a)
    y = -p1 - p2
    return y

if __name__ == '__main__':
    err = 1e-2  # avoid invalid math caculation
    a = np.linspace(0+err,1-err)
    y = 0
    z1 = target_function2(a,y)
    y = 1
    z2 = target_function2(a,y)
    p1, = plt.plot(a,z1)
    p2, = plt.plot(a,z2)
    plt.grid()
    plt.legend([p1,p2],["y=0","y=1"])
    plt.xlabel("a")
    plt.ylabel("Loss")
    plt.show()


import numpy as np
import matplotlib.pyplot as plt

def f_x(x):
    return np.power(x + 2, 2) - 16 * np.exp(-np.power((x - 2), 2))

#Vejamos a sua forma no intervalo [-8, 8]
def main_plot():
    x = np.arange(-8, 8, 0.001)
    y = map(lambda u: f_x(u), x)
    plt.plot(x, list(y))
    plt.title('Cost function f(x)')

plt.grid(True)
main_plot()
plt.show()

def grad_f_x(x):
    return (2 * x - 4) - 16 * (-2 * x + 4) * np.exp(-np.power(x - 2, 2))

def gradient_descent(x0, func, grad):
    #
    precision = 0.001
    #Learning rate
    learning_rate = 0.0001
    #
    max_iter = 10000
    x_new = x0
    res = []
    for i in range(max_iter):
        x_old = x_new
        #Vamos usar B = 1
        x_new = x_old - learning_rate * grad(x_old)
        f_x_new = func(x_new)
        f_x_old = func(x_old)
        res.append([x_new, f_x_new])
        #print(f_x_new - f_x_old)
        if(abs (f_x_new - f_x_old) < precision):
            print("Precisao %f alcancada:" % (f_x_new - f_x_old))
            return np.array(res)
    print("Iteraccao maxima alcancada")
    return np.array(res)

x0 = -8
res = gradient_descent(x0, f_x, grad_f_x)
plt.plot(res[:,0], res[:, 1], '+')
main_plot()
plt.show()

X = np.arange(-10, 10, 1)
Y = np.arange(-10, 10, 1)
U, V = np.meshgrid(X, Y)

fig, ax = plt.subplots()
q = ax.quiver(X, Y, U, V)
ax.quiverkey(q, X=0.3, Y=1.1, U=20,label='Quiver key, length = 10', labelpos='E')

plt.show()

img = np.array([[88, 93, 42, 25, 36, 14, 59, 46, 77, 13, 52, 58],
       [43, 47, 40, 48, 23, 74, 12, 33, 58, 93, 87, 87],
       [54, 75, 79, 21, 15, 44, 51, 68, 28, 94, 78, 48],
       [57, 46, 14, 98, 43, 76, 86, 56, 86, 88, 96, 49],
       [52, 83, 13, 18, 40, 33, 11, 87, 38, 74, 23, 88],
       [81, 28, 86, 89, 16, 28, 66, 67, 80, 23, 95, 98],
       [46, 30, 18, 31, 73, 15, 90, 77, 71, 57, 61, 78],
       [33, 58, 20, 11, 80, 25, 96, 80, 27, 40, 66, 92],
       [13, 59, 77, 53, 91, 16, 47, 79, 33, 78, 25, 66],
       [22, 80, 40, 24, 17, 85, 20, 70, 81, 68, 50, 80]])


#import library we need
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')

#read our dataset
train = pd.read_csv('Data-Train.csv')
test = pd.read_csv('Data-Test.csv')

#change our dataset to matrix and transpose them
x_train = np.transpose(np.asmatrix(train['x']))
y_train = np.transpose(np.asmatrix(train['y']))

x_test = np.transpose(np.asmatrix(test['x']))
y_test = np.transpose(np.asmatrix(test['y']))

#add x0 to our data
ones = np.ones((x_train.shape[0],1))
x_new = np.append(ones, x_train, 1)

#creat our m , n  and theta fill with 1 (2*1)
m, n = np.shape(x_new)
theta = np.ones((1,n))
theta = np.transpose(theta)
theta_new = theta

#choose our iteration & Learning Rate

itr= 200
alpha = 0.00004

#calculate our Gradient Descent (Stochastic)
LSM = np.zeros((itr,2))
d = 0

while d < itr:
    for i in range(0, m):
        for j in range(0, n):
            theta_new[j] = theta[j] - (alpha * ((x_new[i]*theta - y_train[i])*x_new[i, j]))

        theta = theta_new

    y_pred = theta[0] + theta[1]*x_train.T

    Loop_LSM = 0
    for i in range(0, m):
        Loop_LSM += (y_train.A1[i] - y_pred.A1[i])**2
    Loop_LSM = Loop_LSM/(2*m)
    LSM[d,0] = d
    LSM[d,1] = Loop_LSM

    d += 1

print('Number of iteration : ',itr)
print('Learning Rate : ',alpha)
print('Theta[0] = ', theta[0])
print('Theta[1] = ', theta[1])

#calculate our h(theta) or y_predection for both data
y_pred_train = theta[0] + theta[1]*x_train.T

y_pred_test = theta[0] + theta[1]*x_test.T

#calculate our test data cost function
train_LSM = 0
m = y_train.shape[0]

for i in range(m):
    train_LSM += ((y_train.A1[i] - y_pred_train.A1[i])**2)
train_LSM = train_LSM/(2*m)

print("Train Least Squared Error : ", train_LSM)

#calculate our test data cost function
test_LSM = 0
m = y_test.shape[0]

for i in range(m):
    test_LSM += ((y_test.A1[i] - y_pred_test.A1[i])**2)
test_LSM = test_LSM/(2*m)

print("Test Least Squared Error : ", test_LSM)

#plot our data and Gradient
fig, plots = plt.subplots(2,2)
fig.suptitle(' Stochastic Gradient Descent')

plots[0,0].scatter(train['x'],train['y'],color = "green", s = 0.1, label = 'Train data')
plots[0,0].plot(x_train.T.A1, y_pred_train.A1, color = "black")
plots[0,0].set(xlabel='X', ylabel='Y')
plots[0,0].legend(loc = 'upper left')

plots[0,1].scatter(test['x'],test['y'],color = "red", s = 0.1, label = 'Test data')
plots[0,1].plot(x_train.T.A1, y_pred_train.A1, color = "black")
plots[0,1].set(xlabel='X')
plots[0,1].legend(loc = 'upper left')

plots[1,0].plot(LSM.T[0], LSM.T[1], color = "black")
plots[1,0].set(xlabel='Iteration', ylabel='LSM')
plots[1,0].legend(loc = 'upper left')

plt.show()

Linear Regression with Stochastic Gradient Descent/GD Stochastic.py


"""Symbolic Curvature Utilities

This module provides functions for computing components of various curvature-related
tensors, such as Christoffel symbols, Riemann Tensor, and Ricci Tensor. While the
sympy module does offer analogous functions in the sympy.diffgeom subpackage, there is
an obnoxious bug in that derivatives must be take with respect to coordinate functions
as opposed to the identical symbol. We remediate that shortcoming here, allowing for
maximal interoperability with the other sympy utilies for solving differential equations
and computing derivatives.
"""
import itertools

import sympy
from sympy import Derivative as D, Rational, Expr

from pystein import utilities
from pystein.metric import Metric

def christoffel_symbol_component(lam: int, mu: int, nu: int, metric: Metric) -> Expr:
	"""Compute a component of the Chrisoffel symbol for a particular metric corresponding to

		G_mn^l = 1/2 g^ms (p_m g_ns + p_n g_sm - p_s g_mn)

	Args:
		lam:
			int, Upper index of Christoffel symbol
		mu:
			int, lower left index of Christoffel symbol
		nu:
			int, lower right index of Christoffel symbol
		metric:
			Metric

	Returns:
		Expression of the G_mn^l
	"""
	M = metric.matrix
	I = metric.inverse.matrix
	coord_symbols = metric.coord_system.base_symbols()
	dim = len(coord_symbols)
	return Rational(1, 2) * sum([I[lam, sig] * (D(M[nu, sig], coord_symbols[mu]) +
												D(M[sig, mu], coord_symbols[nu]) -
												D(M[mu, nu], coord_symbols[sig])) for sig in range(dim)])

def riemann_tensor_component(rho: int, sig: int, mu: int, nu: int, metric: Metric, simplify_intermediate: bool = False) -> Expr:
	"""Compute a component of the Riemann Tensor for a particular metric corresponding to

		R^r_smn = p_m G_ns^r - p_n G_ms^r + G_ml^r G_ns^l - G_nl^r G_ms^l

	Args:
		rho:
			int, Upper index of the Riemann Tensor
		sig:
			int, lower left index of Riemann Tensor
		mu:
			int, lower middle index of Riemann Tensor
		nu:
			int, lower right index of Riemann Tensor
		metric:
			Metric

	Returns:
		Expression of the R^r_smn
	"""

	def G(l, m, n):
		"""Shorthand"""
		c = christoffel_symbol_component(l, m, n, metric)
		return sympy.simplify(c) if simplify_intermediate else c

	coord_symbols = metric.coord_system.base_symbols()
	dim = len(coord_symbols)
	return D(G(rho, nu, sig), coord_symbols[mu]) - \
		   D(G(rho, mu, sig), coord_symbols[nu]) + \
		   sum([G(rho, mu, lam) * G(lam, nu, sig) for lam in range(dim)]) - \
		   sum([G(rho, nu, lam) * G(lam, mu, sig) for lam in range(dim)])

def ricci_tensor_component(mu: int, nu: int, metric: Metric, simplify_intermediate: bool = False):
	"""Compute a component of the Ricci Tensor for a particular metric corresponding to

		R_mn = R_m^l_ln

	Args:
		mu:
			int, lower left index of Ricci Tensor
		nu:
			int, lower right index of Ricci Tensor
		metric:
			Metric

	Returns:
		Expression of the R_mn
	"""

	def R(r, s, m, n):
		"""Shorthand"""
		r = riemann_tensor_component(r, s, m, n, metric=metric, simplify_intermediate=simplify_intermediate)
		return sympy.simplify(r) if simplify_intermediate else r

	return sum([R(lam, mu, lam, nu) for lam in range(metric.coord_system.dim)])

def ricci_scalar(metric: Metric, simplify_intermediate: bool = False) -> Expr:
	"""Compute the Ricci Scalar for a particular metric corresponding to

		R = R^l_l = g^mn R_mn

	Args:
		metric:
			Metric

	Returns:
		Expression of R
	"""
	I = metric.inverse.matrix
	return sum(sum(I[lam, rho] * ricci_tensor_component(rho, lam, metric=metric, simplify_intermediate=simplify_intermediate) for rho in range(metric.coord_system.dim)) for lam in range(metric.coord_system.dim))

def einstein_tensor_component(mu: int, nu: int, metric: Metric):
	"""Compute a component of the Einstein Tensor for a particular metric corresponding to

		G_mn = R_mn - (1/2) R g_mn

	Args:
		mu:
			int, lower left index of Einstein Tensor
		nu:
			int, lower right index of Einstein Tensor
		metric:
			Metric

	Returns:
		Expression of the G_mn
	"""
	return ricci_tensor_component(mu, nu, metric) - Rational(1, 2) * ricci_scalar(metric) * metric.matrix[mu, nu]

def compute_components(metric: Metric, non_trivial: bool = True):
	N = len(metric.coord_system.base_symbols())
	christoffels = [((m, n, l), utilities.full_simplify(christoffel_symbol_component(l, m, n, metric=metric))) for l, m, n in itertools.product(range(N), range(N), range(N))]
	riemanns = [((m, n, r, s), utilities.full_simplify(riemann_tensor_component(r, s, m, n, metric=metric))) for m, n, r, s in
				itertools.product(range(N), range(N), range(N), range(N))]
	riccis = [((m, n), utilities.full_simplify(ricci_tensor_component(m, n, metric=metric))) for m, n in itertools.product(range(N), range(N))]

	if non_trivial:
		christoffels = [x for x in christoffels if x[1]]
		riemanns = [x for x in riemanns if x[1]]
		riccis = [x for x in riccis if x[1]]

	return christoffels, riemanns, riccis

def display_components(cps):
	label_names = ['\\mu', '\\nu', '\\rho', '\\sigma'][:len(cps)]
	exprs = [c[1] for c in cps]
	labels = [c[0] for c in cps]
	utilities.concat_latex(exprs, labels, label_names, display=True)


import sympy
import time

## From Bent: 2008_2 Computer Bonus
## Computer Bonus
##
## Find the smallest integer greater than 7 which has the property that
## the sum of all the integral divisors of its cube equals a perfect
## square. One and N are both divisors of N.
##
## -- Pierre de Fermat (circa 1650)
##
##

max_n = 1_000_000
solutions = []

t1=time.time()
for n in range(8,max_n+1):
    x=sympy.factorint(n*n*n)
    s=1
    for k in x:
        t=1
        for m in range(x[k]):
            t=k*t+1
        s=s*t
    # s = sum of the factors of the cube of n
    # Check to see if it is a perfect square
    c=round(s**(1/2))
    if c*c == s:
        print("Solution = ",n,"   Time = ",time.time()-t1)
        solutions.append(n)
t2=time.time()
print("Total elapsed time = ",t2-t1)
print("Largest value tested = ",max_n)
print("Number of solutions = ",len(solutions))
print("Solution set:")
print(solutions)


# numpy provide trigonometric ufunc sin(), cos(), tan()
# that takes values in radians and produce corresponding sin, cos, tan values
import numpy as np
x = np.sin(np.pi/2)            # np.sin function does operation sin() on values in array
print(x)

y = np.array([np.pi/2, np.pi/3, np.pi/4, np.pi/5])
z = np.sin(y)                  # putting whole array in sin() function
print(z)

a = np.array([360, 540, 720, 900])
b = np.deg2rad(a)                      # converting degree values to radian
print(b)

c = np.array([1, 2, 3, 4])
d = np.rad2deg(c)                      # converting radian values to degree
print(d)

e = np.array([1.0, 0.1, 1, -1])                     # converting sin, cos, tan values into radian values
f = np.arcsin(e)
print(f)

base = 3
perp = 4
h = np.hypot(base, perp)                     # finding hypotenuse length of pythagoras triangle
print(h)

Python/Numpy/numpy 41 - ufunc trigonometric function.py


import numpy as np
from math import *
import matplotlib.pyplot as plt

''' The problem is: dy/dt = f(t,y).'''

def f(t, y):
    return 0.5*y

# a,b: edges of the interval, w0:ititial value, h:step
def PredictorCorrector(a, b, w0, h):
    n = ceil((b - a) / h)

    w, t = np.zeros(n+1), np.zeros(n+1)
    w[0], t[0] = w0, a

    for i in range(3):
        k1 = h * f(t[i], w[i])
        k2 = h * f(t[i] + h / 2, w[i] + k1 / 2)
        k3 = h * f(t[i] + h / 2, w[i] + k2 / 2)
        k4 = h * f(t[i] + h, w[i] + k3)
        w[i+1] = w[i] + 1 / 6 * (k1 + 2 * k2 + 2 * k3 + k4)
        t[i+1] = t[i] + h

    for i in range(3, n):
        #Predictor
        w[i+1] = w[i] + h/24*(55*f(t[i], w[i]) - 59*f(t[i-1], w[i-1]) + 37*f(t[i-2], w[i-2]) - 9*f(t[i-3], w[i-3]))
        #Corrector
        w[i+1] = w[i] + (h/24)*(9*f(t[i+1], w[i+1]) + 19*f(t[i], w[i]) - 5*f(t[i-1], w[i-1]) + f(t[i-2], w[i-2]))

        t[i+1] = t[i] + h

    return w, t

if __name__ == '__main__':

    a, b, w0, h = 0, 2, 1, 0.2

    print("\n", PredictorCorrector(a, b, w0, h)[0])

    # Visualization
    x = np.linspace(0, 2, 100)

    y = np.zeros(len(x))

    for j in range(len(x)):
        y[j] = exp(0.5*x[j])

    plt.plot(x, y, color="black", label="Solution")
    plt.plot(PredictorCorrector(a, b, w0, h)[1], PredictorCorrector(a, b, w0, h)[0], label="Predictor-Corrector")
    plt.xlabel("t")
    plt.ylabel("y")
    plt.legend()
    plt.show()


# requirements.txt:
# pyro 1.6.0
# torch 1.8.0

import numpy as np
import matplotlib.pyplot as plt

def rosenbrock(x,y):
    return (1-x)**2 + 100* (y-x*x)**2

def viz(xspace=(-30, 30, 100), yspace=(-300, 800, 100), trajectory=None):
    x = np.linspace(*xspace)
    y = np.linspace(*yspace)
    X, Y = np.meshgrid(x, y)
    Z = rosenbrock(X,Y)

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

    ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
                    cmap='viridis', edgecolor='none')
    if trajectory is not None:
        ax.scatter(*trajectory)
    plt.show()
viz()

# sanity check for the analytical solution.
epsilon = 1e-8
minimum = rosenbrock(np.array([1-epsilon,1,1+epsilon]),np.array([1-epsilon,1,1+epsilon]))
assert minimum[0] > minimum[1] and minimum[2] > minimum[1]

# SGD
def gradient_descent(x0=0, y0=0, lr=1e-3, n_step=int(1e4), momentum=0.0):
    import torch
    import torch.optim as optim
    x = torch.zeros([1]) + x0
    y = torch.zeros([1]) + y0
    x.requires_grad_(True)
    y.requires_grad_(True)

    optimizer = optim.SGD([x,y], lr=lr, momentum=momentum)
    ts = ([],[],[])
    for i in range(n_step):
        optimizer.zero_grad()
        z = rosenbrock(x,y)
        if i % 200==0:
            if i%1000==0:
                print(f"z = {z.detach().numpy()[0]}")
            ts[0].append(x.detach().numpy()[0])
            ts[1].append(y.detach().numpy()[0])
            ts[2].append(z.detach().numpy()[0])
        z.backward()
        # print(f"x = {x[0]} - {optimizer.param_groups[0]['lr']} * {x.grad[0]}")
        optimizer.step()
        # print(f" = {x[0]}")
        # print("")
    return x[0],y[0],ts

# routine gradient descent
x,y,ts = gradient_descent()
print(f"final result x={x:.3f}, y={y:.3f}")
viz( (0,1,100), (0,1,100), trajectory=ts)

# gradient descent with harder initialization, smaller learning rate, and momentum.
x,y,ts = gradient_descent(x0=3, y0=-2, lr=1e-5, momentum=0.99)
print(f"final result x={x:.3f}, y={y:.3f}")
viz( (0,3,100), (-2,5,100), trajectory=ts)


# -*- coding: utf-8 -*-
"""L04_Welliton.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1Z4mLm2egCuODcKhluqWbwYHbnOIjB_y7

**Welliton Leal - Aula de Exercícios 01**

***N-dimensional Arrays***
"""

import numpy as np #importa biblioteca e define atalho pra chama-la
lst = [[1, 2, 3], [4, 5, 6]] #cria lista com duas linhas
ary2d = np.array(lst)  #armazena em um vetor de 2 dimensões
ary2d

ary2d.dtype #exibe o tipo

"""***Array Construction Routines***"""

float32_ary = ary2d.astype(np.float32) #muda o tipo
float32_ary

float32_ary.dtype

ary2d.size #mostra tamanho

ary2d.ndim #mostra dimensão

ary2d.shape #mostra formato

np.array([1, 2, 3]).shape

np.ones((3, 3)) #matriz de 1's

np.zeros((3, 3)) #matriz de 0's

np.eye(3) #matriz ID

np.diag((3, 3, 3)) #matriz IDxEscalar

np.arange(4., 10.) #cria array com valores dentro do intervalo

np.arange(5) #cria array com valores de 0 até o valor

np.linspace(0., 1., num=5) #cria array no intervalo de 0 a 1 dividido em 5 partes = 1/5

"""***Array Indexing***"""

ary = np.array([1, 2, 3]) #exibe valor da pos 0
ary[0]

ary[:2] # equivalent to ary[0:2]

ary = np.array([[1, 2, 3],
... [4, 5, 6]])
ary[0, 0] #exibe valor na pos superior esquerda

ary[-1, -1] # exibe valor na pos inferior da direita

ary[0, 1] #exibe primeira linha segunda coluna

ary[0] # exibe primeira linha inteira

ary[:, 0] # exibe a primeira coluna inteira

ary[:, :2] #exibe as primeiras duas colunas

ary[0,0]

"""***Array Math and Universal Functions***"""

lst = [[1, 2, 3], [4, 5, 6]] #cria lista
for row_idx, row_val in enumerate(lst):
  for col_idx, col_val in enumerate(row_val):
    lst[row_idx][col_idx] += 1
lst

lst = [[1, 2, 3], [4, 5, 6]]
[[cell + 1 for cell in row] for row in lst]

ary = np.array([[1, 2, 3], [4, 5, 6]])
ary = np.add(ary, 1)
ary

ary + 1 #soma 1 em tudo

ary**2 #multiplica tudo por 2

ary = np.array([[1, 2, 3],
... [4, 5, 6]])
np.add.reduce(ary) #soma as colunas

np.add.reduce(ary, axis=1) #soma as linha

ary.sum(axis=0) #soma as colunas

ary.sum() #some todos os valores

"""***Broadcasting***"""

ary1 = np.array([1, 2, 3])
ary2 = np.array([4, 5, 6])
ary1 + ary2 #soma os 2 vetores valor a valor

ary3 = np.array([[4, 5, 6],
... [7, 8, 9]]) #definindo nova lista

ary3 + ary1 #soma ary1 + ary3

"""***Advanced Indexing – Memory Views and Copies***"""

ary = np.array([[1, 2, 3],
... [4, 5, 6]])
first_row = ary[0] #cria variável e armazena toda a primeira linha
first_row += 99 #soma 99 a a todos os valores
ary

ary = np.array([[1, 2, 3],
... [4, 5, 6]])
center_col = ary[:, 1] #recebe só a coluna do meio
center_col += 99 #soma a coluna do meio + 99
ary

ary = np.array([[1, 2, 3],
... [4, 5, 6]])
second_row = ary[1].copy()
second_row += 99
ary

ary = np.array([[1, 2, 3],
... [4, 5, 6]])
ary[:, [0, 2]] # first and and last column

ary[:, [2, 0]] # first and and last column

ary = np.array([[1, 2, 3],
... [4, 5, 6]])
greater3_mask = ary > 3 #retorna "true" pra valores maiores que 3
greater3_mask

ary[greater3_mask] #retorna os valores maiores que 3

ary[(ary > 3) & (ary % 2 == 0)] #maiores que 3 e divisíveis por 2

"""***Random Number Generators***"""

np.random.seed(123) #gerador de randomicos
np.random.rand(3) #quantidade de números

rng1 = np.random.RandomState(seed=123)
rng1.rand(3)

"""***Reshaping Arrays***"""

ary1d = np.array([1, 2, 3, 4, 5, 6])
ary2d_view = ary1d.reshape(2, 3)
ary2d_view

np.may_share_memory(ary2d_view, ary1d)

ary1d.reshape(2, -1)

ary1d.reshape(-1, 2)

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

ary.reshape(-1)

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

# stack along the first axis
np.concatenate((ary, ary))

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

# stack along the first axis (here: rows)
np.concatenate((ary, ary), axis=0)

# stack along the second axis (here: column)
np.concatenate((ary, ary), axis=1)

"""***Comparison Operators and Masks***"""

ary = np.array([1, 2, 3, 4])
mask = ary > 2 #true para todos os masiores
mask

ary[mask] #todos que cumpriram a restrição

mask.sum() #qtd deles

np.where(ary > 2, 1, 0) # 1 para os que cumpriram a restrição

ary = np.array([1, 2, 3, 4])
mask = ary > 2
ary[mask] = 1
ary[~mask] = 0
ary

ary = np.array([1, 2, 3, 4])
(ary > 3) | (ary < 2) #retorna de acordo com a condição

~((ary > 3) | (ary < 2)) #retorna o contrário da condição, sua negação

"""*** Linear Algebra with NumPy Arrays***"""

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

column_vector = np.array([[1, 2, 3]]).reshape(-1, 1)
column_vector

row_vector[:, np.newaxis]

row_vector[:, None]

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

np.matmul(matrix, column_vector)

np.matmul(matrix, row_vector)

np.matmul(row_vector, row_vector)

np.dot(row_vector, row_vector)

np.dot(matrix, row_vector)

np.dot(matrix, column_vector)

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

matrix.transpose()

np.matmul(matrix, matrix.transpose())

matrix.T

"""***Matplotlib***"""

# Commented out IPython magic to ensure Python compatibility.
# %matplotlib inline
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
plt.plot(x, np.sin(x))
plt.show()

x = np.linspace(0, 10, 100)

plt.plot(x, np.sin(x))
plt.xlim([2, 8])
plt.ylim([0, 0.75])
plt.xlabel('x-axis')
plt.ylabel('y-axis')

x = np.linspace(0, 10, 100)
plt.plot(x, np.sin(x), label=('sin(x)'))
plt.plot(x, np.cos(x), label=('cos(x)'))
plt.ylabel('f(x)')
plt.xlabel('x')
plt.legend(loc='lower left')

"""*** Scatter Plots***"""

rng = np.random.RandomState(123)
x = rng.normal(size=500)
y = rng.normal(size=500)
plt.scatter(x, y)
plt.show()

"""***Bar Plots***"""

# input data
means = [1, 2, 3]
stddevs = [0.2, 0.4, 0.5]
bar_labels = ['bar 1', 'bar 2', 'bar 3']
# plot bars
x_pos = list(range(len(bar_labels)))
plt.bar(x_pos, means, yerr=stddevs)
plt.show()

"""***Histograms***"""

rng = np.random.RandomState(123)
x = rng.normal(0, 20, 1000)
# fixed bin size
bins = np.arange(-100, 100, 5) # fixed bin size
plt.hist(x, bins=bins)
plt.show()

rng = np.random.RandomState(123)
x1 = rng.normal(0, 20, 1000)
x2 = rng.normal(15, 10, 1000)
# fixed bin size
bins = np.arange(-100, 100, 5) # fixed bin size
plt.hist(x1, bins=bins, alpha=0.5)
plt.hist(x2, bins=bins, alpha=0.5)
plt.show()

"""***Subplots***"""

import matplotlib.pyplot as plt
x = range(11)
y = range(11)
fig, ax = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True)
for row in ax:
  for col in row:
    col.plot(x, y)
plt.show()

"""***Colors and Markers***"""

x = np.linspace(0, 10, 100)
plt.plot(x, np.sin(x),
color='orange',
marker='^',
linestyle='')
plt.show()

"""***Saving Plots***"""

x = np.linspace(0, 10, 100)
plt.plot(x, np.sin(x))
plt.savefig('myplot.png', dpi=300)
plt.savefig('myplot.pdf')
plt.show()


# MSDS 400 Module 5 Practice 2

import numpy
from numpy import arange, cos
import matplotlib.pyplot
from matplotlib.pyplot import *

# A general function for calculating the slope between two points: x and
# x+delta.  See Lial Section 11.3 dealing with instantaneous rates of change.

def der(x,delta):
    delta = float(delta)
    if delta < (0.0000001):
        print ('Value chosen for delta is too small.')
        return 1/delta
    else:
        slope = (f(x + delta) - f(x))/delta
        return slope

# Define a function for demonstration.  This function may be changed.

def f(x):
    f = cos(x)
    return f

point = 1.0  #This is a point at which a derivative will be calculated.
# The following statements initialize variables for computation.

number = 510
increment =10
y = []
x = []

# What follows shows calculations and list manipulations. Recall that a range
# statement is inclusive of the first number and exclusive of the last.  In this
# example we are incrementing by units of 10 from 1 to 500.  We are reducing
# the distance between x=1.0 and x=1.0+delta by reducing delta.  The slopes
# being calculated are stored in the list y.

for k in range(increment, number, increment):
    delta = 1.0/(k+1)
    d = der(point,delta)
    x = x + [k]
    y = y + [d]
    max_x = k + increment

limit=der(point,0.000001)
print ('Final value equals', limit)

# The plot shows convergence of the slopes to the instantaneous rate of change.
# Black dots mark computed slopes as delta was reduced.  The x-axis is plotted
# using values of k from the range statement in the for loop.

figure()
xlim(0, max_x+50 )
ylim(min(y)-0.05, max(y)+0.05)

scatter(540,limit,color='g',s=40,label='limiting slope')
legend(('limiting slope'),loc='best')
scatter(x,y,c='k',s=20)

title ('Example of Convergence to Instanteous Rate of Change')
xlabel('x-axis')
ylabel('y-axis')
ylabel('y-axis')
plot(x,y)
show()

# The next section will show the tangent line at the point x=1.0.
# We are using the equation for a straight line y=mx+b where the slope is
# y[-1] from above and the point given above is x=1.0.  We are only going
# to plot this tangent line over a limited distance given by w defined below.

# Calculate values for the tangent.
w=arange(point-1.0,point+1.1,0.1)
t=f(point)+limit*(w-point)

# Now we are going to plot the original function over a wider range.
# Define a domain for the function.
domain=3.14

# Calculate values for the function on both sides of x=1.0.
u=arange(point-domain,point+domain+0.1,0.1)
z=f(u)

# This allows us to plot in layers showing the tangent and the function.
# The scatter command allows a single point to be plotted.
figure()
xlim(point-domain-.1,point+domain+0.1)
ylim(max(z)+.5,min(z)-.5)

plot(w,t,c='r')                        # This plots the tangent line.
plot(u,z,c='b')                        # This plots the curve itself.
scatter(point,f(point),c='g',s=40)     # This is the point of contact.
xlabel('x-axis')
ylabel('y-axis')
title('Plot showing function and tangent at a point')
show()

# Exercise #1:  Refer to Lial Section 11.3 Examples 3-5.  Using the function
# der() as defined, calculate approximate slopes for the functions given in
# Lial Section 11.3 Examples 3(b), 4(c), & 5.  Use a small value for delta and
# evaluate der() at the points used in the examples. Round to 4 decimal places.

# Exercise #2: Refer to Lial 11.1 Example 1.  This was used in Session 6
# Module1. The solution code is presented in the answer sheet.  Modify the code
# so that the tangent line at x=2 appears on the preceeding plot.  This
# necessitates determining the linear equation for the tangent line using
# y=mx+b and writing the statements to plot this line on the existing plot.
# Use arange().


# -*- coding: utf-8 -*-
"""
Auxiliary functions for interpolation

@author: Nicolas Guarin-Zapata
"""
from __future__ import division, print_function
import numpy as np
import matplotlib.pyplot as plt
from gauss_lobatto import gauss_lobatto

def vander_mat(x):
    """Vandermonde matrix for points in x"""
    n = len(x)
    van = np.zeros((n, n))
    power = np.array(range(n))
    for row in range(n):
        van[row, :] = x[row]**power
    return van

def conf_vander_mat(x):
    """Confluent Vandermonde matrix for points in x

    References
    ----------
    .. [1] Walter Gautschi (1962). On inverses of Vandermonde
        and confluent Vandermonde matrices. Numerische Mathematik, 4
        117-123.
    """

    n = len(x)
    conf_van = np.zeros((2*n, 2*n))
    power = np.array(range(2*n))
    for row in range(n):
        if x[row] == 0:
            conf_van[row, 0] = 1
            conf_van[row + n, 1] = 1
        else:
            conf_van[row, :] = x[row]**power
            conf_van[row + n, :] = power*x[row]**(power - 1)
    return conf_van

def inter_coef(x, inter_type="lagrange"):
    """Compute the coefficients for interpolation

    The desired interpolation is for the points x
    """
    if inter_type == "lagrange":
        vand_mat = vander_mat(x)
    elif inter_type == "hermite":
        vand_mat = conf_vander_mat(x)
    coef = np.linalg.solve(vand_mat, np.eye(vand_mat.shape[0]))
    return coef

def compute_interp(x, f, x_eval, df=None):
    """
    Compute the interpolation for points x_eval given by
    points x.

    If derivatives are given (df) it computes the
    Hermite interpolation for x_eval.
    """
    n = len(x)
    if df is None:
        coef = inter_coef(x, inter_type="lagrange")
    else:
        coef = inter_coef(x, inter_type="hermite")
    f_eval = np.zeros_like(x_eval)
    nmat = coef.shape[0]
    for row in range(nmat):
        for col in range(nmat):
            if col < n or nmat == n:
                f_eval += coef[row, col]*x_eval**row*f[col]
            else:
                f_eval += coef[row, col]*x_eval**row*df[col - n]
    return f_eval

if __name__ == "__main__":
    equispaced = False
    n = 11
    if equispaced:
        x = np.linspace(-1, 1, n)
    else:
        x, _ = gauss_lobatto(n)
    f = 1/(1 + 25*x**2)
    df = -50*x/(1 + 25*x**2)**2
    x_eval = np.linspace(-1, 1, 500)
    interp_f = compute_interp(x, f, x_eval, df=df)
    plt.plot(x_eval, 1/(1 + 25*x_eval**2))
    plt.plot(x_eval, interp_f)
    plt.plot(x, f, '.')
    plt.ylim(0, 2)
    plt.show()


import numpy as np

A=np.array([[4,12,-16],[12,37,-43],[-16,-43,98]])
x=np.array([1,-2,3])
b=A.dot(x)
print(b)

print(np.linalg.cholesky(A))

#Using Cholesky Fractorization for solving Linear Equation.
#Ax=b --> L.dot(L.transpose()).x=b
#Solving Ly=b
#After solving L.transpose().x=y
#Fast way for solving linear equation.
#A must be a positive definite matrix.

def CholeskyLinearEquation(A,b):
    #Find x with Ax=b
    L=np.linalg.cholesky(A)
    y=(np.linalg.inv(L)).dot(b)
    x=(np.linalg.inv(np.transpose(L))).dot(y)
    return x

c=np.array([-68,-191,364])
x=CholeskyLinearEquation(A,b)
print(x)


import matplotlib.pyplot as plt
import numpy as np

def laplace_pdf(x, b, μ):
    return (1 / (2 * b)) * np.e ** (-1 * (np.abs(x - μ) / b))

x = np.linspace(-10, 10, 10000)
y1 = [laplace_pdf(x_, 1, 0) for x_ in x]
y2 = [laplace_pdf(x_, 2, 0) for x_ in x]
y3 = [laplace_pdf(x_, 4, 0) for x_ in x]
y4 = [laplace_pdf(x_, 4, -5) for x_ in x]

plt.plot(x, y1, label="μ=0,b=1")
plt.plot(x, y2, label="μ=0,b=2")
plt.plot(x, y3, label="μ=0,b=4")
plt.plot(x, y4, label="μ=-5,b=4")

plt.title("Laplace pdf curves")
plt.legend()
plt.show()


import numpy as np

def spherical_to_cartesian(r, theta, phi, degrees=True):
    """
    Convert spherical coordinates (r, theta, phi) to cartesian (x, y, z).

    Parameters
    ----------
    r: (N,) ndarray
        Radial distance.
    theta: (N,) ndarray
        Azimuthal angle.
    phi: (N,) ndarray
        Polar angle.
    degrees: bool, optional
        If True, theta and phi will be assumed to be in degrees.

    Returns
    -------
    xyz: (N, 3) ndarray
        Corresponding cartesian coordinates.

    Notes
    -----
    Use notation of mathematical systems, NOT physics.
    """
    if degrees:
        theta = np.deg2rad(theta)
        phi = np.deg2rad(phi)

    sin_theta = np.sin(theta)
    cos_theta = np.cos(theta)
    sin_phi = np.sin(phi)
    cos_phi = np.cos(phi)

    xyz = np.empty((r.shape[0], 3), dtype=np.float32)

    xyz[:, 0] = r * sin_phi * cos_theta
    xyz[:, 1] = r * sin_phi * sin_theta
    xyz[:, 2] = r * cos_phi

    return xyz

def cartesian_to_spherical(xyz, degrees=True):
    """
    Convert cartesian coordinates (x, y, z) to spherical (r, theta, phi).

    Parameters
    ----------
    xyz: (N, 3) ndarray
        Corresponding cartesian coordinates.
    degrees: bool, optional
        If True, azimuthal and polar will be returned in degrees.

    Returns
    -------
    radius: (N,) ndarray
        Radial distance.
    inclination: (N,) ndarray
        Polar angle.
    azimuth: (N,) ndarray
        Azimuthal angle.
    """
    x = xyz[:, 0]
    y = xyz[:, 1]
    z = xyz[:, 2]

    radius = np.nan_to_num(np.sqrt((x * x) + (y * y) + (z * z)))

    inclination = np.nan_to_num(np.arccos(z / radius))

    azimuth = np.nan_to_num(np.arctan2(y, x))

    if degrees:
        inclination = np.rad2deg(inclination)
        azimuth = np.rad2deg(azimuth)

    return radius, inclination, azimuth

def cylindrical_to_cartesian(ro, phi, z, degrees=True):
    """
    Convert cylindrical coordinates (ro, phi, zeta) to cartesian (x, y, z).

    Parameters
    ----------
    ro: (N,) ndarray
        Radial distance.
    phi: (N,) ndarray
        Angular position.
    z: (N,) ndarray
        Altitude.
    degrees: bool, optional
        If True, angular will be assumed to be in degrees.

    Returns
    -------
    xyz: (N, 3) ndarray
        Corresponding cartesian coordinates.

    Notes
    -----
    The polar axis in the cylindrical system corresponds to the 'x' axis in the
    cartesian system.

    The longitudinal axis corresponds to the 'z' axis.
    """
    if degrees:
        phi = np.deg2rad(phi)

    sin_phi = np.sin(phi)
    cos_phi = np.cos(phi)

    xyz = np.empty((ro.shape[0], 3), dtype=np.float32)

    xyz[:, 0] = ro * cos_phi
    xyz[:, 1] = ro * sin_phi
    xyz[:, 2] = z

    return xyz

def cartesian_to_cylindrical(xyz, degrees=True):
    """
    Convert cartesian coordinates (x, y, z) to cylindrical (ro, phi, zeta).

    Parameters
    ----------
    xyz: (N, 3) ndarray
        Corresponding cartesian coordinates.
    degrees: bool, optional
        If True, azimuthal and polar will be returned in degrees.

    Returns
    -------
    radial_cylindrical: (N,) ndarray
        Radial distance.
    angular_cylindrical: (N,) ndarray
        Angular position.
    z: (N,) ndarray
        Altitude.

    Notes
    -----
    The polar axis in the cylindrical system corresponds to the 'x' axis in the
    cartesian system.

    The longitudinal axis corresponds to the 'z' axis.
    """
    x = xyz[:, 0]
    y = xyz[:, 1]
    z = xyz[:, 2]

    radial_cylindrical = np.nan_to_num(np.sqrt((x * x) + (y * y)))

    angular_cylindrical = np.nan_to_num(np.arctan2(y, x))

    if degrees:
        angular_cylindrical = np.rad2deg(angular_cylindrical)

    return radial_cylindrical, angular_cylindrical, z

def cylindrical_to_spherical(ro, phi, zeta, degrees=True, phi_is_inclination=True):
    """
    Convert cylindrical coordinates (ro, phi, zeta) to spherical (r, theta, phi).

    Parameters
    ----------
    ro: (N,) ndarray
        Radial distance.
    phi: (N,) ndarray
        Angular position.
    zeta: (N,) ndarray
        Altitude.
    degrees: bool, optional
        If True, azimuthal and polar will be returned in degrees.
    phi_is_inclination: bool, optional
        See https://en.wikipedia.org/wiki/Cylindrical_coordinate_system#Spherical_coordinates.

    Returns
    -------
    r: (N,) ndarray
        Radial distance.
    theta: (N,) ndarray
        Azimuthal angle.
    phi: (N,) ndarray
        Polar angle.
    """

    r = np.sqrt((ro * ro) + (zeta * zeta))

    theta = phi

    if phi_is_inclination:
        phi = np.arctan2(ro, zeta)
    else:
        phi = np.arctan2(zeta, ro)

    if degrees:
        phi = np.rad2deg(phi)

    return r, theta, phi

def spherical_to_cylindrical(r, theta, phi, degrees=True, phi_is_inclination=False):
    """
    Convert spherical coordinates (r, theta, phi) to cylindrical (ro, phi, zeta).

    Parameters
    ----------
    r: (N,) ndarray
        Radial distance.
    theta: (N,) ndarray
        Azimuthal angle.
    phi: (N,) ndarray
        Polar angle.
    degrees: bool, optional
        If True, azimuthal and polar will be returned in degrees.
    phi_is_inclination: bool, optional
        See https://en.wikipedia.org/wiki/Cylindrical_coordinate_system#Spherical_coordinates.

    Returns
    -------
    ro: (N,) ndarray
        Radial distance.
    phi: (N,) ndarray
        Angular position.
    z: (N,) ndarray
        Altitude.
    """
    if degrees:
        phi = np.deg2rad(phi)

    sin_phi = np.sin(phi)
    cos_phi = np.cos(phi)

    ro = r * sin_phi
    z = r * cos_phi

    phi = theta

    return ro, phi, z


import numpy as np
import tensorflow as tf

def cross_entropy_np(y_true, y_pred, epsilon=1e-12):
    """
    Cross entropy loss implementation with Numpy
    Args:
        y_true [ndarray]: Ground truth values (NxC).
                          N batch size, C number of classe.
        y_pred [ndarray]: The predicted values (NxC).
                          N batch size, C number of classe.
        epsilon: Defaults to 1e-12.

    Returns:
        loss: cross entropy
    """
    y_pred = np.clip(y_pred, epsilon, 1. - epsilon)
    N = y_pred.shape[0]
    ce = -np.sum(y_true * np.log(y_pred)) / N
    return ce

if __name__ == "__main__":
    # y_true = np.array([[0, 0, 0, 1],
    #                    [0, 0, 0, 1]])
    # y_pred = np.array([[0.25, 0.25, 0.25, 0.25],
    #                    [0.01, 0.01, 0.01, 0.96]])

    y_true = np.array([[0, 1, 0], [0, 0, 1]])
    y_pred = np.array([[0.05, 0.95, 0], [0.1, 0.8, 0.1]])

    cross_entropy_tf = tf.keras.losses.CategoricalCrossentropy()
    tf_ce = cross_entropy_tf(y_true, y_pred) # 1.177. Correct answer
    np_ce = cross_entropy_np(y_true, y_pred)

    print("Cross Entropy:")
    print("\tCorrect answer (tf): ", tf_ce.numpy())
    print("\tImplementation with Numpy: ", np_ce)

    ll_norm = tf.norm(tf_ce - np_ce, ord=1)
    assert ll_norm < 1e-5, "Cross Entropy calcuoation is wrong"
    print("Cross Entropy implementation is correct!")


# Exercise_1
# Perform the necessary imports
from scipy.cluster.hierarchy import linkage, dendrogram
import matplotlib.pyplot as plt

# Calculate the linkage: mergings
mergings = linkage(samples, method='complete')

# Plot the dendrogram, using varieties as labels
dendrogram(mergings ,
           labels=varieties,
           leaf_rotation=90,
           leaf_font_size=6,
)
plt.show()

--------------------------------------------------
# Exercise_2
# Import normalize
from sklearn.preprocessing import normalize

# Normalize the movements: normalized_movements
normalized_movements = normalize(movements)

# Calculate the linkage: mergings
mergings = linkage(normalized_movements,method='complete' )

# Plot the dendrogram
dendrogram(mergings,
            labels=companies,
            leaf_rotation=90,
            leaf_font_size=6)

plt.show()

--------------------------------------------------
# Exercise_3
# Perform the necessary imports
import matplotlib.pyplot as plt
from scipy.cluster.hierarchy import linkage, dendrogram

# Calculate the linkage: mergings
mergings = linkage(samples, method='single')

# Plot the dendrogram
dendrogram(mergings,
        labels=country_names,
        leaf_rotation=90,
        leaf_font_size=6)
plt.show()

--------------------------------------------------
# Exercise_4
# Perform the necessary imports
import pandas as pd
from scipy.cluster.hierarchy import fcluster

# Use fcluster to extract labels: labels
labels = fcluster(mergings, 6,criterion='distance', )

# Create a DataFrame with labels and varieties as columns: df
df = pd.DataFrame({'labels': labels, 'varieties': varieties})

# Create crosstab: ct
ct =  pd.crosstab(df['labels'], df['varieties'])

# Display ct
print(ct)

--------------------------------------------------
# Exercise_5
# Import TSNE
from sklearn.manifold import TSNE

# Create a TSNE instance: model
model = TSNE(learning_rate=200)

# Apply fit_transform to samples: tsne_features
tsne_features = model.fit_transform(samples)

# Select the 0th feature: xs
xs = tsne_features[:,0]

# Select the 1st feature: ys
ys = tsne_features[:,1]

# Scatter plot, coloring by variety_numbers
plt.scatter(xs, ys,c=variety_numbers )
plt.show()

--------------------------------------------------
# Exercise_6
# Import TSNE
from sklearn.manifold import TSNE

# Create a TSNE instance: model
model = TSNE(learning_rate=50)

# Apply fit_transform to normalized_movements: tsne_features
tsne_features = model.fit_transform(normalized_movements)

# Select the 0th feature: xs
xs = tsne_features[:,0]

# Select the 1th feature: ys
ys = tsne_features[:,1]

# Scatter plot
plt.scatter(xs, ys, alpha=0.5)

# Annotate the points
for x, y, company in zip(xs, ys, companies):
    plt.annotate(company, (x, y), fontsize=5, alpha=0.75)
plt.show()

--------------------------------------------------

Machine Learning Scientist with Python Track/2. Unsupervised Learning in Python/ch2_exercises.py