# Import all neccesary packages to solve assignment
import numpy as np # for creating arrays and essenatial math tools
from scipy import optimize # for finding optimal consumption and labor
%matplotlib inline
import matplotlib.pyplot as plt
%load_ext autoreload
%autoreload 2

# set all of the parameters of the labor supply problem
m = 1
v = 10
e = 0.3
t0 = 0.4
t1 = 0.1
k = 0.4

# a. Create utility function that will be optimized to find L* and C*
def u(L, c, v, e):
    ''' calculates utility based upon combinations of labor supply and consumption.

    Arguments:
    L(float) = labor supply
    c(float) = consumption
    v(float) = disutility of work
    e(float)= labor supply elasticity

    Returns:
    utility
    '''
    return np.log(c) - v*((L**(1+(1/e)))/(1 + (1/e)))

# b. Create best choice function used in minimization problem
def best_choices(L, w, m, v, e, t0, t1, k):
    ''' Function used to calculate negative utility

    Arguments:
    L(float) = labor supply
    w(float) = wage rate
    m(float) = initial cash
    v(float) = disutility of work
    e(float) = labor supply elasticity
    t0(float) = base tax level
    t1(float) = upper tax level
    k(float) = cutoff

    Returns:
    Negative utility function
    '''
    c = m + w*L - (t0*w*L + t1*max(w*L - k, 0))

    return -u(L, c, v, e)

# c. minimize negative utility function

def optimization(w, m, v, e, t0, t1, k):
    ''' Function used to calculate optimal labor and consumption at a given wage

    Arguments:
    w(float) = wage rate
    m(float) = initial cash
    v(float) = disutility of work
    e(float) = labor supply elasticity
    t0(float) = base tax level
    t1(float) = upper tax level
    k(float) = cutoff

    Returns:
    L = optimal labor supply at a given wage
    c = optimal consumption at a given wage

    '''
    sol = optimize.minimize_scalar(best_choices, method='bounded', bounds=(0,1), args=(w, m, v, e, t0, t1, k))

    L = sol.x
    c = m + w*L - (t0*w*L + t1*max(w*L - k, 0))
    return [L, c]

# a. create empty lists for Labor and consumption
L_best = [] # List of optimal values of labor for given wages
c_best = [] # list of optimal values of consumption given wages
N = 10000 # Number of wages to loop through

# b. loop through wage levels of 0.5 and 1.5 to find optimal consumption and labor
w = np.linspace(0.5, 1.5, N) # range of wages between 0.5 and 1.5 for optimizer to use

for w_now in w: # wage loop
    optimal_par = optimization(w_now, m, v, e, t0, t1, k)
    L_best.append(optimal_par[0]) #append optimal labor values
    c_best.append(optimal_par[1]) # append optimal consumption values

# c. plotting optimal consumption and labor as functions of wage
plt.style.use('dark_background') # setting personal style

fig = plt.figure(figsize=(10,4))

# Left plot - Optimal consumption to wage
ax_left = fig.add_subplot(1,2,1)
ax_left.plot(w, c_best)

ax_left.set_title('Optimal Consumption Relative to Wage Rate')
ax_left.set_xlabel('$Wage Rate$')
ax_left.set_ylabel('$Optimal Consumption$')
ax_left.grid(True)

# Right plot - Optimal Labor to wage
ax_right = fig.add_subplot(1,2,2)
ax_right.plot(w, L_best)

ax_right.set_title('Optimal Labor Supply Relative to Wage Rate')
ax_right.set_xlabel('$Wage Rate$')
ax_right.set_ylabel('$Labor Supply$')
ax_right.grid(True)

# a. Calculate total tax revenue based upon a given population
def totaltaxrevenue(w, v=10, e=0.3, t0=0.4, t1=0.1, k=0.4):
    ''' Calculates the total tax revenue recieved by a given population size and wage

    Arguments:
    w(float) = wage rate
    m(float) = initial cash
    v(float) = disutility of work
    e(float) = labor supply elasticity
    t0(float) = base tax level
    t1(float) = upper tax level
    k(float) = cutoff

    Returns:
    total tax revenue that will be recieved from the population'''
    T= 0
    for w_now in w:
        optimal_val = optimization(w_now, m, v, e, t0, t1, k)
        L = optimal_val[0]
        T += (t0*w_now*L + t1*max(w_now*L - k, 0))
    return T

# b. print total tax revenue collected
print("Total tax revenue collected" + " " + str(totaltaxrevenue(w)))

print("Total tax revenue collected" + " " + str(totaltaxrevenue(w, e=0.1)))

# a. Create an objective function to maxamize taxes
def best_tax_levels(tax, w, v, e, m):
    ''' Create function that outputs negative total tax revenue that will be used to find optimal values of T0, T1, and K

    Arguments:
    tax(float) = list of various tax paramaters
    w(float) = wage rate

    Results:
    Negative total tax revenue
    '''
    tax_low = tax[0]
    tax_high = tax[1]
    tax_cutoff = tax[2]

    return -totaltaxrevenue(w, v, e, tax_low, tax_high, tax_cutoff)

initial_guess = [.1, .1, .1] # Initial guess for optimizing tax revenue
sol = optimize.minimize(best_tax_levels, initial_guess, method='Nelder-Mead', args=(w, e, v, m))

tax1 = sol.x[0] # Optimal standard labor income tax
tax2 = sol.x[1] # Optimal top bracket labor income tax
tax3 = sol.x[2] # optimal cutoff

print("Standard labor income tax " + str(tax1))
print("Top bracket labor income tax " + str(tax2))
print("Cutoff " + str(tax3))


########################
### PERCEPTRON CLASS ###
########################

# Import libraries.
import numpy as np
import pandas as pd
import math
import random
from itertools import product

"""
- When the perceptron criterion or hinge loss are used to determine the loss function, it is assumed that the target values are -1 or 1.
- Sigmoid activation function is used with log_likelihood loss function. This model is known as logistic regression, since our objective is to predict a probability.
- Finally, the linear activation function is used with least square regression loss functions. This model is knows as linear regressios; its objective is to predict real values.
"""

# Clase Perceptrón.
class Perceptron:

    # Método constructor.
    def __init__(self, num_neurons, activation = "sign", criterion = "perceptron_criterion", learning_rate = 1):

        if(criterion == "hinge_loss" or criterion == "perceptron_criterion") and (activation != "sign" and activation != "linear"):
            raise Exception(criterion.replace("_", " ").capitalize() + " can only be use with sign or linear activation function.")
        if(criterion == "log_likelihood" and activation != "sigmoid"):
            raise Exception(criterion.replace("_"," ").capitalize() + " can only be used with Sigmoid activation function")
        if(criterion == "least_squares_regression" and activation != "linear"):
            raise Exception(criterion.replace("_"," ").capitalize() + " can only be used with linear activation function")
        if(criterion == "logistic_regression_alternate" and activation != "linear"):
            raise Exception(criterion.replace("_"," ").capitalize() + " can only be used with linear activation function")

        self.num_neurons = num_neurons
        self.activation = getattr(self, "_" + activation)
        self.weights = np.random.rand(1, num_neurons)[0]
        self.learning_rate = learning_rate
        self.criterion = getattr(self, "_" + criterion)
        self.loss_function = getattr(self, "_" + criterion + "_loss")

    # Forward method: computational step.
    def forward(self, vector_x):
        dotproduct = np.dot(vector_x, self.weights)
        return dotproduct

    """
    Funciones de activación.
    """
    # Sign activation.
    def _sign(self, x):
        return np.sign(x)

    # Linear activation.
    def _linear(self, x):
        return x

    # Sigmoid activation.
    def _sigmoid(self, x):
        return 1 / (1 + math.exp(-x))

    # Tanh activation.
    def _tanh(self, x):
        return 2 * self.sigmoid(2*x)-1

    # Relu activation.
    def _relu(self, x):
        return max(0, x)

    # HardTanh activation.
    def _hardTanh(self, x):
        return max(min(x, 1), -1)

    """
    Loss functions.
    """
    # Perceptron criterion.
    def _perceptron_criterion_loss(self,y_true,y_predicted):
        loss = max(0, -y_true * y_predicted)
        return loss

    # Hinge Loss.
    def _hinge_loss_loss(self,y_true,y_predicted):
        loss = max(0, 1 + (-y_true * y_predicted))
        return loss

    # Logistic regression.
    def _logistic_regression_loss(self,y_true,y_predicted):
        loss = -math.log(math.abs(y_true*(1/2)-0.5+y_predicted))
        return loss

    # Least squares regression.
    def _least_squares_regression_loss(self,y_true,y_predicted):
        loss = (y_true-y_predicted)**2
        return loss

    # Logistic regression (alternate).
    def _logistic_regression_alternate_loss(self, y_true, y_predicted):
        loss = math.log(1 + math.exp(-y_true * y_predicted))
        return loss

    # Widrow hoff loss.
    def _widrow_hoff_loss(self,y_true,y_predicted):
        loss = (y_true-y_predicted)**2
        return loss

    """
    Gradient update functions.
    """
    # 1. Perceptron criterion.
    def _perceptron_criterion(self, y_true, y_predicted, vector_x):
        if y_true != y_predicted:
            gradient = np.dot((y_true - y_predicted), vector_x)
            return gradient
        return 0

    # 2. Hinge Loss.
    def _hinge_loss(self, y_true, y_predicted, vector_x):
        gradient = np.dot(y_true, vector_x)
        return gradient

    #3. Log likelihood.
    def _log_likelihood(self, y_true, y_predicted, vector_x):
        gradient = -(y_true*vector_x)/(1+math.exp(y_true*y_predicted))
        return gradient

    #4. Least squares.
    def _least_squares_regression(self, y_true, y_predicted, vector_x):
        gradient = np.dot((y_true - y_predicted), vector_x)
        return gradient

    #4. Least squares.
    def _widrow_hoff(self, y_true, y_predicted, vector_x):
        gradient = np.dot((y_true - y_predicted), vector_x)
        return gradient

    """
    Train and predict methods.
    """
    # Train the perceptron.
    def fit(self, X, Y, max_iterations = 100):

        # Stochastic Gradient Descent.
        for i in range(max_iterations):

            # Select random point.
            randomPoint = random.randint(0, len(X) - 1)
            vector_x = X[randomPoint].copy()

            # Predict point category.
            y_predicted = self.forward(vector_x)
            y_true = Y[randomPoint]

            # Compute gradient.
            gradient = self.criterion(y_true, y_predicted, vector_x)

            # Update weights.
            self.weights = self.weights + self.learning_rate * gradient

    # Predict value/category.
    def predict(self, vector_x):
        dotproduct = np.dot(vector_x, self.weights)
        y_predicted = self.activation(dotproduct)
        return y_predicted

    # Get weights.
    def getWeights(self):
        return self.weights

# Return dataset with bias included.
def add_bias(dataset):
    for element in dataset:
        element.append(1)
    return dataset

# Predict list.
def predictList(perceptron, X, Y, show_results = False):

    error_criterion = np.zeros(len(perceptron.weights))
    accuracy = 0

    for i in range(0, len(X)):

        vector_x = X[i].copy()

        y_true = Y[i]
        y_predicted = perceptron.predict(vector_x)
        error = perceptron.loss_function(y_true, y_predicted)
        correct = (y_true == y_predicted)

        if show_results:
            print("Point: ", vector_x)
            print("True Label: ", y_true)
            print("Prediction: ", y_predicted)
            print("Error: ", error)
            print("")

        error_criterion += error
        if correct:
            accuracy += 1

    print("Criterion Error: ", error_criterion)
    print("Accuracy: ", accuracy / len(X))


import scipy.stats as st
import pandas as pd

def get_best_distribution(data):
    dist_names = ["norm", "exponweib", "weibull_max", "weibull_min", "pareto", "genextreme"]
    dist_results = []
    params = {}
    for dist_name in dist_names:
        dist = getattr(st, dist_name)
        param = dist.fit(data)

        params[dist_name] = param
        # Applying the Kolmogorov-Smirnov test
        D, p = st.kstest(data, dist_name, args=param)
        print("p value for "+dist_name+" = "+str(p))
        dist_results.append((dist_name, p))

    # select the best fitted distribution
    best_dist, best_p = (max(dist_results, key=lambda item: item[1]))
    # store the name of the best fit and its p value

    print("Best fitting distribution: "+str(best_dist))
    print("Best p value: "+ str(best_p))
    print("Parameters for the best fit: "+ str(params[best_dist]))

    return best_dist, best_p, params[best_dist]

df = pd.read_csv("Zoopark.csv")
get_best_distribution(df.sample_4)

docs/Electives/Introduction to Mathematical Statistics/Datasets/HW_1c.py


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

def gaussian_function(mu, sigma_squared, x):
    ''' f takes in a mean and squared variance, and an input x
       and returns the gaussian value.'''
    coefficient = 1.0 / math.sqrt(2.0 * math.pi * sigma_squared)
    exponential = math.exp(-0.5 * (x - mu) ** 2 / sigma_squared)
    return coefficient * exponential

# the update function
def update(mean1, var1, mean2, var2):
    ''' This function takes in two means and two squared variance terms,
        and returns updated gaussian parameters.'''
    # Calculate the new parameters
    new_mean = (var2 * mean1 + var1 * mean2) / (var2 + var1)
    new_var = 1 / (1 / var2 + 1 / var1)

    return [new_mean, new_var]

# the motion update/predict function
def predict(mean1, var1, mean2, var2):
    ''' This function takes in two means and two squared variance terms,
        and returns updated gaussian parameters, after motion.'''
    # Calculate the new parameters
    new_mean = mean1 + mean2
    new_var = var1 + var2

    return [new_mean, new_var]

def gauss_pdf(X, M, S):
    """
    Computes the Predictive probability (likelihood) of measurement
    :param X: measurement vector
    :param M: Mean of predictive distribution of measurement vector
    :param S: the Covariance or predictive mean of measurement vector
    :return: Gaussian probability distribution
    """
    if M.shape[1] == 1:
        DX = X - np.tile(M, X.shape[1])
        E = 0.5 * np.sum(DX * (np.dot(inv(S), DX)), axis=0)
        E = E + 0.5 * M.shape[0] * np.log(2 * np.pi) + 0.5 * np.log(det(S))
        P = np.exp(-E)
    elif X.shape[1] == 1:
        DX = np.tile(X, M.shape[1]) - M
        E = 0.5 * np.sum(DX * (np.dot(inv(S), DX)), axis=0)
        E = E + 0.5 * M.shape[0] * np.log(2 * np.pi) + 0.5 * np.log(det(S))
        P = np.exp(-E)
    else:
        DX = X - M
        E = 0.5 * np.dot(DX.T, np.dot(inv(S), DX))
        E = E + 0.5 * M.shape[0] * np.log(2 * np.pi) + 0.5 * np.log(det(S))
        P = np.exp(-E)
    return (P[0], E[0])


# -*- coding: utf-8 -*
import scipy.ndimage as ndimg
from imagepy.core.engine import Filter, Simple
import numpy as np

class Gaussian3D(Simple):
	title = 'Gaussian 3D'
	note = ['all', 'stack3d']

	#parameter
	para = {'sigma':2}
	view = [(float, (0,30), 1,  'sigma', 'sigma', 'pix')]

	#process
	def run(self, ips, imgs, para = None):
		imgs[:] = ndimg.gaussian_filter(imgs, para['sigma'])

class Uniform3D(Simple):
	title = 'Uniform 3D'
	note = ['all', 'stack3d']

	#parameter
	para = {'size':2}
	view = [(float, (0,30), 1,  'size', 'size', 'pix')]

	#process
	def run(self, ips, imgs, para = None):
		imgs[:] = ndimg.uniform_filter(imgs, para['size'])

plgs = [Gaussian3D, Uniform3D]


# The curl of a vector field

The curl of a vector field ($\vec v$) is also known as the rotor or rotational of the field.  Mathematically, it is expressed as $\nabla \times \vec{v}$.  Where the operator $\nabla \times$ acts on the vector field $\vec v$.  It is a measured of the vorticity of a vector field.

#Python Toolboxes needed
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D #For 3D plots
from matplotlib import cm
#enable Latex syntax in matplotlib
from matplotlib import rc
%matplotlib notebook

The vectorial field (${\bf \vec P}$) has the following form:

$${\bf \hat P} = e^{-(x^2+y^2)}{\bf \hat x} + sin(xy) {\bf \hat y} $$

where $\hat x$ and $\hat y$ are the unit vectors in directions $x$ and $y$ respectively

#Create a mesh
x = np.arange(-1,1,0.1)
y = np.arange(-1,1,0.1)
xx,yy=np.meshgrid(x,y)#[xx,yy] = meshgrid(x,y);

#The parametric equations of the vectorial components
px = np.exp(-(xx**2+yy**2))
py = np.sin(xx*yy)
#The output
plt.figure('Vectorial field')
plt.quiver(xx,yy,px,py,edgecolor='k', facecolor='None',linewidth=0.5)
plt.streamplot(x, y, px, py, color='m', linewidth=1, cmap=plt.cm.inferno,density=2, arrowstyle='->', arrowsize=1.5)
plt.xlabel('x'), plt.ylabel('y');
plt.title(r'Vectorial Field 2-D: ${\bf \hat P} = e^{-(x^2+y^2)}{\bf \hat x} + sin(xy) {\bf \hat y} $')
plt.show()

The curl is a new vector field which is perpendicular to the original local one and its sign is determined by the right-hand rule.

[pxy,pxx]=np.gradient(px,0.1,0.1)#[pxx,pxy]=np.gradient(px,0.1,0.1)
[pyy,pyx]=np.gradient(py,0.1,0.1)#[pyx,pyy]=np.gradient(py,0.1,0.1)
#
curl_p_z=(pyx-pxy);

m,n=curl_p_z.shape
curl_p_x=np.zeros((m,n))
curl_p_y=np.zeros((m,n))

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.quiver(xx,yy,np.zeros((m,n)),curl_p_x,curl_p_y,curl_p_z,3,'r',length=0.03,normalize=False)
ax.plot_surface(xx,yy,np.zeros((m,n)))#surf(xx,yy,zeros(m,n));shading flat;colormap pink;
#rotate3d;
ax.set_xlabel('x'),ax.set_ylabel('y'),ax.set_zlabel('z')
plt.show()

In this next plot we can see the magnitude of the vectors as a coloured image.  Notice where the curl reaches its maximum and minimum values.

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(xx, yy,curl_p_z , cmap=cm.rainbow ,linewidth=0, antialiased=False,shade=True)
ax.view_init(azim=0, elev=90)
ax.set_xlabel('x'), ax.set_ylabel('y'), ax.set_zlabel(r'$|\nabla \times {\bf \vec P}|$');

from IPython.display import HTML

HTML('<iframe width="560" height="315" src="https://www.youtube.com/embed/rB83DpBJQsE" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>')


import numpy as np

class Brownian:
    """
    A Brownian motion class constructor
    """

    def __init__(self, x0=1):
        """
        Init class
        """
        assert (
            type(x0) == float or type(x0) == int or x0 is None
        ), "Expect a float or None for the initial value"

        self.x0 = float(x0)

    def gen_random_walk(self, n_step=100):
        """
        Generate motion by random walk

        Arguments:
            n_step: Number of steps

        Returns:
            A NumPy array with `n_steps` points
        """
        # Warning about the small number of steps
        # if n_step < 30:
        #     print("WARNING! The number of steps is small. It may not generate a good stochastic process sequence!")

        w = np.ones(n_step) * self.x0

        for i in range(1, n_step):
            # Sampling from the Normal distribution with probability 1/2
            yi = np.random.choice([1, -1])
            # Weiner process
            w[i] = w[i - 1] + (yi / np.sqrt(n_step))

        return w

    def gen_normal(self, n_step=100):
        """
        Generate motion by drawing from the Normal distribution

        Arguments:
            n_step: Number of steps

        Returns:
            A NumPy array with `n_steps` points
        """
        if n_step < 30:
            print(
                "WARNING! The number of steps is small. It may not generate a good stochastic process sequence!"
            )

        w = np.ones(n_step) * self.x0

        for i in range(1, n_step):
            # Sampling from the Normal distribution
            yi = np.random.normal()
            # Weiner process
            w[i] = w[i - 1] + (yi / np.sqrt(n_step))

        return w

    def stock_price(self, s0=100, mu=0.2, sigma=0.68, deltaT=52, dt=0.1):
        """
        Models a stock price S(t) using the Weiner process W(t) as
        `S(t) = S(0).exp{(mu-(sigma^2/2).t)+sigma.W(t)}`

        Arguments:
            s0: Iniital stock price, default 100
            mu: 'Drift' of the stock (upwards or downwards), default 1
            sigma: 'Volatility' of the stock, default 1
            deltaT: The time period for which the future prices are computed, default 52 (as in 52 weeks)
            dt (optional): The granularity of the time-period, default 0.1

        Returns:
            s: A NumPy array with the simulated stock prices over the time-period deltaT
        """
        n_step = int(deltaT / dt)
        time_vector = np.linspace(0, deltaT, num=n_step)
        # Stock variation
        stock_var = (mu - (sigma**2 / 2)) * time_vector
        # Forcefully set the initial value to zero for the stock price simulation
        self.x0 = 0
        # Weiner process (calls the `gen_normal` method)
        weiner_process = sigma * self.gen_normal(n_step)
        # Add two time series, take exponent, and multiply by the initial stock price
        s = s0 * (np.exp(stock_var + weiner_process))

        return s

def generate_bm_series(number):
    b = Brownian()
    series = b.gen_random_walk(number)
    return series

series = generate_bm_series(10)


# -*- coding: utf-8 -*-
"""
Created on Wed Nov 17 11:35:46 2021

@author: Bruno Veiga
"""
from pyticleswarm import run_pso
import numpy as np
#import benchmark_functions as bf

# Example 1

# Define fitness function
def func(x):
    # hypersphere function
    f = np.sum(x**2)

    return f
# or a benchmark can also be used
#func = bf.Hypersphere(n_dimensions=2)

# Create variables
n_vars= 2
low_bounds = -5.12
up_bounds = 5.12
# or for the benchmark function
# n_vars=func.n_dimensions()
# m = func.suggested_bounds()
# low_bounds = m[0]
# up_bounds = m[1]

"""
Stantard parameters values:

initial_solution        = []    Matrix or array containing the initial solutions or solution
brm_function            = 4     Function to handle boundary constraint violation.
n_jobs                  = -2    Number of concurrently running jobs.
direct_repair           = None  The direct repair function
perc_repair             = 0     Value between 0 and 1 that determines the percentage of iterations starting from the end where a repair function is applied
wmax                    = 0.5   The maximum value of the inertia weight
wmin                    = 0.1   The minimum value of the itertia weight
c1min                   = 0     Minimum value of the acceleration coefficient c1
c1max                   = 0.4   Maximum value of the acceleration coefficient c1
c2min                   = 0.1   Minimum value of the acceleration coefficient c2
c2max                   = 2     Maximum value of the acceleration coefficient c1
n_iterations            = 100   The total number of iterations
n_particles             = 10    The total number of particles
n_trials                = 30    The total number of trials
show_fitness_graphic    = False Boolean that indicates if the fitness graphic is to be shown or not
show_particle_graphics  = False Boolean that indicates if the particles graphics are to be shown or not (Only works with solutions of 2 dimensions)
"""
# Run PSO
res = run_pso(n_vars, fitness_function=func, low_bounds=low_bounds, up_bounds= up_bounds, c1min = 0.4, c1max = 0.6, c2min = 0.4,n_jobs=-2,
            c2max = 0.6, wmax = 0.6, wmin = 0.4, n_iterations=100,n_particles=100, brm_function=4, show_fitness_grapic=True)

# Print results
"""
Results:

res.fitness_value is a float correspending to the best fitness value with size = 1
res.it_fitness_value is a array with all the fitness values of the best execution with size = n_iterations
res.solution is the solution correspoding to best fitness value with size = n_vars
res.tot_exec_time is the total of time of execution of the algorithm with size = 1
res.avg_exec_time is the average of time of execution of the algorithm with size = 1
"""


"""Schmidt decomposition operation."""
from typing import List, Tuple, Union
from scipy.sparse import issparse, linalg

import numpy as np

def schmidt_decomposition(
    vec: np.ndarray, dim: Union[int, List[int], np.ndarray] = None, k_param: int = 0
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
    r"""
    Compute the Schmidt decomposition of a bipartite vector [WikSD]_.

    Examples
    ==========

    Consider the :math:`3`-dimensional maximally entangled state

    .. math::
        u = \frac{1}{\sqrt{3}} \left( |000 \rangle + |111 \rangle + |222 \rangle \right)

    We can generate this state using the :code:`toqito` module as follows.

    >>> from toqito.states import max_entangled
    >>> max_entangled(3)
    [[0.57735027],
     [0.        ],
     [0.        ],
     [0.        ],
     [0.57735027],
     [0.        ],
     [0.        ],
     [0.        ],
     [0.57735027]]

    Computing the Schmidt decomposition of :math:`u`, we can obtain the corresponding singular
    values of :math:`u` as

    .. math::
        \frac{1}{\sqrt{3}} \left[1, 1, 1 \right]^{\text{T}}.

    >>> from toqito.states import max_entangled
    >>> from toqito.state_ops import schmidt_decomposition
    >>> singular_vals, u_mat, vt_mat = schmidt_decomposition(max_entangled(3))
    >>> singular_vals
    [[0.57735027]
     [0.57735027]
     [0.57735027]]
    >>> u_mat
    [[1. 0. 0.]
     [0. 1. 0.]
     [0. 0. 1.]]
    >>> vt_mat
    [[1. 0. 0.]
     [0. 1. 0.]
     [0. 0. 1.]]

    References
    ==========
    .. [WikSD] Wikipedia: Schmidt decomposition
        https://en.wikipedia.org/wiki/Schmidt_decomposition

    :param vec: A bipartite quantum state to compute the Schmidt decomposition of.
    :param dim: An array consisting of the dimensions of the subsystems (default gives subsystems
                equal dimensions).
    :param k_param: How many terms of the Schmidt decomposition should be computed (default is 0).
    :return: The Schmidt decomposition of the :code:`vec` input.
    """
    eps = np.finfo(float).eps

    if dim is None:
        dim = np.round(np.sqrt(len(vec)))
    if isinstance(dim, list):
        dim = np.array(dim)

    # Allow the user to enter a single number for `dim`.
    if isinstance(dim, float):
        dim = np.array([dim, len(vec) / dim])
        if np.abs(dim[1] - np.round(dim[1])) >= 2 * len(vec) * eps:
            raise ValueError(
                "InvalidDim: The value of `dim` must evenly divide"
                " `len(vec)`; please provide a `dim` array "
                "containing the dimensions of the subsystems."
            )
        dim[1] = np.round(dim[1])

    # Try to guess whether SVD or SVDS will be faster, and then perform the
    # appropriate singular value decomposition.
    adj = 20 + 1000 * (not issparse(vec))

    # Just a few Schmidt coefficients.
    if 0 < k_param <= np.ceil(np.min(dim) / adj):
        u_mat, singular_vals, vt_mat = linalg.svds(
            linalg.LinearOperator(np.reshape(vec, dim[::-1].astype(int)), k_param)
        )
    # Otherwise, use lots of Schmidt coefficients.
    else:
        u_mat, singular_vals, vt_mat = np.linalg.svd(np.reshape(vec, dim[::-1].astype(int)))

    if k_param > 0:
        u_mat = u_mat[:, :k_param]
        singular_vals = singular_vals[:k_param]
        vt_mat = vt_mat[:, :k_param]

    # singular_vals = np.diag(singular_vals)
    singular_vals = singular_vals.reshape(-1, 1)
    if k_param == 0:
        # Schmidt rank.
        r_param = np.sum(singular_vals > np.max(dim) * np.spacing(singular_vals[0]))
        # Schmidt coefficients.
        singular_vals = singular_vals[:r_param]
        u_mat = u_mat[:, :r_param]
        vt_mat = vt_mat[:, :r_param]

    u_mat = u_mat.conj().T
    return singular_vals, u_mat, vt_mat


#!/usr/bin/env python

from sympy import lambdify, diff, Matrix, cos, sin, exp, pprint
from sympy.plotting import plot, plot3d
from sympy.abc import x,y

''' Reference
    https://sistemas.eel.usp.br/docentes/arquivos/519033/LOM3026/Metodos_numericos_calculo_sistemas_equacoes_nao_lineares.pdf
'''

def jacobian_transpose(function):
    '''  Jacobian: init and set  '''
    j = (Matrix([function]).jacobian([x,y])).transpose()
    return (lambdify([x,y], j))

if __name__ == "__main__" :
    euler = exp(-( ( ((x-1)**2)/(2*(0.75**2)) ) + ( ((y-2)**2)/(2*(0.5**2)) )  ))
    f = 1 - euler + ( 0.04 * (((x-1)**2) + ((y-2)**2)) )

    f = x**2 * y**3
    j = (Matrix([f]).jacobian([x,y]))
    j = j.transpose()

    j = lambdify([x,y], j)
    pprint(j(5,2))


#! /usr/bin/env python
from __future__ import division
from scipy.integrate import ode
import numpy as np
import matplotlib.pyplot as plt

def SIR(a,b,beta, gamma,ya):
	def SIR_ode(t,y):
		return np.array([ -beta*y[0]*y[1], beta*y[0]*y[1]-gamma*y[1], gamma*y[1] ])

	example = ode(SIR_ode).set_integrator('dopri5',atol=1e-8,rtol=1e-8)
	example.set_initial_value(ya,a)

	dim, t = 3, np.linspace(a,b,501)
	Y = np.zeros((len(t),dim))
	Y[0,:] = ya
	for j in range(1,len(t)):
		Y[j,:] = example.integrate(t[j])

	return t, Y

#
# def SIS(a,b,beta, gamma,ya):
# 	def SIS_ode(t,y): return np.array([ -beta*y[0]*y[1] +  gamma*y[1],
# 										 beta*y[0]*y[1] - gamma*y[1]    ])
#
# 	example = ode(SIS_ode).set_integrator('dopri5',atol=1e-8,rtol=1e-8)
# 	example.set_initial_value(ya,a)
#
# 	dim, t = 2, np.linspace(a,b,501)
# 	Y = np.zeros((len(t),dim))
# 	Y[0,:] = ya
# 	for j in range(1,len(t)): Y[j,:] = example.integrate(t[j])
#
# 	plt.plot(t,Y[:,0],'-k',label='Susceptible')
# 	plt.plot(t,Y[:,1],'-r',label='Infectious')
# 	plt.axis([a,b,-.1,1.1])
# 	plt.legend(loc=1)
# 	plt.xlabel('T (days)',fontsize=16)
# 	plt.ylabel('Proportion of Population',fontsize=16)
# 	plt.show()
# 	# plt.clf()
# 	return t, Y
#
#
# def SIRS(a,b,beta, gamma, mu, f,ya):
# 	def SIRS_ode(t,y): return np.array([ -beta*y[0]*y[1]+ mu*(1-y[0]) + f*y[2],
# 										  beta*y[0]*y[1] - (gamma + mu) * y[1],
# 										  gamma*y[1] -mu*y[2] - f*y[2]						])
#
# 	example = ode(SIRS_ode).set_integrator('dopri5',atol=1e-8,rtol=1e-8)
# 	example.set_initial_value(ya,a)
#
# 	dim, t = 3, np.linspace(a,b,501)
# 	Y = np.zeros((len(t),dim))
# 	Y[0,:] = ya
# 	for j in range(1,len(t)): Y[j,:] = example.integrate(t[j])
#
# 	plt.plot(t,Y[:,0],'-k',label='Susceptible')
# 	plt.plot(t,Y[:,2],'-b',label='Recovered')
# 	plt.plot(t,Y[:,1],'-r',label='Infected')
# 	plt.axis([a,b,-.1,1.1])
# 	plt.legend(loc=1)
# 	plt.xlabel('T (days)',fontsize=16)
# 	plt.ylabel('Proportion of Population',fontsize=16)
# 	plt.show()
# 	# plt.clf()
# 	return t, Y
#
#

###########################################################################
######      THE SIR MODEL
######      beta  = average number of infectious contacts per day
######      gamma = 1./(average length of time in the infectious phase)

# beta, gamma = 2., 1.
# a, b, ya = 0., 50., np.array([1.-(1.67e-6), 1.67e-6,0.])

# beta, gamma = .340, .333
# a, b, ya = 0., 1600., np.array([1.-(6.25e-7), 6.25e-7,0.])

# t,Y = SIR(a,b,beta, gamma,ya)
# print "The Maximum fraction of the population that will be infected simultaneously is", max(Y[:,1])
###########################################################################

###########################################################################
######      THE SIS MODEL
######		Here we suppose N is the total population without infection. We do
######		suppose that S+I=1
######      beta  = average number of infectious contacts per day
######      gamma = 1./(average length of time in the infectious phase)

# beta, gamma = 3./10., 1./4.
# a, b, ya = 0., 400., np.array([1.-(1.667e-6), 1.667e-6])
# t,Y = SIS(a,b,beta, gamma,ya)
# print "The Maximum fraction of the population that will be infected simultaneously is", max(Y[:,1])
###########################################################################

###########################################################################
######      THE SIRS MODEL
######		Here we suppose N is the total population without infection. We do
######		suppose that S+I+R=1
######      beta  = average number of infectious contacts per day
######      gamma = 1./(average length of time in the infectious phase)

# beta, gamma = 3./10., .7/4.
# mu, f= .1, .3
# a, b, ya = 0., 3600., np.array([1.-50*(1.667e-6), 50*1.667e-6,0.])
# t,Y = SIRS(a,b,beta, gamma, mu, f, ya)
# print "The Maximum fraction of the population that will be infected simultaneously is", max(Y[:,1])
###########################################################################


from scipy.special import expit
import numpy as np

def sigmoid(z):
#SIGMOID Compute sigmoid functoon
#   J = SIGMOID(z) computes the sigmoid of z.

    # You need to return the following variables correctly
    g = np.zeros(z.shape)

# ====================== YOUR CODE HERE ======================
# Instructions: Compute the sigmoid of each value of z (z can be a matrix,
#               vector or scalar).

    # g = 1/(1 + np.exp(-z))
    g = expit(z)

    return g

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


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

# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

import numpy as np

def tensorproduct(*args):
    """
    Calculate tensor product.

    m = tensorproduct(a,b,c,...) returns the kronecker product of its arguments.
    Each argument should either be a tensor, or a tuple containing a
    tensor and an integer, and tensor is put in zero-index slot.
    In the latter case, the integer specifies the repeat count for the tensor,
    e.g. tensorproduct(a,(b,3),c) = tensorproduct(a,b,b,b,c).

    Args:
            - args:
    Returns:
            np.ndarray: the tensor product
    """
    M = 1
    for j in range(len(args)):
        if isinstance(args[j], tuple):
            m = args[j][0] if isinstance(args[j][0], np.ndarray) else np.asarray(args[j][0])
            for k in range(args[j][1]):
                M = np.kron(M, m)
        else:
            m = args[j] if isinstance(args[j], np.ndarray) else np.asarray(args[j])
            M = np.kron(M, m)
    return M


''' Author: Songheng Yin,
    Contact: songheng.yin@mail.utoronto.ca'''

import numpy as np
from matplotlib import pyplot as plt

def shuffle_data(data):
    ''' perform uniformly random permutation'''
    t, X = data
    n = t.shape[0]
    for i in range(n - 1):
        j = np.random.randint(i, n - 1)
        X[[i, j], :] = X[[j, i], :]
        t[[i, j]] = t[[j, i]]
    return (t, X)

def split_data(data, num_folds, fold):
    t, X = data
    X_split = np.array_split(X, num_folds, axis=0)
    t_split = np.array_split(t, num_folds)
    data_fold = (t_split[fold - 1], X_split[fold - 1])
    X_rest = np.delete(X_split, fold - 1, axis=0)
    X_rest = np.concatenate(X_rest, axis=0)
    t_rest = np.delete(t_split, fold - 1, axis=0)
    t_rest = np.concatenate(t_rest, axis=0)
    data_rest = (t_rest, X_rest)
    return data_fold, data_rest

def train_model(data, lambd):
    t, X = data
    N, D = X.shape
    w = np.linalg.inv((X.T @ X) + lambd * N * np.identity(D))
    w = (w @ X.T) @ t
    return w

def predict(data, model):
    t, X = data
    y = X @ model
    return y

def loss(data, model):
    t, X = data
    return (np.linalg.norm(X @ model - t)) ** 2 / (2 * t.shape[0])

def cross_validation(data, num_folds, lambd_seq):
    data = shuffle_data(data)
    cv_error = np.zeros(len(lambd_seq))
    for i, lambd in enumerate(lambd_seq):
        for fold in range(1, num_folds + 1):
            val_cv, train_cv = split_data(data, num_folds=num_folds, fold=fold)
            model = train_model(train_cv, lambd)
            cv_error[i] += loss(val_cv, model) / num_folds
    return cv_error

if __name__ == '__main__':
    data_train = (
        np.genfromtxt('./data/data_train_y.csv', delimiter=','),
        np.genfromtxt('./data/data_train_X.csv', delimiter=','),
    )
    data_test = (
        np.genfromtxt('./data/data_test_y.csv', delimiter=','),
        np.genfromtxt('./data/data_test_X.csv', delimiter=','),
    )
    lambd_seq = np.linspace(0.00005, 0.005, num=50)

    # Question c
    training_errors, test_errors = [], []
    for lambd in lambd_seq:
        model = train_model(data_train, lambd)
        test_errors.append(loss(data_test, model))
        training_errors.append(loss(data_train, model))
    fig, ax = plt.subplots(1, 1)
    ax.plot(lambd_seq, training_errors, label='Training Error')
    ax.plot(lambd_seq, test_errors, label='Test Error')

    # Question d
    cv_5_error = cross_validation(data_train, 5, lambd_seq)
    cv_10_error = cross_validation(data_train, 10, lambd_seq)
    ax.plot(lambd_seq, cv_5_error, label='CV 5 folders error')
    ax.plot(lambd_seq, cv_10_error, label='CV 10 folders error')
    ax.set_xlabel('Lambda')
    ax.set_ylabel('Loss')
    plt.legend(loc='best')
    plt.show()
    plt.close()

    best_lambda_5 = lambd_seq[np.argmin(cv_5_error)]
    best_lambda_10 = lambd_seq[np.argmin(cv_10_error)]
    print('Best lambda by 5-folder CV: {}'.format(best_lambda_5))
    print('Best lambda by 10-folder CV: {}'.format(best_lambda_10))


import math

try:
    from ulab import numpy as np
    from ulab import scipy as spy
except ImportError:
    import numpy as np
    import scipy as spy

result = (np.sin(np.pi/2))
ref_result = 1.0
print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6))

result = (np.cos(np.pi/2))
ref_result = 0.0
print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6))

result = (np.tan(np.pi/2))
ref_result = 1.633123935319537e+16
print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6))

result = (np.sinh(np.pi/2))
ref_result = 2.3012989023072947
print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6))

result = (np.cosh(np.pi/2))
ref_result = 2.5091784786580567
print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6))

result = (np.tanh(np.pi/2))
ref_result = 0.9171523356672744
print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6))

ref_result = np.pi/2
result = (np.asin(np.sin(np.pi/2)))
print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6))

result = (np.acos(np.cos(np.pi/2)))
print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6))

result = (np.atan(np.tan(np.pi/2)))
print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6))

result = (np.cosh(np.acosh(np.pi/2)))
print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6))

result = (np.sinh(np.asinh(np.pi/2)))
print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6))

print(np.degrees(np.pi))
print(np.radians(np.degrees(np.pi)))
print(np.floor(np.pi))
print(np.ceil(np.pi))
print(np.sqrt(np.pi))
print(np.exp(1))
print(np.log(np.exp(1)))

print(np.log2(2**1))

print(np.log10(10**1))
print(np.exp(1) - np.expm1(1))

x = np.array([-1, +1, +1, -1])
y = np.array([-1, -1, +1, +1])
result = (np.arctan2(y, x) * 180 / np.pi)
ref_result = np.array([-135.0, -45.0, 45.0, 135.0], dtype=np.float)
cmp_result = []
for i in range(len(x)):
    cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9))
print(cmp_result)

x = np.linspace(-2*np.pi, 2*np.pi, 5)
result = np.sin(x)
ref_result = np.array([2.4492936e-16, -1.2246468e-16,  0.0000000e+00,  1.2246468e-16, -2.4492936e-16], dtype=np.float)
cmp_result = []
for i in range(len(x)):
    cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9))
print(cmp_result)

result = np.cos(x)
ref_result = np.array([1., -1.,  1., -1.,  1.], dtype=np.float)
cmp_result = []
for i in range(len(x)):
    cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9))
print(cmp_result)

result = np.tan(x)
ref_result = np.array([2.4492936e-16, 1.2246468e-16, 0.0000000e+00, -1.2246468e-16, -2.4492936e-16], dtype=np.float)
cmp_result = []
for i in range(len(x)):
    cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9))
print(cmp_result)

result = np.sinh(x)
ref_result = np.array([-267.74489404, -11.54873936, 0., 11.54873936, 267.74489404], dtype=np.float)
cmp_result = []
for i in range(len(x)):
    cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9))
print(cmp_result)

result  = np.cosh(x)
ref_result = np.array([267.74676148,  11.59195328, 1.0, 11.59195328, 267.74676148], dtype=np.float)
cmp_result = []
for i in range(len(x)):
    cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9))
print(cmp_result)

result = np.tanh(x)
ref_result = np.array([-0.9999930253396107, -0.99627207622075, 0.0, 0.99627207622075, 0.9999930253396107], dtype=np.float)
cmp_result = []
for i in range(len(x)):
    cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9))
print(cmp_result)

result = (spy.special.erf(np.linspace(-3, 3, num=5)))
ref_result = np.array([-0.9999779095030014, -0.9661051464753108, 0.0, 0.9661051464753108, 0.9999779095030014], dtype=np.float)
cmp_result = []
for i in range(len(ref_result)):
	cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9))
print(cmp_result)

result = (spy.special.erfc(np.linspace(-3, 3, num=5)))
ref_result = np.array([1.99997791e+00, 1.96610515e+00, 1.00000000e+00, 3.38948535e-02, 2.20904970e-05], dtype=np.float)
cmp_result = []
for i in range(len(ref_result)):
	cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-6, abs_tol=1E-6))
print(cmp_result)

result = (spy.special.gamma(np.array([0, 0.5, 1, 5])))
ref_result = np.array([1.77245385,  1.0, 24.0])
cmp_result = []
cmp_result.append(math.isinf(result[0]))
for i in range(len(ref_result)):
	cmp_result.append(math.isclose(result[i+1], ref_result[i], rel_tol=1E-9, abs_tol=1E-9))
print(cmp_result)

result = (spy.special.gammaln([0, -1, -2, -3, -4]))
cmp_result = []
for i in range(len(ref_result)):
	cmp_result.append(math.isinf(result[i]))
print(cmp_result)


## Euler_Maruyama_integration_AshivD.py
# Demonstration of Euler and Euler-Maruyama integration on the SHM problem.
# ------------------------- #
# Description:
# This project demonstrates numerical integration of the Simple Harmonic Motion DE
# using an Euler scheme. Numerical integration of the SHM DE perturbed by diagonal
# independent Wiener processes.
# ------------------------- #
# Created by: Ashiv Dhondea, RRSG, UCT.
# Date created: 04 July 2016
# Edits:
# ------------------------- #
# Theoretical background
# 1. Bayesian Signal Processing, Sarkka. 2013.
# 2. ekfukf toolbox documentation
# ------------------------- #
# Import libraries
import numpy as np
import matplotlib.pyplot as plt
#import sdeint
# f - frequency of SHM
f = 1.0; # [Hz]
omega2 = (2*np.pi*f)**2;

A = np.array([[0, 1.0],
              [ -omega2, 0]],dtype=np.float64);

def fnSHM(x,t):
    de = np.dot(A,x);
    return de

dt = f/1000;
num_samples =5*1/dt;
tspan = np.linspace(0.0, dt*num_samples, num_samples);

x0 = np.array([3.0, 0.0]);
X = np.zeros([2,len(tspan)],dtype=np.float64);
Y = np.zeros([2,len(tspan)],dtype=np.float64);
X[:,0] =x0;
P_0 = np.diag([1e-6,1e-6]);
Y[:,0] =x0 + np.random.multivariate_normal([0,0],np.sqrt(P_0));
# Dispersion matrix
L = np.array([[0.0,0.0],[0.0,1.0]],dtype=np.float64);
true_Qc =  np.diag([1.2,2.4]);
B = dt*true_Qc;

def G(x, t):
    return np.dot(L,B)

for index in range (0,len(tspan)-1):
    # Euler integration scheme.
    X[:,index+1] = X[:,index] + dt*fnSHM(X[:,index],tspan[index]);
    # Euler-Maruyama integration
    Y[:,index+1] = Y[:,index] + dt*fnSHM(Y[:,index],tspan[index])+ np.dot(L,np.random.multivariate_normal([0,0],B));
    #Y[:,index+1] = Y[:,index] + dt*fnSHM(Y[:,index],tspan[index])+ np.random.multivariate_normal([0,0],np.dot(L,B));

#result = sdeint.itoEuler(fnSHM, G, Y[:,0], tspan) # Euler-Maruyama

# Show results for the deterministic solution and the stochastic solution.
fig = plt.figure()
fig.suptitle('Euler integration on SHM DE')
plt.plot(tspan,X[0,:],'b.',label='Euler pos');
#plt.plot(tspan,Y[0,:],'bo',label='EM pos');
plt.plot(tspan,X[1,:],'r.',label='Euler vel');
#plt.plot(tspan,Y[1,:],'ro',label='EM vel');
plt.xlabel('t')
plt.legend(loc='upper left')
ax = plt.gca()
ax.grid(True)
plt.show()

## Compare results from my implementation with those from sdeint
fig = plt.figure()
fig.suptitle('Euler-Maruyama integration test')
plt.plot(tspan,Y[0,:],'b.',label='pos');
plt.plot(tspan,Y[1,:],'r.',label='vel');
#plt.plot(tspan,result[:,0],'g.',label='sdeint pos');
#plt.plot(tspan,result[:,1],'m.',label='sdeint vel');
plt.xlabel('t')
plt.legend(loc='upper left')
ax = plt.gca()
ax.grid(True)
plt.show()


# Implementing PageRank using random walks
# Procedure :
# 1. Create/take a directed graph.
# 2. Initially all the nodes have zero points.
# 3. Select a random node and make it the start node.
# 4. Perform random walks on the graph with the goal of visiting each node at least once.
# 	4.1. When a node is visited, increment its point(s) by one.
# 	4.2. If a node having no outlinks is reached, do teleportation, and resume the random walk.
# 5. Rank the nodes according to their accumulated points.
# 6. Compare the ranking generated with the inbuilt PageRank algorithm function.

import networkx as nx
import random
import numpy as np

# Function to add edges to the directed graph
def add_edges(G,p):
	for i in G.nodes():
		for j in G.nodes():
			if i != j :
				r = random.random()
				if r <= p:
					G.add_edge(i,j)
				else:
					continue
	return G

# Function to sort nodes according to their accumulated points
# We will denote "random-walk-point" by "RWP"
def get_nodes_sorted_by_RWP(RWP_list):
	RWP_array = np.array(RWP_list) # Converting list to numpy array
	nodes_sorted_by_RWP = np.argsort(-RWP_array) # The minus sign is used for sorting in descending order
	return nodes_sorted_by_RWP

# Function to perform random walks and increment random-walk-point of visited node by 1
def random_walk(G):
	nodes = list(G.nodes()) # List of nodes of graph
	RWP = [0 for i in range(G.number_of_nodes())]  # List containing RWP of all nodes which are initially 0
	s_node = random.choice(nodes)  # Choosing starting (source) node at random
	RWP[s_node] += 1
	outlinked_neigh = G.out_edges(s_node)
	c = 0 # Iteration variable
	while (c != 100000):
		if (len(outlinked_neigh) == 0): # Case when the node has no outlink
			focus = random.choice(nodes) # focus is the node currently being visited
		else:
			random_neigh = random.choice(list(outlinked_neigh))
			focus = random_neigh[1]
		RWP[focus] += 1
		outlinked_neigh = G.out_edges(focus)
		c += 1
	return RWP

# Function for main program
def main():
	G = nx.DiGraph() # Creating a directed graph object
	N = 10 # Number of nodes in the graph
	p = 0.3 # Probability for generating random graph
	G.add_nodes_from([i for i in range(N)]) # Adding nodes to the graph object
	G = add_edges(G,p) # Adding edges to the graph object, making it a random graph

	RWP_list = random_walk(G) # Performing random walks on the graph and getting list of RWP for nodes
	nodes_sorted_by_RWP = get_nodes_sorted_by_RWP(RWP_list) # Ranking (ordering) nodes on the basis of accumulated RWP

	print 'Nodes sorted (ranked) according to the accumulated random-walk-points : ',
	for i in nodes_sorted_by_RWP:
		print i,

	pr = nx.pagerank(G) # Getting PageRank of nodes, output is a dictionary
	pr_sorted = sorted(pr.items(), key=lambda x:x[1], reverse=True)
	print '\nNodes sorted (ranked) using the builtin PageRank algo function : ',
	for i in pr_sorted:
		print i[0],

main() # Invoking the main function

PageRank Implementation/PageRank - Random Walks/PageRank_random_walks.py


#!/usr/bin/env python3
"""Peter Rasmussen, Programming Assignment 4, utils.py

This module provides miscellaneous utility functions that support the core perceptrons of this program.

"""
# Third party libraries
import numba as nb
import numpy as np
import pandas as pd
from numba import njit

def bias(X):
    bias_term = np.ones([len(X), 1])
    return np.hstack([X, bias_term])

def cross_entropy(Y: np.array, Yhat: np.array) -> float:
    return -np.sum(Y * np.log(Yhat) + (1 - Y) * np.log(1 - Yhat))

@njit
def mse(Y, Yhat):
    return np.sum(np.square(np.subtract(Y, Yhat))) / len(Y)

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

def sigmoid_update(weights):
    return weights * (1 - weights)

@njit
def shuffle_indices(n: int) -> nb.int64[:]:
    """
    Shuffle a zero-indexed index.
    :param n: Number of elements in array
    :return: Array of randomly ordered indices
    """
    indices = np.arange(n)
    np.random.shuffle(indices)
    return indices

def dummy_categorical_label(data: pd.DataFrame, label: str) -> tuple:
    """
    Dummy categorical label.
    :param data: Dataframe
    :param label: Label column
    :return: Tuple of data with dummied labels and label cols
    """

    dummied_labels: pd.DataFrame = pd.get_dummies(data[label].astype("category"), prefix=label)
    # Sort dummied cols in ascending order
    label_cols = sorted(list(dummied_labels))
    return dummied_labels[label_cols], label_cols

def accuracy(Y, Yhat):
    maxes = np.broadcast_to(np.max(Yhat, axis=1), Yhat.T.shape).T
    pred = np.greater_equal(Yhat, maxes).astype(np.uint8)
    pred_correct = (Y == pred).sum(axis=1) == Y.shape[1]
    return np.sum(pred_correct) / len(pred_correct)


import scipy

def get_ramp(x0,x1,vmax,a,dt, output='ramp only'):
    """
    Generate a ramp trajectory from x0 to x1 with constant
    acceleration, a, to maximum velocity v_max.

    Note, the main purlpose of this routine is to generate a
    trajectory from x0 to x1. For this reason v_max and a are adjusted
    slightly to work with the given time step.

    Arguments:
     x0 = starting position
     x1 = ending position
     vmax = maximum allowed velocity
     a = constant acceleration

     Keywords:
       output = 'ramp only' or 'full'
       when ramp only is selected then only the velocity ramp is returned.
       If 'full' is selected the adjusted acceleration and maximum velocity
       are also returned.

    Ouput:
      ramp = ramp trajectory form x0 to x1

    """
    # Insure we are dealing with floating point numbers
    x0, x1 = float(x0), float(x1)
    vmax, a = float(vmax), float(a)
    dt = float(dt)
    vmax, a = abs(vmax), abs(a) # Make sure that v_max and a are positive

    # Check to see if there is anything to do
    if x0==x1:
        return scipy.array([x0])

    # Get distance and sign indicating direction
    dist = abs(x1-x0)
    sign = scipy.sign(x1-x0)

    # Determine if we will reach v_max
    t2vmax = vmax/a
    t2halfdist = scipy.sqrt(0.5*dist/a)

    if t2vmax > t2halfdist:
        # Trajectory w/o constant velocity segment
        T = scipy.sqrt(dist/a)
        n = int(scipy.round_((1.0/dt)*T))

        # Adjust accel and duration for rounding of n (discrete time steps)
        a = dist/(n*dt)**2
        T = scipy.sqrt(dist/a)

        # Generate trajectory
        t = scipy.linspace(0.0,2.0*T,2*n+1)
        def f1(t):
            return 0.5*sign*a*(t**2)
        def f2(t):
            s = t-T
            return f1(T)+ sign*a*T*s - 0.5*sign*a*s**2
        func_list = [f1,f2]
        cond_list = [t<=T, t>T]
        ramp = x0+scipy.piecewise(t,cond_list,func_list)

    else:
        # Trajectory w/ constant velocity segment
        # Compute acceleration time and adjust acceleration
        T1 = vmax/a
        n = int(scipy.round_(T1/dt))
        a = vmax/(n*dt) # Adjusted acceleration
        T1 = vmax/a # Adjusted acceleration time

        # Compute and adjust constant velocity time
        T2 = dist/vmax - T1
        m = int(scipy.round_(T2/dt))
        vmax = dist/(dt*(n+m)) # Adjusted max velocity
        T2 = dist/vmax - T1 # Adjusted constant velocity time

        # Generate trajectory
        t = scipy.linspace(0.0,2.0*T1+T2,2*n+m+1)
        def f1(t):
            return 0.5*sign*a*(t**2)
        def f2(t):
            s = t-T1
            return f1(T1) + sign*vmax*s
        def f3(t):
            s = t-T1-T2
            return f2(T1+T2)+sign*vmax*s-0.5*sign*a*s**2
        func_list = [f1,f2,f3]
        cond_list = [t<=T1, scipy.logical_and(t>T1,t<=T1+T2), t>T1+T2]
        ramp = x0+scipy.piecewise(t,cond_list,func_list)

    if output=='ramp only':
        return ramp
    elif output=='full':
        return ramp, vmax, a
    else:
        raise(ValueError, 'unknown keyword option output=%s'%(output,))


import numpy as np
import cv2
import time

def nothing(x):
    pass

def corner_detection(img_path, window_size, method):
    start = time.time()
    window_size = np.asarray(window_size, dtype=np.int)
    img_origin = cv2.imread(img_path)
    img_gray = cv2.cvtColor(img_origin, cv2.COLOR_BGR2GRAY)
    img_gray = cv2.GaussianBlur(img_gray, (3, 3), 0)
    window_size_halved = np.array(np.floor(window_size / 2), dtype=np.int)

    # Calculate Ix and Iy based on Sobel filter
    img_dx = cv2.Sobel(img_gray, cv2.CV_64F, 1, 0, ksize=5)
    img_dy = cv2.Sobel(img_gray, cv2.CV_64F, 0, 1, ksize=5)

    # Calculate (Ix)^2 integral
    img_dx_squared = np.square(img_dx)
    img_dx_squared_integral = cv2.integral(img_dx_squared)

    # Calculate (Iy)^2 integral
    img_dy_squared = np.square(img_dy)
    img_dy_squared_integral = cv2.integral(img_dy_squared)

    # Calculate Ix*Iy integral
    img_dxy = img_dx * img_dy
    img_dxy_integral = cv2.integral(img_dxy)

    # Initialize response matrix
    R_values = np.zeros([img_gray.shape[0],
                        img_gray.shape[1]], dtype=np.float)

    # Integrate and calculate all value in matrix R_values
    for i in range(window_size_halved[0], img_gray.shape[0] - window_size_halved[0]):
        if i % 10 == 0:
            print("Completed %0.2f%%" % (100*(i - window_size_halved[0]) /
                  (img_gray.shape[0] - window_size_halved[0])))
        for j in range(window_size_halved[1], img_gray.shape[1] - window_size_halved[1]):
            # Intergral implementation
            M_11 = img_dx_squared_integral[i - window_size_halved[0], j - window_size_halved[1]] +\
                img_dx_squared_integral[i + window_size_halved[0] + 1, j + window_size_halved[1] + 1] -\
                img_dx_squared_integral[i - window_size_halved[0], j + window_size_halved[1] + 1] -\
                img_dx_squared_integral[i + window_size_halved[0] + 1, j - window_size_halved[1]]

            M_22 = img_dy_squared_integral[i - window_size_halved[0], j - window_size_halved[1]] +\
                img_dy_squared_integral[i + window_size_halved[0] + 1, j + window_size_halved[1] + 1] -\
                img_dy_squared_integral[i - window_size_halved[0], j + window_size_halved[1] + 1] -\
                img_dy_squared_integral[i + window_size_halved[0] + 1, j - window_size_halved[1]]

            M_12 = img_dxy_integral[i - window_size_halved[0], j - window_size_halved[1]] +\
                img_dxy_integral[i + window_size_halved[0] + 1, j + window_size_halved[1] + 1] -\
                img_dxy_integral[i - window_size_halved[0], j + window_size_halved[1] + 1] -\
                img_dxy_integral[i + window_size_halved[0] + 1, j - window_size_halved[1]]
            # End of Intergral implementation
            if method == "Harris":
                # Harris response formula implementation
                trace = M_11+M_22
                det = M_11*M_22 - np.square(M_12)
                if trace > 0:
                    R_values[i, j] = det / trace
                pass
                # End of Harris implementation
            elif method == "Shi-Tomasi":
                # Shi - tomashi formula implementation
                M = np.array([[M_11, M_12], [M_12, M_22]], dtype=float)
                A = np.min(np.linalg.eigvalsh(M))
                R_values[i, j] = A
                # End of Shi - tomashi implementation
            else:
                raise NameError("Wrong method name, try \"Harris\" or \"Shi-Tomasi\"")

    stop = time.time()
    print("Completed 100%")
    print("Total processing time: %0.2f" % (stop - start))
    return R_values

if __name__ == "__main__":
    R_values = corner_detection("./Project/Tho/Linux/data/lena.jpg", (5, 5), "Harris")
    cv2.namedWindow("Result")
    cv2.createTrackbar("threshold", "Result", 2000, 6000, nothing)
    while True:
        threshold = cv2.getTrackbarPos("threshold", "Result")
        percent = R_values.max()*np.power(10, -threshold/1000)
        output = R_values.copy()
        output[output < percent] = 0
        output[output > percent] = 255
        corner = output.astype(np.uint8)
        cv2.imshow("Result", corner)
        if cv2.waitKey(100) & 0xff == 27:
            break


# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

# This Python script implements Remez' algorithm (https://en.wikipedia.org/wiki/Remez_algorithm).
# To use the script, you can modify what happens when this script is executed:
# See the `if __name__ == "__main__":` branch near the end of this file.
#
# Alternatively, `run_remez` can be imported and run directly, see the docstring
# of run_remez.

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

# Return n chebyshev nodes on the interval (a,b)
def _get_chebyshev_nodes(n, a, b):
    nodes = [.5 * (a + b) + .5 * (b - a) * math.cos((2 * k + 1) / (2. * n) * math.pi)
             for k in range(n)]
    return nodes

# Return the error on given nodes of a polynomial with coefficients polycoeff
# approximating the function with function values exactvals (on these nodes).
def _get_errors(exactvals, polycoeff, nodes):
    ys = np.polyval(polycoeff, nodes)
    for i in range(len(ys)):
        ys[i] = abs(ys[i] - exactvals[i])
    return ys

"""
Return the coefficients of a polynomial of degree d approximating
the function fun on the interval (a,b).

Args:
    fun: Function to approximate
    a: Left interval border
    b: Right interval border
    d: The polynomial degree will be d, 2*d or 2*d + 1 depending
        on the values of odd and even below
    odd: If True, use odd polynomial of degree 2*d+1
    even: If True, use even polynomial of degree 2*d
    tol: Tolerance to use when checking for convergence

Returns: Tuple where the first entry is the achieved absolute error
    and the second entry is a list of the polynomial coefficients in
    the order that is required by the QDK Numerics library. This is
    the inverse order compared to what np.polyval expects.
"""
def run_remez(fun, a, b, d=5, odd=False, even=False, tol=1.e-13):
    finished = False
    # initial set of points for the interpolation
    cn = _get_chebyshev_nodes(d + 2, a, b)
    # mesh on which we'll evaluate the error
    cn2 = _get_chebyshev_nodes(100 * d, a, b)

    # do at most 50 iterations and cancel if we "lose" an interpolation
    # point
    it = 0
    while not finished and len(cn) == d + 2 and it < 50:
        it += 1
        # set up the linear system of equations for Remez' algorithm
        b = np.array([fun(c) for c in cn])
        A = np.matrix(np.zeros([d + 2,d + 2]))
        for i in range(d + 2):
            x = 1.
            if odd:
                x *= cn[i]
            for j in range(d + 2):
                A[i, j] = x
                x *= cn[i]
                if odd or even:
                    x *= cn[i]
            A[i, -1] = (-1)**(i + 1)
        # this will give us a polynomial interpolation
        res = np.linalg.solve(A, b)

        # add padding for even/odd polynomials
        revlist = reversed(res[0:-1])
        sccoeff = []
        for c in revlist:
            sccoeff.append(c)
            if odd or even:
                sccoeff.append(0)
        if even:
            sccoeff = sccoeff[0:-1]
        # evaluate the approximation error
        errs = _get_errors([fun(c) for c in cn2], sccoeff, cn2)
        maximum_indices = []

        # determine points of locally maximal absolute error
        if errs[0] > errs[1]:
            maximum_indices.append(0)
        for i in range(1, len(errs) - 1):
            if errs[i] > errs[i-1] and errs[i] > errs[i+1]:
                maximum_indices.append(i)
        if errs[-1] > errs[-2]:
            maximum_indices.append(-1)

        # and choose those as new interpolation points
        # if not converged already.
        finished = True
        for idx in maximum_indices[1:]:
            if abs(errs[idx] - errs[maximum_indices[0]]) > tol:
                finished = False

        cn = [cn2[i] for i in maximum_indices]

    # plot approximation error for illustration
    plt.plot(cn2, abs(errs))
    plt.title("Plot of the approximation error")
    plt.xlabel('x')
    plt.ylabel('|poly_fit(x) - f(x)|')
    plt.show()
    return (max(abs(errs)), list(reversed(res[0:-1])))

if __name__ == "__main__":
    # the function to approximate
    def f(x):
       return math.sin(x)

    # f(x) is an odd function, so we can approximate it
    # using a polynomial of degree 2n+1
    odd = True
    even = False

    # approximate f(x) on the interval (a,b), where
    a = 0.
    b = math.pi

    # set the polynomial degree. If the function is even or odd, the polynomial
    # will be of degree `2*degree` or `2*degree + 1`, respectively.
    degree = 3

    # run Remez' algorithm
    err, coeffs = run_remez(f, a, b, degree, odd, even)

    # and output the coefficients & achieved approximation error
    oddEvenStr = ""
    if odd:
        oddEvenStr = " for odd powers of x"
    if even:
        oddEvenStr = " for even powers of x"

    print("Coefficients{}: {}".format(oddEvenStr, list(reversed(coeffs))))
    print("The polynomial achieves an L_inf error of {}.".format(err))


#!/bin/python
from random import randrange
from numpy import *

trainFile = array([list(map(lambda i: float(i), line.split(','))) for line in open('train_warfarin.csv', 'r')])
validationFile = array([list(map(lambda i: float(i), line.split(','))) for line in open('validation_warfarin.csv', 'r')])
testFile = array([list(map(lambda i: float(i), line.split(','))) for line in open('test_warfarin.csv', 'r')])

def cost(w, b, dataSet, labelSet):
	return average((labelSet - dot(w, dataSet) - b) ** 2)

def fileCost(file, result):
	return cost(result['w'], result['b'], file[:, 1:].transpose(), file[:, 0].transpose())

def analysys(file, rate):
	dataSet = file[:, 1:].transpose()
	labelSet = file[:, 0].transpose()
	initW = empty(dataSet.shape[0])
	initB = 0

	for count in range(100):
		half = labelSet - dot(initW, dataSet) - initB
		i = randrange(dataSet.shape[1])
		meta = dot(dataSet[:, i], half[i]) * 2 * rate

		initW += meta
		initB += average(half) * 2 * rate

	return {
		"w": initW,
		"b": initB,
		"cost": cost(initW, initB, dataSet, labelSet)
	}

def frange(start, stop, step):
	while start < stop:
		yield start
		start += step

bestRate = 0.01
bestResult = analysys(trainFile, bestRate)

for rate in frange(0.01, 0.25, 0.01):
	result = analysys(trainFile, rate)
	if fileCost(validationFile, result) < fileCost(validationFile, bestResult):
		bestResult = result
		bestRate = rate

print("Best learning rate: %s" % bestRate)
print("Trainning set error: %s" % bestResult['cost'])
print("Validation set error: %s" % fileCost(validationFile, bestResult))
print("Test set error: %s" % fileCost(testFile, bestResult))


import ransac.core as ransac
import math
import numpy as np

class Circle(ransac.Model):  # The input is a 2D point. The output is the distance from the circle
    def __init__(self, center=None, radius=None, zero_threshold=1e-6):
        super().__init__()
        self.center = center
        self.radius = radius
        self.zero_threshold = zero_threshold

    def Evaluate(self, x):  # Take an input variable x and return an output variable y
        distance_from_center = math.sqrt((x[0] - self.center[0])**2 + (x[1] - self.center[1])**2)
        return abs(distance_from_center - self.radius)  # Points located at a distance radius from the center will evaluate to 0.

    def Distance(self, y1, y2):  # Compute the distance between two output variables. Must return a float.
        return abs(y1 - y2)

    def Create(self, xy_tuples, **kwargs):  # Create a model with the given (x, y) observations
        if len(xy_tuples) < self.MinimumNumberOfDataToDefineModel():
            raise ValueError("Circle.Create(): len(xy_tuples) ({}) < {}".format(len(xy_tuples), self.MinimumNumberOfDataToDefineModel()))

        # (x - cx)^2 + (y - cy)^2 = r^2
        # (-2x) cx + (-2y) cy + (cx^2 + cy^2 - r^2) = -x^2 - y^2
        # | -2x   -2y    1 | | cx    |   | -x^2 - y^2 |
        # | ...            | | cy    | = | ...        |
        # | ...            | | gamma |   | ...        |
        # where gamma: = cx^2 + cy^2 - r^2

        A = np.zeros((len(xy_tuples), 3), dtype=float)
        b = np.zeros((len(xy_tuples), 1), dtype=float)
        for row in range(len(xy_tuples)):
            x0 = xy_tuples[row][0][0]
            x1 = xy_tuples[row][0][1]
            A[row, 0] = -2 * x0
            A[row, 1] = -2 * x1
            A[row, 2] = 1
            b[row, 0] = -x0**2 -x1**2
        z, residuals, rank, singular_values = np.linalg.lstsq(A, b, rcond=None)
        self.center = (z[0, 0], z[1, 0])
        self.radius = math.sqrt(self.center[0]**2 + self.center[1]**2 - z[2, 0])

    def MinimumNumberOfDataToDefineModel(self):  # The minimum number or (x, y) observations to define the model
        return 3


#!/usr/bin/env python

import random, sys
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from math import sqrt

inside = 0
piresults = {}
errorsize = {}
pi = np.pi
points = []

print ("\n" * 20)
print("****Welcome to Monte Carlo PI Simulator***")
print("Note: Simulating less than 1000 points will show a Cartesian Coordinate System with their locations.")
print("\n")

while True:
    try:
        total = int(input("How many points to generate: "))
    except ValueError:
        print("Sorry that's not a number.")
        continue
    if total == 0:
        print("Please try again with a number different from 0")
        continue

    if 10**7 <= total < 10**9:
        print("That may take a while!!!")
    elif total >= 10**9:
        print("Try with a smaller number of points")
        continue
    break

def set_window_geometry(x, y, z, k):
    mvr = plt.get_current_fig_manager()
    mvr.window.setGeometry(x, y, z, k)

if total<=10**3:
    plt.figure("Distribution")
    plt.title("Point distribution")
    set_window_geometry(800, 0, 700, 700)
    ax = plt.axes()
    ax.set_aspect(1)
    theta = np.linspace(-np.pi, np.pi, 200)
    plt.plot(np.sin(theta), np.cos(theta))
    plt.show(block=False)

def check_if_inside(x,y):
    if sqrt(x*x + y*y)<=1:
        return 1
    else:
        return 0

def estimate_pi(inside,total):
    return 4*inside/total

for i in range(1,total+1):
     x = random.uniform(-1, 1)
     y = random.uniform(-1, 1)
     inside += check_if_inside(x,y)
     points.append([x,y])

     if total<=10**3:
        plt.plot(x,y, 'or')

     if i<= 100 or i%(10**2) == 0:
         piest = estimate_pi(inside,i)
         piresults[i] = piest
         errorsize[i] = abs(pi-piest)
     if i%(2*(10**6)) == 0:
         print("Reached point %s"% i)

print("The final calculation for PI is:%s"%estimate_pi(inside,total))
print("The average calculated PI is %s"%(sum(piresults.values())/len(piresults)))

plt.figure("Absolute Difference")
plt.plot(list(errorsize.keys()), list(errorsize.values()))
mngr = plt.get_current_fig_manager()
set_window_geometry(0, 0, 700, 700)
plt.title("Abs difference from true PI")
plt.xlabel("Points")
plt.ylabel("Diff")
plt.show()

sys.exit()


from sympy import sin, cos, exp, cot, I, symbols

x, y, z, n = symbols("x,y,z,n")

def test_has():
    assert cot(x).has(x)
    assert cot(x).has(cot)
    assert not cot(x).has(sin)
    assert sin(x).has(x)
    assert sin(x).has(sin)
    assert not sin(x).has(cot)

def test_sin_exp_rewrite():
    assert sin(x).rewrite(sin, exp) == -I / 2 * (exp(I * x) - exp(-I * x))
    assert sin(x).rewrite(sin, exp).rewrite(exp, sin) == sin(x)
    assert cos(x).rewrite(cos, exp).rewrite(exp, cos) == cos(x)
    assert (sin(5 * y) - sin(2 * x)).rewrite(sin, exp).rewrite(exp, sin) == sin(
        5 * y
    ) - sin(2 * x)
    assert sin(x + y).rewrite(sin, exp).rewrite(exp, sin) == sin(x + y)
    assert cos(x + y).rewrite(cos, exp).rewrite(exp, cos) == cos(x + y)
    # This next test currently passes... not clear whether it should or not?
    assert cos(x).rewrite(cos, exp).rewrite(exp, sin) == cos(x)


import numpy as np
from numpy import cos, sin, sqrt, radians

from . import helpers

n = 100
angles = np.linspace(0, 360, n)
unit_x = np.array([1.0, 0.0, 0.0])
unit_y = np.array([0.0, 1.0, 0.0])
unit_z = np.array([0.0, 0.0, 1.0])

def test_rotation_x():
    """Unit tests for the roation-around-x matrix calculation
    Assumes right-hand rule. That means that, when viewed from positive infinity,
    positive angles mean a counter-clockwise rotation
    Cardinal matricies taken from the Wikipedia page
    https://en.wikipedia.org/wiki/Rotation_matrix#In_three_dimensions"""
    angle_90 = radians(90)
    angle_45 = radians(45)
    angle_30_minus = radians(-30)
    rotation_matrix_x_90 = helpers.rotate_around_x(angle_90)
    rotation_matrix_x_90_correct = np.array(
        [[1.0, 0.0, 0.0], [0.0, 0.0, -1.0], [0.0, 1.0, 0.0],]
    )
    assert np.allclose(
        rotation_matrix_x_90, rotation_matrix_x_90_correct, atol=1e-12, rtol=1e-12
    )
    # Should be accurate to floating point precision, i.e. around 1e-16

    rotation_matrix_x_45 = helpers.rotate_around_x(angle_45)
    rotation_matrix_x_45_correct = np.array(
        [
            [1.0, 0.0, 0.0],
            [0.0, cos(angle_45), -sin(angle_45)],
            [0.0, sin(angle_45), cos(angle_45)],
        ]
    )
    assert np.allclose(
        rotation_matrix_x_45, rotation_matrix_x_45_correct, atol=1e-12, rtol=1e-12
    )

    rotation_matrix_x_30 = helpers.rotate_around_x(angle_30_minus)
    rotation_matrix_x_30_correct = np.array(
        [
            [1.0, 0.0, 0.0],
            [0.0, cos(angle_30_minus), -sin(angle_30_minus)],
            [0.0, sin(angle_30_minus), cos(angle_30_minus)],
        ]
    )
    assert np.allclose(
        rotation_matrix_x_30, rotation_matrix_x_30_correct, atol=1e-12, rtol=1e-12
    )
    return

def test_rotation_z():
    """Unit tests for the roation-around-x matrix calculation
    Assumes right-hand rule. That means that, when viewed from positive infinity,
    positive angles mean a counter-clockwise rotation"""
    angle_90 = radians(90)
    angle_45 = radians(45)
    angle_30_minus = radians(-30)
    rotation_matrix_z_90 = helpers.rotate_around_z(angle_90)
    rotation_matrix_z_90_correct = np.array(
        [[0.0, -1.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0],]
    )
    assert np.allclose(
        rotation_matrix_z_90, rotation_matrix_z_90_correct, atol=1e-12, rtol=1e-12
    )
    # Should be accurate to floating point precision, i.e. around 1e-16

    rotation_matrix_z_45 = helpers.rotate_around_z(angle_45)
    rotation_matrix_z_45_correct = np.array(
        [
            [cos(angle_45), -sin(angle_45), 0.0],
            [sin(angle_45), cos(angle_45), 0.0],
            [0.0, 0.0, 1.0],
        ]
    )
    assert np.allclose(
        rotation_matrix_z_45, rotation_matrix_z_45_correct, atol=1e-12, rtol=1e-12
    )

    rotation_matrix_z_30 = helpers.rotate_around_z(angle_30_minus)
    rotation_matrix_z_30_correct = np.array(
        [
            [cos(angle_30_minus), -sin(angle_30_minus), 0.0],
            [sin(angle_30_minus), cos(angle_30_minus), 0.0],
            [0.0, 0.0, 1.0],
        ]
    )
    assert np.allclose(
        rotation_matrix_z_30, rotation_matrix_z_30_correct, atol=1e-12, rtol=1e-12
    )
    return

def test_forward_transformation():
    """Integration tests for the mass rotation case, i.e. `rotate_to_dashed_frame`"""

    # verify that unit vectors are correctly rotated around a single axis
    # Reminder: theta is angle around Z-axis, phi is angle around X axis
    # Reminder: right-hand convention throughout
    #    i.e. rotation around an axis by a postive angle is counter-clockwise
    #    when viewed from positive infinity on that axis
    assert np.allclose(
        helpers.rotate_to_dashed_frame(unit_y, theta=radians(90), phi=0),
        -1 * unit_x,
        atol=1e-12,
        rtol=1e-12,
    )
    assert np.allclose(
        helpers.rotate_to_dashed_frame(unit_y, theta=radians(-90), phi=0),
        unit_x,
        atol=1e-12,
        rtol=1e-12,
    )
    assert np.allclose(
        helpers.rotate_to_dashed_frame(unit_y, theta=radians(45), phi=0),
        np.array([-1 / sqrt(2), 1 / sqrt(2), 0]),
        atol=1e-12,
        rtol=1e-12,
    )
    assert np.allclose(
        helpers.rotate_to_dashed_frame(unit_x, theta=radians(90), phi=0),
        unit_y,
        atol=1e-12,
        rtol=1e-12,
    )
    assert np.allclose(
        helpers.rotate_to_dashed_frame(unit_x, theta=radians(30), phi=0),
        np.array([cos(radians(30)), sin(radians(30)), 0]),
        atol=1e-12,
        rtol=1e-12,
    )

    assert np.allclose(
        helpers.rotate_to_dashed_frame(unit_y, theta=0, phi=radians(90)),
        unit_z,
        atol=1e-12,
        rtol=1e-12,
    )
    assert np.allclose(
        helpers.rotate_to_dashed_frame(unit_y, theta=0, phi=radians(45)),
        np.array([0, 1 / sqrt(2), 1 / sqrt(2)]),
        atol=1e-12,
        rtol=1e-12,
    )

    # All rotations of unit_x or -unit_x, around X, should always have no effect
    # Likewise, all rotations of unit_z around Z, should alwaus have no effect
    for angle in radians(angles):
        assert np.array_equal(
            unit_x, helpers.rotate_to_dashed_frame(unit_x, theta=0, phi=angle)
        )
        assert np.array_equal(
            -unit_x, helpers.rotate_to_dashed_frame(-unit_x, theta=0, phi=angle)
        )
        assert np.array_equal(
            unit_z, helpers.rotate_to_dashed_frame(unit_z, theta=angle, phi=0)
        )
        assert np.array_equal(
            -unit_z, helpers.rotate_to_dashed_frame(-unit_z, theta=angle, phi=0)
        )

    # Verify that unit vectors are correctly rotated around two axes
    # This is where things are most likely to go wrong.
    # The transformation is defined as "first rotate around X, then rotate around Z".

    # This follows the two examples given in the docstring of rotate_to_dashed_frame,
    # i.e. unit_y, theta=90, phi=45
    # rotation 1a should be 1/sqrt(2) (0, 1, 1)
    # rotation 2a should be 1/sqrt(2) (-1, 0, 1)
    # rotation_1b and rotation_2b should be (-1, 0, 0)
    theta = radians(90)
    phi = radians(45)
    rotation_1a = helpers.rotate_to_dashed_frame(unit_y, theta=0, phi=phi)
    rotation_2a = helpers.rotate_to_dashed_frame(rotation_1a, theta=theta, phi=0)
    combined = helpers.rotate_to_dashed_frame(unit_y, theta=theta, phi=phi)

    rotation_1b = helpers.rotate_to_dashed_frame(unit_y, theta=theta, phi=0)
    rotation_2b = helpers.rotate_to_dashed_frame(rotation_1b, theta=0, phi=phi)

    assert np.allclose(
        rotation_1a, 1 / sqrt(2) * (unit_y + unit_z), atol=1e-12, rtol=1e-12
    )
    assert np.allclose(
        rotation_2a, 1 / sqrt(2) * (-unit_x + unit_z), atol=1e-12, rtol=1e-12
    )
    assert np.array_equal(rotation_2a, combined)

    assert not np.allclose(rotation_2b, combined, atol=1e-12, rtol=1e-12)
    assert not np.allclose(rotation_1b, rotation_1a, atol=1e-12, rtol=1e-12)
    assert np.allclose(rotation_1b, rotation_2b, atol=1e-12, rtol=1e-12)
    assert np.allclose(rotation_1b, -unit_x, atol=1e-12, rtol=1e-12)

    # And test a more complicated object, i.e. not a unit vector, not normalised
    # Begin with (1,1,1), and perform the same rotation
    # Rotation 1 (45° around X) should rotates into the YXZ plane, to (1,0, 1.414)
    # Rotation 2 (90° around Z) should rotate into the YZ plane to (0, 1, 1.414)
    theta = radians(90)
    phi = radians(45)
    unit = unit_x + unit_y + unit_z  # i.e. (1,1,1)
    rotation_1 = helpers.rotate_to_dashed_frame(unit, theta=0, phi=phi)
    rotation_2 = helpers.rotate_to_dashed_frame(rotation_1, theta=theta, phi=0)
    combined = helpers.rotate_to_dashed_frame(unit, theta=theta, phi=phi)

    assert np.allclose(rotation_1, (1, 0, sqrt(2)), atol=1e-12, rtol=1e-12)
    assert np.allclose(rotation_2, (0, 1, sqrt(2)), atol=1e-12, rtol=1e-12)
    assert np.allclose(rotation_2, combined, atol=1e-12, rtol=1e-12)

    return

def test_inverse_transformation():
    """Integration tests to ensure that the reverse transform, i.e.
    `rotate_to_normal_frame` always reverses the forward transform.

    For every possible angle, the effect of (forward, reverse) should always be
    to return the input, accurate to floating-point precision"""
    inputs = (unit_x, unit_y, unit_z, (2 * unit_x + 2.5 * unit_y - 0.3 * unit_z))
    for inp in inputs:
        for theta in radians(angles):
            for phi in radians(angles):
                forward = helpers.rotate_to_dashed_frame(inp, theta, phi)
                reverse = helpers.rotate_to_normal_frame(forward, theta, phi)
                assert np.allclose(inp, reverse, atol=1e-9, rtol=1e-9)
    return

def test_evaluate_axis_projection():
    """Unit tests for converting projection strings"""

    values = [
        ("x", (0, 2, 1)),
        ("xy", (0, 1, 2)),
        ("xyz", (0, 1, 2)),
        ("xz", (0, 2, 1)),
        ("yxz", (1, 0, 2)),
    ]
    for value in values:
        assert helpers.evaluate_axis_projection(value[0]) == value[1], value[0]
    return


import numpy as np
import math

_FLOAT_EPS_4 = np.finfo(float).eps * 4.0

def QuatSum(Q, R):
	T = [0, 0, 0, 0]
	T[0] = Q[0] + R[0]
	T[1] = Q[1] + R[1]
	T[2] = Q[2] + R[2]
	T[3] = Q[3] + R[3]

	return T

def QuatMultiply(Q, R):
    T = [0, 0, 0, 0]
    Qs = Q[0]
    Qv = np.array(Q[1:4])
    Rs = R[0]
    Rv = np.array(R[1:4])
    T[0] = Qs*Rs - np.dot(Qv,Rv)
    T[1:4] = Qs*Rv + Rs*Qv + np.cross(Qv,Rv)

    return T

def QuatConjugate(Q):
	T = [0, 0, 0, 0]
	Qs = Q[0]
	Qv = np.array(Q[1:4])

	T[0] = Qs
	T[1:4] = -Qv
	return T

def QuatNorm(Q):
	T = Q[0]**2 + Q[1]**2 + Q[2]**2 + Q[3]**2
	return T

def NormalizeQuat(Q):
	T = [0,0,0,0]
	T = Q
	QN = QuatNorm(np.array(Q))
	if(QN>0):
		T = np.array(Q)/math.sqrt(QN)

	return T

def QuatInverse(Q):
    T = QuatConjugate(Q)

    T[0] = float(T[0])/float(QuatNorm(Q))
    T[1] = float(T[1])/float(QuatNorm(Q))
    T[2] = float(T[2])/float(QuatNorm(Q))
    T[3] = float(T[3])/float(QuatNorm(Q))

    return T

def QuatLog(Q):
	T = [0, 0, 0, 0]
	Qv = np.array(Q[1:4])
	if (np.linalg.norm(Q) > 0):
		T[0] = np.log(math.sqrt(QuatNorm(Q)))
	if (np.linalg.norm(Qv) > 0):
		T[1:4] = (Qv/np.linalg.norm(Qv))*math.acos(Q[0]/math.sqrt(QuatNorm(Q)))

	return T

def QuatExp(Q):
	T = [0, 0, 0, 0]
	H = [0, 0, 0, 0]
	Qs = Q[0]
	Qv = np.array(Q[1:4])
	Scalar = math.exp(Qs)
	QN = math.sqrt(Qv[0]**2 + Qv[1]**2 + Qv[2]**2)
	T[0] = Scalar*math.cos(QN)
	if(QN>0):
		H[1:4] = Scalar*math.sin(QN)*Qv/QN
		if(H[1].shape == ()):
			T[1:4] = H[1:4]
		else:
			T[1] = H[1][0]
			T[2] = H[1][1]
			T[3] = H[1][2]

	return T

def Quat2Rot(Q):
    w, x, y, z = Q
    QN = QuatNorm(Q)
    if np.all(QN < _FLOAT_EPS_4):
        return np.eye(3)
    s = 2.0 / QN
    X = x * s
    Y = y * s
    Z = z * s
    wX, wY, wZ = w * X, w * Y, w * Z
    xX, xY, xZ = x * X, x * Y, x * Z
    yY, yZ, zZ = y * Y, y * Z, z * Z
    return np.array([[1.0 - (yY + zZ), xY - wZ, xZ + wY],
                     [xY + wZ, 1.0 - (xX + zZ), yZ - wX],
                     [xZ - wY, yZ + wX, 1.0 - (xX + yY)]])

def Rot2Quat(M):
    Qxx, Qyx, Qzx, Qxy, Qyy, Qzy, Qxz, Qyz, Qzz = M.flat

    K = np.array([
        [Qxx - Qyy - Qzz, 0, 0, 0],
        [Qyx + Qxy, Qyy - Qxx - Qzz, 0, 0],
        [Qzx + Qxz, Qzy + Qyz, Qzz - Qxx - Qyy, 0],
        [Qyz - Qzy, Qzx - Qxz, Qxy - Qyx, Qxx + Qyy + Qzz]]
    ) / 3.0

    vals, vecs = np.linalg.eigh(K)
    Q = vecs[[3, 0, 1, 2], np.argmax(vals)]

    if Q[0] < 0:
        Q *= -1
    return Q

def RotVector(V, Q):
    Vec = np.zeros((4,))
    Vec[1:] = V
    return QuatMultiply(Q, QuatMultiply(Vec, QuatConjugate(Q)))[1:]

def Euler2Rot(x=0, y=0, z=0):
    Ms = []
    if z:
        cosz = math.cos(z)
        sinz = math.sin(z)
        Ms.append(np.array(
                [[cosz, -sinz, 0],
                 [sinz, cosz, 0],
                 [0, 0, 1]]))
    if y:
        cosy = math.cos(y)
        siny = math.sin(y)
        Ms.append(np.array(
                [[cosy, 0, siny],
                 [0, 1, 0],
                 [-siny, 0, cosy]]))
    if x:
        cosx = math.cos(x)
        sinx = math.sin(x)
        Ms.append(np.array(
                [[1, 0, 0],
                 [0, cosx, -sinx],
                 [0, sinx, cosx]]))
    if Ms:
        return reduce(np.dot, Ms[::-1])
    return np.eye(3)

def Rot2Euler(M, cy_thresh=None):
    M = np.asarray(M)
    if cy_thresh is None:
        try:
            cy_thresh = np.finfo(M.dtype).eps * 4
        except ValueError:
            cy_thresh = _FLOAT_EPS_4
    r11, r12, r13, r21, r22, r23, r31, r32, r33 = M.flat
    cy = math.sqrt(r33*r33 + r23*r23)
    if cy > cy_thresh: # cos(y) not close to zero, standard form
        z = math.atan2(-r12,  r11) # atan2(cos(y)*sin(z), cos(y)*cos(z))
        y = math.atan2(r13,  cy) # atan2(sin(y), cy)
        x = math.atan2(-r23, r33) # atan2(cos(y)*sin(x), cos(x)*cos(y))
    else:
        z = math.atan2(r21,  r22)
        y = math.atan2(r13,  cy) # atan2(sin(y), cy)
        x = 0.0
    return x,y,z

def Euler2Quat( x=0, y=0, z=0 ):
    z = z/2.0
    y = y/2.0
    x = x/2.0
    cz = math.cos(z)
    sz = math.sin(z)
    cy = math.cos(y)
    sy = math.sin(y)
    cx = math.cos(x)
    sx = math.sin(x)
    return np.array([
             cx*cy*cz - sx*sy*sz,
             cx*sy*sz + cy*cz*sx,
             cx*cz*sy - sx*cy*sz,
             cx*cy*sz + sx*cz*sy])

def Quat2Euler(Q):
    return Rot2Euler(Quat2Rot(Q))

def quaternion_to_rotation(q):
	assert isinstance(q, np.ndarray), 'q must be of type numpy.ndarray'
	assert len(q.shape) == 1, 'function only accepts singular quaternions'
	assert len(q) == 4, 'a quaternion must have 4 elements'

	if np.array_equal(q, np.array([1, 0, 0, 0])):
		return np.zeros((3, 1))

	w0 = 2 * np.array(QuatLog(q))

	return w0[1:]

def rotation_to_quaternion(w):
	vector = [0,0,0,0]
	vector[1:4] = w
	q = np.array(QuatExp(np.array(vector)/2))

	return q

def RotVel2Quat(W, dt):
	x = np.array([0,0,0,0],dtype=np.float64)
	x[1:] = np.array(W)*dt

	Q = QuatExp(x)

	return Q

def RotVel2QuatIntagration(W, dt):
	Q = [0,0,0,0]
	angle = np.linalg.norm(np.array(W))
	axis = [0,0,0]
	if (angle>0):
		axis = np.array(W)/angle
	Q[0] = math.cos(angle*dt/2)
	Q[1:4] = np.array(axis)*math.sin(angle*dt/2)
	return Q

def QuatAve(Q, Qguess, alphas):
	'''
	INPUTS:::
		Q					:=	Quaternions vectors to average
		Qguess				:=	Initial guess for average
		alphas				:=	Weight vector for averaging
	OUTPUTS:::
		Qguess				:=	Predicted Quaternion Average of Q
		Covar				:=	Error Covariance
		EviMod				:=	Error vectors
	'''
	numQuats = len(Q)
	D = 3
	EviMod = np.zeros((numQuats, 3))
	EviHold = np.zeros((numQuats, 3))

	Covar = np.zeros((3, 3))
	C = float(1)/(2*D)
	EvNORM = 1
	guessQuat = [0,0,0,0]
	#print "going into algorithm"
	while (EvNORM > 0.0001):
		EviMod = np.zeros((numQuats, 3))
		EviHold = np.zeros((numQuats, 3))
		for i in range(numQuats):
			Qt = QuatMultiply(QuatInverse(Qguess), Q[i])
			Evi = np.array([0,0,0,0])
			Evi = 2*np.array(QuatLog(Qt))
			QN = math.sqrt(Evi[1]**2 + Evi[2]**2 + Evi[3]**2)
			if(QN>0):
				EviMod[i,:] = (-math.pi + (QN + math.pi)%(2*math.pi))*np.array([Evi[1],Evi[2],Evi[3]])/QN

		for i in range(numQuats):
			EviHold[i,:] = EviMod[i,:]*alphas[i]

		Ev = np.sum(EviHold, axis=0)
		guessQuat[1:4] = Ev
		Qguess = QuatMultiply(Qguess, QuatExp(np.array(guessQuat)/2.0))
		EvNORM = math.sqrt(Ev[0]**2 + Ev[1]**2 + Ev[2]**2)
		#print "Norm of Ev: ", EvNORM

	Covar += np.array(2*np.outer(EviMod[0,:], EviMod[0,:]))
	for i in range(1,numQuats):
		Covar += np.array((float(1)/6.0)*np.outer(EviMod[i,:],EviMod[i,:]))

	return Qguess, EviMod, Covar


# -*- coding: utf-8 -*-
"""
@Title:
    Gauss Quadrature Rules

@author:
    Ehsan Kharazmi
    Division of Applied Mathematics
    Brown University
    ehsan_kharazmi@brown.edu

Created on Fri Apr 12 15:06:19 2019
"""

import numpy as np
from scipy.special import gamma
from scipy.special import jacobi
from scipy.special import roots_jacobi
#from scipy.special import legendre
#import matplotlib.pyplot as plt

##################################################################
# Recursive generation of the Jacobi polynomial of order n
def Jacobi(n,a,b,x):
    x=np.array(x)
    return (jacobi(n,a,b)(x))

##################################################################
# Derivative of the Jacobi polynomials
def DJacobi(n,a,b,x,k: int):
    x=np.array(x)
    ctemp = gamma(a+b+n+1+k)/(2**k)/gamma(a+b+n+1)
    return (ctemp*Jacobi(n-k,a+k,b+k,x))

##################################################################
# Weight coefficients
def GaussJacobiWeights(Q: int,a,b):
    [X , W] = roots_jacobi(Q,a,b)
    return [X, W]

##################################################################
# Weight coefficients
def GaussLobattoJacobiWeights(Q: int,a,b):
    W = []
    X = roots_jacobi(Q-2,a+1,b+1)[0]
    if a == 0 and b==0:
        W = 2/( (Q-1)*(Q)*(Jacobi(Q-1,0,0,X)**2) )
        Wl = 2/( (Q-1)*(Q)*(Jacobi(Q-1,0,0,-1)**2) )
        Wr = 2/( (Q-1)*(Q)*(Jacobi(Q-1,0,0,1)**2) )
    else:
        W = 2**(a+b+1)*gamma(a+Q)*gamma(b+Q)/( (Q-1)*gamma(Q)*gamma(a+b+Q+1)*(Jacobi(Q-1,a,b,X)**2) )
        Wl = (b+1)*2**(a+b+1)*gamma(a+Q)*gamma(b+Q)/( (Q-1)*gamma(Q)*gamma(a+b+Q+1)*(Jacobi(Q-1,a,b,-1)**2) )
        Wr = (a+1)*2**(a+b+1)*gamma(a+Q)*gamma(b+Q)/( (Q-1)*gamma(Q)*gamma(a+b+Q+1)*(Jacobi(Q-1,a,b,1)**2) )
    W = np.append(W , Wr)
    W = np.append(Wl , W)
    X = np.append(X , 1)
    X = np.append(-1 , X)
    return [X, W]
##################################################################


import numpy as np

def tridiagonal(A, f):
    n = len(A)
    a = np.zeros(n)
    b = np.zeros(n - 1)
    c = np.zeros(n - 1)
    d = f.copy()
    a = A.diagonal().copy()
    b = A.diagonal(offset=1).copy()
    c = A.diagonal(offset=-1).copy()
    for i in range(n-1):
        b[i] = b[i] / a[i]
        a[i + 1] = a[i + 1] - c[i] * b[i]
    d[0] = d[0] / a[0]
    for j in range(1, n):
        d[j] = (d[j] - c[j-1] * d[j - 1]) / a[j]
    for k in range(n - 2, -1, -1):
        d[k] = d[k] - b[k] * d[k + 1]

    return d

#def LUbandmatrix(A, r, s):
#    n = A.shape[1]
#    m = r+s+1

A = [[8., -1., 0., 0., 0.],
     [2., 8., 1., 0., 0.],
     [0., 1., 8., -1., 0.],
     [0., 0., 2., 8., 1.],
     [0., 0., 0., 1., 8.]]
A = np.array(A)
b = [2.2, -2.54, 8.26, 8.32, -4.3]
b = np.array(b)
print(tridiagonal(A, b))
LUbandmatrix(A,1,1)


import numpy as np

def mean_square_error(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate MSE loss

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    MSE of given predictions
    """
    return float(np.mean(((y_true - y_pred) ** 2)))

def misclassification_error(y_true: np.ndarray, y_pred: np.ndarray, normalize: bool = True) -> float:
    """
    Calculate misclassification loss

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values
    normalize: bool, default = True
        Normalize by number of samples or not

    Returns
    -------
    Misclassification of given predictions
    """
    # num_of_mistakes, num_of_samples = 0, y_true.shape[0]
    # for i in range(num_of_samples):
    #     if y_true[i] != y_pred[i]:
    #         num_of_mistakes += 1
    # if normalize:
    #     return num_of_mistakes / num_of_samples
    # return num_of_mistakes
    num_of_samples = y_true.shape[0]
    loss = np.sum(np.where(y_true != y_pred, 1, 0))
    if normalize:
        return loss / num_of_samples
    return float(loss)

def accuracy(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate accuracy of given predictions

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    Accuracy of given predictions
    """
    # true_predictions, num_of_samples = 0, y_true.shape[0]
    # for i in range(num_of_samples):
    #     if y_pred[i] == y_true[i]:
    #         true_predictions += 1
    # return true_predictions / num_of_samples
    return np.sum(np.where(y_true == y_pred, 1, 0)) / y_true.shape[0]

def cross_entropy(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate the cross entropy of given predictions

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    Cross entropy of given predictions
    """
    raise NotImplementedError()


import numpy
import matplotlib
import matplotlib.pyplot as plt

# Load the data
errors = numpy.loadtxt('errors.txt')
resolutions = numpy.loadtxt('resolutions.txt')

# Plot the errors
plt.loglog(resolutions, errors, "-o", label='$\\max_{i,j}\{|u(x_i,y_j)-U_{i,j}|\}$')

# Now we want to approximate the convergence rate
convergencePolynomial = numpy.polyfit(numpy.log(resolutions), numpy.log(errors), 1)
plt.loglog(resolutions, numpy.exp(convergencePolynomial[1])*resolutions**convergencePolynomial[0], '--', label='$\mathcal{O}(N^{%.2f})$' % convergencePolynomial[0])
plt.legend()
plt.xlabel('$N$')
plt.ylabel('Error')
plt.grid('on')
plt.show()


import numpy as np

def inverse(A):
    return np.linalg.inv(A)

def eigen_decom(A):
    return np.linalg.eig(A)

"""
Frobenius normalization
"""
def norml21(A):
    row, col= A.shape
    l=[0 for j in range(col)]
    for j in range(col):
        s=0
        for i in range(row):
            s+=A[i][j]**2
        l[j]=s**0.5
    return np.array(l)

def converge(L1,L2):
    return np.array_equal(L1,L2)

"""
R: 3D array
    R is a three dimensional list
    Each matrix in R represents observations from different view
    Column of each matrix represents attributes of vth view and
    Row of each matrix represents different objects

d: int
    Dimension of the common representation

neta: float
      Regularization parameter

maxIter1: int
            Maximum iteration number

maxIter2: int
            Maximum iteration number
"""

def l21_cca(R, d=1, neta=1, maxIter1=1, maxIter2=1):
    R=np.array(R)
    v=R.shape[0]
    A=[Xv/neta-np.identity(Xv.shape[0]) for Xv in R]
    D=[np.identity(Xv.shape[0]) for Xv in R]
    Q=[0 for i in range(v)]
    for i in range(v):
        T1=np.dot(inverse(D[i]),A[i].T)
        Q[i]=np.dot(T1, inverse(np.dot(A[i],T1)))
    T1=[0 for i in range(v)]
    for i in range(v):
        T2=np.dot(Q[i].T, D[i])
        T1[i]=np.dot(T2,Q[i])
    B=sum(T1)
    Uo=eigen_decom(B)[1]
    Fo=[0 for i in range(v)]
    F=[0 for i in range(v)]
    for p in range(maxIter1):
        for q in range(maxIter2):
            for i in range(v):
                T1=np.dot(inverse(D[i]),A[i].T)
                T2=inverse(np.dot(A[i],T1))
                T3=np.dot(T1,T2)
                F[i]=np.dot(T3,Uo)
                T1=2*norml21(F[i])
                T1=1/T1
                D[i]=np.diag(T1)
                #D[i]=inverse(np.diag(T1))
            if converge(F,Fo):
                break
        Fo=F
        T1=[0 for i in range(v)]
        for i in range(v):
            T2=np.dot(Q[i].T, D[i])
            T1[i]=np.dot(T2,Q[i])
        B=sum(T1)
        T1=eigen_decom(B)
        dic={j:i for i,j in enumerate(T1[0])}
        T1=T1[1]
        U=[0 for i in range(d)]
        count=0
        for i in sorted(dic.keys()):
            U[count]=T1[:,dic[i]]
            count+=1
            if count==d:
                break
        U=np.array(U)
        U=U.T
        if converge(U,Uo):
            break
        Uo=U
    return U


import numpy as np
from sklearn.decomposition import PCA, TruncatedSVD
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.impute import SimpleImputer

from dffml.df.base import op

from .definitions import (
    n_iter,
    strategy,
    input_data,
    categories,
    output_data,
    random_state,
    n_components,
    missing_values,
)

@op(
    inputs={"data": input_data, "n_components": n_components},
    outputs={"result": output_data},
)
async def principal_component_analysis(
    data, n_components=None,
):
    """
    Decomposes the data into (n_samples, n_components)
    using PCA method

    Parameters
    ----------
    data : List[List[int]]
        data to be decomposed.

    n_components : int
        number of colums the data should have after decomposition.

    Returns
    -------
    result: Data having dimensions (n_samples, n_components)
    """
    pca = PCA(n_components=n_components)
    new_data = pca.fit_transform(data)
    return {"result": new_data}

@op(
    inputs={
        "data": input_data,
        "n_components": n_components,
        "n_iter": n_iter,
        "random_state": random_state,
    },
    outputs={"result": output_data},
)
async def singular_value_decomposition(
    data, n_components=2, n_iter=5, random_state=None,
):
    """
    Decomposes the data into (n_samples, n_components)
    using SVD method.

    Parameters
    ----------
    data : List[List[int]]
        data to be decomposed.

    n_components : int
        number of colums the data should have after decomposition.

    Returns
    -------
    result: Data having dimensions (n_samples, n_components)
    """
    svd = TruncatedSVD(
        n_components=n_components, n_iter=n_iter, random_state=random_state
    )
    new_data = svd.fit_transform(data)
    return {"result": new_data}

@op(
    inputs={
        "data": input_data,
        "missing_values": missing_values,
        "strategy": strategy,
    },
    outputs={"result": output_data},
)
async def simple_imputer(data, missing_values=np.nan, strategy="mean"):
    """
    Imputation method for missing values

    Parameters
    ----------
    data : List[List[int]]
        data in which missing values are present

    missing_values : Any str, int, float, None default = np.nan
        The value present in place of missing value

    strategy : str "mean", "median", "constant", "most_frequent" default = "mean"
        The value present in place of missing value

    Returns
    -------
    result: Dataset having missing values imputed with the strategy
    """
    if missing_values not in (int, float, str, None, np.nan):
        raise Exception(
            f"Missing values should be one of: str, float, int, None, np.nan got {missing_values}"
        )

    if strategy not in ("mean", "median", "constant", "most_frequent"):
        raise Exception(
            f"Strategy should be one of mean, median, constant, most_frequent got {strategy}"
        )

    imp = SimpleImputer(missing_values=missing_values, strategy=strategy)
    new_data = imp.fit_transform(data)
    return {"result": new_data}

@op(
    inputs={"data": input_data, "categories": categories},
    outputs={"result": output_data},
)
async def one_hot_encoder(data, categories):
    """
    One hot encoding for categorical data columns

    Parameters
    ----------
    data : List[List[int]]
        data to be encoded.

    categories : List[List[str]]
        Categorical values which needs to be encoded

    Returns
    -------
    result: Encoded data for categorical values
    """
    enc = OneHotEncoder(categories=categories)
    enc.fit(data)
    new_data = enc.transform(data).toarray()
    return {"result": new_data}

@op(inputs={"data": input_data}, outputs={"result": output_data})
async def standard_scaler(data):
    """
    Standardize features by removing the mean and
    scaling to unit variance.

    Parameters
    ----------
    data: List[List[int]]
        data that needs to be standardized

    Returns
    -------
    result: Standardized data
    """
    scaler = StandardScaler()
    new_data = scaler.fit_transform(data)
    return {"result": new_data.tolist()}

@op(
    inputs={"data": input_data}, outputs={"result": output_data},
)
async def remove_whitespaces(data):
    """
    Removes white-spaces from the dataset

    Parameters
    ----------
    data : List[List[int]]
        dataset.

    Returns
    -------
    result: dataset having whitespaces removed
    """
    new_data = np.char.strip(data)
    return {"result": new_data}

@op(
    inputs={"data": input_data}, outputs={"result": output_data},
)
async def ordinal_encoder(data):
    """
    One hot encoding for categorical data columns

    Parameters
    ----------
    data : List[List[int]]
        data to be encoded.

    categories : List[List[str]]
        Categorical values which needs to be encoded

    Returns
    -------
    result: Encoded data for categorical values
    """
    enc = OneHotEncoder()
    enc.fit(data)
    new_data = enc.transform(data).toarray()
    return {"result": new_data}