# =========================================================================== #
#                                VALIDITY                                     #
# =========================================================================== #
# =========================================================================== #
# Project: Visualate                                                          #
# Version: 0.1.0                                                              #
# File: \model_validation.py                                                  #
# Python Version: 3.8.0                                                       #
# ---------------                                                             #
# Author: John James                                                          #
# Company: Decision Scients                                                   #
# Email: jjames@decisionscients.com                                           #
# ---------------                                                             #
# Create Date: Thursday November 28th 2019, 1:49:18 pm                        #
# Last Modified: Thursday November 28th 2019, 1:50:37 pm                      #
# Modified By: John James (jjames@decisionscients.com)                        #
# ---------------                                                             #
# License: Modified BSD                                                       #
# Copyright (c) 2019 Decision Scients                                         #
# =========================================================================== #
"""Model validation and verification module."""
#%%
import math
from math import erf
import numpy as np
from scipy.stats import norm
# --------------------------------------------------------------------------- #
#                                 LEVERAGE                                    #
# --------------------------------------------------------------------------- #
def leverage(X):
    """Computes leverage.

    Leverage is a measure of how far away an independent variable values of an
    observation are from those of other observations.
    """
    hat = X.dot(np.linalg.inv(X.T.dot(X)).dot(X.T))
    hii = np.diagonal(hat)
    return hii
print(leverage.__doc__)

# --------------------------------------------------------------------------- #
#                           RESIDUAL ANALYSIS                                 #
# --------------------------------------------------------------------------- #
def standardized_residuals(model, X, y, return_predictions=False):
    """Computes standardized residuals.

    Standardized residuals (sometimes referred to as "internally studentized
    residuals") are defined for each observation, i = 1, ..., n as an
    ordinary residual divided by an estimate of its standard deviation:
    ..math:: r_i = \\frac{e_i}{\\sqrt{MSE(1-h_{ii})}}

    Parameters
    ----------
    model : Estimator or BaseEstimator
        ML Studio or Scikit Learn estimator

    X : ndarray or DataFrame of shape n x m
        A matrix of n instances with m features

    y : ndarray or Series of length n
        An array or series of target or class values
    """
    # Compute residuals
    y_pred = model.predict(X)
    residuals = y - y_pred

    # Compute Leverage
    hii = leverage(X)

    # Compute degrees of freedom and MSE
    rank = np.linalg.matrix_rank(X)
    df = X.shape[0] - rank
    mse = np.matmul(residuals, residuals) / df

    # Calculate standardized
    standardized_residuals = residuals / np.sqrt(mse  * (1-hii))

    # Return standardized residuals and optionally the predictions
    if return_predictions:
        return standardized_residuals, y_pred
    else:
        return standardized_residuals

def studentized_residuals(model, X, y, return_predictions=False):
    """Computes studentized residuals.

    Studentized residuals are just a deleted residual divided by its estimated
    standard deviation. This turns out to be equivalent to the ordinary residual
    divided by a factor that includes the mean square error based on the
    estimated model with the ith observation deleted, MSE(i), and the leverage, hii
    .. math:: r_i = \\frac{e_i}{\\sqrt{MSE_{(i)}(1-h_{ii})}}

    Parameters
    ----------
    model : Estimator or BaseEstimator
        ML Studio or Scikit Learn estimator

    X : ndarray or DataFrame of shape n x m
        A matrix of n instances with m features

    y : ndarray or Series of length n
        An array or series of target or class values
    """
    # Compute residuals
    y_pred = model.predict(X)

    # Using the calculation from
    # https://newonlinecourses.science.psu.edu/stat462/node/247/
    n = X.shape[0]
    k = X.shape[1]
    r = standardized_residuals(model=model, X=X, y=y)

    # Calculate studentized residuals
    studentized_residuals = r * np.sqrt((n-k-2)/(n-k-1-np.square(r)))

    # Return studentized residuals and optionally the predictions
    if return_predictions:
        return studentized_residuals, y_pred
    else:
        return studentized_residuals

# --------------------------------------------------------------------------- #
#                  INVERSE CUMULATIVE DISTRIBUTION FUNCTION                   #
# --------------------------------------------------------------------------- #
def quantile(p):
    """Inverse Cumulative Distribution Function for Normal Distribution.

    The cumulative distribution function (CDF) of the random variable X
    has the following definition:
    .. math::
                    \\mathbb{F}_X(t) = \\mathbb{P}(X \\le t)
    The notation \\mathbb{F}_X(t) means that \\mathbb{F} is the cdf for
    the random variable \\mathbb{X} but it is a function of t. It can be
    defined for any kind of random variable (discrete, continuous, and
    mixed).

    Parameters
    ----------
    p : Array-like
        Sample vector of real numbers

    Note
    ----
    The original function was obtained from the google courtesy of
    Dr. John Cook and his group of consultants. The following code
    first appeared as A literate program to compute the inverse of
    the normal CDF. See that page for a detailed explanation of the
    algorithm. Ultimately had to swap it out because it could only
    handle positive values.
    Source: Author  : John D. Cook
             Date   : December 1, 2019
            Title   : Inverse Normal CDF
          Website   : https://www.johndcook.com/blog/python_phi_inverse/

    The second algorithm was obtained from stackoverflow
    https://stackoverflow.com/questions/809362/how-to-calculate-cumulative-normal-distribution
    """
    #'Cumulative distribution function for the standard normal distribution'
    #i_cdf = normal_CDF_inverse(p)
    return (1.0 + erf(p / np.sqrt(2.0))) / 2.0
    #i_cdf = normal_CDF_inverse(p)

def rational_approximation(t):

    # Abramowitz and Stegun formula 26.2.23.
    c = [2.515517, 0.802853, 0.010328]
    d = [1.432788, 0.189269, 0.001308]
    numerator = (c[2]*t + c[1])*t + c[0]
    denominator = ((d[2]*t + d[1])*t + d[0])*t + 1.0
    return t - numerator / denominator

def normal_CDF_inverse(p):

    assert p > 0.0 and p < 1

    # See article above for explanation of this section.
    if p < 0.5:
        # F^-1(p) = - G^-1(p)
        return -rational_approximation( math.sqrt(-2.0*math.log(p)) )
    else:
        # F^-1(p) = G^-1(1-p)
        return rational_approximation( math.sqrt(-2.0*math.log(1.0-p)) )


def getGoldenRatio():
    from math import sqrt as mmmsqr
    return((mmmsqr(5))+1)/2

def GoldenNumber(index=1,Pair=False,roundi=True):
    from sympy import Pow as mmmpow
    from math import sqrt as mmmsqr
    q = mmmsqr(5)
    pp = getGoldenRatio()
    r = ((mmmpow(pp,index) - mmmpow(-pp,-index))/q)
    if(roundi):
        if(Pair):
            return (NextGoldenNumber(round(r)),round(r))
        else:
            return round(r)
    else:
        if(Pair):
            return (NextGoldenNumber(r,False,False),r)
        else:
            return r

#Companion Golden Number
def NextGoldenNumber(Golden,Pair=False,roundi=True):
    r=Golden*getGoldenRatio()
    if(roundi):
        if(Pair):
            return (Golden,round(r))
        else:
            return round(r)
    else:
        if(Pair):
            return (Golden,r)
        else:
            return r

def GoldenFractions(toEnd=100):
    pp=getGoldenRatio()
    for i in range(1,toEnd):
        a=i*pp
        if(a%1 *100 <10):
            print((int(a),i),end=', ')

def doTest(toPrint=False,toProgress=False,start=0,toEnd=1000,algo="s"):
    s=set()
    KK=10000
    from IPython.display import clear_output
    for i in range(start,toEnd+1):
        if(toProgress and (i<KK or (i>=KK and i%(KK/100)==0))):
            clear_output(wait=True)
            print(i,end="\t")
        if(algo=="s"):
            gold=GoldenNumber(i)
        elif(algo=="pairs"):
            gold=GoldenNumber(i,True)
        if(gold):
            s.add(gold)
            if(toPrint and not toProgress):
                print(gold,end=", ")
        if(toProgress and (i<KK or (i>=KK and i%(KK/100)==0))):
            print(s)
    if(not toPrint):
        return s

#GoldenNumber(8)
#NextGoldenNumber(34)
#GoldenRatio(100)
#doTest(False,False,1,100,"pairs")
#doTest(False,False,1,100)


import numpy as np
import tensorflow as tf
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

def get_minibatch():
    ''' This is called every time the optimizer needs a minibatch. Since the points
    are generated randomly, it's like having an infinite amount of data'''
    x_val = np.random.uniform(-10,10,size=100)
    y_val = 10 * np.square(x_val) - 5

    return x_val,y_val

## build computational graph

# define placeholder variables
x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)

w = tf.get_variable("w", shape=[3,1])

# compute the estimate
f = tf.stack([tf.square(x), x, tf.ones_like(x)], 1)
yhat = tf.squeeze(tf.matmul(f, w), 1)

# compute the loss
loss = tf.nn.l2_loss(yhat - y) + 0.1 * tf.nn.l2_loss(w)

# define the optimizer
# train_op = tf.train.AdamOptimizer(0.1).minimize(loss)
# train_op = tf.train.AdadeltaOptimizer(0.01).minimize(loss)
train_op = tf.train.AdagradOptimizer(learning_rate=1.0).minimize(loss)
# train_op = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(loss)

# define the tensorflow session
sess = tf.Session()
sess.run(tf.global_variables_initializer())

## define stopping criteria

# a) directly specify the minimum loss value
min_loss = 1
loss_val = 1e10
weights = np.array([3,1])

# b) directly specify the minimum loss update
min_update = 0.1
update = 1e5

# c) minimum update ratio
min_loss_update_ratio = 1e-5
min_param_update_ratio = 1e-5

# d) fractional loss criteria

def fn_loss_update_ratio(val,old_val):

    return np.abs(val - loss_val)/old_val

# e) fractional weight update criteria

def fn_iterate_update_ratio(val,old_val):

    return np.linalg.norm(np.array(val) - np.array(old_val))/np.linalg.norm(old_val)

# collect some statistics
num_iter = 0
loss_vals = []

# while loss_val > min_loss and np.abs(update) > min_update:
while True:
    num_iter+=1
    x_val, y_val = get_minibatch()
    # print(sess.run([tf.shape(f)],{x:x_val}))
    # print(sess.run([tf.shape(yhat)],{x:x_val,y:y_val}))
    old_loss_val = loss_val
    _, loss_val = sess.run([train_op, loss], {x: x_val, y: y_val})
    old_weights = weights
    weights = sess.run([w])
    loss_vals.append(loss_val)
    # update_ratio = fn_loss_update_ratio(loss_val,old_loss_val)
    iterate_update_ratio = fn_iterate_update_ratio(weights,old_weights)
    if iterate_update_ratio < min_param_update_ratio:
        print("converged in {} iterations".format(num_iter))
        print("weights: ",sess.run([w]))
        break
    # update = old_loss - loss_val
    print("loss: ",loss_val,iterate_update_ratio)

plt.plot(np.arange(num_iter),loss_vals)
plt.show()
plt.savefig('fig_train_loss.png')


import numpy as np
import matplotlib.pyplot as plt

def decompLU(A):
	L = np.eye(np.shape(A)[0]) #matriz L com a dimensao de A com a diagonal principla igual a 1
	U = np.zeros(np.shape(A)) #matriz U full zero
	lim = np.shape(A)[1] #pegando o tamanho da coluna de A (matriz quadrada)
	sum = 0

	for i in range(0, lim):
		for j in range(0, lim):
			sum = 0
			#Parte do somatorio de U que vai de 0 a i-1 e acumula L[i][k]*U[k][j] sendo k a variavel iteradora
			for k in range (0, i):
				sum += L[i,k]*U[k,j]
			U[i,j] = A[i,j] - sum #atribuindo o valor de U[i][j]

		for j in range (0, lim):
			sum = 0
			#Parte do somatorio de L que vai de 0 a i-1 e acumula L[j][k]*U[k][i] sendo k a variavel iteradora
			for k in range (0, i):
				sum+= L[j,k]*U[k,i]
			L[j,i] = (A[j,i] - sum)/U[i,i] #atribuindo o valor L[i][j]

	return L, U #retornando o resultado

def solveLU(L, U, b):
	#Resolvendo o sistema A*x = b
	#Como A = L*U, entao (L*U)*x = b
	#Vamos fazer L*(U*x) = b e U*x=y, portanto L*y=b
	#Logo, para encontrarmos o resultado resolvemos o sistema U*x = y

	y = np.zeros(np.shape(b)) #matriz coluna y com a mesma dimensao de b
	x = np.zeros(np.shape(b)) #matriz coluna x (resultado do sistema) com a mesma dimensao de b

	for i in range (0, np.shape(b)[0]): #resolvendo o sistema  L*y=b
		for j in range (0,i):
			y[i] -= y[j]*L[i,j]
		y[i]+=b[i]

	for i in range (np.shape(b)[0]-1, -1, -1): #resolvendo o sistema U*x=b
		for j in range (np.shape(b)[0]-1, i, -1):
			x[i] -= x[j]*U[i,j]
		x[i]+=y[i]
		x[i]/=U[i,i]

	return x #retornando o resultado

A = np.array([[1.0, 1.0/2.0, 1.0/3.0],
              [1.0/2.0, 1.0/3.0, 1.0/4.0],
              [1.0/3.0, 1.0/4.0, 1.0/5.0]], dtype='double')

e = np.exp(1);
b = [e-1,1,e-2];

(L, U) = decompLU(A)
alpha = solveLU(L, U, b)

print('Matriz A:\n{}\n'.format(A))
print('Matriz B:\n{}\n'.format(b))
print('Matriz X:\n{}\n'.format(alpha))

p = lambda x: alpha[0] + alpha[1]*x + alpha[2]*x**2;
x = np.linspace(0, 1, num=41, endpoint=True)

# Vamos plotar os resultados
plt.figure(figsize=(10,6),facecolor='white')
plt.plot(x,np.exp(x),label = 'f(x)',linewidth = 3)
plt.plot(x,p(x),label = 'p(x)',linewidth = 2,marker='>')
plt.xlabel('x',fontsize='large')
plt.ylabel('y',fontsize='large')
plt.title('Comparação da função aproximada')
plt.legend(fontsize='large')
plt.show()


import matplotlib.pyplot as plt
import csv
import numpy as np
from random import random
from sys import argv, exit

if len(argv) < 2:
    print(f"Verwendung: python3 {argv[0]} CSV-Datei [p]")
    exit(1)

# Daten importieren
filename = argv[1]
data = []
with open(filename, 'r', newline='') as data_file:
    reader = csv.reader(data_file)
    for line in reader:
        data.append([float(value) for value in line])

# min_x und max_x speichern Minimum und Maximum der Originalwerte,
# damit bei der Prognose Eingabewerte skaliert werden können.
x = np.array([row[0] for row in data])
min_x = min(x)
max_x = max(x)
y = np.array([row[1] for row in data])
n = len(data)

# Feature-Skalierung
x = (x - min(x)) / (max(x) - min(x))

# Lernrate
learning_rate = 0.2

# Bei theta_j = 0 beginnen
theta0 = 0
theta1 = 0

theta0s = []
theta1s = []
record_step = 2

# Gradientenabstieg
for step in range(0, 1000):
    y_pred = theta0 + x * theta1
    theta1_new = theta1 - learning_rate * (1 / n) * sum(x * (y_pred - y))
    theta0_new = theta0 - learning_rate * (1 / n) * sum(y_pred - y)
    theta0, theta1 = theta0_new, theta1_new
    if step == record_step:
        theta0s.append(theta0)
        theta1s.append(theta1)
        record_step *= 2

if len(argv) >= 3 and argv[2] == 'p':
    # Modus Vorhersage
    print("Geben Sie x-Werte für Prognosen ein; Q zum Beenden")
    while True:
        v_input = input("> ")
        if v_input == 'q' or v_input == 'Q':
            break
        try:
            value = float(v_input)
            value = (value - min_x) / (max_x - min_x)
            print(f"Prognose: {theta0 + theta1 * value}")
        except ValueError:
            print("Bitte nur Zahlen!")
else:
    # Modus Zeichnung
    plt.xlabel("Input data")
    plt.ylabel("Output data")
    plt.scatter(x, y, color='blue')
    xcoords = np.linspace(min(x), max(x), 100)
    ycoords = theta0 + theta1 * xcoords
    for i, old_theta0 in enumerate(theta0s):
        old_theta1 = theta1s[i]
        ycoords = old_theta0 + old_theta1 * xcoords
        plt.plot(xcoords, ycoords, '--', color=(i / len(theta0s), 0, 0))
    plt.plot(xcoords, ycoords, color='red')
    plt.show()


# Digital Signal Processing - Lab 1 - Part 3
# Christos Dimopoulos - 03117037
# Dimitris Dimos - 03117165

import numpy as np
import matplotlib.pyplot as plt
import scipy as sp
import sounddevice as sd

plt.close('all')
counter =0

# Part 3

#3.1: Short-Time Energy & Zero Crossing of speech signal

# Open .wav file of speech signal
from scipy.io import wavfile
fs, speech = wavfile.read('speech_utterance.wav')

Ts = 1/fs # fs = 16kHz sampling frequency
t = np.arange(0,np.size(speech)*Ts, Ts) #time index

# Plot speech signal
counter = counter+1
plt.figure(counter)
plt.plot(t,speech,'b', label = 'Sampling Fs = 16kHz')
plt.ylabel('Amplitude of Speech Signal')
plt.xlabel('Time [sec]')
plt.legend()
plt.title('‘Αλλά και για να επέμβει χρειάζεται συγκεκριμένη καταγγελία’')
plt.show()
sd.play(speech,fs)
sd.wait(6)

# Function that calculates sgn(x) = (1 if x>=0| -1 if x<0)
def sgn(x):
  y = np.zeros_like(x)
  y[np.where(x >= 0)] = 1.0
  y[np.where(x < 0)] = -1.0
  return y

# Function that calculates Short-Time Zero Crossings of signal x with window win
def stzerocr(x, win):
  #Compute short-time zero crossing rate.
  if isinstance(win, str):
    win = sp.signal.get_window(win, max(1, len(x) // 8))
  win = 0.5 * win / len(win)
  x1 = np.roll(x, 1)
  x1[0] = 0.0
  abs_diff = np.abs(sgn(x) - sgn(x1))
  return sp.signal.convolve(abs_diff, win, mode="same")

# Function that calculates Short-Time Energy of signal x with window win
def stenergy(x, win):
  #Compute short-time energy.
  if isinstance(win, str):
    win = sp.signal.get_window(win, max(1, len(x) // 8))
  win = win / len(win)
  return sp.signal.convolve(x**2, win, mode="same")

M = 0.025/Ts #Window length of 25msec --> 400 samples
window_hamming = sp.signal.get_window("hamming", int(M))
window_rectangular = sp.signal.get_window("boxcar", int(M))

speech = np.array(speech, dtype=float)

#Calculate Short-Time Energy of Speech Signal
energy = stenergy(speech,window_hamming)

# Divide with max values to normalize axis
maxspeech = max(abs(speech))
maxenergy = max(abs(energy))

counter = counter+1
plt.figure(counter)
plt.plot(t, speech/maxspeech, 'b', label='Speech Signal')
plt.plot(t, energy/maxenergy, 'r', label='Short Time Energy')
plt.xlabel('Time [sec]')
plt.ylabel('Normalised Amplitude')
plt.title('Short-Time Energy of Speech Signal with Window Length = 25msec')
plt.legend()
plt.show()

#Calculate Short-Time Zero Crossings of Speech Signal
zerocross = stzerocr(speech,window_rectangular)

# Divide with max values to normalize axis
maxspeech = max(abs(speech))
maxzerocross = max(abs(zerocross))

counter = counter+1
plt.figure(counter)
plt.plot(t, speech/maxspeech, 'b', label='Speech Signal')
plt.plot(t, zerocross/maxzerocross, 'g', label='Zero Crossings')
plt.xlabel('Time [sec]')
plt.ylabel('Normalised Amplitude')
plt.title('Short-Time Zero Crossings of Speech Signal with Window Length = 25msec')
plt.legend()
plt.show()

# Changing Window length to see how it affects energy and zero crossings
N = np.array([50, 100, 200, 400, 800, 1000])

# Short-Time Energy:
counter = counter+1
plt.figure(counter)
for i in range(np.size(N)):
    window_hamming = sp.signal.get_window("hamming", N[i])
    #Calculate Short-Time Energy of Speech Signal
    energy = stenergy(speech,window_hamming)
    plt.subplot(np.size(N), 1, i+1)
    plt.plot(t, energy, 'r', label='Window length = %i samples' %N[i])
    plt.legend()

plt.xlabel('Time [sec]')
plt.suptitle('Short-Time Energy of Speech Signal for different Window Lengths')
plt.show()

# Short-Time Zero Crossings:
counter = counter+1
plt.figure(counter)
for i in range(np.size(N)):
    window_rectangular = sp.signal.get_window("boxcar", N[i])
    #Calculate Short-Time Energy of Speech Signal
    zerocross = stzerocr(speech,window_rectangular)
    plt.subplot(np.size(N), 1, i+1)
    plt.plot(t, zerocross, 'g', label='Window length = %i samples' %N[i])
    plt.legend()

plt.xlabel('Time [sec]')
plt.suptitle('Short-Time Zero Crossings of Speech Signal for different Window Lengths')
plt.show()

#3.2: Short-Time Energy & Zero Crossing of music signal

# Open .wav file of music signal
fs, music = wavfile.read('music.wav')

Ts = 1/fs # fs = 44100Hz sampling frequency
t = np.arange(0,np.size(music)*Ts, Ts) #time index

# Plot music signal
counter = counter+1
plt.figure(counter)
plt.plot(t,music,'b', label = 'Sampling Fs = 44100Hz')
plt.ylabel('Amplitude of Music Signal')
plt.xlabel('Time [sec]')
plt.legend()
plt.title('Music Signal')
plt.show()
sd.play(music,fs)

M = 0.025/Ts #Window length of 25msec --> 1102.5 samples
window_hamming = sp.signal.get_window("hamming", int(M))
music = np.array(music, dtype=float)

#Calculate Short-Time Energy of Music Signal
energy = stenergy(music,window_hamming)

# Divide with max values to normalize axis
maxmusic = max(abs(music))
maxenergy = max(abs(energy))

counter = counter+1
plt.figure(counter)
plt.plot(t, music/maxmusic, 'b', label='Music Signal')
plt.plot(t, energy/maxenergy, 'r', label='Short Time Energy')
plt.xlabel('Time [sec]')
plt.ylabel('Normalised Amplitude')
plt.title('Short-Time Energy of Music Signal with Window Length = 25msec')
plt.legend()
plt.show()

#Calculate Short-Time Zero Crossings of Music Signal
zerocross = stzerocr(music,window_rectangular)

# Divide with max values to normalize axis
maxmusic = max(abs(music))
maxzerocross = max(abs(zerocross))

counter = counter+1
plt.figure(counter)
plt.plot(t, music/maxmusic, 'b', label='Music Signal')
plt.plot(t, zerocross/maxzerocross, 'g', label='Zero Crossings')
plt.xlabel('Time [sec]')
plt.ylabel('Normalised Amplitude')
plt.title('Short-Time Zero Crossings of Music Signal with Window Length = 25msec')
plt.legend()
plt.show()

# Changing Window length to see how it affects energy and zero crossings
N = np.array([50, 100, 200, 400, 800, 1000])

# Short-Time Energy:
counter = counter+1
plt.figure(counter)
for i in range(np.size(N)):
    window_hamming = sp.signal.get_window("hamming", N[i])
    #Calculate Short-Time Energy of Music Signal
    energy = stenergy(music,window_hamming)
    plt.subplot(np.size(N), 1, i+1)
    plt.plot(t, energy, 'r', label='Window length = %i samples' %N[i])
    plt.legend()

plt.xlabel('Time [sec]')
plt.suptitle('Short-Time Energy of Music Signal for different Window Lengths')
plt.show()

# Short-Time Zero Crossings:
counter = counter+1
plt.figure(counter)
for i in range(np.size(N)):
    window_rectangular = sp.signal.get_window("boxcar", N[i])
    #Calculate Short-Time Energy of Music Signal
    zerocross = stzerocr(music,window_rectangular)
    plt.subplot(np.size(N), 1, i+1)
    plt.plot(t, zerocross, 'g', label='Window length = %i samples' %N[i])
    plt.legend()

plt.xlabel('Time [sec]')
plt.suptitle('Short-Time Zero Crossings of Music Signal for different Window Lengths')
plt.show()


import pandas as pd
import numpy as np
import math, statistics, functools
import matplotlib.pyplot as plt
from sklearn.metrics.cluster import adjusted_rand_score

def read_csv_input(filename):
  df = pd.read_csv(filename, header = None).to_numpy()
  y = df[:, [0]]
  X = df[:, range(1, df.shape[1])]
  return X, y

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

def kmeans_random_init(n, k, low=-3, high=3):
  return np.random.uniform(low, high, k*n).reshape(k, n)

def gmm_random_init(m, n, k):
  means = np.random.multivariate_normal(np.zeros(n), np.identity(n), k)
  return means

def kmeans_plus_plus_init(X, k):
  m, n = X.shape
  means = np.zeros((k, n))
  means[0, :] = X[np.random.choice(m), :]
  for i in range(1, k):
    dis = distance(X, means[:i, :])
    nearest_dis_sq = np.power(np.min(dis, axis=1), 2)
    pi = nearest_dis_sq / np.sum(nearest_dis_sq)
    lucky = np.random.choice(np.arange(m), 1, p=pi)
    means[i, :] = X[lucky, :]
  return means

def calc_probs(X, means, cov_matrix):
  m, n = X.shape
  X_diff = X[None, :, :] - means[:, None, :]
  var = np.sum(np.matmul(X_diff, np.linalg.inv(cov_matrix)) * X_diff, axis = -1)
  numer = np.exp(-0.5 * var).T
  denom = ((2*np.pi)**(n/2))*(np.linalg.det(cov_matrix)**(0.5))
  return numer/denom

def e_step(X, means, cov_matrix, lams):
  probs = calc_probs(X, means, cov_matrix)
  lam_probs = probs * lams
  q = lam_probs / np.sum(lam_probs, axis = 1, keepdims=True)
  return q

def m_step(X, q):
  m, n = X.shape
  _, k = q.shape
  q_3d = np.broadcast_to(q, (1, m, k)).T
  X_3d = np.broadcast_to(X, (k, m, n))
  numer = np.sum(q_3d * X_3d, axis=1)
  denom = np.sum(q_3d, axis=1)
  means = numer/denom
  X_diff = X_3d - means[:, None, :]
  cov_matrix = np.matmul(np.transpose(q_3d * X_diff, (0, 2, 1)), X_diff)/denom[:, :, None]
  cov_matrix += (np.identity(n)*1e-6)[None, :, :]
  lams = np.sum(q, axis=0)/m
  return means, cov_matrix, lams

def gmm(X, k, init_means):
  m, n = X.shape
  means = init_means
  cov_matrix = np.broadcast_to(np.identity(n), (k, n, n))
  lams = np.ones(k)/k
  losses = []
  while True:
    q = e_step(X, means, cov_matrix, lams)
    means, cov_matrix, lams = m_step(X, q)
    probs = calc_probs(X, means, cov_matrix)
    loss = np.sum(np.log(np.sum(probs * lams, axis=1)))
    losses.append(loss)
    if len(losses) > 2 and abs(loss - losses[-2]) < 1e-3:
      break
  lam_probs = probs * lams
  classes = np.argmax(lam_probs, axis=1)
  return means, cov_matrix, lams, losses, classes

def distance(X1, X2):
  X1_sq = np.diag(np.dot(X1, X1.T)).reshape(X1.shape[0], -1)
  X2_sq = np.diag(np.dot(X2, X2.T)).reshape(-1, X2.shape[0])
  X1X2_2 = 2*np.dot(X1, X2.T)
  dist = X1_sq + X2_sq - X1X2_2
  return dist

def kmeans(X, k, init_centroids):
  m, n = X.shape
  prev_clusters = np.zeros(m) - 1
  centroids = init_centroids
  objectives = []
  while True:
    dis = distance(X, centroids)
    objectives.append(np.sum(np.min(dis, axis = 1))/m)
    clusters = np.argmin(dis, axis = 1)
    for i in range(k):
      if np.sum(clusters == i) > 0:
        centroids[i, :] = np.mean(X[clusters == i, :], axis = 0)
    if np.all(clusters == prev_clusters):
      break
    prev_clusters = clusters
  return clusters, centroids, objectives

def run_kmeans(X, ks, init_fun):
  print("######################")
  print("K-Means:")
  _, n = X.shape
  for k in ks:
    print("~~~~~~~~~~~~~~~~~~~~~")
    print(f"For k: {k}")
    loss_vals = []
    for r in range(20):
      init_centroids = init_fun(k)
      clusters, centroids, losses = kmeans(X, k, init_centroids)
      loss_vals.append(losses[-1])
    mean, var = statistics.mean(loss_vals), statistics.variance(loss_vals)
    print(f"\tmean:     {mean}\n\tvariance: {var}\n")

def run_gmms(X, ks, init_fun):
  print("######################")
  print("Gaussian Mixture Model:")
  for k in ks:
    print("~~~~~~~~~~~~~~~~~~~~~")
    print(f"For k: {k}")
    loss_vals = []
    for r in range(20):
      init_means = init_fun(k)
      means, cov_matrix, lams, losses, classes = gmm(X, k, init_means)
      loss_vals.append(losses[-1])
    mean, var = statistics.mean(loss_vals), statistics.variance(loss_vals)
    print(f"\tmean:     {mean}\n\tvariance: {var}\n")

def compare_clusterings(X, k, kmeans_init_fun, gmm_init_fun, R=20):
  print("######################")
  print(f"Comparing Kmeans and GMM for k={k}:")
  aris = [[], []]
  for r in range(R):
    init_centroids = kmeans_init_fun(k)
    kmeans_clusters, _, _ = kmeans(X, k, init_centroids)
    init_means = gmm_init_fun(k)
    _, _, _, _, gmm_clusters = gmm(X, k, init_means)
    aris[0].append(adjusted_rand_score(y[:, 0].tolist(), kmeans_clusters))
    aris[1].append(adjusted_rand_score(y[:, 0].tolist(), gmm_clusters))
  kmeans_ari_mean = statistics.mean(aris[0])
  gmm_ari_mean = statistics.mean(aris[1])
  print(f"\tK-Means Similarity Rand Score: {kmeans_ari_mean}")
  print(f"\tGMM Similarity Rand Score:     {gmm_ari_mean}\n")

def main():
  X, y = read_csv_input('leaf.data')
  m, n = X.shape
  X_norm, mu, sigma = normalize(X)
  ks = [12, 18, 24, 36, 42]

  kmean_rand_fun = functools.partial(kmeans_random_init, n)
  gmm_rand_fun = functools.partial(gmm_random_init, m, n)
  kmeans_pp_fun = functools.partial(kmeans_plus_plus_init, X_norm)

  print("WITH RANDOM INITIALIZATION\n")
  run_kmeans(X_norm, ks, kmean_rand_fun)
  run_gmms(X_norm, ks, gmm_rand_fun)
  compare_clusterings(X_norm, 36, kmean_rand_fun, gmm_rand_fun)

  print("\n\nWITH KMEANS++ INITIALIZATION\n")
  run_kmeans(X_norm, ks, kmeans_pp_fun)
  run_gmms(X_norm, ks, kmeans_pp_fun)
  compare_clusterings(X_norm, 36, kmeans_pp_fun, kmeans_pp_fun)

main()


from sympy import Eq, symbols, solve

def jacobi_method():
    '''
    Jacobi method

    we wanna create algorithm to solve linear equation

    the use will give three equation and these equations have symbol like x1, x2, x3

    then will give initial guess like 0, 1, 0. Now we wanna take number iteration from user

    to find the last values of x1, x2, x3

    now run program and see the result

    '''

    x1, x2, x3 = symbols('x1 x2 x3')

    initial_guess1, initial_guess2, initial_guess3 = map(int, input('Enter initial guesses respectively: ').split())

    li_e1 = list()
    li_e2 = list()
    li_e3 = list()

    iterations = int(input('Enter numbers iterations: '))

    eq1 = Eq(12*x1 + 3 * initial_guess2 - 5 * initial_guess3, 1)  # x2 = initial_guess2 , x3 = initial_guess3

    li_e1.append(*eval(f'{solve(eq1)}'))

    eq2 = Eq(initial_guess1 + 5 * x2 + 3 * initial_guess3, 28)  # x1 = initial_guess1, x3 = initial_guess3

    li_e2.append(*eval(f'{solve(eq2)}'))

    eq3 = Eq(3*initial_guess1 + 7 * initial_guess2 + 13 * x3, 76)  # x1 = initial_guess1, x2 = initial_guess2

    li_e3.append(*eval(f'{solve(eq3)}'))

    for i in range(iterations - 1):
        eq1 = Eq(12 * x1 + 3 * li_e2[i] - 5 * li_e3[i], 1)  # x2 = initial_guess2 , x3 = initial_guess3
        eq2 = Eq(li_e1[i] + 5 * x2 + 3 * li_e3[i], 28)  # x1 = initial_guess1, x3 = initial_guess3
        eq3 = Eq(3 * li_e1[i] + 7 * li_e2[i] + 13 * x3, 76)  # x1 = initial_guess1, x2 = initial_guess2
        li_e1.append(*eval(f'{solve(eq1)}'))
        li_e2.append(*eval(f'{solve(eq2)}'))
        li_e3.append(*eval(f'{solve(eq3)}'))

    print('x1', li_e1)
    print('x2', li_e2)
    print('x3', li_e3)

print(jacobi_method.__doc__)
jacobi_method()


import numpy as np
from scipy.stats import linregress

def determineLinearRegions(data, minLength=.1, minR2=.96, maxSlopeInterceptDiff=.75):
    """
    Determine regions of a plot that are approximately linear by performing
    linear least-squares on a rolling window.

    Parameters
    ----------

    data : array_like
        Data within which linear regions are to be identified

    minLength : int or float
        The minimum length of a linear segment, either as an
        integer number of indices, or as a float fraction of the
        overall data length.

    minR2 : float
        The minimum r-squared value for a region to be
        considered linear.

    maxSlopeInterceptDiff : float
        The float percentage difference allowed between slopes
        and intercepts of adjacent slices for them to be
        considered the same region.

    Returns
    -------

    regionIndices : np.ndarray[N,2]
        The start and end indices for the N detected regions.

    slopes : np.ndarray[N]
        The slope of each region.

    intercepts : np.ndarray[N]
        The intercept of each region.
    """
    if minLength < 1:
        minLinSteps = int(len(data)*minLength)
    else:
        minLinSteps = int(minLength)

    inLinearRegion = False
    linearRegions = []
    slopes = []
    intercepts = []

    # Perform least squares on a rolling window
    i = 0
    while i < len(data) - minLinSteps:
        xArr = np.arange(i, i+minLinSteps)
        slope, intercept, r2, p_value, std_err = linregress(xArr, data[i:i+minLinSteps])

        if np.abs(r2) > minR2:

            if inLinearRegion:
                # Calculate how different new slope is from old one
                if np.abs((np.mean(slopes[-1]) - slope) / np.mean(slopes[-1])) < maxSlopeInterceptDiff and np.abs((np.mean(intercepts[-1]) - intercept) / np.mean(intercepts[-1])) < maxSlopeInterceptDiff:
                    # This is still the same linear region, so we extend the bounds
                    linearRegions[-1][1] = i+minLinSteps

                    # And average in the slopes and intercepts
                    slopes[-1] += [slope]
                    intercepts[-1] += [intercept]
                else:
                    # Otherwise, we have a new linear region, which we start
                    # at the end of the other one
                    i = linearRegions[-1][1]
                    inLinearRegion = False
                    continue

            else:
                # New linear region
                linearRegions.append([i, i+minLinSteps])
                slopes.append([slope])
                intercepts.append([intercept])

            inLinearRegion = True

        else:
            inLinearRegion = False

        i += 1

    slopes = np.array([np.mean(s) for s in slopes])
    intercepts = np.array([np.mean(inter) for inter in intercepts])
    return np.array(linearRegions), slopes, intercepts


"""
Implement a mathematic matrix factorization that in linear algebra and numerical analysis
For Example:
    Given a square matrix A
        | a11    a12    a13 |       | 1     0     0 |   | U11    U12    U13 |
    A = | a21    a22    a23 |  =    | L21   1     0 | * | 0      U22    U23 |
        | a31    a23    a33 |       | L31   L32   1 |   | 0      0      U33 |

    and the L is the lower triangular and U is the upper triangular matrix
"""

import numpy as np

def lu_decompose(matrix):
    """perform A = LU decomposition

    Args:
        matrix: numpy array of shape (n, n)
                a square matrix

    Returns:
        L : numpy array of shape (n, n)
            the lower triangular matrix
        U : numpy array of shape (n ,n)
            the upper triangular matrix
    """
    n = matrix.shape[0]

    # Initialization for L and U matrix
    L = np.zeros((n, n))
    U = np.zeros((n, n))

    for i in range(n):
        # produce the k-th row of U
        U[i] = matrix[i] - np.matmul(L[i], U)
        # produce the k-th column of L
        L[:, i] = (matrix[:, i] - np.matmul(L, U[:, i])) / U[i, i]

    return L, U

if __name__ == "__main__":

    matrix = np.array([[2, 1, 1, 0], [4, 3, 3, 1], [8, 7, 9, 5], [6, 7, 9, 8]], dtype='float32')
    l, u = lu_decompose(matrix)
    print("L:->", l)
    print("U:->", u)


# Credit to original goes to wwnick
# from https://gis.stackexchange.com/questions/66/trilateration-using-3-latitude-and-longitude-points-and-3-distances

import math
import numpy
import numpy.linalg

def locate(LatA, LonA, DistA, LatB, LonB, DistB, LatC, LonC, DistC):
    #assuming elevation = 0
    earthR = 6371
    # LatA = 37.418436
    # LonA = -121.963477
    # DistA = 0.265710701754
    # LatB = 37.417243
    # LonB = -121.961889
    # DistB = 0.234592423446
    # LatC = 37.418692
    # LonC = -121.960194
    # DistC = 0.0548954278262

    #using authalic sphere
    #if using an ellipsoid this step is slightly different
    #Convert geodetic Lat/Long to ECEF xyz
    #   1. Convert Lat/Long to radians
    #   2. Convert Lat/Long(radians) to ECEF
    xA = earthR *(math.cos(math.radians(LatA)) * math.cos(math.radians(LonA)))
    yA = earthR *(math.cos(math.radians(LatA)) * math.sin(math.radians(LonA)))
    zA = earthR *(math.sin(math.radians(LatA)))

    xB = earthR *(math.cos(math.radians(LatB)) * math.cos(math.radians(LonB)))
    yB = earthR *(math.cos(math.radians(LatB)) * math.sin(math.radians(LonB)))
    zB = earthR *(math.sin(math.radians(LatB)))

    xC = earthR *(math.cos(math.radians(LatC)) * math.cos(math.radians(LonC)))
    yC = earthR *(math.cos(math.radians(LatC)) * math.sin(math.radians(LonC)))
    zC = earthR *(math.sin(math.radians(LatC)))

    P1 = numpy.array([xA, yA, zA])
    P2 = numpy.array([xB, yB, zB])
    P3 = numpy.array([xC, yC, zC])

    #from wikipedia
    #transform to get circle 1 at origin
    #transform to get circle 2 on x axis
    ex = (P2 - P1)/(numpy.linalg.norm(P2 - P1))
    i = numpy.dot(ex, P3 - P1)
    ey = (P3 - P1 - i*ex)/(numpy.linalg.norm(P3 - P1 - i*ex))
    ez = numpy.cross(ex,ey)
    d = numpy.linalg.norm(P2 - P1)
    j = numpy.dot(ey, P3 - P1)

    #from wikipedia
    #plug and chug using above values
    x = (pow(DistA,2) - pow(DistB,2) + pow(d,2))/(2*d)
    y = ((pow(DistA,2) - pow(DistC,2) + pow(i,2) + pow(j,2))/(2*j)) - ((i/j)*x)

    # only one case shown here
    z = math.sqrt(abs(pow(DistA,2) - pow(x,2) - pow(y,2)))

    #triPt is an array with ECEF x,y,z of trilateration point
    triPt = P1 + x*ex + y*ey + z*ez

    #convert back to lat/long from ECEF
    #convert to degrees
    lat = math.degrees(math.asin(triPt[2] / earthR))
    lon = math.degrees(math.atan2(triPt[1],triPt[0]))

    lat_long = str(lat) + ',' + str(lon)
    return lat_long


import csv
import numpy as np
import matplotlib.pyplot as plt

def loadCSV(filename):
    with open(filename,"r") as csvfile:
        lines = csv.reader(csvfile)
        dataset = list(lines)
        for i in range(len(dataset)):
            dataset[i] = [float(x) for x in dataset[i]]
    return np.array(dataset)

def normalize(X):
    mins = np.min(X, axis = 0)
    maxs = np.max(X, axis = 0)
    rng = maxs - mins
    norm_X = 1 - ((maxs - X)/rng)
    return norm_X

def logistic_func(beta, X):
    return 1.0/(1 + np.exp(-np.dot(X, beta.T)))

def log_gradient(beta, X, y):
    first_calc = logistic_func(beta, X) - y.reshape(X.shape[0], -1)
    final_calc = np.dot(first_calc.T, X)
    return final_calc

def cost_func(beta, X, y):
    log_func_v = logistic_func(beta, X)
    y = np.squeeze(y)
    step1 = y * np.log(log_func_v)
    step2 = (1 - y) * np.log(1 - log_func_v)
    final = -step1 - step2
    return np.mean(final)

def grad_desc(X, y, beta, lr=.01, converge_change=.001):
    cost = cost_func(beta, X, y)
    change_cost = 1
    num_iter = 1

    while(change_cost > converge_change):
        old_cost = cost
        beta = beta - (lr * log_gradient(beta, X, y))
        cost = cost_func(beta, X, y)
        change_cost = old_cost - cost
        num_iter += 1

    return beta, num_iter

def pred_values(beta, X):
    pred_prob = logistic_func(beta, X)
    pred_value = np.where(pred_prob >= .5, 1, 0)
    return np.squeeze(pred_value)

def plot_reg(X, y, beta):
    x_0 = X[np.where(y == 0.0)]
    x_1 = X[np.where(y == 1.0)]

    plt.scatter([x_0[:, 1]], [x_0[:, 2]], c='b', label='y = 0')
    plt.scatter([x_1[:, 1]], [x_1[:, 2]], c='r', label='y = 1')

    x1 = np.arange(0, 1, 0.1)
    x2 = -(beta[0,0] + beta[0,1]*x1)/beta[0,2]
    plt.plot(x1, x2, c='k', label='reg line')

    plt.xlabel('x1')
    plt.ylabel('x2')
    plt.legend()
    plt.show()

if __name__ == "__main__":
    dataset = loadCSV('dataset1.csv')

    X = normalize(dataset[:, :-1])

    X = np.hstack((np.matrix(np.ones(X.shape[0])).T, X))

    y = dataset[:, -1]

    beta = np.matrix(np.zeros(X.shape[1]))

    beta, num_iter = grad_desc(X, y, beta)

    print("Estimated regression coefficients:", beta)
    print("No. of iterations:", num_iter)

    y_pred = pred_values(beta, X)

    print("Correctly predicted labels:", np.sum(y == y_pred))

    plot_reg(X, y, beta)


import numpy as np

wsum = np.array([0.3, 2.9, 4.0])

def softmax(ws):
    exp_a = np.exp(ws)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y

output = softmax(wsum)
print(output)
print(output.sum(), '\n')

def softmax2(ws):
    c = np.max(ws)
    exp_a = np.exp(ws - c)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y

output2 = softmax2(wsum)
print(output2)
print(output2.sum())


"""
A module to have different distance metrics for spatial interpolation
"""
import numpy as np
from scipy.spatial.distance import cdist

def haversine(X1, X2):
    """
    Arguments
    ---------
    One test point
    Multiple Train Points

    Long Lat Order
    """

    # Non-vectorized version
    # X1 = X1.reshape(1, 2)
    # difference = (X1 - X2) * np.pi / 180
    # test_point_lat = X1[:, 1] * np.pi / 180
    # training_locations_lat = X2[:, 1] * np.pi / 180

    # a = np.sin(difference[:, 0] / 2)**2 * np.cos(test_point_lat) * np.cos(training_locations_lat) +\
    #     np.sin(difference[:, 1] / 2)**2
    # radius = 6371
    # c = 2 * np.arcsin(np.sqrt(a))
    # return radius * c

    # Vectorized code
    lon1, lat1, lon2, lat2 = map(
        np.radians, [X1[:, 0, None], X1[:, 1, None], X2[:, 0, None], X2[:, 1, None]])

    dlon = lon2.T - lon1
    dlat = lat2.T - lat1

    a = np.sin(dlat/2.0)**2 + np.cos(lat1)@np.cos(lat2.T) * np.sin(dlon/2.0)**2

    c = 2 * np.arcsin(np.sqrt(a))
    km = 6371 * c
    return km

def euclidean(X1, X2):
    # return np.linalg.norm(X1 - X2, 2, axis=1)
    return cdist(X1, X2)


import numpy as np
P=np.array(([0.5, 0.25, 0, 0.25, 0, 0, 0, 0, 0],
            [0.25, 0.25, 0.25, 0, 0.25, 0, 0, 0, 0],
            [0, 0.25, 0.5, 0, 0, 0.25, 0, 0, 0],
            [0.25, 0, 0, 0.25, 0.25, 0, 0.25, 0, 0],
            [0, 0.25, 0, 0.25, 0, 0.25, 0, 0.25, 0],
            [0, 0, 0.25, 0, 0.25, 0.25, 0, 0, 0.25],
            [0, 0, 0, 0.25, 0, 0, 0.5, 0.25, 0],
            [0, 0, 0, 0, 0.25, 0, 0.25, 0.25, 0.25],
            [0, 0, 0, 0, 0, 0.25, 0, 0.25, 0.5]))
print(P)
Pi=[0]*8+[1]
print(Pi)

def transfer_matrix(Pi):
        S=[0]*9
        for a in range(9):
                S[a]=0
                for b in range(9):
                        S[a]+=P[b, a]*Pi[b]
        return S

for i in range(1000):
        Pi=transfer_matrix(Pi)
        print(Pi)

# After 1000 iterations we get:
>>> [0.11111111111111109, 0.11111111111111109, 0.1111111111111111, 0.11111111111111109, 0.1111111111111111, 0.11111111111111113, 0.1111111111111111, 0.11111111111111113, 0.11111111111111113]


#Regressão linear pt2 SCIKIT LEARN
from matplotlib import pyplot as plt
import numpy as np

#dados
x = [1, 2 ,3 ,4 , 5, 6]
y = [10, 50 , 100, 150, 200, 250]

#plot dos dados
plt.figure(figsize=(10,5))
plt.plot(x,y,'o',label = 'Dados originais')
plt.legend()
plt.xlabel("x")
plt.ylabel("Y")
plt.grid()
plt.show()

#Transformando em numpy array
x,y = np.array(x).reshape(-1, 1), np.array(y).reshape(-1, 1)

#Modelo
from sklearn.linear_model import LinearRegression

#Treinando o modelo: y = a*x + b, valores reais (a,b) = (2,1)
reg = LinearRegression()
reg.fit(x,y)

#Coeficientes a,b estimados
#Valores estimados usando numpy diretamente...

print("A estimado:",reg.coef_.ravel()[0])
print('B estimado: ',reg.intercept_[0]) #modelo independente

#Predição do modelo
y_pred = reg.predict(x)

#Score do modelo
#Caracteriza se o modelo foi bom ou ruim para a base de dados
# quanto mais proximo de 1 é melhor, quanto mais perto 0 pior.
score = reg.score(x, y)
print("Score: ",score)

#Plot de dados
plt.figure(figsize=(10, 5))
plt.plot(x, y, '*', label = 'Dados originais')
plt.plot(x, y_pred, label = 'Regressao linear (R2: {:.3f})'.format(score))
plt.legend()
plt.xlabel('x')
plt.ylabel('y')
plt.title = 'Regressão Linear'
plt.grid()
plt.show()
print(80*'=')

#Parte 2

plt.figure(figsize=(10, 5))
plt.plot(x, y, '*', label = 'Dados originais')
plt.plot(x, y_pred, label = 'Regressao linear (R2: {:.3f})'.format(score))
plt.hlines(y=y.mean(), xmin = x.min(),xmax=x.max(),linestyles='dashed',
           label='Modelo de referencia $R^2$')
plt.legend()
plt.xlabel('x')
plt.ylabel('y')
plt.title = 'Regressão Linear'
plt.grid()
plt.show()

#Função para o calculo do MSE
def mse(y_true, y_pred, is_ref = False):
    #MSE modelo
    if is_ref:
        mse = ((y_true - y_true.mean())**2).mean()
    else:
        mse = ((y_true - y_pred)**2).mean()
    return mse
#Função para o calculo do coeficiente de determinação R2
def r2(mse_reg,mse_ref):
    return 1 - mse_reg/mse_ref

#Visualizando y e y pred
print('y_true: ',y.ravel())
print('y_pred: ',y_pred.ravel())

#Calculando o mse dos modelos
mse_reg = mse(y_true=y,y_pred=y_pred)
print('MSE do modelo de regeressao: ', mse_reg)
mse_ref = mse(y_true=y, y_pred=y_pred, is_ref=True)
print('MSE dos modelo de referencia: ', mse_ref)

#Calculando o R2 score
r2_score = r2(mse_reg=mse_reg,mse_ref=mse_ref)
print('Coeficiente R2 do modelo implementado(calculado): ',r2_score)

#Score retornado pelo scikit lean
r2_score_skl = reg.score(x, y)
print('Coeficiente R2 do modelo implementado(Scikit Learn): ',r2_score_skl)


import argparse
import math
import numpy as np
import pandas as pd
from numpy.linalg import norm

def load_data(filename):
    edges = []
    vertexes = set()
    largest = 0
    with open(filename) as f:
        for l in f:
            l = l.strip().split(' ')
            l[0] = int(l[0])
            l[1] = int(l[1])
            if l[0] > largest:
                largest = l[0]
            if l[1] > largest:
                largest = l[1]
            vertexes.add(l[0])
            vertexes.add(l[1])
            edges.append((l[0],l[1]))
    return edges, vertexes, largest+1

def create_adjancecy(edges, size):
    a = np.zeros((size, size))
    for i,j in edges:
        a[i][j] = 1
        a[j][i] = 1
    return a

def normalize(a):
    d = np.zeros(a.shape)
    for i in range(a.shape[0]):
        d_cur = 0
        for j in range(a.shape[0]):
            d_cur += a[i][j]
        d[i][i] = d_cur
    for i in range(a.shape[0]):
        d[i][i] = 1/(math.sqrt(d[i][i]))
    return d*a*d

def run_rwr(args, a, largest):
    e = np.zeros(largest)
    e[args.seed] = 1
    r = e
    r1 = e
    scores = np.zeros(args.max_runs)
    for i in range(args.max_runs):
        r = args.c * (a.dot(r1)) + (1- args.c) * e
        scores[i] = norm(r - r1, 1)
        if scores[i] <= args.epsilon:
            break
        r1 = r
    return r

def print_results(ids, x):
    df = pd.DataFrame()
    df['Node'] = ids
    df['Score'] = x
    df = df.sort_values(by=['Score'], ascending=False)
    df = df.reset_index(drop=True)
    print(df[0:10])

def main(args):
    edges, vertexes, largest = load_data(args.input_file)
    a = create_adjancecy(edges, largest)
    if args.normalize:
        a = normalize(a)
    a = a.T
    x = run_rwr(args, a, largest)
    print_results(np.arange(0, largest), x)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='RWR on email data')
    parser.add_argument('--input_file', default='HW1_dataset/email-Eu-core.txt', type=str, help='input graph file')
    parser.add_argument('--c', default=0.9, type=float, help='dampening factor')
    parser.add_argument('--seed', default=42, type=int, help='seed node to start rwr on')
    parser.add_argument('--max_runs', default=100, type=int, help='number of times to run the matix multiply')
    parser.add_argument('--epsilon', default=1e-7, type=float, help='Keep iterating until the normilized difference is less than this value')
    parser.add_argument('--normalize', action='store_true', help='Normalize the adjacency matrix')
    args = parser.parse_args()
    main(args)


import numpy as np
from scipy.stats import norm
from sklearn.decomposition import PCA
from KDEpy import NaiveKDE

def create_shift(
    data,
    src_split=0.4,
    alpha=1,
    beta=2,
    kdebw=0.3,
    eps=0.001,
):
    """
    Creates covariate shift sampling of data into disjoint source and target set.

    Let \mu and \sigma be the mean and the standard deviation of the first principal component retrieved by PCA on the whole data.
    The target is randomly sampled based on a Gaussian with mean = \mu and standard deviation = \sigma.
    The source is randomly sampled based on a Gaussian with mean = \mu + alpha and standard devaition = \sigma / beta

    data: [m, n]
    alpha, beta: the parameter that distorts the gaussian used in sampling
                   according to the first principle component
    output: source indices, target indices, ratios based on kernel density estimation with bandwidth = kdebw and smoothed by eps
    """
    m = np.shape(data)[0]
    source_size = int(m * src_split)
    target_size = source_size

    pca = PCA(n_components=2)
    pc2 = pca.fit_transform(data)
    pc = pc2[:, 0]
    pc = pc.reshape(-1, 1)

    pc_mean = np.mean(pc)
    pc_std = np.std(pc)

    sample_mean = pc_mean + alpha
    sample_std = pc_std / beta

    # sample according to the probs
    prob_s = norm.pdf(pc, loc=sample_mean, scale=sample_std)
    sum_s = np.sum(prob_s)
    prob_s = prob_s / sum_s
    prob_t = norm.pdf(pc, loc=pc_mean, scale=pc_std)
    sum_t = np.sum(prob_t)
    prob_t = prob_t / sum_t

    source_ind = np.random.choice(
        range(m), size=source_size, replace=False, p=np.reshape(prob_s, (m))
    )

    pt_proxy = np.copy(prob_t)
    pt_proxy[source_ind] = 0
    pt_proxy = pt_proxy / np.sum(pt_proxy)
    target_ind = np.random.choice(
        range(m), size=target_size, replace=False, p=np.reshape(pt_proxy, (m))
    )

    assert np.all(np.sort(source_ind) != np.sort(target_ind))
    src_kde = KDEAdapter(kde=NaiveKDE(kernel="gaussian", bw=kdebw)).fit(
        pc2[source_ind, :]
    )
    trg_kde = KDEAdapter(kde=NaiveKDE(kernel="gaussian", bw=kdebw)).fit(
        pc2[target_ind, :]
    )

    ratios = src_kde.p(pc2, eps) / trg_kde.p(pc2, eps)
    print("min ratio= {:.5f}, max ratio= {:.5f}".format(np.min(ratios), np.max(ratios)))

    return source_ind, target_ind, ratios

class KDEAdapter:
    def __init__(self, kde=NaiveKDE(kernel="gaussian", bw=0.3)):
        self._kde = kde

    def fit(self, sample):
        self._kde.fit(sample)
        return self

    def pdf(self, sample):
        density = self._kde.evaluate(sample)
        return density

    def p(self, sample, eps=0):
        density = self._kde.evaluate(sample)
        return (density + eps) / np.sum(density + eps)


import numpy

import mcc_nn_funcs

def gradient_function_regularized(theta, x_data, y_data, regularization_lambda=1.0):

    num_examples = y_data.shape[0]
    regularized_term = numpy.zeros(theta.shape)

    hypothesis = mcc_nn_funcs.sigmoid_function(numpy.dot(theta, x_data.T))
    error = hypothesis - y_data
    hypothesis_gradient = numpy.dot(x_data.T, error)/num_examples

    regularized_term[1:] = (regularization_lambda/num_examples)*theta[1:]

    gradient = hypothesis_gradient + regularized_term

    return gradient


#!/usr/bin/env python
import numpy as np
from scipy.stats import norm

def bachelier(So, K, sigma, T, option_type):
    '''
    Calculate European option price using Bachelier model:
        dSt = sigma * S0 * dWt
        St = S0*(1 + sigma*Wt)

    Parameter
    ---------
    So: float
        price of underlying asset at time 0
    K: float
        strike price of option
    sigma: float
        variance of Brownian motion
    T: float
        length of time
    option_type: str
        type of European option.
        Including: van call/put (vanilla), con call/put (cash-or-nothing), aon call/put (asset-or-nothing)

    Return
    ------
    val: value of the option at time 0
    '''

    xs = (K-So) / (So * sigma * np.sqrt(T))
    val = None

    if So == K:
        return sigma*So*np.sqrt(T/(2*np.pi))

    if option_type == 'van call':
        val = (So - K) * norm.cdf(-xs) + So*sigma*np.sqrt(T)*norm.pdf(-xs)
    elif option_type == 'van put':
        val = (K - So) * norm.cdf(xs) + So*sigma*np.sqrt(T)*norm.pdf(xs)
    elif option_type == 'con call':
        val = norm.cdf(-xs)
    elif option_type == 'con put':
        val = norm.cdf(xs)
    elif option_type == 'aon call':
        val = So*norm.cdf(-xs) + So*sigma*np.sqrt(T)*norm.pdf(-xs)
    elif option_type == 'aon put':
        val = So*norm.cdf(xs) - So*sigma*np.sqrt(T)*norm.pdf(xs)
    else:
        raise(ValueError("Option type is invalid. " +
                         "Should be either 'van call', 'van put', 'con call', 'con put', 'aon call', or 'aon put'"))

    return val

def black_scholes(So, K, r, sigma, T, option_type):
    '''
    Calculate European option price using Black-Scholes (1973) model:
        dSt = r*dSt + sigma*St*dWt
        St = S0*exp{(r-sigma^2/2)t + sigma*Wt}

    Parameter
    ---------
    So: float
        price of underlying asset at time 0
    K: float
        strike price of option
    r: float
        drift of St
    sigma: float
        variance of Brownian motion
    T: float
        length of time
    option_type: str
        type of European option.
        Including: van call/put (vanilla), con call/put (cash-or-nothing), aon call/put (asset-or-nothing)

    Return
    ------
    val: value of the option at time 0
    '''

    d1 = (np.log(So/K) + (r+sigma**2/2)*T) / (sigma*np.sqrt(T))
    d2 = (np.log(So/K) + (r-sigma**2/2)*T) / (sigma*np.sqrt(T))
    val = None

    if So == K:
        return sigma*So*np.sqrt(T/(2*np.pi))

    if option_type == 'van call':
        val = So*norm.cdf(d1) - K*np.e**(-r*T)*norm.cdf(d2)
    elif option_type == 'van put':
        val = -So*norm.cdf(-d1) + K*np.e**(-r*T)*norm.cdf(-d2)
    elif option_type == 'con call':
        val = np.e**(-r*T) * norm.cdf(d2)
    elif option_type == 'con put':
        val = np.e**(-r*T) * norm.cdf(-d2)
    elif option_type == 'aon call':
        val = So*norm.cdf(d1)
    elif option_type == 'aon put':
        val = So*norm.cdf(-d1)
    else:
        raise(ValueError("Option type is invalid. " +
                         "Should be either 'van call', 'van put', 'con call', 'con put', 'aon call', or 'aon put'"))

    return val


def stiff_2nd_order(n_elem, T, L, fixed_dofs):
    #Assembly of 2nd order pre-tension matrix for an Euler-Bernoulli beam
    #of elements n_elem, pre-tension T, length L and BCs fixed_dofs.

    import numpy as np

    Le = L / n_elem
    #local stiffness matrix from 2nd order term
    k = np.array([[6 / 5 * T / Le,  T / 10,\
                  -6 / 5 * T / Le,  T / 10],
                 [ T / 10, 2 * Le * T / 15,\
                  -T / 10,    -Le * T / 30 ],
                 [-6 / 5 * T / Le, -T / 10,\
                   6 / 5 * T / Le, -T / 10],
                 [ T / 10,    -Le * T / 30 ,\
                  -T / 10, 2 * Le * T / 15]])

    dof_node = 2
    dof_elem = 4
    tot_dofs = n_elem * dof_node + 2

    k_struct = np.zeros([tot_dofs,tot_dofs])

    for i in range(n_elem):
        k_struct[2*i:2*i+4, 2*i:2*i+4] += k

    for dof in fixed_dofs:
        for i in [0, 1]:
            k_struct = np.delete(k_struct, dof, axis = i)

    return  k_struct


import math
import numpy
from collections import namedtuple

class KNN_Classifier(object):

	DatapointTuple = namedtuple('DatapointTuple', ['datapoint', 'distance'])

	def __init__(self):
		self.reset()

	def reset(self):
		self.distance_features_list = []
		self.k_neighbors = 0 # hyper parameter 1
		self.distance_function = self.euclidean_distance # hyper parameter 2
		self.classification_label = None
		self.feature_labels = []
		self.dataset = []

	def train(self, dataset, classification_label, distance_features_list):
		self.distance_features_list = distance_features_list
		self.dataset = dataset # this classifier memorizes more than learn
		self.classification_label = classification_label
		self.feature_labels = dataset[0].keys()
		self.feature_labels.remove(self.classification_label)

	def euclidean_distance(self, data_point1, data_point2):

		dimension = len(self.distance_features_list)
		distance = 0
		for x in range(dimension):
			value1 = data_point1[self.distance_features_list[x]]
			value2 = data_point2[self.distance_features_list[x]]
			distance += pow((value2 - value1), 2)
		return math.sqrt(distance)

	def cosine_simmilarity(self, data_point1, data_point2):

		dimension = len(self.distance_features_list)
		a = []
		b = []
		# build the two vectors
		for x in range(dimension):
			a.append(data_point1[self.distance_features_list[x]])
			b.append(data_point2[self.distance_features_list[x]])

		dot_product = numpy.dot(a, b)
		norm_a = numpy.linalg.norm(a)
		norm_b = numpy.linalg.norm(b)
		return dot_product / (norm_a * norm_b)

	def classify(self, item_classify):

		closest_distance_list = []
		# iterate through all the data points and build list of closest neighbors
		for datapoint in self.dataset:
			# compute distance
			distance = self.distance_function(item_classify, datapoint)
			distance_item = self.DatapointTuple(datapoint, distance)
			# pass through add items until closest distance is initially filled up
			if len(closest_distance_list) < self.k_neighbors:
				closest_distance_list.append(distance_item)
				closest_distance_list.sort(key=lambda x: x.distance)
			# compare against largest distance found so far and insert if new found distance is less
			elif distance < closest_distance_list[self.k_neighbors-1].distance:
				closest_distance_list.pop() # remove old largest value
				closest_distance_list.append(distance_item)
				closest_distance_list.sort(key=lambda x: x.distance)
		#print "Closest distance list", closest_distance_list
		return self.__majority_vote_label(closest_distance_list)

	def __majority_vote_label(self, closest_distance_list):

		count_dict = {}
		# cast the votes
		for item in closest_distance_list:
			classification = item.datapoint[self.classification_label]
			if classification in count_dict.keys():
				count = count_dict[classification]
				count_dict[classification] = count + 1
			else:
				count_dict[classification] = 1
		# count the votes
		winner_label = 0
		largest_count = -1
		for key in count_dict.keys():
			if count_dict[key] > largest_count:
				largest_count = count_dict[key]
				winner_label = key
		return winner_label


from typing import Dict, Union

import numpy as np

COVARIANCE_MATRICES = dict()

def get_eigenval_diversity_index(eig_vals: np.ndarray):
    """Return Simpson diversity index of eigvalue explained variance ratios.
    Args:
        eig_vals   : eigenvalues in descending order

    """
    tot = sum(eig_vals)
    var_exp = [(i / tot) for i in eig_vals]
    simpson_di = sum(x**2 for x in var_exp) * 100
    return simpson_di

def get_explained_variance(eig_vals: np.ndarray,
                           threshold: float = 0.99,
                           return_cum: bool = False):
    """Return number of `eig_vals` needed to explain `threshold`*100 percent of variance
    Args:
        eig_vals   : numpy.ndarray of eigenvalues in descending order
        threshold  : percent of variance to explain
        return_cum : return the cumulative array of eigenvalues
    Return:
        nr_eig_vals : int
        cum_var_exp : numpy.ndarray

            or

        nr_eig_vals : int
    """
    tot = sum(eig_vals)
    var_exp = [(i / tot) for i in eig_vals]
    cum_var_exp = np.cumsum(var_exp)
    nr_eig_vals = np.argmax(cum_var_exp > threshold)
    if return_cum:
        return nr_eig_vals, cum_var_exp
    return nr_eig_vals

def get_layer_saturation(nr_eig_vals: np.ndarray, layer_width: int) -> int:
    saturation = round(100 * nr_eig_vals / layer_width, 2)
    return saturation

def batch_mean(batch: np.ndarray):
    """Get mean of first vector in `batch`."""  # TODO: Add support for non-dense layers.
    return np.mean(batch[0])

def batch_cov(batch: np.ndarray):
    """Get covariance of first instance in `batch`."""  # TODO: Add support for non-dense layers.
    return np.cov(batch[0])

def compute_saturation(cov: np.ndarray, thresh: float = .99) -> float:
    """
    Provides layer saturation
    :param covariance_matrix:
    :param thresh:
    :param conv_method:
    :return:
    """

    eig_vals = np.linalg.eigvalsh(cov)

    # Sort the eigenvalues from high to low
    eig_vals = sorted(eig_vals, reverse=True)
    total_dim = len(cov)
    nr_eigs = get_explained_variance(eig_vals=eig_vals, threshold=thresh, return_cum=False)
    return get_layer_saturation(nr_eig_vals=nr_eigs, layer_width=total_dim)


import numpy as np
import math
from scipy import signal
"""
windowIndex: index/(windowLength-1)
0:SMA, 1:Gaussian, 2:Hanning, 3:Sin, 4:Vorbis
5:Blackman, 6:Nutall, 7:Blackman-Harris, 8:Kaiser(beta14), 9:Dolph-Chebyshev(100dB)
"""

_FILTERTYPE = {'SMA':0, 'Gaussian':1, 'Hanning':2, 'Sin':3, 'Vorbis':4, 'Blackman':5, 'Nuttall':6, 'BH':7, 'Kaiser':8, 'DCheb':9 }

#mode0:constant time, mode1:constant period, mode2:Sweep
def createWavetable(amp, length, *, mode=1, freq=1.0, maxTime=1.0, period=1.0, fstart=0.0, fstop=1.0):
	cTable = np.zeros(length)
	indice1 = np.arange(0, length, 1)

	if(mode == 0):
		timeArray = (indice1/(length-1))*maxTime
	if(mode == 1):
		timeArray = (indice1/((length-1)/period)/freq)
	if(mode==2):
		timeArray = (indice1/(length-1))*maxTime
		freqArray = np.linspace(fstart, fstop, length)

	for ctr in indice1:
		if(mode != 2):
			cTable[ctr] = amp*math.sin(timeArray[ctr]*2*math.pi*freq)
		else:
			cTable[ctr] = amp*math.sin(timeArray[ctr]*2*math.pi*freqArray[ctr])

	if(mode != 2):
		return np.vstack((timeArray, cTable))#時間軸:[0,:], 正弦波テーブル:[1,:]
	else:
		return np.vstack((timeArray, cTable, freqArray))#時間軸:[0,:], 正弦波テーブル:[1,:]

def GaussianWindow(wsize):
	"""
	ref: http://www.eng.kagawa-u.ac.jp/~tishii/Lab/Etc/gauss.html
	"""
	warray = np.zeros(wsize)
	iterator1 = np.arange(0,wsize,1)
	sigma = np.std(iterator1)
	for i in iterator1:
		warray[i] = (1/(math.sqrt(2*math.pi)*sigma))*math.exp(-1*(math.pow(i-((wsize-1)/2),2)/(2*math.pow(sigma,2))))
	return warray

def HanningWindow(wsize):
	"""
	ref: http://www.fbs.osaka-u.ac.jp/labs/ishijima/FFT-06.html
	"""
	warray = np.zeros(wsize)
	iterator1 = np.arange(0,wsize,1)
	for i in iterator1:
		warray[i] = 0.5-(0.5*math.cos(2*math.pi*(i/(wsize-1))))
	return warray

def SinWindow(wsize):
	"""
	ref: http://www.spcom.ecei.tohoku.ac.jp/~aito/kisosemi/slides2.pdf
	"""
	warray = np.zeros(wsize)
	iterator1 = np.arange(0,wsize,1)
	for i in iterator1:
		warray[i] = math.sin((math.pi*(i/(wsize-1))))
	return warray

def VorbisWindow(wsize):
	"""
	ref: https://ja.wikipedia.org/wiki/%E7%AA%93%E9%96%A2%E6%95%B0#Vorbis%E7%AA%93
	"""
	warray = np.zeros(wsize)
	iterator1 = np.arange(0,wsize,1)
	for i in iterator1:
		warray[i] = math.sin( (math.pi / 2.0) * math.pow(math.sin(math.pi*(i/(wsize-1))), 2))
	return warray

def BlackmanWindow(wsize):
	warray = np.zeros(wsize)
	warray = signal.get_window('blackman', wsize)
	return warray

def NuttallWindow(wsize):
	warray = np.zeros(wsize)
	warray = signal.get_window('nuttall', wsize)
	return warray

def BHWindow(wsize):#Blackman-Harris
	warray = np.zeros(wsize)
	warray = signal.get_window('blackmanharris', wsize)
	return warray

def KaiserWindow(wsize, *, beta=14):#Kaiser(beta=14)
	warray = np.zeros(wsize)
	warray = signal.get_window(('kaiser',beta), wsize)
	return warray

def DChebWindow(wsize):#Dolph-Chebyshev(100dB)
	warray = np.zeros(wsize)
	warray = signal.get_window(('chebwin',100.0), wsize)
	return warray

def CreateWindow(wsize, wtype, *, ckbeta=14):
	window_array = np.zeros(wsize)
	if(wtype==0):
		window_array[:] = 1
	elif (wtype == 1):
		window_array = GaussianWindow(wsize)
	elif (wtype == 2):
		window_array = HanningWindow(wsize)
	elif (wtype == 3):
		window_array = SinWindow(wsize)
	elif (wtype == 4):
		window_array = VorbisWindow(wsize)
	elif (wtype == 5):
		window_array = BlackmanWindow(wsize)
	elif (wtype == 6):
		window_array = NuttallWindow(wsize)
	elif (wtype == 7):
		window_array = BHWindow(wsize)
	elif (wtype == 8):
		window_array = KaiserWindow(wsize, beta=ckbeta)
	elif (wtype == 9):
		window_array = DChebWindow(wsize)
	return window_array


import numpy as np
from scipy import spatial
import matplotlib.pyplot as plt
import sys

file_name = sys.argv[1] if len(sys.argv) > 1 else 'data/nctu.csv'
points_coordinate = np.loadtxt(file_name, delimiter=',')
num_points = points_coordinate.shape[0]
distance_matrix = spatial.distance.cdist(points_coordinate, points_coordinate, metric='euclidean')
distance_matrix = distance_matrix * 111000  # 1 degree of lat/lon ~ = 111000m

def cal_total_distance(routine):
    '''The objective function. input routine, return total distance.
    cal_total_distance(np.arange(num_points))
    '''
    num_points, = routine.shape
    return sum([distance_matrix[routine[i % num_points], routine[(i + 1) % num_points]] for i in range(num_points)])

# %%
from sko.SA import SA_TSP

sa_tsp = SA_TSP(func=cal_total_distance, x0=range(num_points), T_max=100, T_min=1, L=10 * num_points)

best_points, best_distance = sa_tsp.run()
print(best_points, best_distance, cal_total_distance(best_points))
# %% Plot the best routine
from matplotlib.ticker import FormatStrFormatter

fig, ax = plt.subplots(1, 2)

best_points_ = np.concatenate([best_points, [best_points[0]]])
best_points_coordinate = points_coordinate[best_points_, :]
ax[0].plot(sa_tsp.best_y_history)
ax[0].set_xlabel("Iteration")
ax[0].set_ylabel("Distance")
ax[1].plot(best_points_coordinate[:, 0], best_points_coordinate[:, 1],
           marker='o', markerfacecolor='b', color='c', linestyle='-')
ax[1].xaxis.set_major_formatter(FormatStrFormatter('%.3f'))
ax[1].yaxis.set_major_formatter(FormatStrFormatter('%.3f'))
ax[1].set_xlabel("Longitude")
ax[1].set_ylabel("Latitude")
plt.show()

# %% Plot the animation
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

best_x_history = sa_tsp.best_x_history

fig2, ax2 = plt.subplots(1, 1)
ax2.set_title('title', loc='center')
line = ax2.plot(points_coordinate[:, 0], points_coordinate[:, 1],
                marker='o', markerfacecolor='b', color='c', linestyle='-')
ax2.xaxis.set_major_formatter(FormatStrFormatter('%.3f'))
ax2.yaxis.set_major_formatter(FormatStrFormatter('%.3f'))
ax2.set_xlabel("Longitude")
ax2.set_ylabel("Latitude")
plt.ion()
p = plt.show()

def update_scatter(frame):
    ax2.set_title('iter = ' + str(frame))
    points = best_x_history[frame]
    points = np.concatenate([points, [points[0]]])
    point_coordinate = points_coordinate[points, :]
    plt.setp(line, 'xdata', point_coordinate[:, 0], 'ydata', point_coordinate[:, 1])
    return line

ani = FuncAnimation(fig2, update_scatter, blit=True, interval=25, frames=len(best_x_history))
plt.show()

# ani.save('sa_tsp.gif', writer='pillow')


import copy as cp
import numpy as np

class Spline():
    def cubic_spline(self, points):
        result = {
            'aMatrix': None,
            'bMatrix': None,
            'resultMessage': None,
            'error': False,
            'errorMessage': None
        }
        n = len(points)

        if n <= 2:
            result['error'] = True
            result['errorMessage']= 'Points must be greater than 2'
        else:
            A = list()
            b = list()
            eq1 = n-1
            k = 0

            while k < eq1:
                for i in range(2):
                    ec = []

                    for j in range(eq1):
                        if j == k:
                            if i == 0:
                                x = [points[k][0]**3, points[k][0]**2, points[k][0], 1]
                            else:
                                x = [points[k+1][0]**3, points[k+1][0]**2, points[k+1][0], 1]
                            ec += x
                        else:
                            x = [0, 0, 0, 0]
                            ec += x

                    A.append(ec)
                    b.append(points[k+i][1])

                k += 1

            eq2 = n-2
            k = 0

            while k < eq2:
                der1 = []
                der2 = []

                for j in range(eq1):
                    if j == k:
                        x = [3*points[k+1][0]**2, 2*points[k+1][0], 1, 0]
                        der1 += x
                        x = [6*points[k+1][0], 2, 0, 0]
                        der2 += x
                    elif j== k+1:
                        x = [-3*points[k+1][0]**2, -2*points[k+1][0], -1, 0]
                        der1 += x
                        x = [-6*points[k+1][0], -2, 0, 0]
                        der2 += x
                    else:
                        x = [0, 0, 0, 0]
                        der1 += x
                        der2 += x

                A.append(der1)
                A.append(der2)
                b.append(0)
                b.append(0)
                k += 1

            x = [6*points[0][0], 2, 0, 0]

            for j in range(eq1-1):
                x += [0, 0, 0, 0]

            A.append(x)
            b.append(0)
            x = []

            for j in range(eq1-1):
                x += [0, 0, 0, 0]

            x += [6*points[n-1][0], 2, 0, 0]
            A.append(x)
            b.append(0)

        if not result['error']:
            result['aMatrix'] = A
            result['bMatrix'] = b
            result['resultMesage'] = 'The method successfully created the system of equations'

        return result


import pandas as pd
from statistics import mean
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import style
import random

style.use('fivethirtyeight')

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

def create_dataset(hm, variance, step=2, correlation=False):
    val = 1
    ys = []
    for i in range(hm):
        y = val + random.randrange(-variance, variance)
        ys.append(y)
        if correlation and correlation == 'pos':
            val+=step
        elif correlation and correlation == 'neg':
            val -= tep
        xs = [i for i in range(len(ys))]

    return np.array(xs, dtype=np.float64), np.array(ys, dtype=np.float64)

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

    b = mean(ys) - (m * mean(xs))
    return m, b

def squared_error(ys_orig, ys_line):
    return sum((ys_line-ys_orig)**2)

def coefficient_of_determination(ys_orig,ys_line):
    y_mean_line = [mean(ys_orig) for y in ys_orig]
    squared_error_regr = squared_error(ys_orig, ys_line)
    squared_error_y_mean = squared_error(ys_orig, y_mean_line)
    return 1 - (squared_error_regr / squared_error_y_mean)

xs, ys = create_dataset(40, 40, 2, correlation='pos')

m, b = best_fit_slope_and_intercept(xs,ys)

regression_line = [(m*x) +b for x in xs]

r_squared = coefficient_of_determination(ys, regression_line)
print(r_squared)

predict_x = 8
predict_y = (m*predict_x)+b

plt.scatter(xs,ys)
plt.scatter(predict_x,predict_y)
plt.plot(xs, regression_line)

plt.show()

#print(m,b)


from abc import abstractmethod, ABC
import numpy as np

class Loss(ABC):
    @abstractmethod
    def __call__(self, true_labels, predictions):
        pass

    @abstractmethod
    def derivative(self, true_labels, predictions):
        pass

class SquaredLoss(Loss):
    def __call__(self, true_labels, predictions):
        diff = true_labels - predictions
        loss = diff.T @ diff
        return loss / 2

    def derivative(self, true_labels, predictions):
        return predictions - true_labels  # turn this around and do gradient ASCENT, works too ;)

class CrossEntropy(Loss):
    def __init__(self):
        from src.activation_functions import Softmax
        self.softmax = Softmax()

    def __call__(self, true_labels, predictions):
        y = true_labels.argmax(axis=1) if true_labels.ndim > 1 else true_labels
        m = y.shape[0]
        p = self.softmax(predictions)
        log_likelihood = -np.log(p[list(range(m)), y])
        loss = np.sum(log_likelihood) / m
        return loss

    def derivative(self, true_labels, predictions):
        y = true_labels.argmax(axis=1) if true_labels.ndim > 1 else true_labels
        m = y.shape[0]
        grad = self.softmax(predictions)
        grad[range(m), y] -= 1
        grad = grad / m
        return grad


import numpy as np

def frobenius_distance(A, B):
    # Given two nxn matrices, return the 'Frobenius distance' between them

    '''
    Inputs
    -----
    A - matrix A with dimensions n*n
    B - matrix B with dimensions n*n

    Returns
    -----
    Frobenius distance between A and B
    '''
    return np.sqrt(np.sum(np.square(A - B)))


from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

def get_min_dimensions(flattened):
    pca = PCA().fit(flattened)
    # plt.figure()
    # plt.title('PCA')
    # plt.xlabel('Dimensions')
    # plt.ylabel('Variance Retention')
    # plt.plot(pca.explained_variance_ratio_.cumsum(), lw=3)
    # plt.show()
    min_dim = (np.where(pca.explained_variance_ratio_.cumsum() > 0.95))[0][0]
    print('Minimum dimensions required for 95% retention = ', min_dim)
    return min_dim

def doPCA(flattened, dim=None):
    if dim is None:
        dim = get_min_dimensions(flattened)
    pca = PCA(dim)
    projected = pca.fit_transform(flattened)
    return projected

# MDA
def doMDA(X, Y, dim):
    mda = LinearDiscriminantAnalysis(n_components=dim)
    projected = mda.fit_transform(X,Y)
    return projected


# -*- coding: utf-8 -*-
"""
Created on Thu May 21 18:48:36 2020

@author: Fernando

=== Linear Regression Formula ===
### Formula
y = a + b * x

a = y axis line Intercept (y value where x = 0)
b = slope of the regression line

How to calculate B
Slope (b) of regression line formula
### Formula
b = r * sy / sx

r = pearson correlation coeficient
    How to calculate (R) Pearson correlation coeficient
    ### Formula
    R = SUM((x - _x) * (y - _y)) / SQRT(SUM(x - _x)**2 * SUM(y - _y)**2)

    _x = The Mean value of x
    _y = The Mean value of y

sy = standard deviation of y
    ### Formula
    sy = SQRT(SUM(y - _y)**2 / n - 1)
sx = standard deviation of x
    sx = SQRT(SUM(x - _x)**2 / n - 1)

How to calculate A
Y-Intercept (a) of Regression line
### Formula
a = _y - b *_x
"""

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from statistics import mean
from math import sqrt

# Indedependent variable - number of chimpanzees in hunting party
x = np.array([1,2,3,4,5,6,7,8])
# Dependent Variable - percent of successful hunts
y = np.array([30,45,51,57,60,65,70,71])

x_mean = mean(x)
# x_mean = sum(x)/len(x)
y_mean = mean(y)
# y_mean = sum(y)/len(y)

# Create (x - _x) and Create (x - _x)**2
x_minus_mean_x = []
sqrd_x_minus_mean_x = []
for i in range (len(x)):
    x_minus_mean_x.append(x[i] - x_mean)
    sqrd_x_minus_mean_x.append((x[i] - x_mean)**2)

# Create (y - _y) and Create (y - _y)**2
y_minus_mean_y = []
sqrd_y_minus_mean_y = []
for i in range (len(y)):
    y_minus_mean_y.append(y[i] - y_mean)
    sqrd_y_minus_mean_y.append((y[i] - y_mean)**2)

# Create (x - _x) * (y - _y) and x * y
x_times_y_mean = []
x_times_y = []
for i in range (len(x)):
    x_times_y_mean.append(x_minus_mean_x[i] * y_minus_mean_y[i])
    x_times_y.append(x[i] * y[i])

# Create the sum for (x - _x)**2, (y - _y)**2
sum_sqrd_x_minus_mean_x , sum_sqrd_y_minus_mean_y, = sum(sqrd_x_minus_mean_x), sum(sqrd_y_minus_mean_y)
# Create the sum for (x - _x) * (y - _y) and (x * y)
sum_x_times_y_mean, sum_x_times_y = sum(x_times_y_mean), sum(x_times_y)

# Calculate Pearson correlation coeficient
r = sum_x_times_y_mean / sqrt(sum_sqrd_x_minus_mean_x * sum_sqrd_y_minus_mean_y)

# Calculate y and x standard deviation
sy = sqrt(sum_sqrd_y_minus_mean_y / len(y) - 1)

sx = sqrt(sum_sqrd_x_minus_mean_x / len(x) - 1)

# Calculate B - Slope of regression line formula
b = r * (sy / sx)

# Calculate A - Y-Intercept (a) of Regression line
a = y_mean - b * x_mean

# Calculate Linear Regression Function for all X values
regression = a + b * x

# Plot the visualization
df = pd.DataFrame({'Number of Chimpanzees':x,'Percent Successful Hunts':y})
sns.scatterplot(x='Number of Chimpanzees',y='Percent Successful Hunts',data=df)
plt.plot(x, regression,'-g',label='chimp')


""""
The goal of this module is to implement all algorithms and numerical
methods needed to solve the Task 5 from the coding homeworks in the
Machine Learning course on coursera.com.
"""

from typing import Tuple
import numpy as np
import scipy.optimize

def hypothesis_function(x: np.ndarray, theta: np.ndarray) -> np.ndarray:
    """
    Hypothesis function for linear regression. It is a linear function  of the form:
    h(x) = theta0 + theta1 * x1 + theta2 * x2 + ... + thetaN * xN.
    Theta is a vector containing the parameter values.

    Args:
        x: Matrix of features.
        theta: Vector of parameters.

    Returns:
        Vector of predictions.
    """
    return np.dot(x, theta)

def compute_cost(
    x: np.ndarray, y: np.ndarray, theta: np.ndarray = None, _lambda: int = 0
) -> np.float64:
    """
    Computes the cost of using theta as the parameter for linear regression to fit the data points in x and y.

    Args:
        x: Matrix of features.
        y: Vector of labels.
        theta: Vector of parameters.
        _lambda: Regularization parameter.

    Returns:
        Cost of using theta as the parameter for linear regression to fit the data points in x and y.
    """
    if theta is None:
        theta = np.zeros((x.shape[1], 1))

    m = y.size

    j = (
        1
        / (2 * m)
        * np.dot(
            (hypothesis_function(x, theta).reshape((m, 1)) - y).T,
            (hypothesis_function(x, theta).reshape((m, 1)) - y),
        )
    )
    reg = _lambda / (2 * m) * np.dot(theta[1:].T, theta[1:])

    return (j + reg)[0][0]

def compute_gradient(
    x: np.ndarray, y: np.ndarray, theta: np.ndarray = None, _lambda: int = 0
) -> np.ndarray:
    """
    Computes the gradient of the cost function.

    Args:
        x: Matrix of features.
        y: Vector of labels.
        theta: Vector of parameters.
        _lambda: Regularization parameter.

    Returns:
        Vector of gradient.
    """
    if theta is None:
        theta = np.zeros((x.shape[1], 1))

    m = y.size
    theta = theta.reshape((theta.shape[0], 1))

    gradient = 1 / m * np.dot(x.T, hypothesis_function(x, theta) - y)
    reg = _lambda / m * theta

    # don't regularize the bias term
    reg[0] = 0

    return gradient + reg.reshape((gradient.shape[0], 1))

def optimize_theta(
    x: np.ndarray, y: np.ndarray, theta: np.ndarray, _lambda: int = 0
) -> np.ndarray:
    """
    Optimizes theta using the scipy.optimize.minimize function.

    Args:
        x: Matrix of features.
        y: Vector of labels.
        theta: Vector of parameters.
        _lambda: Regularization parameter.

    Returns:
        Vector of optimized parameters.
    """
    return scipy.optimize.minimize(
        lambda _theta: compute_cost(x, y, _theta, _lambda),
        x0=theta,
        method="BFGS",
        options={
            "disp": False,
            "gtol": 1e-05,
            "eps": 1.4901161193847656e-08,
            "return_all": False,
            "maxiter": None,
        },
    ).x

def construct_polynomial_matrix(x: np.ndarray, p: int) -> np.ndarray:
    """
    Takes an x matrix and returns an x matrix with additional columns.
    First additional column is 2'nd column with all values squared,
    the next additional column is 2'nd column with all values cubed etc.

    Args:
        x: Matrix of features.
        p: Degree of the polynomial.

    Returns:
        Matrix of features with additional columns.
    """

    p_matrix = x.copy()

    for i in range(2, p + 2):
        p_matrix = np.insert(p_matrix, p_matrix.shape[1], np.power(x[:, 1], i), axis=1)

    return p_matrix

def normalize_features(x: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
    """
    Normalizes the features in x.

    Args:
        x: Matrix of features.

    Returns:
        The normalized x, the mean of the original features and the standard deviation of the original features
    """
    x_norm = x.copy()

    feature_means = np.mean(x_norm, axis=0)
    x_norm[:, 1:] = x_norm[:, 1:] - feature_means[1:]
    feature_stds = np.std(x_norm, axis=0, ddof=1)
    x_norm[:, 1:] = x_norm[:, 1:] / feature_stds[1:]

    return x_norm, feature_means, feature_stds


import numpy as np

def gaussian_elimination_sequence(a, b):
    """
    用「顺序高斯消去法」解线性方程 `ax = b`。

    Args:
        a : np_array_like 系数矩阵（nxn）
        b : np_array_like 右端常数（n）

    Returns:
        x : np.array `ax=b` 的解（n）

    Raises:
        Exception("求解失败") if a[k][k] == 0
    """
    A = np.c_[a, b]  # 增广矩阵

    n, c = A.shape
    assert c == n + 1, f'bad shape: {A.shape}'

    x = np.zeros(n)

    # 消元
    for k in range(n-1):
        if A[k][k] == 0:
            raise Exception("求解失败")

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

    # 回代
    x[n-1] = A[n-1][n] / A[n-1][n-1]
    for k in range(n-2, -1, -1):  # from n-2 (included) to 0 (included)
        for j in range(k+1, n):
            A[k][n] -= A[k][j] * x[j]
        x[k] = A[k][n] / A[k][k]

    return x

def gaussian_elimination(a, b, sequence=False):
    """
    用「列主元高斯消去法」解线性方程 `ax = b`。

    本函数可以通过「列主元高斯消元法」或「顺序高斯消元法」计算，
    通过参数 sequence 控制，默认 sequence=False 使用「列主元高斯消元法」。

    Args:
        a : np_array_like 系数矩阵（nxn）
        b : np_array_like 右端常数（n）

    Returns:
        x : np.array `ax=b` 的解（n）

    Raises:
        Exception("求解失败") if a[k][k] == 0
    """
    A = np.c_[a, b]  # 增广矩阵

    n, c = A.shape
    assert c == n + 1, f'bad shape: {A.shape}'

    x = np.zeros(n)

    # 消元
    for k in range(0, n-1):
        if not sequence:  # 列主元
            i_max = k + np.argmax(np.abs(A[k:n, k]))

            if A[i_max][k] == 0:
                raise Exception("A 奇异，求解失败")

            A[[i_max, k]] = A[[k, i_max]]  # swap rows

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

    # 回代
    if a[n-1][n-1] == 0:
        raise Exception("矩阵奇异，求解失败")

    x[n-1] = A[n-1][n] / A[n-1][n-1]
    for i in range(n-2, -1, -1):  # from n-2 (included) to 0 (included)
        for j in range(i+1, n):
            A[i][n] -= A[i][j] * x[j]
        x[i] = A[i][n] / A[i][i]

    return x


import streamlit as st
import pandas as pd
import numpy as np
import seaborn as sns

st.title("2-D Gaussian heatmap using Seaborn")

code = """
data_density = st.slider("Data density",
                    min_value= 25,
                    max_value=200,
                    value=75,
                    step=25)

sigma = st.slider("Sigma",
                    min_value= 0.1,
                    max_value=2.0,
                    value=1.0,
                    step=0.1)

mu = st.slider("Sigma",
                    min_value= -1.0,
                    max_value=1.0,
                    value=0.0,
                    step=0.1)

x, y = np.meshgrid(np.linspace(-2,2,data_density), np.linspace(-2,2,data_density))
d = np.sqrt(x*x+y*y)
sigma, mu = sigma, mu
g = np.exp(-( (d-mu)**2 / ( 2.0 * sigma**2 ) ) )
sns.heatmap(g)
"""

st.markdown("## Code")
st.code(code)

st.markdown("## Controls")

data_density = st.slider("Data density",
                    min_value= 25,
                    max_value=200,
                    value=75,
                    step=25)

sigma = st.slider("Sigma",
                    min_value= 0.1,
                    max_value=2.0,
                    value=1.0,
                    step=0.1)

mu = st.slider("Sigma",
                    min_value= -1.0,
                    max_value=1.0,
                    value=0.0,
                    step=0.1)

x, y = np.meshgrid(np.linspace(-2,2,data_density), np.linspace(-2,2,data_density))
d = np.sqrt(x*x+y*y)
sigma, mu = sigma, mu
g = np.exp(-( (d-mu)**2 / ( 2.0 * sigma**2 ) ) )
sns.heatmap(g)

st.markdown("## Plot")
st.pyplot()


from pyquaternion import Quaternion
import numpy as np
import math

def angle2radians(angle):
    return angle / 180.0 * math.pi

def radians2angle(radians):
    return radians / math.pi * 180.0

def rpy_to_rotation_matrix(rpy):
    roll = rpy[0]
    pitch = rpy[1]
    yaw = rpy[2]

    R_roll = np.array([[1, 0, 0], [0, math.cos(roll), -math.sin(roll)], [0, math.sin(roll), math.cos(roll)]])

    R_pitch = np.array([[math.cos(pitch), 0, math.sin(pitch)], [0, 1, 0], [-math.sin(pitch), 0, math.cos(pitch)]])

    R_yaw = np.array([[math.cos(yaw), -math.sin(yaw), 0], [math.sin(yaw), math.cos(yaw), 0], [0, 0, 1]])

    return R_yaw.dot(R_pitch).dot(R_roll)

def rpy_to_angle_axis(rpy):
    quat = rpy_to_quaternion(rpy)
    len = quat[0] ** 2 + quat[1] ** 2 + quat[2] ** 2 + quat[3] ** 2
    quat /= len
    print("quat = ", quat)

    angle = 2.0 * math.acos(quat[0])
    while (angle < -math.pi):
        angle += math.pi * 2.0
    while (angle > math.pi):
        angle -= math.pi * 2.0

    a = math.sqrt(1.0 - quat[0] * quat[0])
    axis = np.array([quat[1] / a, quat[2] / a, quat[3] / a])
    print("angle = ", angle)
    print("axis = ", axis)

    return axis * angle

def quaternion_to_rpy(attitude_quaternion):
    # based on wikipedia: https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
    attitude_quaternion._normalise()

    w = attitude_quaternion[0]
    x = attitude_quaternion[1]
    y = attitude_quaternion[2]
    z = attitude_quaternion[3]

    t0 = 2.0 * (w * x + y * z)
    t1 = 1.0 - 2.0 * (x * x + y * y)
    X = math.atan2(t0, t1)

    t2 = 2.0 * (w * y - z * x)
    t2 = 1.0 if t2 > 1.0 else t2
    t2 = -1.0 if t2 < -1.0 else t2
    Y = math.asin(t2)

    t3 = 2.0 * (w * z + x * y)
    t4 = 1.0 - 2.0 * (y * y + z * z)
    Z = math.atan2(t3, t4)

    return np.array([X, Y, Z])

def rpy_to_quaternion(rpy):
    # based on wikipedia: https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
    roll = rpy[0]
    pitch = rpy[1]
    yaw = rpy[2]

    cy = math.cos(yaw * 0.5)
    sy = math.sin(yaw * 0.5)
    cr = math.cos(roll * 0.5)
    sr = math.sin(roll * 0.5)
    cp = math.cos(pitch * 0.5)
    sp = math.sin(pitch * 0.5)

    w = cy * cr * cp + sy * sr * sp
    x = cy * sr * cp - sy * cr * sp
    y = cy * cr * sp + sy * sr * cp
    z = sy * cr * cp - cy * sr * sp

    quat = Quaternion(w, x, y, z)
    quat._normalise()

    return quat

def angular_rate_to_euler_rate_matrix(rpy):
    roll = rpy[0]
    pitch = rpy[1]
    s_roll = math.sin(roll)
    c_roll = math.cos(roll)
    c_pitch = math.cos(pitch)
    t_pitch = math.tan(pitch)
    return np.array([[1, s_roll * t_pitch, c_roll * t_pitch], [0, c_roll, -s_roll], [0, s_roll / c_pitch, c_roll / c_pitch]])

def compute_rpy_rate(rpy, angular_rate):
    # problematic, the incoming angular rate is not in body frame, but it will not affect the simulation
    return angular_rate_to_euler_rate_matrix(rpy).dot(angular_rate)

# testing
import random

def test_rpy_quaternion():
    # testing rpy-quaternion conversion
    rpy = np.zeros(3)
    rpy[0] = random.uniform(-math.pi, math.pi )
    rpy[1] = random.uniform(-math.pi / 2.0, math.pi / 2.0)
    rpy[2] = random.uniform(-math.pi, math.pi)

    orientation = rpy_to_quaternion(rpy)
    inverse_rpy = quaternion_to_rpy(orientation)

    roll_quat = Quaternion(axis = [1, 0, 0], angle = rpy[0])
    pitch_quat = Quaternion(axis = [0, 1, 0], angle = rpy[1])
    yaw_quat = Quaternion(axis = [0, 0, 1], angle = rpy[2])

    orientation_from_rpy = yaw_quat * pitch_quat * roll_quat

    print("-------------test rpy to orientation-----------------")
    print("rpy = ", rpy, ", inverse rpy = ", inverse_rpy, ", norm(diff) = ", np.linalg.norm(rpy - inverse_rpy))
    print("orientation = ", orientation, ", another orientation = ", orientation_from_rpy, ", diff = ", orientation - orientation_from_rpy)

def test_rpy_rotation_matrix():
    # testing rpy-rotation conversion
    rpy = np.zeros(3)
    rpy[0] = random.uniform(-math.pi, math.pi )
    rpy[1] = random.uniform(-math.pi / 2.0, math.pi / 2.0)
    rpy[2] = random.uniform(-math.pi, math.pi)

    orientation = rpy_to_quaternion(rpy)

    rotation_from_quat = orientation.rotation_matrix

    rotation = rpy_to_rotation_matrix(rpy)

    print("-------------test rpy to rotation-----------------")
    print("rpy = ", rpy)
    print("rotation = \n", rotation)
    print("rotation from quat = \n", rotation_from_quat)
    print("diff = \n", rotation - rotation_from_quat)
    if (np.linalg.norm(rotation - rotation_from_quat) > 1e-7):
        input()

def test_rpy_angle_axis():
    # testing rpy-angle axis conversion
    rpy = np.zeros(3)
    rpy[0] = random.uniform(-math.pi / 2.0, math.pi / 2.0)
    rpy[1] = random.uniform(-math.pi / 2.0, math.pi / 2.0)
    rpy[2] = random.uniform(0, math.pi * 2.0)
    # rpy[0] = 3.0664
    # rpy[1] = 0.17985
    # rpy[2] = -2.4785

    orientation = rpy_to_quaternion(rpy)
    print("quat = ", orientation)
    print("angle = ", orientation.angle)
    print("axis = ", orientation.axis)

    angleaxis_from_quat = orientation.angle * orientation.axis

    angleaxis = rpy_to_angle_axis(rpy)

    print("-------------test rpy to angle axis-----------------")
    print("rpy = ", rpy)
    print("angle axis = \n", angleaxis)
    print("angle axis from quat = \n", angleaxis_from_quat)
    print("diff = \n", angleaxis - angleaxis_from_quat)
    if (np.linalg.norm(angleaxis - angleaxis_from_quat) > 1e-7):
        input()

def main():
    for i in range(1000):
        # test_rpy_quaternion()

        # test_rpy_rotation_matrix()

        test_rpy_angle_axis()

if __name__=='__main__':
    main()


'''
Created on Apr 29, 2018

@author: Brandon Bevan
'''

import numpy
import matplotlib.pyplot as plt

import imageio

class Fourier2:

    def __init__(self, image):
        img = imageio.imread(image)
        self.trans = numpy.fft.fft2(img)
        phase = self.trans.imag
        freq = self.trans.real
        self.inverse = numpy.fft.ifft2(self.trans)

    def viewfft2(self,f):
        fp = abs(f)

        # The following two lines are for the sake of Histogram equalization. This is the dirtiest implementation imaginable.
        # We use the mean as the maximum value since the max of an fft2 is usually an outlier.
        mx = fp.mean()
        mn = fp.min()

        #fp = numpy.divide(fp, mx)

        # Shift for viewing
        fps = numpy.fft.fftshift(fp)

        plt.imshow(fps, vmin=mn, vmax=mx)

        plt.show()

    def viewifft2(self):
        fp = abs(self.inverse)

        # The following two lines are for the sake of Histogram equalization. This is the dirtiest implementation imaginable.
        # We use the mean as the maximum value since the max of an fft2 is usually an outlier.
        mx = fp.mean()
        mn = fp.min()

        #fp = numpy.divide(fp, mx)

        fps = fp

        plt.imshow(fps, vmin=mn, vmax=mx)

        plt.show()

    def view(self):
        self.viewfft2(self.trans)

    def viewinverse(self):
        self.viewifft2()

    def viewphase(self):
        self.viewfft2(phase)

    def viewfrequency(self):
        self.viewfft2(freq)


import numpy as np
from scipy.special import expit
import matplotlib.pyplot as plt
from scipy.stats import norm
from scipy.stats import multivariate_normal

##################################################################################################################################
############################################################# PART A #############################################################
##################################################################################################################################
mu = np.zeros(2)
covariance = np.array([[3, 2.9], [2.9, 3]])
true_dist = multivariate_normal(mean=mu, cov=covariance).rvs(500)
plt.scatter(true_dist[:, 0], true_dist[:, 1])
plt.xlabel("z0")
plt.ylabel("z1")
plt.title("Drawing samples")
plt.show()

##################################################################################################################################
############################################################# PART B #############################################################
##################################################################################################################################
n = 2
n_iter = 100
# Initialise x
z = np.array([-4, -4], dtype=np.float64)
accepted = np.array(z)[np.newaxis,:]
for i in range(n_iter):
    for j in range(n):
        k = (j+1)%2
        mu_j = mu[j] + covariance[j][k]*(z[k] - mu[k])/covariance[k][k]
        var_j = covariance[j][j] - covariance[j][k]*covariance[k][j]/covariance[k][k]
        z[j] = norm(loc = mu_j, scale=np.sqrt(var_j)).rvs(1)
        accepted = np.vstack((accepted, z))

plt.plot(accepted[:, 0], accepted[:, 1], 'ro')
plt.xlabel("z0")
plt.ylabel("z1")
plt.title("Gibbs Sampling")
plt.show()

true_dist = multivariate_normal(mean=mu, cov=covariance).rvs(500)
plt.scatter(true_dist[:, 0], true_dist[:, 1], label="Normal Sampling")
plt.plot(accepted[:, 0], accepted[:, 1], 'ro', label="Gibbs Sampling")
plt.xlabel("z0")
plt.ylabel("z1")
plt.title("Gibbs Sampling vs Normal Sampling")
plt.legend()
plt.show()

##################################################################################################################################
############################################################# PART C #############################################################
##################################################################################################################################
def dU_dz(mu, cov, z):
    z = np.array(z-mu)
    grad = np.dot(np.linalg.inv(cov),z)
    return grad

def leapfrog(z, r, s, mu, cov, eps, L):

    for i in range(L):
        r -= (eps/2)*dU_dz(mu, cov, np.copy(z))
        z += eps*np.dot(np.linalg.inv(s), r)
        r -= (eps/2)*dU_dz(mu, cov, np.copy(z))
    return (z, r)

def accept_prob(pos_dist, current_state, next_state, mu, cov, s):
    current_state_p = pos_dist(current_state, mu, cov, s)
    next_state_p = pos_dist(next_state, mu, cov, s)
    return(np.min([1, next_state_p/current_state_p]))

def total_energy(state, mu, cov, s):
    z = state[0]
    r = np.array(state[1])
    z = np.array(z-mu)
    u = 0.5*(np.dot(np.dot(z.transpose(),np.linalg.inv(cov)), z))
    k = 0.5*(np.dot(np.dot(r.transpose(),np.linalg.inv(s)), r))
    return(np.exp(-u-k))

def hybrid_monte_carlo(mu, cov, burn_in, n_iter, eps, L, z):
    s = np.eye(2)
    r = multivariate_normal(mean=np.zeros(2), cov=s)
    mu = mu[:,np.newaxis]
    z_p = z[:,np.newaxis]
    rejected = np.array(z_p)
    accepted = np.array(z_p)
    for i in range(1, burn_in + 1):
        r_p = r.rvs(1)[:, np.newaxis]
        z_n, r_n = leapfrog(np.copy(z_p), np.copy(r_p), s, mu, cov, eps, L)
        r_n *= (-1)
        prob = accept_prob(total_energy, [z_p, r_p], [z_n, r_n], mu, cov, s)
        u = np.random.uniform(0, 1, 1)
        if (u <= prob):
            z_p = z_n

    for i in range(1, n_iter + 1):
        accept = False
        r_p = r.rvs(1)[:, np.newaxis]
        z_n, r_n = leapfrog(np.copy(z_p), np.copy(r_p), s, mu, cov, eps, L)
        r_n *= (-1)
        prob = accept_prob(total_energy, [z_p, r_p, s], [z_n, r_n, s], mu, cov, s)
        u = np.random.uniform(0, 1, 1)
        if (u <= prob):
            accept = True
        if (i % m == 0):
            if (accept):
                accepted = np.hstack((accepted, z_n))
            else:
                accepted = np.hstack((accepted, z_p))
                rejected = np.hstack((rejected, z_n))
        if (accept):
            z_p = z_n
    return accepted.transpose() #, rejected.transpose()

eps = 0.1; L = 20; m = 1
burn_in = 100000
accepted_monte = hybrid_monte_carlo(mu, covariance, burn_in, 100, eps, L, z)

plt.plot(accepted_monte[:, 0], accepted_monte[:, 1], 'ro')
plt.xlabel("z0")
plt.ylabel("z1")
plt.title("Monte Carlo Sampling")
plt.show()

true_dist = multivariate_normal(mean=mu, cov=covariance).rvs(500)
plt.scatter(true_dist[:, 0], true_dist[:, 1], label="Normal Sampling")
plt.plot(accepted_monte[:, 0], accepted_monte[:, 1], 'ro', label="Monte Carlo Sampling")
plt.plot(accepted[:, 0], accepted[:, 1], 'go', label="Gibbs Sampling")
plt.xlabel("z0")
plt.ylabel("z1")
plt.title("Monte Carlo Sampling vs Normal Sampling")
plt.legend()
plt.show()


import numpy as np
import matplotlib.pyplot as plt

class MohrsCircle():
    def __init__(self,sigmax,sigmay,tauxy):
        ''' INPUT INITIAL INFORMATION
                σ_x : sigmax
                σ_y : sigmay
                τ_xy : tauxy  (shear stress on x-face)
        '''
        self.sigmax = sigmax
        self.sigmay = sigmay
        self.tauxy = tauxy

    def circleCenter(self):
        '''
        Calculate the value of center of the Mohrs circle which is the average of sigma x and sigma y
        '''
        return((self.sigmax + self.sigmay)/2)

    def radius(self):
        '''
        Calculate the radius of Mohrs circle which is the distance between center point and the point of tau_xy
        '''
        a = (self.sigmax-self.sigmay)/2
        b = self.tauxy
        return np.sqrt(a**2 + b**2)

    def maximumPrincipalStress(self):
        '''
        Return the value of center point of the circle added with the radius
        '''
        return self.circleCenter() + self.radius()

    def minimumPrincipalStress(self):
        '''
        Return the value of center point of the circle subtracted with the radius
        '''
        return self.circleCenter() - self.radius()

    def maximumShearStress(self):
        '''
        Return the value of radius of Mohrs circle
        '''
        return self.radius()

    def mohrsCirclePlot(self):
        radians = np.linspace(0,360,361)*(2*np.pi/360)
        sigmapts = self.circleCenter() + self.radius()*np.cos(radians)
        taupts = self.radius()*np.sin(radians)

        # Figure size and lines
        plt.figure(figsize = [5,5])
        plt.fill_between(sigmapts,taupts,color='blue',alpha=0.1)
        plt.plot(sigmapts, taupts, label = "Mohrs' Circle", color = 'k')
        plt.plot([self.sigmax, self.sigmay],[self.tauxy, -self.tauxy], color = 'r')
        plt.plot([self.circleCenter()],[0], marker = 'o', color = 'k')

        # Stress labels on the graph
        plt.text(self.maximumPrincipalStress(), 0, r'$\sigma_{max}$', va = 'bottom', ha = 'right', fontsize = 14)
        plt.text(self.minimumPrincipalStress(), 0, r'$\sigma_{min}$', ha = 'left', va = 'bottom', fontsize = 14)
        plt.text(self.circleCenter(), self.maximumShearStress(), r'$\tau_{max}$', va='top', ha = 'center', fontsize = 14)

        # Labels
        plt.title('Mohrs\' Circle',fontsize=18)
        plt.xlabel(r'$\sigma$',fontsize=14)
        plt.ylabel(r'$\tau$',fontsize=14)

        # Create horizontal and vertical lines at center
        plt.axhline(color = 'k')
        plt.axvline(color = 'k')

        #'Fits everything in one window'
        plt.tight_layout()
        plt.grid()
        plt.show()

if __name__ == '__main__':
    x1 = float(input('What is the value of sigmax ? '))
    x2 = float(input('What is the value of sigmay ? '))
    x3 = float(input('What is the value of tauxy ? '))

    y =MohrsCircle(x1,x2,x3)
    print('The maximum principal stress is ',round(y.maximumPrincipalStress(),2))
    print('The minimum principal stress is ',round(y.minimumPrincipalStress(),2))
    print('The maximum shear stress is ',round(y.maximumShearStress(),2))
    print('The center of the circle is ',round(y.circleCenter(),2))
    y.mohrsCirclePlot()

# Source : https://topdogengineer.com/object-oriented-programming-mohrs-circle/
#        : https://www.youtube.com/watch?v=lRUkVG25bUU