## 1. Why Learn Calculus? ##

import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 3, 100)
y = -1*(x**2) + x*3 - 1
plt.plot(x,y)

## 4. Math Behind Slope ##

def slope(x1,x2,y1,y2):
    ## Finish the function here
    return 0
slope_one = slope(0,4,1,13)
slope_two = slope(5,-1,16,-2)
def slope(x1,x2,y1,y2):
    rc = (y2 - y1)/(x2 - x1)
    return rc
slope_one = slope(0,4,1,13)
slope_two = slope(5,-1,16,-2)

print(slope_one)
print(slope_two)

## 6. Secant Lines ##

import seaborn
seaborn.set(style='darkgrid')

def draw_secant(x_values):
    x = np.linspace(-20,30,100)
    y = -1*(x**2) + x*3 - 1
    plt.plot(x,y)
    # Add your code here.
    plt.show()
def draw_secant(x_values):
    x = np.linspace(-20,30,100)
    y = -1*(x**2) + x*3 - 1
    plt.plot(x,y)

    x_0 = x_values[0]
    x_1 = x_values[1]
    y_0 = -1*(x_0**2) + x_0*3 - 1
    y_1 = -1*(x_1**2) + x_1*3 - 1
    m = (y_1 - y_0) / (x_1 - x_0)
    b = y_1 - m*x_1

    y_secant = x*m + b
    plt.plot(x, y_secant, c='green')
    plt.show()
draw_secant([3,5])
draw_secant([3,10])
draw_secant([3,15])

Data Scientist In Python/Step 6 - Machine Learning Introduction/2. Calculus For Machine Learning/1. Understanding Linear and Nonlinear Functions.py


#!/usr/bin/env python3
import numpy as np
import sys

with open(sys.argv[1]) as input:
    lines = input.readlines()

lines = [list(line.strip()) for line in lines]

# Part 1
transposed = np.array(lines).T.tolist()

gamma_str = ''.join(['1' if col.count('1') > col.count('0') else '0' for col in transposed])
gamma = int(gamma_str, base = 2)

epsilon_str = ''.join(['0' if c == '1' else '1' for c in gamma_str])
epsilon = int(epsilon_str, base = 2)

print(gamma * epsilon)

# Part 2
def oxygen(lines, depth = 0):
    if len(lines) == 1:
        return int(''.join(lines[0]), base = 2)

    transposed = np.array(lines).T.tolist()

    most_common = '1' if transposed[depth].count('1') >= transposed[depth].count('0') else '0'

    return oxygen([line for line in lines if line[depth] == most_common], depth + 1)

def co2(lines, depth = 0):
    if len(lines) == 1:
        return int(''.join(lines[0]), base = 2)

    transposed = np.array(lines).T.tolist()

    most_common = '1' if transposed[depth].count('1') < transposed[depth].count('0') else '0'

    return co2([line for line in lines if line[depth] == most_common], depth + 1)

print(oxygen(lines) * co2(lines))


from __future__ import annotations

import numpy as np

def modular_inverse(a: int, N: int) -> int:
    """Return the inverse of `a` modulo `N`.

    Args:
        a: The number to invert.
        N: The modulus. Must be > 1.

    Returns:
        The inverse of `a` modulo `N`.

    Raises:
        ValueError: if `N` <= 1 or the inverse does not exist.
    """
    if not N > 1:
        msg = f"modular_inverse: `N` ({N}) must be > 1."
        raise ValueError(msg)
    try:
        return pow(a, -1, N)
    except ValueError:
        msg = f"modular_inverse: invalid arguments a={a} and N={N}."
        raise ValueError(msg)

def continued_fraction(p: int, q: int) -> list[int]:
    """Given p/q, return its continued fraction.

    Args:
        p: The numerator.
        q: The denominator.

    Returns:
        The continued fraction expansion of p/q, [a0; a1, a2, ..., an].
    """
    coeffs = list()
    while q != 0:
        a = p // q
        coeffs.append(a)
        p, q = q, p - q * a
    return coeffs

def approximate_fraction(p: int, q: int, N: int) -> tuple[int, int]:
    """Given p/q, find the closest fraction a/b where b <= N.

    Args:
        p: The numerator.
        q: The denominator.

    Returns:
        The tuple (a, b).
    """
    # truncate sequence of continued fraction approximations when denominator >= N
    a1, a2 = 1, 0
    b1, b2 = 0, 1
    truncated = False
    for k in continued_fraction(p, q):
        if k * b1 + b2 >= N:
            truncated = True
            break
        a1, a2 = k * a1 + a2, a1
        b1, b2 = k * b1 + b2, b1

    if truncated:
        # use largest j where k/2 <= j < k and j*b1 + b2 < N.
        j = (N - b2) // b1
        if j >= k:
            pass
        elif k < 2 * j:  # found good j
            a1 = j * a1 + a2
            b1 = j * b1 + b2
        elif k == 2 * j:  # if k even, j = k/2 only admissible if the approximation is better
            next_a = j * a1 + a2
            next_b = j * b1 + b2
            if abs((p * 1.0) / q - (next_a * 1.0) / next_b) < abs((p * 1.0) / q - (a1 * 1.0) / b1):
                a1, b1 = next_a, next_b

    # else, no better approximation
    return a1, b1

def is_prime(n: int, num_iters: int = 40) -> bool:
    """Returns True if n is a probable prime. Implementation uses a
    Miller-Rabin primality test modified from
    https://gist.github.com/Ayrx/5884790.

    Args:
        n: The number to test.
        num_iters: The number of iterations to run.

    Returns:
        True if n is a probable prime.
    """

    if n == 2 or n == 3:
        return True

    if n % 2 == 0:
        return False

    r, s = 0, n - 1
    while s % 2 == 0:
        r += 1
        s //= 2
    for _ in range(num_iters):
        a = np.random.randint(2, n - 1)
        x = pow(a, s, n)
        if x == 1 or x == n - 1:
            continue
        for _ in range(r - 1):
            x = pow(x, 2, n)
            if x == n - 1:
                break
        else:
            return False
    return True


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

# ========================================== Popular activation functions ==========================================
def sigmoid(z):
    s = 1/(1+np.exp(-z))
    cache = z
    return s,cache

def tanh(z):
    t = np.tanh(z)
    cache = z
    return t, cache

def relu(z):
    r = np.maximum(0, z)
    assert (r.shape == z.shape)
    return r, z

# ========================================== derivatives of activation functions========================================

def sigmoid_prime(z):
    s = 1/(1+np.exp(-z))
    sp = s*(1-s)
    return sp

def tanh_prime(z):
    tp = 1 - np.tanh(z)**2
    return tp

def relu_prime(z):
    rp = np.greater(z, 0).astype(float)  # returns 1 if greater than 0 OR 0 if less or equal to 0
    rp = np.reshape(rp, z.shape)

    assert (z.shape == rp.shape)
    return rp

#================================================= Popular loss functions ==============================================
"""to compute the cost just call compute_cost(your_loss_function())"""

def L1loss_MAE(Y,Y_hat):
    return np.sum(np.abs(Y - Y_hat))

def L2loss_MSE(Y,Y_hat):
    return ((Y - Y_hat)**2)

def binary_cross_entropy(Y,Y_hat):

    if np.min(Y) <= 0  or np.min(Y_hat) <= 0 :
        raise ValueError("Negative element in log function , Solution: try to map your outputs to values that are grater than zero!")
    else:
        return np.sum(-(Y*np.log(Y_hat) + (1-Y)*np.log(1-Y_hat)))

def cross_entropy(Y,Y_hat):

    if np.min(Y) <= 0  or np.min(Y_hat) <= 0 :
        raise ValueError("Negative element or zero in log function , Solution: try to map your outputs to values that are grater than zero!")
    else:
        return np.sum(-(Y*np.log(Y_hat)))

def hurber_loss(Y,Y_hat,delta):
    loss = np.where(np.abs(Y - Y_hat) < delta, 0.5 * ((Y - Y_hat) ** 2),
                    delta * np.abs(Y - Y_hat) - 0.5 * (delta ** 2))
    return np.sum(loss)

def log_Cosh_loss(Y,Y_hat):
    loss = np.log(np.cosh(Y - Y_hat))
    return np.sum(loss)

def getLossDerivative(Y,AL,cost_func_name):
    global dAl

    if cost_func_name == "binary_cross_entropy":
        dAl = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))  # derivative of cost with respect to AL

    elif cost_func_name == "cross_entropy":
        dAl = - np.divide(Y, AL)

    elif cost_func_name == "MSE":
        dAl = 2*(AL - Y)

    return dAl

def compute_cost(loss_func, Y_true, Y_pred):

    if loss_func == "cross_entropy":
        loss = cross_entropy(Y_true, Y_pred)

    elif loss_func == "binary_cross_entropy":
        loss = binary_cross_entropy(Y_true, Y_pred)

    elif loss_func == "MSE":
        loss = L2loss_MSE(Y_true, Y_pred)

    # elif loss_func == "MAE":   #backprop not emplimented yet
    #     loss = L1loss_MAE(Y_true, Y_hat)

    return np.array(loss).mean()

def compute_cost_with_reg(loss_func, Y_true, Y_pred, parameters = None, lambd = None ):

    if loss_func == "cross_entropy":
        loss = cross_entropy(Y_true, Y_pred)

    elif loss_func == "binary_cross_entropy":
        loss = binary_cross_entropy(Y_true, Y_pred)

    elif loss_func == "MSE":
        loss = L2loss_MSE(Y_true, Y_pred)

    # elif loss_func == "MAE":   #backprop not emplimented yet
    #     loss = L1loss_MAE(Y_true, Y_hat)

    squared_weights= 0
    m = Y_true.shape[1]
    L = len(parameters) //2
    for l in range(1,L):

        squared_weights+= np.sum(np.square(parameters["W"+ str(l)]))

    return np.array(loss).mean() +  (lambd * squared_weights / m)

#==================================================== Learning rate decay ===============================================

def step_decay(epoch, current_learning_rate, epochs_step, decay_with, till_epoch):

    lr = current_learning_rate

    if till_epoch != None and till_epoch == epoch :
        lr = current_learning_rate
    else:
        if (epoch % epochs_step) == 0:
            lr -= decay_with
        #avoiding the case where learning_rate is less or eqal to 0
        if lr < 0. or lr == 0. :
            lr = 0.00000001

    return lr

def time_based_decay(epoch, init_learning_rate, decay_rate):
    lr = init_learning_rate / (1 + decay_rate* epoch)
    return lr

def exp_decay(epoch, init_learning_rate, decay_rate = 0.1):
    lr = init_learning_rate * math.exp(-decay_rate*epoch)
    return lr

#================================================= Parameters initialization ===========================================
def init_parameters_deep(layers_dims, type = "random"):

    L = len(layers_dims)
    parameters = {}
    optimization = []

    if type == "random":
        for l in range(1, L):
            parameters["W" + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1])*0.01
            parameters["b" + str(l)] = np.zeros(shape = (layers_dims[l], 1))
            assert (parameters["W" + str(l)].shape == (layers_dims[l], layers_dims[l - 1]))
            assert (parameters["b" + str(l)].shape == (layers_dims[l], 1))

    elif type == "xavier":
        for l in range(1, L):
            parameters["W" + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1])*np.sqrt(1/layers_dims[l-1])
            parameters["b" + str(l)] = np.zeros(shape = (layers_dims[l], 1))
            assert (parameters["W" + str(l)].shape == (layers_dims[l], layers_dims[l - 1]))
            assert (parameters["b" + str(l)].shape == (layers_dims[l], 1))

    elif type == "he":
        for l in range(1, L):
            parameters["W" + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1])*np.sqrt(2/layers_dims[l-1])
            parameters["b" + str(l)] = np.zeros(shape = (layers_dims[l], 1))
            assert (parameters["W" + str(l)].shape == (layers_dims[l], layers_dims[l - 1]))
            assert (parameters["b" + str(l)].shape == (layers_dims[l], 1))

    return  parameters

def initialize_momentum_velocity(parameters):

    L = len(parameters) // 2
    v = {}

    # Initialize velocity
    for l in range(L):
        v["dW" + str(l + 1)] = np.zeros(
            shape=(parameters['W' + str(l + 1)].shape[0], parameters['W' + str(l + 1)].shape[1]))
        v["db" + str(l + 1)] = np.zeros(
            shape=(parameters['b' + str(l + 1)].shape[0], parameters['b' + str(l + 1)].shape[1]))

    return v

def initialize_adam(parameters):

    L = len(parameters) // 2
    v = {}
    s = {}

    for l in range(L):

        v["dW" + str(l + 1)] = np.zeros(
            shape=(parameters['W' + str(l + 1)].shape[0], parameters['W' + str(l + 1)].shape[1]))
        v["db" + str(l + 1)] = np.zeros(
            shape=(parameters['b' + str(l + 1)].shape[0], parameters['b' + str(l + 1)].shape[1]))
        s["dW" + str(l + 1)] = np.zeros(
            shape=(parameters['b' + str(l + 1)].shape[0], parameters['b' + str(l + 1)].shape[1]))
        s["db" + str(l + 1)] = np.zeros(
            shape=(parameters['b' + str(l + 1)].shape[0], parameters['b' + str(l + 1)].shape[1]))

    return v, s

#======================================= One layer Forward propagation ===================================================
# helper function for linear_activation_forward()
def linear_forward(A_prev, W, b):
    Z = np.dot(W, A_prev) + b
    assert (Z.shape == (W.shape[0], A_prev.shape[1]))
    cache = (A_prev, W, b)

    return Z, cache

def linear_activation_forward(A_prev, W, b, activation):
    """
    * Here we are doing forward propagation on one layer on (layer 'l') then we cache A, Z , A_prev (or the layers inputs),w and b.
    * in the model we are going to repeat this for all layers and keep the cache in a dictionary so that we use it for backprop.
    """

    global A, activation_cache

    Z, linear_cache = linear_forward(A_prev, W, b)

    if activation == "sigmoid":
        A, activation_cache = sigmoid(Z)
    elif activation == "relu":
        A, activation_cache = relu(Z)
    elif activation == "tanh":
        A, activation_cache = tanh(Z)
    elif activation == "linear":
        A, activation_cache = Z,Z

    assert (A.shape == (W.shape[0], A_prev.shape[1]))

    # return the cache as a tuple
    cache = (linear_cache, activation_cache)

    return A, cache  # 'A' here will become A_prev (input) for the next layer when we feed the network

# forward prop thought all layers and return y_hat with caches
def L_forward_propagation(X, parameters ,hidden_activation,output_activation):
    caches = []
    A_prev = X
    L = len(parameters) // 2

    for l in range(1, L):
        W = parameters["W" + str(l)]
        b = parameters["b" + str(l)]
        A_prev, cache = linear_activation_forward(A_prev, W, b, hidden_activation)
        caches.append(cache)

    # finding y hat or aka AL

    W = parameters["W" + str(L)]
    b = parameters["b" + str(L)]
    AL, cache = linear_activation_forward(A_prev, W, b, output_activation)
    caches.append(cache)

    assert (AL.shape[1] ==  X.shape[1])

    return AL, caches
#======================================== One layer Backward propagation ===============================================
# helper function for linear_activation_backward()
def linear_backward(dZ, cache):
    A_prev, W, b = cache
    m = A_prev.shape[1]

    dW = (dZ @ A_prev.T) / m
    db = np.sum(dZ, axis=1, keepdims=True) / m
    dA_prev = W.T @ dZ

    assert (dA_prev.shape == A_prev.shape)
    assert (dW.shape == W.shape)

    return dA_prev, dW, db

def linear_activation_backward(dA, caches, activation):
    """
    *Here we take the cache saved from forward prop and use it to calculate gradients for the current layer
    """

    linear_cache, activation_cache = caches
    z = activation_cache

    if activation == "sigmoid":
        dZ = dA * sigmoid_prime(z)

    if activation == "relu":
        dZ = dA * relu_prime(z)

    if activation == "tanh":
        dZ = dA * tanh_prime(z)

    if activation == "linear":
        dZ = dA

    dA_prev, dW, db = linear_backward(dZ, linear_cache)

    return dA_prev, dW, db

#backprop through all layers
def L_model_backward(AL, Y, caches,cost_func_name, hidden_activation, output_activation, L2_reg = False, parameters = None, m = 1 , lambd = 0 ):

    grads = {}
    L = len(caches)  # nbr of layers
    Y = Y.reshape(AL.shape)  # after this line, Y is the same shape as AL

    dAL = getLossDerivative(Y,AL,cost_func_name)

    # checking for L2_regularization request for layer L
    if L2_reg == True :
        L2_L = ((lambd * parameters["W" + str(L)]) / m )
    else:
        L2_L = 0

    # Lth layer (SIGMOID -> LINEAR) gradients. Inputs: "dAL, current_cache". Outputs: "grads["dAL-1"], grads["dWL"], grads["dbL"]
    current_cache = caches[L - 1]  # get the last  element
    dA_prev, dW, db = linear_activation_backward(dAL, current_cache, output_activation)
    grads["dA" + str(L - 1)] = dA_prev
    grads["dW" + str(L)] = dW + L2_L
    grads["db" + str(L)] = db

    # Loop from l=L-2 to l=0
    for l in reversed(range(L - 1)):

        # checking for L2_regularization request for layer L
        if L2_reg == True :
            L2_l = ((lambd * parameters["W" + str(l+1)]) / m )
        else:
            L2_l = 0

        # continueing backprop
        current_cache = caches[l]
        dA_prev_temp, dW_temp, db_temp = linear_activation_backward(grads["dA" + str(l + 1)], current_cache,
                                                                    activation = hidden_activation)
        grads["dA" + str(l)] = dA_prev_temp
        grads["dW" + str(l + 1)] = dW_temp + L2_l
        grads["db" + str(l + 1)] = db_temp

    return grads

def update_params_gd(parameters,grads,learning_rate):
    L = len(parameters) // 2  # number of layers in the neural network

    for l in range(L):
        parameters["W" + str(l + 1)] = parameters["W" + str(l + 1)] - learning_rate * grads["dW" + str(l + 1)]
        parameters["b" + str(l + 1)] = parameters["b" + str(l + 1)] - learning_rate * grads["db" + str(l + 1)]

    return parameters

def update_params_momentum(parameters, grads, v, beta, learning_rate):

    L = len(parameters) // 2

    # Momentum update for each parameter
    for l in range(L):
        # compute velocities
        v["dW" + str(l + 1)] = beta * v["dW" + str(l + 1)] + (1 - beta) * grads["dW" + str(l + 1)]
        v["db" + str(l + 1)] = beta * v["db" + str(l + 1)] + (1 - beta) * grads["db" + str(l + 1)]
        # update parameters
        parameters["W" + str(l + 1)] = parameters["W" + str(l + 1)] - learning_rate * v["dW" + str(l + 1)]
        parameters["b" + str(l + 1)] = parameters["b" + str(l + 1)] - learning_rate * v["db" + str(l + 1)]

    return parameters, v

def update_params_adam(parameters, grads, v, s, t, learning_rate,
                                beta1=0.9, beta2=0.999, epsilon=1e-8  ):

    L = len(parameters) // 2
    v_corrected = {}
    s_corrected = {}

    # Perform Adam update on all parameters
    for l in range(L):

        # Moving average of the gradients
        v["dW" + str(l + 1)] = beta1 * v["dW" + str(l + 1)] + (1 - beta1) * grads["dW" + str(l + 1)]
        v["db" + str(l + 1)] = beta1 * v["db" + str(l + 1)] + (1 - beta1) * grads["db" + str(l + 1)]

        # Compute bias-corrected first moment estimate
        v_corrected["dW" + str(l + 1)] = v["dW" + str(l + 1)] / (1 - beta1 ** t)
        v_corrected["db" + str(l + 1)] = v["db" + str(l + 1)] / (1 - beta1 ** t)

        # Moving average of the squared gradients
        s["dW" + str(l + 1)] = beta2 * s["dW" + str(l + 1)] + (1 - beta2) * grads["dW" + str(l + 1)] ** 2
        s["db" + str(l + 1)] = beta2 * s["db" + str(l + 1)] + (1 - beta2) * grads["db" + str(l + 1)] ** 2

        # Compute bias-corrected second raw moment estimate
        s_corrected["dW" + str(l + 1)] = s["dW" + str(l + 1)] / (1 - beta2 ** t)
        s_corrected["db" + str(l + 1)] = s["db" + str(l + 1)] / (1 - beta2 ** t)

        # Update the parameters combining momentum and RMS_prop

        parameters["W" + str(l + 1)] = parameters["W" + str(l + 1)] - learning_rate * (
                    v_corrected["dW" + str(l + 1)] / (np.sqrt(s_corrected["dW" + str(l + 1)]) + epsilon))
        parameters["b" + str(l + 1)] = parameters["b" + str(l + 1)] - learning_rate * (
                    v_corrected["db" + str(l + 1)] / (np.sqrt(s_corrected["db" + str(l + 1)]) + epsilon))

    return parameters, v, s

# ========================================== mini-batches generator ====================================================

def random_mini_batches(X, Y, mini_batch_size = 64):

    m = X.shape[1]  # number of training examples
    mini_batches = []

    # Step 1: Shuffle (X, Y)
    permutation = list(np.random.permutation(m))
    shuffled_X = X[:, permutation]
    shuffled_Y = Y[:, permutation]

    assert(Y.shape[1] == X.shape[1])
    assert(shuffled_Y.shape[1] == shuffled_X.shape[1])

    # Step 2: Partition (shuffled_X, shuffled_Y). Minus the end case.

    num_complete_minibatches = math.floor(
        m / mini_batch_size)  # number of mini batches of size mini_batch_size in your partitioning
    for k in range(0, num_complete_minibatches):
        mini_batch_X = shuffled_X[:, k * mini_batch_size:(k + 1) * mini_batch_size]
        mini_batch_Y = shuffled_Y[:, k * mini_batch_size:(k + 1) * mini_batch_size]

        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)

    # Handling the end case (last mini-batch < mini_batch_size)
    if m % mini_batch_size != 0:
        mini_batch_X = shuffled_X[:, (num_complete_minibatches) * mini_batch_size:]
        mini_batch_Y = shuffled_Y[:, (num_complete_minibatches) * mini_batch_size:]
        mini_batch = (mini_batch_X, mini_batch_Y)
        mini_batches.append(mini_batch)

    return mini_batches

# ==================================================================================================================

def get_error(Y, Y_hat):
    error = 100* (np.abs(Y - Y_hat))/Y
    return np.mean(error)

def get_accuracy(Y, Y_hat):
    error = get_error(Y , Y_hat)
    return 100 - error


# Refer: https://en.wikipedia.org/wiki/Test_functions_for_optimization

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

pso_solver.setSeed(1)

lower = xlower = ylower = 0
upper = xupper = yupper = 6.28
particleList = pso_solver.createRandomParticleList(2, numParticles=10, lower=lower, upper=upper)

# Testing on Easom function
f = lambda x, y: -np.cos(x)*np.cos(y)*np.exp(-((x-np.pi)**2 + (y-np.pi)**2))

pso_solver.psoVisualizeBivariate(particleList, f, xlower, xupper, ylower, yupper, c1=1, c2=1, W=0.5, numIters=25, maxFlag=False, sleepTime=0.1, density=100, accuracy=2, verbose=False)


##########################
##                      ##
## Irving Gomez Mendez  ##
##   October 30, 2021   ##
##                      ##
##########################

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

img = plt.imread("Taguchi.jpg")

n, p = img.shape
u, d, v_T  = np.linalg.svd(img, full_matrices=False)

img = img/255

img_svd = np.zeros(n*p).reshape(n,p)
plt.figure(figsize=(15,18))
plt.subplots_adjust(wspace=0, hspace=0)
for i in range(16):
    if i == 0:
        plt.subplot(4, 4, i+1)
        plt.imshow(img, cmap='gray')
        plt.xticks([])
        plt.yticks([])
    else:
        img_svd += d[i-1] * u[:,i-1].reshape(n, 1) @ v_T[i-1,:].reshape(1, p)
        plt.subplot(4, 4, i+1)
        plt.imshow(img_svd, cmap='gray')
        plt.xticks([])
        plt.yticks([])

img_block = img[:270,:230]
blocks = img_block.reshape(10,27,10,23).swapaxes(1, 2)

plt.figure(figsize=(7.5,9))
plt.subplots_adjust(wspace=0, hspace=0)
for i in range(10):
    for j in range(10):
        plt.subplot(10, 10, 10*i+(j+1))
        plt.imshow(blocks[i][j], cmap='gray', vmin=0, vmax=1)
        plt.xticks([])
        plt.yticks([])

#plt.figure(figsize=(7.5,9))
#plt.imshow(blocks.swapaxes(1,2).reshape(270,230), cmap='gray')

blocks_flat = blocks.reshape(100,27*23)
n, p = img_block.shape
n_block, p_block =  blocks_flat.shape
u, d, v_T  = np.linalg.svd(blocks_flat, full_matrices=False)

img_svd = np.zeros(n*p).reshape(n,p)
plt.figure(figsize=(15,18))
plt.subplots_adjust(wspace=0, hspace=0)
for i in range(16):
    if i == 0:
        plt.subplot(4, 4, i+1)
        plt.imshow(img, cmap='gray')
        plt.xticks([])
        plt.yticks([])
    else:
        blocks_flat_recons = d[i-1] * u[:,i-1].reshape(n_block, 1) @ v_T[i-1,:].reshape(1, p_block)
        img_svd += blocks_flat_recons.reshape(10,10,27,23).swapaxes(1,2).reshape(270,230)
        plt.subplot(4, 4, i+1)
        plt.imshow(img_svd, cmap='gray')
        plt.xticks([])
        plt.yticks([])

###


import numpy as np
from vectors import distance

def standard_form(v1, v2):
    x1, y1 = v1
    x2, y2 = v2
    a = y2 - y1
    b = x1 - x2
    c = x1 * y2 - y1 * x2
    return a,b,c

def intersection(u1,u2,v1,v2):
    a1, b1, c1 = standard_form(u1,u2)
    a2, b2, c2 = standard_form(v1,v2)
    m = np.array(((a1,b1),(a2,b2)))
    c = np.array((c1,c2))
    return np.linalg.solve(m,c)

## Will fail if lines are parallel!
# def do_segments_intersect(s1,s2):
#     u1,u2 = s1
#     v1,v2 = s2
#     l1, l2 = distance(*s1), distance(*s2)
#     x,y = intersection(u1,u2,v1,v2)
#     return (distance(u1, (x,y)) <= l1 and
#             distance(u2, (x,y)) <= l1 and
#             distance(v1, (x,y)) <= l2 and
#             distance(v2, (x,y)) <= l2)

def segment_checks(s1,s2):
    u1,u2 = s1
    v1,v2 = s2
    l1, l2 = distance(*s1), distance(*s2)
    x,y = intersection(u1,u2,v1,v2)
    return [
        distance(u1, (x,y)) <= l1,
        distance(u2, (x,y)) <= l1,
        distance(v1, (x,y)) <= l2,
        distance(v2, (x,y)) <= l2
    ]

def do_segments_intersect(s1,s2):
    u1,u2 = s1
    v1,v2 = s2
    d1, d2 = distance(*s1), distance(*s2)
    try:
        x,y = intersection(u1,u2,v1,v2)
        return (distance(u1, (x,y)) <= d1 and
                distance(u2, (x,y)) <= d1 and
                distance(v1, (x,y)) <= d2 and
                distance(v2, (x,y)) <= d2)
    except np.linalg.linalg.LinAlgError:
        return False

# print(do_segments_intersect(((0,2),(1,-1)),((0,0),(4,0))))

# a = np.array(((1,0), (0,1)))
# b = np.array((9,0))
# x = np.linalg.solve(a, b)
# print(x)


#!/usr/bin/env python3
'''
Code by Stephane Gallet, <gallet.stephane@gmail.com>
based on "How to Share a Secret" by Adi Shamir
Published by :Communications of the ACM
November 1979, Volume 22, Num. 11
'''

import numpy as np
import random

def split_secret(secret, k, n):
    '''
    Secret in an integer
    k is the minimum number of keys to get the secret back
    n is the total number of keys generated
    '''
    #Create two empty lists and a dictionary
    D = {}
    A = []
    B = []

    #Set A0 to be the secret, as defined a0 = D
    A.append(int(secret))

    #Fill the rest of the list A, from A1 to An, with
    #random numbers, as defined in paper "we pick a random
    # k-1 polynomial"
    for j in range(1,n):
        A.append(random.randrange(1,100))

    #Evaluate each polynomial, q(i)
    for i in range(1,n+1):
        #First item is A0
        B.append(A[0])
        #Every other item is evaluated by substituting x
        for j in range(1,k):
            B.append(A[j]*i**j)
        #Sum all the polynomial terms, save sum as Di
        #these are your keys
        D[i] = sum(B)

        B = []  #reset B in order to use again empty

    return D

def get_secret(k,keys):
    '''
    k is the number of keys you are supplying
    '''

    #Create 3 empty lists
    A = []
    D = []
    C = []

    #Re-create the polynomials to solve
    # for the coefficients
    for i in range(1,k+2):
        C.append(1)
        for j in range(1,k+1):
            C.append(i**j)
        A.append(C)
        D.append(keys[i-1])
        C = []

    #Solve Ax = D
    # x are our coeeficients(a0 to an)
    a = np.array(A)
    d = np.array(D)
    x = np.linalg.solve(a,d)

    #The original Secret is a0
    return int(x[0])

if __name__ == '__main__':
    '''
    Call split_secret() to generate keys
    Call get_secret() to recover your original secret
    Disclaimer: get_secret() just takes the first k keys and assumes
    they are in order, this can be easily implemented for any keys
    in any order, but this code is simply to highlight the simplicity
    of the (k, n) threshold scheme
    '''
    keys = split_secret('12345678910',3,5)
    recovered_secret = get_secret(3,keys)
    print(recovered_secret)

    '''
    Thanks to Vincent Chiodo and Isroel Kogan for review of the code
    Thanks to Kenso Trabing for the inspiration, and ByteAcademy in NY
    for teaching me Python
    '''


import math
import numpy as np

def quat2euler(x, y, z, w):
    """Converts input quaternion to corresponding Euler angles (in rad).
       From: https://computergraphics.stackexchange.com/questions/8195/how-to-convert-euler-angles-to-quaternions-and-get-the-same-euler-angles-back-fr"""
    t0 = +2.0 * (w * x + y * z)
    t1 = +1.0 - 2.0 * (x * x + y * y)
    roll = 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
    pitch = math.asin(t2)
    t3 = +2.0 * (w * z + x * y)
    t4 = +1.0 - 2.0 * (y * y + z * z)
    yaw = math.atan2(t3, t4)
    return [yaw, pitch, roll]

def angle_diff(a1, a2):
    """Computes signed angle diff in rad."""
    d = a1 - a2
    return (d + math.pi) % 2*math.pi - math.pi

def dquat2dangle(q1, q2):
    """Assumes rotation around a single axis. Returns angle around this axis."""
    a1 = quat2euler(*q1)[0]
    a2 = quat2euler(*q2)[0]
    return angle_diff(a1, a2)

def norm(x):
    return x / np.linalg.norm(x)

def lookat_to_quat(forward, up):
    vector = norm(forward)
    vector2 = norm(np.cross(norm(up), vector))
    vector3 = np.cross(vector, vector2)
    m00 = vector2[0]
    m01 = vector2[1]
    m02 = vector2[2]
    m10 = vector3[0]
    m11 = vector3[1]
    m12 = vector3[2]
    m20 = vector[0]
    m21 = vector[1]
    m22 = vector[2]

    num8 = (m00 + m11) + m22
    quaternion = np.zeros(4)
    if num8 > 0:
        num = np.sqrt(num8 + 1)
        quaternion[3] = num * 0.5
        num = 0.5 / num
        quaternion[0] = (m12 - m21) * num
        quaternion[1] = (m20 - m02) * num
        quaternion[2] = (m01 - m10) * num
        return quaternion

    if ((m00 >= m11) and (m00 >= m22)):
        num7 = np.sqrt(((1 + m00) - m11) - m22)
        num4 = 0.5 / num7
        quaternion[0] = 0.5 * num7
        quaternion[1] = (m01 + m10) * num4
        quaternion[2] = (m02 + m20) * num4
        quaternion[3] = (m12 - m21) * num4
        return quaternion

    if m11 > m22:
        num6 = np.sqrt(((1 + m11) - m00) - m22)
        num3 = 0.5 / num6
        quaternion[0] = (m10+ m01) * num3
        quaternion[1] = 0.5 * num6
        quaternion[2] = (m21 + m12) * num3
        quaternion[3] = (m20 - m02) * num3
        return quaternion

    num5 = np.sqrt(((1 + m22) - m00) - m11)
    num2 = 0.5 / num5
    quaternion[0] = (m20 + m02) * num2
    quaternion[1] = (m21 + m12) * num2
    quaternion[2] = 0.5 * num5
    quaternion[3] = (m01 - m10) * num2
    return quaternion

# code from stanford robosuite
def convert_quat(q, to="xyzw"):
    """
    Converts quaternion from one convention to another.
    The convention to convert TO is specified as an optional argument.
    If to == 'xyzw', then the input is in 'wxyz' format, and vice-versa.

    Args:
        q: a 4-dim numpy array corresponding to a quaternion
        to: a string, either 'xyzw' or 'wxyz', determining
            which convention to convert to.
    """
    if to == "xyzw":
        return q[[1, 2, 3, 0]]
    if to == "wxyz":
        return q[[3, 0, 1, 2]]
    raise Exception("convert_quat: choose a valid `to` argument (xyzw or wxyz)")


import numpy as np
from scipy.stats import norm

S0 = 10
K = 9.3
r = 0.025
s = 0.3
T = 1

def calc_d1(St, K, r, s, T, t=0, q=0):
    return (np.log(St / K) + (r - q + 0.5 * s ** 2) * (T - t)) \
           / (s * np.sqrt(T - t))

def calc_d2(d1, s, T, t=0):
    return d1 - s * np.sqrt(T - t)

def price_call_option(S0, d1, d2, r, K, T):
    return S0 * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)

d1 = calc_d1(S0, K, r, s, T)
d2 = calc_d2(d1, s, T)
C = S0 * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
print(C)

F = S0 - K * np.exp(-r * T)
P = C - F
print(P)


import numpy as np
import torch

def naive_pred_error(y_true, period):
    assert len(y_true.shape) == 2, "y_true.shape.ndims != 2"
    y_t_pred = y_true[:, :-period]
    y_t_true = y_true[:, period:]
    mae_npe = torch.mean(torch.abs(y_t_true - y_t_pred))
    return mae_npe

def MASE(y_true, y_pred, sample_weight=None, period=1, epsilon=1e-10):
    assert list(y_true.shape) == list(y_pred.shape), \
        "y_true's shape {} != y_pred's shape {}.".format(y_true.shape, y_pred.shape)
    assert y_pred.shape[-1] > period, "period can't be larger than n_fore."
    mae = torch.mean(torch.abs(y_true - y_pred))
    mae_npe = naive_pred_error(y_true, period)
    return mae / (mae_npe + epsilon)

def ND(y_true, y_pred):
    denominator = torch.sum(torch.abs(y_true))
    diff = torch.sum(torch.abs(y_true - y_pred))
    return diff/denominator

def NRMSE(y_true, y_pred):
    denominator = torch.mean(y_true)
    diff = torch.sqrt(torch.mean(((y_pred - y_true)**2)))
    return diff/denominator

def SMAPE(y_true, y_pred):
    smape = torch.mean(torch.abs((2*(y_true-y_pred) / (y_true+y_pred))))
    return smape

def MAE(y_true, y_pred):
    mae = torch.mean(torch.abs(y_true - y_pred))
    return mae

def MSE(y_true, y_pred):
    mse = torch.mean(torch.abs(y_true - y_pred)**2)
    return mse


from typing import Tuple

import numpy as np

def forward(h1_d: int, w1_d: int, h2_d: int, w2_d: int) -> np.ndarray:
    """
    forward
    :param h1_d: vertical spatial dimension
    :param w1_d: horizontal spatial dimension
    :param h2_d: vertical spectral dimension
    :param w2_d: horizontal spectral dimension
    :return: transform matrix (row-major)
    """
    M = np.empty(shape=(h2_d * w2_d, h1_d * w1_d), dtype=np.complex128)
    for h2 in range(h2_d):
        for w2 in range(w2_d):
            i2 = h2 * w2_d + w2  # row major
            for h1 in range(h1_d):
                for w1 in range(w1_d):
                    i1 = h1 * w1_d + w1  # row major
                    M[i2, i1] = complex(0, - 2 * np.pi * (h2 * h1 / h1_d + w2 * w1 / w1_d))
    return np.exp(M) / (h1_d * w1_d)

def backward(h2_d: int, w2_d: int, h1_d: int, w1_d: int) -> np.ndarray:
    """
    backward
    :param h1_d: vertical spatial dimension
    :param w1_d: horizontal spatial dimension
    :param h2_d: vertical spectral dimension
    :param w2_d: horizontal spectral dimension
    :return: transform matrix (row-major)
    """
    M = np.empty(shape=(h1_d * w1_d, h2_d * w2_d), dtype=np.complex128)
    for h1 in range(h1_d):
        for w1 in range(w1_d):
            i1 = h1 * w1_d + w1  # row major
            for h2 in range(h2_d):
                for w2 in range(w2_d):
                    i2 = h2 * w2_d + w2  # row major
                    M[i1, i2] = complex(0, 2 * np.pi * (h2 * h1 / h1_d + w2 * w1 / w1_d))
    return np.exp(M)

def basis(h1_d: int, w1_d: int, h2_d: int, w2_d: int) -> Tuple[np.ndarray, np.ndarray]:
    """
    :param h1_d: vertical spatial dimension
    :param w1_d: horizontal spatial dimension
    :param h2_d: vertical spectral dimension
    :param w2_d: horizontal spectral dimension
    """
    return forward(h1_d, w1_d, h2_d, w2_d), backward(h2_d, w2_d, h1_d, w1_d)


import config
import numpy as np
import pandas as pd

# Hypothesis Function
def hypothesis(thetarg, x):
    return np.dot(x, thetarg)

# Cost function used to calculate the error between hypothetic and actual value over m training examples
def cost(x, y, thetarg, m):
    return float((1 / (2 * m)) * np.dot((hypothesis(thetarg, x) - y).T, (hypothesis(thetarg, x) - y)))

# Normal Equation method to minimize cost function in configurable alpha and iterations
def normal_equation(x, y, m):
    inverse = np.linalg.inv(np.dot(x.T, x))
    thetarg = np.dot(np.dot(inverse, x.T), y)
    cost_value = cost(x, y, thetarg, m)
    return cost_value, thetarg

muldata = pd.read_csv(config.path)
indata = muldata.drop('price', axis=1)
indata.insert(0, "x0", 1)
outdata = muldata['price']

inmatrix = indata.values
outmatrix = outdata.values.reshape(outdata.size, 1)

msize = len(outmatrix)

cost_final, theta_final = normal_equation(inmatrix, outmatrix, msize)


# encoding:utf-8

import numpy as np
import miniad
import miniad.utils as utils

class Function:
    '''
    Base class for Function
    '''
    @staticmethod
    def forward():
        raise NotImplementedError

    @staticmethod
    def backward():
        raise NotImplementedError

class Add(Function):
    @staticmethod
    def forward(left, right):
        '''
        Add function

        Parameters
        ----------
        left:	Tensor
            left operand
        right:	Tensor or float
            right operand

        Returns
        -------
        Tensor
        '''
        is_right_tensor = True if isinstance(right, miniad.Tensor) else False
        out = miniad.Tensor(data=left.data +
                            right.data if is_right_tensor else left.data +
                            right)
        out.children = (left, right) if is_right_tensor else (left, )
        out.grad_fn = Add.backward

        return out

    @staticmethod
    def backward(out, left, right=None):
        '''
        out = left + right
        left_grad += out_grad
        right += out_grad
        '''
        out_grad = out.grad  # Do not revise out
        if out_grad is None:
            out_grad = np.ones_like(left.data)
        left.grad = out_grad if left.grad is None else left.grad + out_grad
        if right is None:  # Tensor + float = Tensor
            return (left, )
        else:
            right.grad = out_grad if right.grad is None else right.grad + out_grad
            return (left, right)

class Minus(Function):
    @staticmethod
    def forward(left, right):
        '''
        Minus function

        Parameters
        ----------
        left:	Tensor
            left operand
        right:	Tensor or float
            right operand

        Returns
        -------
        Tensor
        '''
        is_right_tensor = True if isinstance(right, miniad.Tensor) else False
        out = miniad.Tensor(data=left.data -
                            right.data if is_right_tensor else left.data -
                            right)
        out.children = (left, right) if is_right_tensor else (left, )
        out.grad_fn = Minus.backward

        return out

    @staticmethod
    def backward(out, left, right=None):
        '''
        out = left - right
        left_grad += out_grad
        right -= out_grad
        '''
        out_grad = out.grad  # Do not revise out
        if out_grad is None:
            out_grad = np.ones_like(left.data)
        left.grad = out_grad if left.grad is None else left.grad + out_grad
        if right is None:  # Tensor + float = Tensor
            return (left, )
        else:
            right.grad = -out_grad if right.grad is None else right.grad - out_grad
            return (left, right)

class Multiply(Function):
    @staticmethod
    def forward(left, right):
        '''Element-wise Multiply function

        Parameters
        ----------
        left:	Tensor
            left operand
        right:	Tensor or float
            right operand

        Returns
        -------
        Tensor
        '''
        is_right_tensor = True if isinstance(right, miniad.Tensor) else False
        out = miniad.Tensor(data=left.data *
                            right.data if is_right_tensor else left.data *
                            right)
        out.children = (left, right) if is_right_tensor else (left, )
        out.grad_fn = Multiply.backward
        out.save_for_backward = None if is_right_tensor else right

        return out

    @staticmethod
    def backward(out, left, right=None):
        '''
        out = left * right
        left_grad += out_grad * right.data
        right += out_grad * left.data
        '''
        out_grad = out.grad  # Do not revise out
        if out_grad is None:
            out_grad = np.ones_like(left.data)
        if right is None:
            right_data = out.save_for_backward
            left.grad = out_grad * right_data if left.grad is None else left.grad + \
                out_grad * right_data
            return (left, )
        else:
            left.grad = out_grad * right.data if left.grad is None else left.grad + \
                out_grad * right.data
            right.grad = out_grad * \
                left.data if right.grad is None else right.grad + out_grad * left.data

            return (left, right)

class Division(Function):
    @staticmethod
    def forward(numerator, denominator):
        '''
        Division function

        Parameters
        ----------
        numerator:	Tensor
            numerator operand
        denominator:	Tensor or float
            denominator operand

        Returns
        -------
        Tensor
        '''
        is_deno_tensor = True if isinstance(denominator,
                                            miniad.Tensor) else False
        EPS = 1e-12
        if is_deno_tensor:
            deno_data = utils.clip(denominator.data, EPS)
            out = miniad.Tensor(data=numerator.data / deno_data)
            out.children = (numerator, denominator)
        else:
            deno_data = utils.clip(denominator, EPS)
            out = miniad.Tensor(data=numerator.data / deno_data)
            out.children = (numerator, )
            out.save_for_backward = deno_data

        out.grad_fn = Division.backward

        return out

    @staticmethod
    def backward(out, numerator, denominator=None):
        '''
        out = nume / deno
        nume_grad += out_grad * (1/deno.data)
        deno_grad -= out_grad * nume.data / (deno.data * deno.data)
        '''

        out_grad = out.grad  # Do not revise out
        if out_grad is None:
            out_grad = np.ones_like(numerator.data)
        EPS = 1e-12
        if denominator is None:
            deno_data = out.save_for_backward
            numerator.grad = out_grad / deno_data if numerator.grad is None else numerator.grad + out_grad / deno_data

            return (numerator, )
        else:
            deno_data = utils.clip(denominator.data, EPS)
            numerator.grad = out_grad / deno_data if numerator.grad is None else numerator.grad + out_grad / deno_data
            deno_data = utils.clip(denominator.data**2, EPS)
            denominator.grad = -out_grad * numerator.data / deno_data if denominator.grad is None else denominator.grad - out_grad * numerator.data / deno_data

            return (numerator, denominator)

class Power(Function):
    @staticmethod
    def forward(base, exponent):
        '''
        Power function

        Parameters
        ----------
        base:	Tensor
            base operand
        exponent:	float
            exponent operand

        Returns
        -------
        Tensor
        '''
        out = miniad.Tensor(data=np.power(base.data, exponent))
        out.children = (base, )
        out.grad_fn = Power.backward
        out.save_for_backward = exponent

        return out

    @staticmethod
    def backward(out, base):
        '''
        out = base ^ {exponent}
        base_grad += exponent * base ^ {exponent - 1}
        '''
        out_grad = out.grad
        if out_grad is None:
            out_grad = np.ones_like(base.data)
        exponent = out.save_for_backward
        base_grad = out_grad * exponent * np.power(base.data, exponent - 1)
        base.grad = base_grad if base.grad is None else base.grad + base_grad

        return (base, )

# TODO bias can be None
class Linear(Function):
    @staticmethod
    def forward(x, weight, bias):
        '''Linear function
        y = x @ weight + bias
        Parameters
        ----------
        x:	Tensor
            input
        weight:	Tensor
            weight parameter
        bias:    Tensor
            bias parameter

        Returns
        -------
        Tensor
        '''
        out = miniad.Tensor(data=x.data @ weight.data + bias.data)
        out.children = (x, weight, bias)
        out.grad_fn = Linear.backward

        return out

    @staticmethod
    def backward(out, x, weight, bias):
        '''
        y = x @ w + b

        dx = dy @ w.T
        dw = x.T @ dy
        db = dy.sum(0)

        Note:
        x: (B, M)
        weight: (M, N)
        bias: (N)
        '''
        out_grad = out.grad
        if out_grad is None:
            out_grad = np.ones(
                (x.data.shape[0], weight.data.shape[1]))  # (B, N)

        x_grad = out_grad @ weight.data.T  # (B, M)
        w_grad = x.data.T @ out_grad  # (M, N)
        b_grad = np.sum(out_grad, 0)  # (N)

        x.grad = x_grad if x.grad is None else x_grad + x.grad
        weight.grad = w_grad if weight.grad is None else w_grad + weight.grad
        bias.grad = b_grad if bias.grad is None else b_grad + bias.grad

        return (x, weight, bias)

class ReLU(Function):
    @staticmethod
    def forward(x):
        '''ReLU function
        y = relu(x) = max(x, 0)

        Parameters
        ----------
        x:	Tensor
            input

        Returns
        -------
        Tensor
        '''
        out = miniad.Tensor(data=np.where(x.data >= 0, x.data, 0))
        out.children = (x, )
        out.grad_fn = ReLU.backward

        return out

    @staticmethod
    def backward(out, x):
        '''
        y = relu(x) = x if x >= 0 else 0
        x_grad = 1 if x >= 0 else 0
        '''
        out_grad = out.grad
        if out_grad is None:
            out_grad = np.ones_like(x.data)
        x_grad = np.where(x.data >= 0, 1., 0.)
        x_grad *= out_grad
        x.grad = x_grad if x.grad is None else x_grad + x.grad

        return (x, )

class Sigmoid(Function):
    @staticmethod
    def forward(x):
        '''Sigmoid function
        y = sigmoid(x) = 1/(1 + exp(-x))

        Parameters
        ----------
        x:	Tensor
            input

        Returns
        -------
        Tensor
        '''
        out = miniad.Tensor(data=1. / (np.exp(-x.data) + 1))
        out.children = (x, )
        out.grad_fn = Sigmoid.backward

        return out

    @staticmethod
    def backward(out, x):
        '''
        y = sigmoid(x)
        x_grad = sigmoid(x)(1 - sigmoid(x))
        '''
        out_grad = out.grad
        if out_grad is None:
            out_grad = np.ones_like(x.data)

        x_grad = (1. / (np.exp(-x.data) + 1)) * (1 - 1. /
                                                 (np.exp(-x.data) + 1))
        x_grad *= out_grad
        x.grad = x_grad if x.grad is None else x.grad + x_grad

        return (x, )

# TODO. dim can be sequence
class Squeeze(Function):
    @staticmethod
    def forward(x, dim=None):
        '''Squeeze function
        Remove dim of length one from x

        Parameters
        ----------
        x:	Tensor
            input
        dim:    int or None
            which dim to squeeze. If dim is None, squeeze all length one dims.

        Returns
        -------
        Tensor
        '''
        if dim is None:
            squeezed_data = np.squeeze(x.data)
        else:
            squeezed_data = np.squeeze(x.data, axis=dim)
        out = miniad.Tensor(data=squeezed_data)
        out.children = (x, )
        out.grad_fn = Squeeze.backward

        return out

    @staticmethod
    def backward(out, x):
        '''
        y = squeeze(x)
        x_grad = y_grad
        '''
        out_grad = out.grad
        if out_grad is None:
            out_grad = np.ones_like(x.data)
        out_grad = out_grad.reshape(x.data.shape)
        x.grad = out_grad if x.grad is None else x.grad + out_grad

        return (x, )

class BinaryCrossEntropyLoss(Function):
    @staticmethod
    def forward(y_hat, y):
        '''Binary Cross Entropy function

        L = -sum([ylog y_hat + (1-y)log(1-y_hat)]) / N

        Parameters
        ----------
        y_hat:	Tensor
            predicts
        y:	numpy.ndarray
            labels

        Returns
        -------
        Tensor
        '''
        EPS = 1e-12
        pos_indexs = np.where(y == 1)
        neg_indexs = np.where(y == 0)
        pos_y_hat = utils.clip(y_hat.data[pos_indexs], EPS)
        neg_y_hat = utils.clip(1 - y_hat.data[neg_indexs], EPS)

        loss_data = -(np.sum(np.log(pos_y_hat)) +
                      np.sum(np.log(neg_y_hat))) / len(y)
        loss = miniad.Tensor(data=loss_data)
        loss.children = (y_hat, )
        loss.grad_fn = BinaryCrossEntropyLoss.backward
        loss.save_for_backward = y

        return loss

    @staticmethod
    def backward(out, y_hat):
        '''
        y_hat_grad = if y == 1, -1/(N* y_hat)
        y_hat_grad = if y == 0,  1/(N * (1 - y_hat))
        '''
        out_grad = out.grad
        if out_grad is None:
            out_grad = 1  # loss is always a scalar
        y = out.save_for_backward
        EPS = 1e-12
        N = len(y)

        pos_indexs = np.where(y == 1)
        neg_indexs = np.where(y == 0)
        pos_y_hat = utils.clip(y_hat.data[pos_indexs] * N, EPS)
        neg_y_hat = utils.clip(N * (1 - y_hat.data[neg_indexs]), EPS)

        dx_pos = -1. / pos_y_hat
        dx_neg = 1. / neg_y_hat
        dx = np.zeros_like(y_hat.data)
        dx[pos_indexs] = dx_pos
        dx[neg_indexs] = dx_neg
        dx *= out_grad

        y_hat.grad = dx if y_hat.grad is None else y_hat.grad + dx

        return (y_hat, )

class MSELoss(Function):
    @staticmethod
    def forward(y_hat, y):
        '''Mean Squared Error function

        L = sum((y_hat - y) ** 2) / N

        Parameters
        ----------
        y_hat:	Tensor
            predicts
        y:	numpy.ndarray
            labels

        Returns
        -------
        Tensor
        '''
        loss_data = np.sum((y_hat.data - y)**2) / len(y)
        loss = miniad.Tensor(data=loss_data)
        loss.children = (y_hat, )
        loss.grad_fn = MSELoss.backward
        loss.save_for_backward = y

        return loss

    @staticmethod
    def backward(out, y_hat):
        '''
        l = sum((y_hat - y) ** 2) / N
        y_hat_grad = 2 * (y_hat - y) / N
        '''
        out_grad = out.grad
        if out_grad is None:
            out_grad = 1  # loss is always a scalar
        y = out.save_for_backward
        N = len(y)
        dx = 2 * (y_hat.data - y) / N
        dx *= out_grad

        y_hat.grad = dx if y_hat.grad is None else y_hat.grad + dx

        return (y_hat, )

add = Add.forward
minus = Minus.forward
multiply = Multiply.forward
division = Division.forward
power = Power.forward
linear = Linear.forward
relu = ReLU.forward
sigmoid = Sigmoid.forward
squeeze = Squeeze.forward
binary_cross_entropy_loss = BinaryCrossEntropyLoss.forward
mse_loss = MSELoss.forward


from numpy import loadtxt, zeros, e, array, log, ones, where, argmax, mean
from scipy.io import loadmat

def feature_normalize(input):
    mu = input.mean(axis=0)
    sd = input.std(axis=0)
    input_norm = (input - mu) / sd

    return input_norm

def cost_function(theta, x, y):
    m = y.size
    h = sigmoid(x.dot(theta))
    J = (1.0 / m) * ((-y.T.dot(log(h))) - ((1.0 - y.T).dot(log(1.0 - h))))
    return - 1 * J.sum()

def sigmoid(X):
    return 1.0 / (1.0 + e ** (-1.0 * X))

def add_column(input_matrix) :
    m, n = input_matrix.shape
    result = ones(shape=(m, n + 1))
    result[:, 1:n + 1] = input_matrix
    return result

def get_accuracy(y_predict, y_real):
    m = y_predict.size
    y_predict.shape = (m, 1)
    result = "accuracy : {: .2%}".format(mean(y_predict == y_real))
    print result

def predict(theta1, theta2, x):
    x = add_column(x)
    h1 = sigmoid(x.dot(theta1.T))

    X_next = add_column(h1)
    h2 = sigmoid(X_next.dot(theta2.T))

    column_idxs = argmax(h2, axis=1)
    p = column_idxs + 1
    return p

data = loadmat('ex3data1.mat')
x = data['X']
y = data['y']

weight = loadmat('ex3weights.mat')
theta1 = weight['Theta1']
theta2 = weight['Theta2']

y_predict = predict(theta1, theta2, x)
get_accuracy(y_predict, y)


import numpy as np
import matplotlib.pyplot as plt

x0 = float(input('Enter initial position(x0 = 1 ,-1 or 1): '))       # Initial position

v0 = float(input('Enter initial velocity (v0 = 0.1, 0.1 or 10): '))  # Initial Velocity
t1 = 0
tn = 100

h = 0.01                                                             # time interval

n = (tn-t1)/h                                                        # number of steps

                                                                     # initialization for position and velocity
x = np.zeros(int(n))
v = np.zeros(int(n))

force0 = -4 *x0*(x0**2 -1)                                           # Initial force
force = np.zeros(int(n))
force[0] = force0
x[0] = x0
v[0] = v0
for i in range(int(n-1)):
  force[i] = -4 * x[i] * (x[i]**2 -1)                                # updating values
  v[i+1] = v[i] + force[i] * h
  x[i+1] = x[i] + v[i] * h

                                    #--------- plotting----------
plt.figure("Phase space Trajectory (x0, p0)=(1, 0.1)", figsize =(7,5))
plt.plot(x, v, color = 'black')

plt.xlabel('position (x)')
plt.ylabel('Velocity (v)')
plt.title("Phase space Trajectory (x0, p0)=" +"("+str(x0) + ',' + str(v0)+")")
# plt.savefig(f"Phase-space-Trajectory-{(x0, v0)}.png")
plt.show()

# plt.show(block =False)
# plt.pause(0.0001)
# plt.clf()


#!/usr/bin/env python

#This script will introduce us to Numpy, a library useful for working with n-dimensional data.
import numpy as np

print("Empty:")
empty = np.empty((2,2))
print(empty)
print("shape: {}".format(empty.shape))

print("\nFilled:")
filled = np.array([[1,2],[3,4]])
print(filled)

print("\nZeros:")
zeros = np.zeros((2,2))
print(zeros)

print("\nEye:")
identity = np.eye(2)
print(identity)

print("\nOnes:")
ones = np.ones((2,2))
print(ones)

print("\nConstants:")
constants = np.full((2,2),4)
print(constants)

print("\nIndexing:")
print("ones[:,0] = {}".format(ones[:,0]))
print("filled[0,-1] = {}".format(filled[0,-1]))
print("constants > 5 =\n{}".format(constants > 5))

print("\nOperations:")
print("filled + ones =\n{}".format(filled + ones))
print("filled - ones =\n{}".format(filled - ones))
print("filled * filled =\n{}".format(filled * filled))
print("filled / filled =\n{}".format(filled / filled))
print("filled.dot(ones) =\n{}".format(filled.dot(ones)))
print("np.sqrt(filled) =\n{}".format(np.sqrt(filled)))

np.reshape(ones,(-1))
np.tile(ones,4)
np.stack((ones,constants),axis=0)


import pyomo.environ as pyo
import numpy as np
import pyomo_utility as util

i_num = 3
j_num = 4

m = pyo.ConcreteModel()
m.i = pyo.RangeSet(0, i_num - 1)
m.j = pyo.RangeSet(0, j_num - 1)

# variable
m.x = pyo.Var(m.i, m.j, bounds=(0, 1))

# parameter
m.A = pyo.Param(m.i, m.j, default=0, mutable=True)

# constraint
m.row_sum_eq_one_con = pyo.Constraint(
    m.i, rule=lambda p, i:
    pyo.quicksum(p.x[i, :]) == 1
)

# objective
m.obj = pyo.Objective(expr=pyo.sum_product(m.A, m.x))

# suffix for dual
m.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT)

A_0 = np.random.rand(i_num, j_num)

# fill parameter A with A_0
util.fill_value(m.A, A_0)

solver = pyo.SolverFactory('gurobi_direct')
solver.solve(m)

# get value of variable x
x = util.value_to_numpy(m.x)
print(f'x = {x}')
# x = [[0. 0. 0. 1.]
#  [0. 0. 1. 0.]
#  [0. 0. 0. 1.]]

# get dual of constraint con
dual = util.suffix_to_numpy(m.dual, m.row_sum_eq_one_con)

print(f'dual = {dual}')
# dual = [0.06459462 0.27276094 0.07508348]

# fill variable x with x_0
x_0 = np.random.rand(i_num, j_num)
util.fill_value(m.x, x_0)


# -*- coding:UTF-8 -*-
import numpy as np
import sys, os
import matplotlib.pyplot as plt

# 求协方差矩阵
def c_x(mat):
    mx = mat.sum(axis=0)/len(mat)
    print(mat.sum(axis=0)/len(mat))
    mt = mat - [mx for _ in range(len(mat))]
    mm = np.zeros(shape=(3,3))
    for i in mt:
        mult = np.matrix(i).T * np.matrix(i)
        mm += mult
    # print(mm/len(mat))
    return mm / len(mat)

def des_dim(x,eig_vector, dim):
    phi = np.matrix([eig_vector[i] for i in range(dim)])
    # print(phi)
    desed_dim = phi * np.matrix(x)
    # print(desed_dim)
    return desed_dim

def plot_dot(x):
    plt.figure()
    plt.plot(np.array(x[0])[0,0:4], np.array(x[1])[0,0:4],'ro',label="w1")
    plt.plot(np.array(x[0])[0,4:8], np.array(x[1])[0,4:8],'bx', label="w2")
    plt.legend(numpoints=1)
    plt.show()

if __name__ == "__main__":
    # mat=np.array([[0,0,0],
    # [2,0,0],
    # [2,0,1],
    # [1,2,0],
    # [0,0,1],
    # [0,1,0],
    # [0,-2,1],
    # [1,1,-2]])
    mat=np.array([
    [-0.75,-0.25,-0.125],
    [1.25,-0.25,-0.125],
    [1.25,-0.25,0.875],
    [0.25,1.75,-0.125],
    [-0.75,-0.25,0.875],
    [-0.75,0.75,-0.125],
    [-0.75,-2.25,0.875],
    [0.25,0.75,-2.125]])
    # mat2=np.array([[0,0,0],
    # [1,0,0],
    # [1,0,1],
    # [1,1,0],
    # [0,0,1],
    # [0,1,0],
    # [0,1,1],
    # [1,1,1]])
    cx = c_x(mat)
    print(cx)
    eigen_value = np.linalg.eig(cx)
    print(eigen_value[0])
    print(eigen_value)
    print(np.matrix(eigen_value[1]).T)

    # 降维
    desed_dim2 = des_dim(mat.T, eigen_value[1],2)
    print(desed_dim2.T)
    plot_dot(desed_dim2)

    desed_dim1 = des_dim(mat.T, eigen_value[1],1)
    print(desed_dim1)
    plt.plot(np.array(desed_dim1[0])[0,0:4],[0 for i in range(-2,2)],'ro', label="w1")
    plt.plot(np.array(desed_dim1[0])[0,4:8],[0 for i in range(-2,2)],'bx', label="w2")
    plt.legend(numpoints=1)
    plt.show()


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

df = pd.read_csv('sbi_data.csv', usecols = ['Date', 'Close'], nrows = 66)

U = []
for i in range(65):
    U.append( math.log(df.Close[i+1]/df.Close[i]))

variance = statistics.variance(U)
sigma = math.sqrt(variance)
print(variance, sigma)

mean = statistics.mean(U)
print(mean)

mu = variance/2 + mean
print(mu)

S = []

data = []
for i in range(1000):
    data.append(0.00)

N = 1000
asian = []
european = []
for ctr in range(N):
    S.clear()
    S.append(df.Close[65])

    for i in range(1, 300):
        S.append(S[i-1]*math.exp((mu - variance/2.00)*0.1 + np.sqrt(variance)*np.sqrt(0.1)*np.random.normal(0,1,1)))

    for j in range(len(S)):
        data[j] += S[j]

    european.append(max(0, 1.1*S[0] - S[-1]))
    asian.append(max(1.1*S[0] - statistics.mean(S), 0))

# print("Mean European = {}, S.D European = {}".format(statistics.mean(european), np.sqrt(statistics.variance(european))))

print("Mean Asian = {}, S.D Asian = {}".format(statistics.mean(asian), np.sqrt(statistics.variance(asian))))

while data[-1] == 0.00:
    data.pop()

for j in range(len(data)):
    data[j] /= N

b = 0.00
for i in range(len(asian)):
    b = b + (asian[i] - statistics.mean(asian))*(european[i] - statistics.mean(european))/(1000*statistics.variance(european))

for i in range(len(asian)):
    asian[i] = asian[i] - b*(european[i] - statistics.mean(european))

print("Mean Asian = {}, S.D Asian = {}".format(statistics.mean(asian), np.sqrt(statistics.variance(asian))))


import numpy as np

class SGD:
    """Stochastic Gradient Descent"""

    def __init__(self, lr=0.01):
        self.lr = lr

    def update(self, params, grads):
        for k in params.keys():
            params[k] -= self.lr * grads[k]

class Momentum:
    """ SGD with Momentum: https://blog.paperspace.com/intro-to-optimization-momentum-rmsprop-adam/"""

    def __init__(self, lr=0.01, momentum=0.9):
        self.lr = lr
        self.momentum = momentum
        self.v = None

    def update(self, params, grads):
        if self.v is None:
            self.v = {}
            for k,v in params.items():
                self.v[k] = np.zeros_like(v)

        for k,v in params.items():
            self.v[k] = self.momentum * self.v[k] - self.lr * grads[k]
            params[k] += self.v[k]

class RMSProp:
    """Root Mean Square Propogation: https://blog.paperspace.com/intro-to-optimization-momentum-rmsprop-adam/

    It is recommended to leave the parameters of this optimizer at their default values (except the learning rate).
    This optimizer is usually a good choice for recurrent neural networks
    """

    def __init__(self, lr=0.01, oth=0.9):
        self.lr = lr
        self.oth = oth
        self.v = None

    def update(self, params, grads):
        if self.v is None:
            self.v = {}
            for k,v in params.items():
                self.v[k] = np.zeros_like(v)

        for k,v in params.items():
            self.v[k] = self.oth * self.v[k] + (1 - self.oth) * grads[k]*grads[k]
            params[k] -= self.lr * grads[k] / (np.sqrt(self.v[k]) + 1e-7)


# -*- coding: utf-8 -*-
"""
Created on Thu Oct 17 16:51:28 2019

@author: jercas
"""
import numpy as np
import math
def softmax1(inMatrix):
    m,n = np.shape(inMatrix)
    outMatrix = np.mat(np.zeros((m,n)))
    soft_sum = 0

    for idx in range(0,n):
        outMatrix[0,idx] = math.exp(inMatrix[0,idx])
        soft_sum += outMatrix[0,idx]
    for idx in range(0,n):
        outMatrix[0,idx] = outMatrix[0,idx] / soft_sum
    return outMatrix

def softmax2(x, axis=1):
    row_max = x.max(axis=axis)  # 计算每行的最大值
    row_max=row_max.reshape(-1, 1)
    x = x - row_max  # 每行元素都需要减去对应的最大值，否则求exp(x)会溢出，导致inf情况

    x_exp = np.exp(x)  # 计算e的指数次幂
    x_sum = np.sum(x_exp, axis=axis, keepdims=True)
    s = x_exp / x_sum
    return s

a = np.array([[1, 2, 1, 2, 1, 1, 3]])
print(softmax1(a))
print('\n')
print(softmax2(a))


#!/usr/bin/env python3
import numpy as np
from matplotlib import pyplot as plt

def plot_vector(vec,lbl):
    assert(len(vec)==2) # Must be 2 dimensional
    x=[0,vec[0]]
    y=[0,vec[1]]
    plt.plot(x,y,label=lbl)

fig=plt.figure("Put directional vectors wherever you want")

plt.xlim(-5,5)
plt.ylim(-5,5)
ax=plt.gca()
ax.spines["top"].set_color("none")
ax.spines["right"].set_color("none")
ax.xaxis.set_ticks_position("bottom")
ax.yaxis.set_ticks_position("left")
ax.spines["left"].set_position(("data",0))
ax.spines["bottom"].set_position(("data",0))
ax.set_aspect("equal",adjustable="box")

vec1=np.array([1,2])
vec2=np.array([-4,2])
vec3=vec1+vec2
vec4=vec1*vec2

plot_vector(vec1,"vec1")
plot_vector(vec2,"vec2")
plot_vector(vec3,"vec3")
plot_vector(vec4,"vec4")

plt.legend()
plt.show()


"""
  Implementing various dimensionality reduction methods with PyTorch Tensors

  Under development. Please use with caution.

"""
import torch
from torch.autograd import Variable

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

def distance_matrix(mat):
    d= ((mat.unsqueeze (0)-mat.unsqueeze (1))**2).sum (2)**0.5
    return d

def similarity_matrix(mat):
    d= distance_matrix(mat)
    D = torch.exp(-(d ))
    return D.sqrt()

# Generate Clusters
mat = torch.cat([torch.randn(500,2)+torch.Tensor([-2,-3]),   torch.randn(500,2)+torch.Tensor([2,1])])

mat = mat[torch.randperm(mat.size(0))]
plt.scatter(mat[:,0].numpy(),mat[:,1].numpy())
plt.show(block=False)

##-------------------------------------------
#         Spectral analysis on distance matrix
##-------------------------------------------
d= distance_matrix(mat);

plt.figure()
plt.imshow(d.numpy())
plt.title('Distance Matrix-Before Ordering')
plt.show(block=False)

[u,s,v]=torch.svd(d)

colors = cm.rainbow(np.linspace(0, 1, mat.size(0)))
[val, ind] = torch.sort(u[:,1] )
plt.figure()

sorted_u  = u[ind,:]

for x, color in zip(sorted_u.numpy(), colors):
    plt.scatter(x[1],x[2], color=color)

plt.title('Eigenvector-Mapping')
plt.show(block=False)

plt.figure()
plt.imshow(d[[ind]][:,ind].numpy())
plt.show(block=False)
plt.title('Sorted Matrix');

plt.figure()
plt.plot(torch.sort(u[:,1 ])[0].numpy())
plt.show(block=False)
plt.title("Sorted Eigenvector")

raw_input("Press Enter to exit..")
plt.close('all')


import numpy as np
import matplotlib.pyplot as plt

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

#The distances are calculated from origin in 3 dimensional space

x_domain = 20
y_domain = 20

def euclidean_distance(x,y,z,dimension=3):
    point_b = [x,y,z]
    distance_squared_sum = 0
    for n in range(dimension):
        distance_squared_sum += abs(point_b[n])**2
    return distance_squared_sum**0.5

def manhattan_distance(x,y,z,dimension=3):
    point_b = [x,y,z]
    distance_sum = 0
    for n in range(dimension):
        distance_sum += abs(point_b[n])
    return distance_sum

def minkowski_distance(x,y,z,p,dimensions=3):
    point_b = [x,y,z]
    minkowski_distance_sum = 0
    for n in range(dimensions):
        minkowski_distance_sum += abs(point_b[n]**p)
    return minkowski_distance_sum**(1/p)

# print(euclidean_distance(1,1,0))
# print(manhattan_distance(14,14,0))
# print(str(minkowski_distance(1,1,0,2))+' Minkowski E')
# print(str(minkowski_distance(14,14,0,1))+' Minkowski M')

# #Euclidean Distance
# x = np.linspace(0, x_domain)
# y = np.linspace(0, y_domain)
# z = euclidean_distance(x,y,0)
# ax.plot3D(x,y,z,'green')
#
# #Manhattan Distance
# x1 = np.linspace(0, x_domain)
# y1 = np.linspace(0, y_domain)
# z1 = manhattan_distance(x1,y1,0)
# ax.plot3D(x1,y1,z1,'red')
#
# #Chebyshev Distance (Minkowski Limit Implementation)
# x2 = np.linspace(0, x_domain)
# y2 = np.linspace(0, y_domain)
# z2 = minkowski_distance(x2,y2,0,100)
# ax.plot3D(x2,y2,z2,'blue')
#
# #Minkowski Distance (2**-2)
# x3 = np.linspace(0, x_domain)
# y3 = np.linspace(0, y_domain)
# z3 = minkowski_distance(x3,y3,0,0.25)
# ax.plot3D(x3,y3,z3,'black')
#
# #Minkowski Distance (2**-1)
# x4 = np.linspace(0, x_domain)
# y4 = np.linspace(0, y_domain)
# z4 = minkowski_distance(x4,y4,0,0.5)
# ax.plot3D(x4,y4,z4,'purple')
#
# ax.set_xlabel('X Coordinate')
# ax.set_ylabel('Y Coordinate')
# ax.set_zlabel('Distance')
#
# p_order_1 = mpatches.Patch(color='black',label='p = 0.25')
# p_order_2 = mpatches.Patch(color='purple',label='p = 0.50')
# p_order_3 = mpatches.Patch(color='red',label='p = 1.00')
# p_order_4 = mpatches.Patch(color='green',label='p = 2.00')
# p_order_5 = mpatches.Patch(color='blue',label='p = ∞')
# plt.legend(handles=[p_order_1,p_order_2,p_order_3,p_order_4,p_order_5])

#Euclidean Space
for x in range(-x_domain,x_domain):
    for y in range(-y_domain, y_domain):
        ax.scatter(x, y, minkowski_distance(x, y, 0, 5), cmap ='viridis', edgecolor ='green', color='purple')

ax.set_xlabel('X Coordinate')
ax.set_ylabel('Y Coordinate')
ax.set_zlabel('Distance')

ax.set_title('P=10 Minkowski Distance')

plt.show()


import numpy as np
import scipy
from scipy import stats
import pandas as pd
from scipy.stats import entropy
from scipy.special import gamma
from sklearn.preprocessing import scale,normalize
def my_scale(vec):
        vec = (vec-np.mean(vec))/np.std(vec, ddof=1)
        return vec
def get_nss_param(vec):
     """Estimate NSS parameters.
        :param vec: The vector that we want to approximate its parameter.
        :type vec: np.ndarray
        :scale is the normalization function
        """
     return [estimate_basic_param(vec),estimate_ggd_param(vec),estimate_aggd_param(my_scale(vec)),estimate_gamma_param(vec)]
#      return [estimate_basic_param(vec),estimate_ggd_param(vec),estimate_aggd_param(my_scale(vec))]

def Entropy(labels):
    #probs = pd.Series(labels).value_counts() / len(labels)
    probs = pd.Series(labels).value_counts(bins = 2000) / len(labels)
    en = stats.entropy(probs)
    return en

def estimate_basic_param(vec):
        """Estimate basic parameter.
        :param vec: The vector that we want to approximate its parameter.
        :type vec: np.ndarray
        """
        result = [np.mean(vec),np.std(vec, ddof=1),Entropy(vec)]
        return result

def estimate_ggd_param(vec):
        """Estimate GGD parameter.
        :param vec: The vector that we want to approximate its parameter.
        :type vec: np.ndarray
        """
        gam = np.arange(0.2, 10 + 0.001, 0.001)
        r_gam = (gamma(1.0 / gam) * gamma(3.0 / gam) / (gamma(2.0 / gam) ** 2))

        sigma_sq = np.mean(vec ** 2)
        sigma = np.sqrt(sigma_sq)
        E = np.mean(np.abs(vec))
        rho = sigma_sq / E ** 2

        differences = abs(rho - r_gam)
        array_position = np.argmin(differences)
        gamparam = gam[array_position]
        result = [gamparam, sigma]
        return result

def estimate_aggd_param(vec):
        """Estimate AGGD parameter.
        :param vec: The vector that we want to approximate its parameter.
        :type vec: np.ndarray
        """
        gam = np.arange(0.2, 10 + 0.001, 0.001)
        r_gam = ((gamma(2.0 / gam)) ** 2) / (
                    gamma(1.0 / gam) * gamma(3.0 / gam))

        left_std = np.sqrt(np.mean((vec[vec < 0]) ** 2))
        right_std = np.sqrt(np.mean((vec[vec > 0]) ** 2))
        gamma_hat = left_std / right_std
        rhat = (np.mean(np.abs(vec))) ** 2 / np.mean((vec) ** 2)
        rhat_norm = (rhat * (gamma_hat ** 3 + 1) * (gamma_hat + 1)) / (
                (gamma_hat ** 2 + 1) ** 2)

        differences = (r_gam - rhat_norm) ** 2
        array_position = np.argmin(differences)
        alpha = gam[array_position]
        const = np.sqrt(gamma(1 / alpha)) / np.sqrt(gamma(3 / alpha))
        mean_param = (right_std - left_std) * (
                        gamma(2 / alpha) / gamma(1 / alpha)) * const
        result = [alpha, mean_param,left_std, right_std]
        return result

def estimate_gamma_param(vec):
        """Estimate AGGD parameter.
        :param vec: The vector that we want to approximate its parameter.
        :type vec: np.ndarray
        """
        mean = np.mean(vec)
        std = np.std(vec)
        shape = (mean/std)**2
        scale = (std**2)/mean
        result = [shape,scale]
        return result


import numpy as np
import pandas as pd

## p (x,c) = (1/np.sqrt(2*np.pi*std_value)) * np.exp(-(x_value-mean_value)**2/2*std_value)
## receive: x_value - valued to be examined, mean_value and std_value of a feature
## returns: probability of x
def calculate_gaussian_distribution(x_value, mean_value, std_value):

    return (1/np.sqrt(2*np.pi*std_value)) * np.exp(-(x_value-mean_value)**2/
                                                   (2*std_value))

## receives: a data frame
## return: a DataFrame that contains feature title, its mean and standard deviation
def mean_and_std(data):

   x_train_summerized = []

   for feature in data.columns:
       x_train_summerized.append([feature, data[feature].mean(), data[feature].std()])

   return pd.DataFrame(x_train_summerized)

def main():

    # 1. Handle the Data
    diabetes = pd.read_csv('diabetes.csv')

    x_train = diabetes.sample(frac = 0.7)
    x_test = diabetes.drop(x_train.index)

    x_train_0 = x_train[x_train['Outcome']==0]
    x_train_1 = x_train[x_train['Outcome']==1]

    y_test = x_test['Outcome']

    # 2. Summarize the Data (train)
    x_train_0_mean_and_std =  mean_and_std(x_train_0.drop('Outcome', axis=1))
    x_train_0_mean_and_std.columns = ['title','mean','str']
    x_train_0_mean_and_std = x_train_0_mean_and_std.set_index('title')
    print(x_train_0_mean_and_std)

    x_train_1_mean_and_std =  mean_and_std(x_train_1.drop('Outcome', axis=1))
    x_train_1_mean_and_std.columns = ['title','mean','str']
    x_train_1_mean_and_std = x_train_1_mean_and_std.set_index('title')
    print(x_train_1_mean_and_std)

    # 3. Write a prediction function
    predicte_label_0 = np.prod(calculate_gaussian_distribution(x_test.drop('Outcome', axis=1).iloc[0,:],
                                          x_train_0_mean_and_std.iloc[:,0],
                                          x_train_0_mean_and_std.iloc[:,1]))
    predicte_label_1 =  np.prod(calculate_gaussian_distribution(x_test.drop('Outcome', axis=1).iloc[0,:],
                                          x_train_1_mean_and_std.iloc[:,0],
                                          x_train_1_mean_and_std.iloc[:,1]))
    print('single prediction for label 1 is ', predicte_label_1>predicte_label_0)

    # 4. Make Predictions

    predicte_label_0 = []
    predicte_label_1 = []
    for index_value in range(0,len(x_test)):
        predicte_label_0.append(np.prod(calculate_gaussian_distribution(x_test.drop('Outcome', axis=1).iloc[index_value,:],
                                          x_train_0_mean_and_std.iloc[:,0],
                                          x_train_0_mean_and_std.iloc[:,1])))
        predicte_label_1.append(np.prod(calculate_gaussian_distribution(x_test.drop('Outcome', axis=1).iloc[index_value,:],
                                          x_train_1_mean_and_std.iloc[:,0],
                                          x_train_1_mean_and_std.iloc[:,1])))

    merged_predictions = np.greater(predicte_label_1, predicte_label_0)

    # 5. Evaluate Accuracy
    y_test = y_test.reset_index(drop=True)
    success_prediction_rate = np.equal(merged_predictions,y_test)
    count_true = np.count_nonzero(success_prediction_rate)

    print('Naise Bayse was correct {} times out of {}, which equals to a success rate of {}%' .format(count_true, len(y_test), round(100*count_true/len(y_test),2)))

if __name__ == "__main__":
    main()


import sys,json
import numpy as np

def f_xy(x,y):
    f1x = (np.sin(5.1 * np.pi * x + 0.5))**6
    f2x = np.exp(-4*np.log(2) * (x - 0.0667)**2/0.64)
    f1y = (np.sin(5.1 * np.pi * y + 0.5))**6
    f2y = np.exp(-4*np.log(2) * (y - 0.0667)**2/0.64)
    return f1x*f2x*f1y*f2y

if __name__ == '__main__':

    # Reading x and y
    x = float(sys.argv[1])
    y = float(sys.argv[2])

    # Calculating f_xy
    z = f_xy(x, y)

    ###################
    # Writing metrics #
    ###################
    # Reading name of .txt file
    #metricsfile = sys.argv[3]
    # f = open(metricsfile, 'w')
    # f.write("x="+str(x)+'\n')
    # f.write("y="+str(y)+'\n')
    # f.write("z="+str(z)+'\n')
    # f.close()

    result = {
        "x": x,
        "y": y,
        "z": round(z,6)
    }

    print(json.dumps(result))


import numpy as np
import math
import os

def haversine(coord1, coord2):
    R = 6372800  # Earth radius in meters
    lat1, lon1 = coord1
    lat2, lon2 = coord2

    phi1, phi2 = math.radians(lat1), math.radians(lat2)
    dphi = math.radians(lat2 - lat1)
    dlambda = math.radians(lon2 - lon1)

    a = math.sin(dphi / 2) ** 2 + \
        math.cos(phi1) * math.cos(phi2) * math.sin(dlambda / 2) ** 2

    return 2 * R * math.atan2(math.sqrt(a), math.sqrt(1 - a))

def getGpsGT(dbgps, qgps, err):
    qn = qgps.shape[1]
    dbn = dbgps.shape[1]
    dist = np.zeros((dbn, qn))
    for i in range(dbn):
        for j in range(qn):
            dist[i, j] = haversine(dbgps[:, i], qgps[:, j])

    gtm = (dist <= err)
    gt = []
    for i in range(qn):
        gt.append(np.where(gtm[:, i] == 1)[0])

    return gt, gtm

root = r'E:/project/scut/graduation/datasets/oxford_robotcar/'

dbName = 'day'
qName = 'night'

dbgps = np.load(root + 'gps_' + dbName + '.npy')
qgps = np.load(root + 'gps_' + qName + '.npy')

err = 4
gt, gtm = getGpsGT(dbgps, qgps, err)


import math
import matplotlib.pyplot as plt
from prettytable import PrettyTable
from sympy import *
import numpy as np
x = symbols('x')
#Raízes de Equações
##Método da Bissecção
def plot2d(f, inicio, fim):
    z = np.arange(inicio,fim,0.1)

    y = []
    for i in range(len(z)):
        y.append(f.subs(x,z[i]))

    fig, ax = plt.subplots()
    ax.set(title='Gráfico função f(x)='+str(f))
    ax.plot(z,y)
    ax.grid()
    plt.show()

def bisseccao(f, e, a, b):
    fa = f.subs(x,a)
    fb = f.subs(x,b)
    if fa * fb >= 0:
        print("Não atende ao critério f(a) * f(b) < 0")
        return

    k = 0
    ak = []
    bk = []
    xk = []
    fak = []
    fbk = []
    xk = []
    fxk = []
    xk_x = []
    ak.append(a)
    bk.append(b)

    kf = math.log((b-a)/e,2)-1
    times = math.ceil(kf) + 1

    for k in range(times):
        if k == 0:
            y = ak[len(ak)-1]
            fak.append(round(f.subs(x,y),9))
            y = bk[len(bk)-1]
            fbk.append(round(f.subs(x,y),9))
            xk.append((ak[len(ak)-1] + bk[len(bk)-1])/2)
            y = xk[len(xk)-1]
            fxk.append(round(f.subs(x,y),9))
            xk_x.append('-')
        else:
            if (fak[len(fak)-1] < 0 and fxk[len(fxk)-1] < 0) or (fak[len(fak)-1] > 0 and fxk[len(fxk)-1] > 0):
                ak.append(xk[len(xk)-1])
                bk.append(bk[len(bk)-1])
            else:
                ak.append(ak[len(ak)-1])
                bk.append(xk[len(xk)-1])

            y = ak[len(ak)-1]
            fak.append(round(f.subs(x,y),9))
            y = bk[len(bk)-1]
            fbk.append(round(f.subs(x,y),9))
            xk.append((ak[len(ak)-1] + bk[len(bk)-1])/2)
            y = xk[len(xk)-1]
            fxk.append(round(f.subs(x,y),9))
            temp = xk[len(xk)-1] - xk[len(xk)-2]
            if temp < 0:
                temp = temp * -1
            xk_x.append(temp)

    Table = PrettyTable(["k", "a", "b", "f(a)", "f(b)", "x", "f(x)", "|x(k) - x(k-1)|"])
    for k in range(times):
        Table.add_row([k, ak[k], bk[k], fak[k], fbk[k], xk[k], fxk[k], xk_x[k]])

    print(Table)
    print("Donde \u03B5 é aproximadamente " + str(xk[len(xk)-1]))

# def f(x): return pow(x,2)-3
# plot2d(f(x), 0, 2)
# bisseccao(f(x), 0.01, 1, 2)

## Método do Ponto Fixo
def pontoFixo(f,e,xi):
    xk = []
    xk.append(xi)
    xk_x = []
    xk_x.append("-")
    end_condition = 0
    while not end_condition:
        xk.append(f.subs(x,xk[len(xk)-1]))
        xk_x.append(abs(xk[len(xk)-1]-xk[len(xk)-2]))
        if xk_x[len(xk_x)-1] < e:
            end_condition = 1

    Table = PrettyTable(["k", "xk", "|x(k) - x(k-1)|"])
    for k in range(0, len(xk)):
        Table.add_row([k, xk[k], xk_x[k]])

    print(Table)
    print("Donde \u03B5 é aproximadamente " + str(xk[len(xk)-1]))

# def f(x): return cos(x)
# pontoFixo(f(x),10**(-2), math.pi/4)

## Método de Newton
def newton(f, e, a, b):
    xk = []
    xk.append(b)
    xk_x = []
    xk_x.append(0)
    end_condition = 0

    if f.subs(x,xk[len(xk)-1]) * diff(diff(f,x),x).subs(x,xk[len(xk)-1]) > 0:
        while not end_condition:
            func = f.subs(x,xk[len(xk)-1])
            derivate = diff(f,x).subs(x,xk[len(xk)-1])
            temp = xk[len(xk)-1] - func/derivate
            xk.append(N(temp))

            temp2 = xk[len(xk)-2] - xk[len(xk)-1]
            if temp2 < 0:
                temp2 = temp2 * -1

            xk_x.append(N(temp2))
            if xk_x[len(xk_x)-1] < e:
                end_condition = 1

        Table = PrettyTable(["k", "xk", "|x(k) - x(k-1)|"])
        for k in range(1, len(xk)):
            Table.add_row([k, xk[k], xk_x[k]])

        print(Table)

        print("Donde \u03B5 é aproximadamente " + str(xk[len(xk)-1]))

# def f(x): return x**2-2
# newton(f(x), 0.00005, 1, 2)

## Método da Secante
def secante(f, e, a, b):
    xk = []
    xk.append(a)
    xk.append(b)
    xk_x = []
    xk_x.append(0)
    xk_x.append(0)
    end_condition = 0

    while not end_condition:
        temp  = f.subs(x, xk[len(xk)-1]) * (xk[len(xk)-1] - xk[len(xk)-2])
        temp2 = f.subs(x, xk[len(xk)-1]) - f.subs(x,xk[len(xk)-2])
        temp3 = xk[len(xk)-1] - (temp/temp2)
        xk.append(temp3)

        temp4 = xk[len(xk)-1] - xk[len(xk)-2]

        if temp4 < 0:
            temp4 = temp4 * -1

        xk_x.append(temp4)

        if xk_x[len(xk_x)-1] < e:
            end_condition = 1

    Table = PrettyTable(["k", "xk", "|x(k+1) - x(k)|"])
    for k in range(2, len(xk)):
        Table.add_row([k, xk[k], xk_x[k]])

    print(Table)
    print("Donde \u03B5 é aproximadamente " + str(xk[len(xk)-1]))

print("Secante\n")
def f(x): return 2*x**3-5*x**2-10*x+20
secante(f(x), 10**(-5), 1.2, 1.7)

## Método Regula Falsi
def regulaFalsi(f, e, a, b):
    xk = []
    xk_x = []

    x0 = a
    x1 = b
    print(f.subs(x,a))
    print(f.subs(x,b))
    end_condition = 0

    while not end_condition:
        temp = x1 - f.subs(x, x1) * (x1 - x0) / (f.subs(x, x1) - f.subs(x, x0))

        temp2 = temp - x1

        if temp2 < 0:
            temp2 = temp2 * -1

        if temp2 < e:
            xk.append(temp)
            xk_x.append(temp2)
            end_condition = 1
            continue

        k = f.subs(x, temp)

        if k*f.subs(x, x1) < 0:
            x0 = x1

        x1 = temp
        xk.append(temp)
        xk_x.append(temp2)

    Table = PrettyTable(["k", "xk", "|x(k) - x(k-1)|"])
    for k in range(len(xk)):
        Table.add_row([k+2, xk[k], xk_x[k]])

    print(Table)
    print("Donde \u03B5 é aproximadamente " + str(xk[len(xk)-1]))

print("\nRegula Falsi\n")
def f(x): return 2*x**3-5*x**2-10*x+20
regulaFalsi(f(x), 0.0001, 1.2, 1.7)


from sympy.abc import _clash1 # So that sympify will be able to convert string to symbolic objects
from statistics import mean # Average method
from math import log10 # Log base 10
from sympy import *
from sympy.solvers.diophantine.diophantine import norm # Module to work with symbolic variables
from util import * # Auxiliar function in  util.py

# POWER METHOD
def powerMethod(A: Matrix, y_0: Matrix, epsilon = 10**-6, MAXITER = 100, assureConvergence = True, displayConsoleLog = True, printTotalIterations = True):
    # Checks if all A's elements are numeric
    try:
        for e in A: e = float(e)
    except:
        raise Exception("All of A's must be numeric.")

    # Checks if A is a square matrix
    if A.shape[0] != A.shape[1]:
        raise Exception("A must be a square matrix.")

    # Checks if y_0 is null
    if y_0 == 0:
        raise Exception("The initial approximation y_0 must be != 0.")

    # Checks if y_0 is a column vector with as much rows as A
    if y_0.shape[0] != A.shape[0] or y_0.shape[1] != 1:
        raise Exception("The initial approximation y_0 must be a column vector with as many rows as the matrix A.")

    # Checks if ||y_0||oo == 1
    if assureConvergence:
        if y_0.norm(oo) != 1:
            raise Exception("The initial approximation y_0 must have an infinity norm of 1.")

    # No. of decimal places for the results
    precision = int(abs(log10(epsilon))) if epsilon > 0 and log10(epsilon).is_integer else int(6)

    if displayConsoleLog:
        printTotalIterations = True
        print("___________________________________________________________________________\n\n")
        print(f"POWER METHOD ::: Iteration no. 00: z^T = %s ; alpha = %s ; y^T = [ %s  ]"
            % ( '-'*((precision + 5)*len(y_0) + 3), '-'*(precision + 2), "  ".join([str(f"% .{precision}f" % e) for e in y_0]) )
        )

    z = [0, 0]
    y = [y_0, 0] # --> u (eigenvector)
    a = [0, 0] # alpha --> lambda (eigenvalue)

    # Auxiliar index variable correspondent to the current element in the above lists
    j = 0

    # When the solution was found, the algorithm'll go over one more
    # iteration in order to check the eigenvalue's signal
    # And this variable checks is that is the extra iterations or not
    hasFinished = False

    for i in range(1, MAXITER+1):
        j += 1 if j < 1 else -j # j = 0 --> j = 1 --> j = 0 --> j = 1 ...

        z[j] = (A*y[j-1]).evalf()
        a[j] = (z[j].norm(oo)).evalf()
        y[j] = (z[j]/a[j]).evalf()

        if displayConsoleLog and not hasFinished:
            print(f"POWER METHOD ::: Iteration no. %s: z^T = [ %s  ] ; alpha = %.{precision}f ; y^T = [ %s  ]"
                % ( str(i).zfill(2), "  ".join([str(f"% .{precision}f" % e) for e in z[j]]), a[j], "  ".join([str(f"% .{precision}f" % e) for e in y[j]]) )
            )

        if abs(a[j] - a[j-1]) < epsilon * max(1, abs(a[j])):
            # If the solution was just found, go over one more iteration
            if not hasFinished: hasFinished = True

            else:
                # Trucante the eigenvector's values to the requested precision
                y[j] = Matrix([float(f"% .{precision}f" % e) for e in y[j]])
                y[j-1] = Matrix([float(f"% .{precision}f" % e) for e in y[j-1]])

                # Checks if the lambda = |lambda| or lambda = -|lambda|
                if y[j] != y[j-1] and abs(y[j]) == abs(y[j-1]): a[j] = -a[j]

                if printTotalIterations:
                    print("___________________________________________________________________________\n\n") if not displayConsoleLog else print("\n")
                    print(f"POWER METHOD ::: The solution was successfully found after {i+1} iterations.\n")
                    print("___________________________________________________________________________\n\n")

                return a[j], y[j], precision # eigenvalue, eigenvector

    # If it manages to get out of the loop, it means no root was found, so it prints an error message
    raise Exception("The maximum number of iterations was met and no root was found.")

def inversePower(A: Matrix, y_0: Matrix, epsilon = 10**-6, MAXITER = 100, assureConvergence = True, displayConsoleLog = True, printTotalIterations = True):
    # Checks if all A's elements are numeric
    try:
        for e in A: e = float(e)
    except:
        raise Exception("All of A's elements must be numeric.")

    # Checks if A is a square matrix
    if A.shape[0] != A.shape[1]:
        raise Exception("A must be a square matrix.")

    # Checks if y_0 is null
    if y_0 == 0:
        raise Exception("The initial approximation y_0 must be != 0.")

    # Checks if y_0 is a column vector with as much rows as A
    if y_0.shape[0] != A.shape[0] or y_0.shape[1] != 1:
        raise Exception("The initial approximation y_0 must be a column vector with as many rows as the matrix A.")

    # Checks if ||y_0||oo == 1
    if assureConvergence:
        if y_0.norm(oo) != 1:
            raise Exception("The initial approximation y_0 must have an infinity norm of 1.")

    # Inverts A
    try:
        A = A**-1
    except:
        raise Exception("As A is not invertible, the method cannot be applied.")

    # No. of decimal places for the results
    precision = int(abs(log10(epsilon))) if epsilon > 0 and log10(epsilon).is_integer else int(6)

    if displayConsoleLog:
        printTotalIterations = True
        print("___________________________________________________________________________\n\n")
        print(f"INVERSE POWER METHOD ::: Iteration no. 00: z^T = %s ; alpha = %s ; y^T = [ %s  ]"
            % ( '-'*((precision + 5)*len(y_0) + 3), '-'*(precision + 2), "  ".join([str(f"% .{precision}f" % e) for e in y_0]) )
        )

    z = [0, 0]
    y = [y_0, 0] # --> u (eigenvector)
    a = [0, 0] # alpha --> lambda (eigenvalue)

    # Auxiliar index variable correspondent to the current element in the above lists
    j = 0

    # When the solution was found, the algorithm'll go over one more
    # iteration in order to check the eigenvalue's signal
    # And this variable checks is that is the extra iterations or not
    hasFinished = False

    for i in range(1, MAXITER+1):
        j += 1 if j < 1 else -j # j = 0 --> j = 1 --> j = 0 --> j = 1 ...

        z[j] = (A*y[j-1]).evalf()
        a[j] = (z[j].norm(oo)).evalf()
        y[j] = (z[j]/a[j]).evalf()

        if displayConsoleLog and not hasFinished:
            print(f"INVERSE POWER METHOD ::: Iteration no. %s: z^T = [ %s  ] ; alpha = %.{precision}f ; y^T = [ %s  ]"
                % ( str(i).zfill(2), "  ".join([str(f"% .{precision}f" % e) for e in z[j]]), a[j], "  ".join([str(f"% .{precision}f" % e) for e in y[j]]) )
            )

        if abs(a[j] - a[j-1]) < epsilon * max(1, abs(a[j])):
            # If the solution was just found, go over one more iteration
            if not hasFinished: hasFinished = True

            else:
                # Trucante the eigenvector's values to the requested precision
                y[j] = Matrix([float(f"% .{precision}f" % e) for e in y[j]])
                y[j-1] = Matrix([float(f"% .{precision}f" % e) for e in y[j-1]])

                # Checks if the lambda = |lambda| or lambda = -|lambda|
                if y[j] != y[j-1] and abs(y[j]) == abs(y[j-1]): a[j] = -a[j]

                if printTotalIterations:
                    print("___________________________________________________________________________\n\n") if not displayConsoleLog else print("\n")
                    print(f"INVERSE POWER METHOD ::: The solution was successfully found after {i+1} iterations.\n")
                    print("___________________________________________________________________________\n\n")

                return a[j], y[j], precision # eigenvalue, eigenvector

    # If it manages to get out of the loop, it means no root was found, so it prints an error message
    raise Exception("The maximum number of iterations was met and no root was found.")

# is not working properly
def jacobi(A: Matrix, displayConsoleLog = True):
    # Checks if all A's elements are numeric
    try:
        for e in A: e = float(e)
    except:
        raise Exception("All of A's elements must be numeric.")

    # Checks if A is a square matrix
    if A.shape[0] != A.shape[1] or A.shape[0] <= 1:
        raise Exception("A must be a square matrix.")
    else:
        order = A.shape[0]

    # Checks if the matrix is simetric
    if not A.is_symmetric(): raise Exception("As A is not symmetric, the method can't be applied.")

    D = [A, 0] # diagonal eigenvalues' matrix
    V = 1 # eigenvectors matrix

    # Auxiliar index variable correspondent to the current element in the 'D' list
    j = 0

    # Index variable correspondent to the current step
    i = 1

    # Total number of steps
    noSteps = len(str(int((len(A)-order)/2)))

    if displayConsoleLog:
        print("___________________________________________________________________________\n\n")
        print(f"JACOBI'S METHOD ::: Step no.{str(i).zfill(noSteps)}: A = ")
        pprint(A)
        print()

    while True:
        i += 1
        j += 1 if j < 1 else -j # j = 0 --> j = 1 --> j = 0 --> j = 1 ...

        a_pq = 0; p = q = 0
        for x in range(order):
            for y in range(x+1, order):
                if x == y: continue

                if abs(float(D[j-1].row(x)[y])) >= abs(a_pq):
                    a_pq = float(D[j-1].row(x)[y])
                    p = x
                    q = y

        if displayConsoleLog:
            print(f"JACOBI'S METHOD ::: Step no.{str(i).zfill(noSteps)}:  a_pq = % .3f ; p = {p+1} ; q = {q+1}"
                % a_pq
            )

        PHI = (D[j-1].row(q)[q] - D[j-1].row(p)[p])/(2*a_pq)
        t = 1/(PHI+(PHI/abs(PHI))*sqrt(1+PHI**2)) if PHI != 0 else 1
        cos_phi = 1/sqrt(1+t**2)
        sen_phi = t*cos_phi

        if displayConsoleLog:
            print(f"JACOBI'S METHOD ::: Step no.{str(i).zfill(noSteps)}: Φ = {PHI} = % .3f ; t = {t} = %.3f ; cos(φ) = {cos_phi} = %.3f ; sen(φ) = {sen_phi} = %.3f"
                % ( PHI, t, cos_phi, sen_phi )
            )

        U = []
        auxU = []
        for x in range(order):
            row = []
            auxRow = []

            for y in range(order):
                if x == y == p or x == y == q:
                    row.append(cos_phi)
                    auxRow.append("cos(phi)")

                elif x == p and y == q:
                    row.append(sen_phi)
                    auxRow.append("sin(phi)")

                elif x == q and y == p:
                    row.append(-1*sen_phi)
                    auxRow.append("-sin(phi)")

                elif x == y:
                    row.append(1)
                    auxRow.append(1)

                else:
                    row.append(0)
                    auxRow.append(0)

            U.append(row)
            auxU.append(auxRow)

        U = Matrix(U)
        auxU = Matrix(auxU)

        if displayConsoleLog:
            print(f"JACOBI'S METHOD ::: Step no.{str(i).zfill(noSteps)}: U = ")
            pprint(auxU)
            print()
            pprint(U)
            print()

        D[j] = (U.T * D[j-1]) * U
        V = V*U

        if displayConsoleLog:
            print(f"JACOBI'S METHOD ::: Step no.{str(i).zfill(noSteps)}: A = ")
            pprint(D[j])
            print()

        # When D is diagonal, the proccess is finished
        if D[j].is_diagonal(): break

    return D[j], V

if __name__ == "__main__":
    A = Matrix([[-2, 6], [-6, 13]])
    y_0 = Matrix([1, 1])

    value, vector, precision = powerMethod(A, y_0, epsilon=10**-3)

    print(f"%.{precision}f" % value)
    pprint(vector)

    # A = Matrix([[2, 4, -2], [4, 2, 2], [-2, 2, 5]])

    # D, V = jacobi(A, displayConsoleLog=True)

    # pprint(D.evalf())
    # print()

    # pprint(V.evalf())
    # print()


from math import *
import numpy as np

class Similarity():

    @staticmethod
    def euclidean_distance(x, y):
        # print("Usando a distancia euclidana")
        # print(x, y)
        return sqrt(sum(pow(a - b, 2) for a, b in zip(x, y)))

    @staticmethod
    def manhattan_distance(x, y):
        return sum(abs(a - b) for a, b in zip(x, y))

    def square_rooted(x):
        return round(sqrt(sum([a * a for a in x])), 3)

    @staticmethod
    def jaccard_similarity(x, y):
        intersection_cardinality = len(set.intersection(*[set(x), set(y)]))
        union_cardinality = len(set.union(*[set(x), set(y)]))
        return intersection_cardinality / float(union_cardinality)

    @staticmethod
    def chi2_distance(histA, histB, eps=1e-10):
        # compute the chi-squared distance
        d = 0.5 * np.sum([((a - b) ** 2) / (a + b + eps)
                          for (a, b) in zip(histA, histB)])

        # return the chi-squared distance
        return d


import numpy as np

#input is an adjacent matrix
#with calc_lenght you get a matrix with number of paths of a particular given length the co-ord of matrix
#the start and end node
#with calc_path you can query the specific number of path between start node m and end node n

def calculate_length(matrix,length):
    k = np.linalg.matrix_power(matrix,length)
    return k

def calculate_paths(matrix,length,m,n):
    k = np.linalg.matrix_power(matrix,length)
    return k[m,n]


import math
import numpy as np
from numpy.linalg import inv, cholesky

class Digit:

    def __init__(self):
        self.curves = []
        self.label = -1

    def add_curve(self, points):
        self.curves.append(points)

    def set_label(self, label):
        self.label = int(label)

    def set_observations(self, observations):
        self.observations = observations
        self.np_array_observations = np.asarray(observations)

    def normalise(self):
        self.normalise_average()
        #self.normalise_variance()
        self.normalise_variance_covariance()

    def normalise_average(self):

        x_total = 0
        y_total = 0
        n = 0

        for curve in self.curves:
            for point in curve:
                x_total += point[0]
                y_total += point[1]
                n += 1

        x_avg = int(( float(x_total) / float(n) ))
        y_avg = int(( float(y_total) / float(n) ))

        for i in range(0, len(self.curves)):
            for j in range(0, len(self.curves[i])):
                self.curves[i][j][0] -= x_avg
                self.curves[i][j][1] -= y_avg

    # only call after normalising by average
    def normalise_variance(self):

        dx2_total = 0
        dy2_total = 0
        n = 0

        for curve in self.curves:
            for point in curve:
                dx2_total += point[0]*point[0]
                dy2_total += point[1]*point[1]
                n += 1

        x_var = float(dx2_total) / float(n)
        y_var = float(dy2_total) / float(n)

        x_stddev = math.sqrt(x_var)
        y_stddev = math.sqrt(y_var)

        for i in range(0, len(self.curves)):
            for j in range(0, len(self.curves[i])):

                x = float(self.curves[i][j][0]) / x_stddev
                y = float(self.curves[i][j][1]) / y_stddev
                self.curves[i][j] = [x, y]

    def normalise_variance_covariance(self):

        total_points = []
        for curve in self.curves:
            for point in curve:
                total_points.append(point)

        points_array = np.array(total_points).T
        covariance_matrix = np.cov(points_array)
        inverse_covariance_matrix = inv(covariance_matrix)
        chol = cholesky(inverse_covariance_matrix)

        normalised_points_array = np.dot(chol,points_array)

        i = 0
        for j in range(0, len(self.curves)):
            for k in range(0, len(self.curves[j])):

                x = normalised_points_array[0][i]
                y = normalised_points_array[1][i]

                self.curves[j][k][0] = x
                self.curves[j][k][1] = y

                i += 1

    def __repr__(self):
        ret = "label : " + str(self.label) + "\n"

        n_points = 0
        for curve in self.curves:
            n_points += len(curve)

        ret += "Number of Curves : " + str(len(self.curves)) + " , Number of Points : " + str(n_points) + "\n"
        ret += str(self.curves)
        return ret


import numpy as np

# Euclidean (L1) distance.
def euclidean(p, q):
    return np.linalg.norm(p - q)

# Cosine distance.
def cosine(p, q):
    return 1.0 - (np.dot(p, q) / (np.linalg.norm(p) * np.linalg.norm(q)))

# Manhattan (L1) distance.
def manhattan(p, q):
    return np.sum(np.abs(p - q))

# Hellinger distance.
def hellinger(p, q):
    _SQRT2 = np.sqrt(2)
    return euclidean(np.sqrt(p), np.sqrt(q)) / _SQRT2

# Jensen-Shannon Divergence.
def jsd(P, Q):
    from scipy.stats import entropy
    return entropy(0.5 * (P + Q)) - 0.5 * (entropy(P) + entropy(Q))

# Jaccard distance.
def jaccard(P, Q):
    N = len(P)
    eps = 1.0 / N
    P = P > eps
    Q = Q > eps
    union = (P | Q).sum()
    intersection = (P & Q).sum()
    return 1.0 - (1.0 * intersection) / union

# Chebyshev distance.
def chebyshev(p, q):
    return np.max(np.abs(p - q))

metrics_list = [
    "euclidean",
    "cosine",
    "manhattan",
    "hellinger",
    "jsd",
    "jaccard",
    "chebyshev"]

default_metric = "jaccard"

def get_metric_by_name(name):
    if name == "default":
        return get_metric_by_name(default_metric)
    elif name == "euclidean":
        return euclidean
    elif name == "cosine":
        return cosine
    elif name == "manhattan":
        return manhattan
    elif name == "cov":
        return cov
    elif name == "hellinger":
        return hellinger
    elif name == "kld":
        return kld
    elif name == "jsd":
        return jsd
    elif name == "jaccard":
        return jaccard
    elif name == "chebyshev":
        return chebyshev
    else:
        return name