from utils import r
from sympy import lambdify, latex

def rk4(f, h, x0, y0, iterations=2, i=1):
    out_str = f"\\textbf{{Iteration {i}}}\n"
    out_str += f'($x_{i-1}$, $y_{i-1}$) = ({r(x0)}, {r(y0)})\n\n'

    out_str += f'$$ y_{i} = y_{i-1} + \\frac{{1}}{{6}}\\left[k_1+2k_2+2k_3+k_4\\right]h $$\n'
    out_str += 'Where,\n'
    out_str += f'$$ k_1 = f(x_{i-1}, y_{i-1}) $$\n'
    out_str += f'$$ k_2 = f(x_{i-1}+\\frac{{1}}{{2}}h, y_{i-1}+\\frac{{1}}{{2}}k_1h) $$\n'
    out_str += f'$$ k_3 = f(x_{i-1}+\\frac{{1}}{{2}}h, y_{i-1}+\\frac{{1}}{{2}}k_2h) $$\n'
    out_str += f'$$ k_4 = f(x_{i-1}+h, y_{i-1}+k_3h) $$\n\n'

    x, y = symbols('x y')
    fn = lambdify((x, y), f)
    k1 = fn(x0, y0)
    k2 = fn(x0+1/2*h, y0+1/2*k1*h)
    k3 = fn(x0+1/2*h, y0+1/2*k2*h)
    k4 = fn(x0+h, y0+k3*h)
    y2 = y0 + 1/6*(k1+2*k2+2*k3+k4)*h

    out_str += f'$$ k_1 = f({r(x0)}, {r(y0)}) = {latex(f)} = {r(k1)} $$\n'
    out_str += f'$$ k_2 = f\\left({r(x0)}+\\frac{{1}}{{2}}({h}), {r(y0)}+\\frac{{1}}{{2}}({r(k1)})({h})\\right) = {latex(f)} = {r(k2)} $$\n'
    out_str += f'$$ k_3 = f\\left({r(x0)}+\\frac{{1}}{{2}}({h}), {r(y0)}+\\frac{{1}}{{2}}({r(k2)})({h})\\right) = {latex(f)} = {r(k3)} $$\n'
    out_str += f'$$ k_4 = f\\left({r(x0)}+({h}), {r(y0)}+({r(k3)})({h})\\right) = {latex(f)} = {r(k4)} $$\n'

    out_str += f'\n Substituting values\n'
    out_str += f'$$ y_{i} = {r(y0)} + \\frac{{1}}{{6}}\\left[{r(k1)}+2({r(k2)})+2({r(k3)})+{r(k4)}\\right]({r(h)}) = {r(y2)} $$\n'

    out_str += f'\n$$ (x_{i}, y_{i}) = ({r(h+x0)}, {r(y2)}) $$\n'

    if iterations > 1:
        out_str += rk4(f, h, h+x0, y2, iterations-1, i+1)

    return out_str

if __name__ == '__main__':
    from sympy import symbols

    x, y = symbols('x y')
    print(rk4((x+0-y)/2, 0.2, 0, 1, 2))


'''
Logarithm Curve
@ author: Suyash Shivaji Phatak
Date = 25\04\2020
'''

# Defining Modules
import numpy as np
import matplotlib.pyplot as plt

# Taking input from user
range_for_log = int(input('\nEnter a range of numbers for logarithm with base 2,10 & e: '))

# Log with base 2

# Setting x
x = np.arange(1, range_for_log)

# Setting y fo base 2
y1 = np.log2(x)

# Setting y for base 10
y2 = np.log10(x)

# Setting y for base e
y3 = np.log(x)

# Plotting Points
plt.plot(x,y1, label='Log With Base 2')
plt.plot(x,y2, label='Log With Base 10')
plt.plot(x,y3, label='Log With Base e')
# Seperating figure
plt.figure(1)

# Naming the x axis
plt.xlabel('X')

# Naming the y axis
plt.ylabel('Y')

# Giving a title to graph
plt.title('Logarithm Function')

# Showing legend
plt.legend()
# Function to show the plot
plt.show()


import numpy as np

def camel_hump_six_old(x1, x2):
    x1_2 = np.square(x1)
    x1_4 = np.square(x1_2)
    x2_2 = np.square(x2)
    term1 = (4.0 - 2.1 * x1_2 + x1_4 / 3.0) * x1_2
    # term1 = term1*x1_2
    prod = x1 * x2
    term2 = (4.0 * x2_2 - 4) * x2_2
    # term2 = term2*x2_2
    fx = term1 + prod + term2
    return fx

def camel_hump_six(xx):
    """
    minima: -1.03316 for
    Range: [-3, 3, -2, 2]
    :param xx: minimum x = (0.0898, -0.7126), (-0.0898, 0.7126)
    :return: function value
    """
    x1_2 = np.square(xx[0])
    x1_4 = np.square(x1_2)
    x2_2 = np.square(xx[1])
    term1 = (4.0 - 2.1 * x1_2 + x1_4 / 3.0) * x1_2
    # term1 = term1*x1_2
    prod = xx[0] * xx[1]
    term2 = (4.0 * x2_2 - 4) * x2_2
    # term2 = term2*x2_2
    fx = term1 + prod + term2
    return fx

def f(x, y):
    return np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)

def rastringin(x1, x2, n=2, A=0.5):

    def calc(x):
        return np.square(x) - A * np.cos(2 * np.pi * x)

    fx = A * n + calc(x1) + calc(x2)
    return fx

def rastringin_gen(xx, n=2, A=10):
    """
    optimum is at 0.0 when all xx = 0
    range:  [-5.11, 5.11, -5.11, 5.11, ...]
    :param xx: array of input variables
    :param n:  number of input variables
    :param A:
    :return: function value
    """
    def calc(xv):
        return np.square(xv) - A * np.cos(2 * np.pi * xv)

    summation = 0
    for x in xx:
        summation += calc(x)
    fx = A * n + summation
    return fx


'''
Linear Regression by SVD on TensorFlow
Author: Rowel Atienza
Project: https://github.com/roatienza/Deep-Learning-Experiments
'''
# On command line: python3 linear_inv.py
# Prerequisite: tensorflow 1.0 (see tensorflow.org)
#             : matplotlib (http://matplotlib.org/)

from __future__ import print_function

import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import numpy as np

# Tunable parameters (Try changing the values and see what happens)
# Variable samples >= 3 ; stddev > 0.; xcoeff are real numbers
samples = 100
stddev = 1.0
# xcoeff should be predicted by solving y = A*x using SVD; try changing the values
xcoeff = tf.transpose(tf.constant([[2., -3.5, 12.5]]))

# The computation
# We get elements of A by sampling a normal distribution
a = tf.Variable(tf.random_normal([1, samples],stddev=stddev))
# Sort to produce a nice plot later
b, _ = tf.nn.top_k(a,k=samples)
# Correct the shape
a = tf.reshape(b,[samples,1])

# Inputs to form y = a*a*xcoeff[0] + a*xcoeff[1] + xcoeff[2]
A = tf.concat([tf.concat([a*a,a],1),tf.ones_like(a)],1)
# Observable outputs
y = tf.matmul(A,xcoeff)

# SVD - Singular Value Decomposition
d, U, V = tf.svd(A, full_matrices=True, compute_uv=True)

# Wondering why tensorflow does not generate the diagonal matrix directly
# D is the diagonal matrix with the diagonal elements being the reciprocal of d
D = tf.diag(np.reciprocal(d))

# D is actually nxm so zero padding is needed
r = D.get_shape().as_list()[0]
Z = tf.zeros([r,samples-r])
D = tf.concat([D,Z],1)

# This is linear regression by SVD
# Ax = y  mxn nx1 = mx3 3x1 = mx1
# x = Inv(A)y = nxm mx1 = 3xm mx1  ; x is our predicted xcoeff
# Inv(A) = A_ = VDtran(U) = nxn nxm mxm = nxm = 3x3 3xm 3xm = 3xm

# x (predicted xcoeff) is determined using Moore-Penrose pseudoinverse
A_ = tf.matmul(V,tf.matmul(D,tf.transpose(U)))
x = tf.matmul(A_,y)

init = tf.global_variables_initializer()
with tf.Session() as session:
    session.run(init)
    # values are the xcoeff
    print("Actual x =")
    print(xcoeff.eval())

    print("\nPredicted x = ")
    print(x.eval())

    # Let's plot; Make all variables 1D by reshaping
    a = tf.reshape(a,[a.get_shape().as_list()[0]])
    y = tf.reshape(y,[y.get_shape().as_list()[0]])
    # Predicted model, yp, based on x
    yp = tf.matmul(A,x)
    yp = tf.reshape(yp,[yp.get_shape().as_list()[0]])
    plt.plot(a.eval(), y.eval(), 'ro', a.eval(), yp.eval(), 'b')
    red = mpatches.Patch(color='red', label='Data')
    blue = mpatches.Patch(color='blue', label='Model')
    plt.legend(handles=[red,blue])
    plt.show()


import numpy as np
from scipy.stats import entropy
from math import log, e
import pandas as pd

import timeit

def entropy1(labels, base=None):
  value,counts = np.unique(labels, return_counts=True)
  return entropy(counts, base=base)

def entropy2(labels, base=None):
  """ Computes entropy of label distribution. """

  n_labels = len(labels)

  if n_labels <= 1:
    return 0

  value,counts = np.unique(labels, return_counts=True)
  probs = counts / n_labels
  n_classes = np.count_nonzero(probs)

  if n_classes <= 1:
    return 0

  ent = 0.

  # Compute entropy
  base = e if base is None else base
  for i in probs:
    ent -= i * log(i, base)

  return ent

def entropy3(labels, base=None):
  vc = pd.Series(labels).value_counts(normalize=True, sort=False)
  base = e if base is None else base
  return -(vc * np.log(vc)/np.log(base)).sum()

def entropy4(labels, base=None):
  value,counts = np.unique(labels, return_counts=True)
  norm_counts = counts / counts.sum()
  base = e if base is None else base
  return -(norm_counts * np.log(norm_counts)/np.log(base)).sum()

labels = [1,3,5,2,3,5,3,2,1,3,4,5]

print(entropy1(labels))
print(entropy2(labels))
print(entropy3(labels))
print(entropy4(labels))


import numpy

def cg(x_mat, y_vec, tol=1e-12, max_iter_int=10000):
    '''
    Conjugate Gradient (CG) Algorithm for Least Squares Regression: argmin_w || X * w - y ||_2^2

    Input
        x_mat: n-by-d NumPy matrix X;
        y_vec: n-dim vector y;
        tol: convergence tolerance (optional);
        max_iter_int: (>0) maximum number of iterations.

    Output
        w_vec: solution to the LSR problem;
        is_converged_bool: whether CG attains convergence tolerance.
    '''

    n_int, d_int = x_mat.shape
    y_vec = numpy.dot(x_mat.T, y_vec.reshape(n_int, 1))

    w_vec = numpy.zeros((d_int, 1))

    xw_vec = numpy.dot(x_mat, w_vec)
    r_vec = y_vec - numpy.dot(x_mat.T, xw_vec)
    p_vec = r_vec
    rsold_real = numpy.sum(r_vec ** 2)

    is_converged_bool = False
    i = -1

    for i in range(max_iter_int):
        xp_vec = numpy.dot(x_mat.T, numpy.dot(x_mat, p_vec))
        alp_real = rsold_real / numpy.sum(p_vec * xp_vec)
        w_vec += alp_real * p_vec
        r_vec -= alp_real * xp_vec
        rsnew_real = numpy.sum(r_vec ** 2)

        if i % 100 == 0:
            print('Iteration ' + str(i) + ': residual=' + str(rsnew_real))

        if rsnew_real < tol:
            is_converged_bool = True
            print('Iteration ' + str(i) + ': residual=' + str(rsnew_real))
            break

        p_vec = r_vec + (rsnew_real / rsold_real) * p_vec
        rsold_real = rsnew_real

    if not is_converged_bool:
        print('Warn: CG did not converge after ' + str(i+1) + ' iterations!')

    return w_vec, is_converged_bool

def demo_cg(x_mat, y_vec, w_opt_vec, tol=1e-12, max_iter_int=10000):
    '''
    For Demo Usage Only!

    Conjugate Gradient (CG) Algorithm for Least Squares Regression: argmin_w || X * w - y ||_2^2

    Input
        x_mat: n-by-d NumPy matrix X;
        y_vec: n-dim vector y;
        w_opt_vec: optimal solution;
        tol: convergence tolerance (optional);
        max_iter_int: maximum number of iterations.

    Output
        w_vec: solution to the LSR problem;
        is_converged_bool: whether CG attains convergence tolerance;
        tmp_err_vec: the error || X * w_opt - X * w ||_2^2 of each step.
    '''

    tmp_xw_opt_vec = numpy.dot(x_mat, w_opt_vec.reshape(len(w_opt_vec), 1)) # for test only

    n_int, d_int = x_mat.shape
    y_vec = numpy.dot(x_mat.T, y_vec.reshape(n_int, 1))

    w_vec = numpy.zeros((d_int, 1))

    xw_vec = numpy.dot(x_mat, w_vec)
    r_vec = y_vec - numpy.dot(x_mat.T, xw_vec)
    p_vec = r_vec
    rsold_real = numpy.sum(r_vec ** 2)

    is_converged_bool = False

    tmp_err_vec = numpy.zeros(max_iter_int) # for test only

    for i in range(max_iter_int):
        xp_vec = numpy.dot(x_mat.T, numpy.dot(x_mat, p_vec))
        alp_real = rsold_real / numpy.sum(p_vec * xp_vec)
        w_vec += alp_real * p_vec
        r_vec -= alp_real * xp_vec
        rsnew_real = numpy.sum(r_vec ** 2)

        if i % 100 == 0:
            print('Iteration ' + str(i) + ': residual=' + str(rsnew_real))

        tmp_dist_vec = numpy.dot(x_mat, w_vec) - tmp_xw_opt_vec # for test only
        tmp_err_vec[i] = numpy.sum(tmp_dist_vec ** 2) # for test only

        if rsnew_real < tol:
            is_converged_bool = True
            print('Iteration ' + str(i) + ': residual=' + str(rsnew_real))
            break

        p_vec = r_vec + (rsnew_real / rsold_real) * p_vec
        rsold_real = rsnew_real

    if not is_converged_bool:
        print('Warn: CG did not converge after ' + str(i+1) + ' iterations!')

    tmp_err_vec = tmp_err_vec[0: i+1] # for test only

    return w_vec, is_converged_bool, tmp_err_vec


import numpy as np
import matplotlib.pyplot as plt

class Sine_Wave:
    def __init__(self,A,f,t,res,phase):
        self.A = A
        self.f= f
        self.t= np.arange(0,t,res)
        self.phase= phase
        self.phi= phase*np.pi
        self.calc_x()
    def calc_x(self):
        self.x = self.A*np.sin(2*np.pi*self.f*self.t + self.phi)
    def show_plot(self,x0=0,x1=8,y0=-5,y1=5):   #0,8,-5,5
        #self.calc_x()
        plt.plot(self.t,self.x)
        plt.axis([x0,x1,y0,y1])
        plt.xlabel('time in seconds')
        plt.ylabel('amplitude')
        plt.show()

if  __name__ == "__main__":
    s1=Sine_Wave(3,.25,8,0.01,0)
    s1.show_plot()


import math
import numpy as np
import scipy.ndimage.filters as fi

def mse(noisy: np.ndarray, clean: np.ndarray) -> float:
    """
    Calculate the MSE value between noise and clean image.

    :param noisy: ndarray, noisy image
    :param clean: ndarray, clean image
    :return: float, mean-square-error value
    """
    assert noisy.shape == clean.shape, "Shape mismatch when computing MSE."
    res = np.square(noisy.astype(float) - clean.astype(float)).mean()
    return res

def psnr(noisy: np.ndarray, clean: np.ndarray, dynamic: float=1.0) -> float:
    """
    Calculate the PSNR value between noise and clean image.

    :param noisy: ndarray, noisy image
    :param clean: ndarray, clean image
    :param dynamic: float, the scale (max value) of the image
    :return: float, PSNR value
    """
    assert noisy.shape == clean.shape, "Shape mismatch when computing PSNR."
    peak = dynamic * dynamic
    return 10 * math.log10(peak / mse(noisy, clean))

def gaussian_kernel(size: int, sigma: float=1, scale: float=1) -> np.ndarray:
    """
    Create a 2-dimensional Gaussian kernel

    :param size: integer, size of the kernel / width and height
    :param sigma: float, standard variance of the kernel
    :param scale: float, sum of the output
    :return: ndarray, Gaussian kernel array
    """
    inp = np.zeros((size, size))
    # set element at the middle to one, a dirac delta
    inp[size // 2, size // 2] = 1
    # gaussian-smooth the dirac, resulting in a gaussian filter mask
    return fi.gaussian_filter(inp, sigma) * scale


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

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

def predict(X, weights):
  '''
  Returns 1D array of probabilities
  that the class label == 1
  '''
  z = np.dot(X, weights)
  return sigmoid(z)

def decision_boundary(prob):
  return 1 if prob >= .5 else 0

def classify(preds):
  f = np.vectorize(decision_boundary)
  return f(preds).flatten()

def cost_function(X, y, weights):
    '''
    Using Mean Absolute Error
    Features:(100,3)
    Labels: (100,1)
    Weights:(3,1)
    Returns 1D matrix of predictions
    Cost = ( log(predictions) + (1-labels)*log(1-predictions) ) / len(labels)
    '''
    observations = len(y)
    predictions = predict(X, weights)
    #Take the error when label=1
    class1_cost = -y*np.log(predictions)
    #Take the error when label=0
    class2_cost = (1-y)*np.log(1-predictions)
    #Take the sum of both costs
    cost = class1_cost - class2_cost
    #Take the average cost
    cost = cost.sum()/observations
    return cost

def calc_delta(X, y, weights, lr):
    '''
    Vectorized Gradient Descent
    Features:(200, 3)
    Labels: (200, 1)
    Weights:(3, 1)
    '''
    n = X.shape[0]
    #1 - Get Predictions
    predictions = predict(X, weights)
    #2 Transpose features from (200, 3) to (3, 200)
    # So we can multiply w the (200,1)  cost matrix.
    # Returns a (3,1) matrix holding 3 partial derivatives --
    # one for each feature -- representing the aggregate
    # slope of the cost function across all observations
    gradient = np.dot(X.T, predictions - y)
    #3 Take the average cost derivative for each feature
    gradient /= n
    #4 - Multiply the gradient by our learning rate
    gradient *= lr
    return gradient

def train(X, y, weights, lr, iters):
    cost_history = []
    delta_history = []
    weight_history = []
    for i in range(iters):
        gradient = calc_delta(X, y, weights, lr)
        weights -= gradient
        #Calculate error for auditing purposes
        cost = cost_function(X, y, weights)
        cost_history.append(cost)
        delta_history.append(gradient.flatten())
        weight_history.append(weights.flatten())
        # Log Progress
        if i % 1000 == 0:
            print("iter: "+str(i) + " cost: "+str(cost))
    return weights, cost_history, delta_history, weight_history

def accuracy(predicted_labels, actual_labels):
    diff = predicted_labels - actual_labels
    return 1.0 - (float(np.count_nonzero(diff)) / len(diff))

def plot_decision_boundary(trues, falses):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter([i for i in range(len(trues))], trues, s=25, c='b', marker="o", label='Trues')
    ax.scatter([i for i in range(len(falses))], falses, s=25, c='r', marker="s", label='Falses')
    plt.legend(loc='upper right');
    ax.set_title("Decision Boundary")
    ax.set_xlabel('N/2')
    ax.set_ylabel('Predicted Probability')
    plt.axhline(.5, color='black')
    plt.show()

def normalize(v):
    upper=v.max(0)
    lower=v.min(0)
    v=2*(v-lower)/(upper-lower) -1
    return v;

def load_data(fn, do_normalize=False):
    d=pandas.read_csv(fn, header=None)
    (n,m)=d.shape
    y=d[m-1].values
    y.resize(n,1)
    v=d.iloc[:,0:m-1].values
    if do_normalize:
        v=normalize(v)
    X=np.hstack((v, np.ones([n,1])))
    return (X,y)

'''
return a matrix (w*n), each column is a weight vector
'''
def load_param(fn):
    d=pandas.read_csv(fn, header=None)
    (n,m)=d.shape
    w=d.iloc[:,2:].values
    return w.transpose()

def dump_param(fn, weight):
    f=open(fn, 'w')
    s=','.join([str(v) for v in weight.flatten()])
    f.write(s)
    f.close()

def main(fn, lrate, iters):
    X,y=load_data(fn)
    n,m=X.shape
    weight=np.zeros([m, 1])+0.01
    weight, chis, whis, ghis= train(X, y, weight, lrate, iters)
    prob=predict(X, weight)
    pred=classify(prob)
    acc = accuracy(pred, y)
    print('accuracy: '+str(acc))
    if m-1==2:
        trues=X[pred==y,0:2]
        falses=X[pred!=y,0:2]
        plot_decision_boundary(trues, falses)

if __name__ == '__main__':
    if len(sys.argv) <= 3:
        print('Usage: <fn> <lrate> <iter>')
        #exit(0)
    else:
        fn = sys.argv[1]
        lrate = float(sys.argv[2])
        iters = int(sys.argv[3])
        #main(fn, lrate, iters)


# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
import scipy.linalg as la
from sklearn.decomposition import PCA

'''
Data
'''
data = np.matrix([[1,2,4],
               [4,1,2],
               [5,4,8]])

df = pd.DataFrame(data)

'''
Manual calculation
'''

# standardize data
standardized_data  = (df - df.mean()) / (df.std())

# Finding covariance
covarance = np.cov(standardized_data.T, bias = 1)

# find eigen value& eigen vector
eigenvalue, eigenvectors = np.linalg.eig(covarance)

# Find PCA
n_components = 3

pca_manual = np.matmul(np.array(standardized_data),eigenvectors)

pca_manual  = pca_manual[:,:n_components]

'''
calculate using SKlearn
'''

# PCA
pca_sklearn = (PCA(n_components).fit_transform(standardized_data))

print('Standardized data')
print(standardized_data.round(2))
print('')

print('Covariance')
print(covarance.round(2))
print('')

print('eigen_value')
print(eigenvalue.round(4))
print('')

print('eigen_vector')
print(eigenvectors.round(4))
print('')

print('PCA manually calculated')
print(pca_manual.round(2))
print('')

print('PCA - sklearn')
print(pca_sklearn.round(2))


import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn')

# define equations

def dydt(t, y): return np.sin(t)**2*y
def f(t): return 2*np.exp(0.5*(t-np.sin(t)*np.cos(t)))

def RK3(t, y, h):
    # compute approximations
    k_1 = dydt(t, y)
    k_2 = dydt(t+h/2, y+(h/2)*k_1)
    k_3 = dydt(t+h/2, y+h*(-k_1 + 2*k_2))

    # calculate new y estimate
    y = y + h * (1/6) * (k_1 + 4 * k_2 + k_3)
    return y

def RK4(t, y, h):
    # compute approximations
    k_1 = dydt(t, y)
    k_2 = dydt(t+h/2, y+(h/2)*k_1)
    k_3 = dydt(t+h/2, y+(h/2)*k_2)
    k_4 = dydt(t+h, y+h*k_3)

    # calculate new y estimate
    y = y + h * (1/6)*(k_1 + 2*k_2 + 2*k_3 + k_4)
    return y

# Initialization
ti = 0
tf = 5
h = 0.5
n = int((tf-ti)/h)
t = 0
y = 2
y_rk3 = 2

print("t \t\t yRK3 \t\t yRK4 \t\t f(t)")
print(f"{t:.1f} \t\t {y_rk3:4f} \t\t {y:4f} \t\t {f(t):.4f}")

t_plot = []
y_RK3 = []
y_RK4 = []
y_analytical = []

##
for i in range(1, n+1):
    t_plot.append(t)
    y_RK4.append(y)
    y_RK3.append(y_rk3)
    y_analytical.append(f(t))

    # calculate new y estimate
    y = RK4(t, y, h)
    y_rk3 = RK3(t, y_rk3, h)

    t += h
    print(f"{t:.1f} \t\t {y_rk3:4f} \t\t {y:4f} \t\t {f(t):.4f}")

t_plot.append(t)
y_RK3.append(y_rk3)
y_RK4.append(y)
y_analytical.append(f(t))

# Visualization
fig, (ax, ax2) = plt.subplots(2, 1)
ax.plot(t_plot, y_analytical, 'ro', label='Analytical solution')
ax.plot(t_plot, y_RK4, '.b', label='Fourth-order Runge-Kutta estimate')
ax.plot(t_plot, y_RK3, '.g', label='Third-order Runge-Kutta estimate')
ax.set_ylabel("y", fontsize=18)
ax.legend()

ax2.plot(t_plot, np.abs(np.array(y_analytical) -
                        np.array(y_RK4)), '.-b', label='Fourth-order Runge-Kutta')
ax2.plot(t_plot, np.abs(np.array(y_analytical) -
                        np.array(y_RK3)), '.-g', label='Third-order Runge-Kutta')
ax2.set_ylabel("Abs Error", fontsize=18)
ax2.legend()
ax2.set_xlabel("t", fontsize=18)
plt.savefig('runge_kutta_analytical.png', dpi=300, bbox_inches='tight')


"""ЛР 3.2, Ларькин Владимир, М8О-303Б-18"""

import numpy as np
import fire  # CLI
import matplotlib.pyplot as plt

from sem1.lab1_2.tdma import tdma_solve

def f(a, b, c, d, x):
    return a + b * x + c * (x ** 2) + d * (x ** 3)

def get_a(f):
    return [0] + [f[i] for i in range(0, len(f) - 1)]

def get_b(f, h, c):
    b = [0]
    n = len(f) - 1
    for i in range(1, n):
        b.append((f[i] - f[i - 1]) / h[i] - 1/3 * h[i] * (c[i + 1] + 2 * c[i]))
    b.append((f[n] - f[n - 1]) / h[n] - 2/3 * h[n] * c[n])
    return b

def get_c(x, f, h):
    n = len(f)
    a = [h[i - 1] for i in range(3, n)]
    b = [2 * (h[i - 1] + h[i]) for i in range(2, n)]
    c = [h[i] for i in range(2, n - 1)]
    d = np.array([3 * ((f[i] - f[i - 1]) / h[i] - ((f[i - 1] - f[i - 2]) / h[i - 1])) for i in range(2, n)])
    x = tdma_solve(np.array([
        [b[0], c[0], 0],
        [a[0], b[1], c[1]],
        [0, a[1], b[2]]
    ]), d)
    res = [0, 0, *x]
    return res

def get_d(h, c):
    d = [0]
    n = len(c) - 1
    for i in range(1, n):
        d.append((c[i + 1] - c[i]) / (3 * h[i]))
    d.append(-c[n] / (3 * h[n]))
    return d

def find_interval(points, x):
    for i in range(0, len(points) - 1):
        if points[i] <= x <= points[i + 1]:
            return i

def spline_interpolation(points, values, x):
    h = [0] + [points[i] - points[i - 1] for i in range(1, len(points))]
    c = get_c(points, values, h)
    a = get_a(values)
    b = get_b(values, h, c)
    d = get_d(h, c)

    i = find_interval(points, x)
    res = f(a[i + 1], b[i + 1], c[i + 1], d[i + 1], x - points[i])
    return res, a, b, c, d

def draw_plot(points, vals, a, b, c, d, x_star, y_star):
    x, y = [], []
    n = len(points) - 1
    for i in range(n):
        x1 = np.linspace(points[i], points[i + 1], 10, endpoint=True)
        y1 = [f(a[i + 1], b[i + 1], c[i + 1], d[i + 1], j - points[i]) for j in x1]
        x.append(x1)
        y.append(y1)

    for i in range(n):
        plt.plot(x[i], y[i], color="red")

    plt.plot(points, vals, "o")
    plt.plot(x_star, y_star, "o", color="purple", label=f"$x^*=[{x_star:.1f}, {y_star:.3f}]$")
    plt.legend()
    # plt.axis("equal")
    plt.grid(True)
    plt.savefig("plot.jpg", dpi=300)
    plt.show()

def main():
    """Интерполяция функции кубическим сплайном"""

    init_dict = {
        "x": [-2.0, -1.0, 0.0, 1.0, 2.0],
        "y": [0.13534, 0.36788, 1.0, 2.7183, 7.3891],
        "x*": -0.5
    }

    val, a, b, c, d = spline_interpolation(init_dict["x"], init_dict["y"], init_dict["x*"])
    draw_plot(init_dict["x"], init_dict["y"], a, b, c, d, init_dict["x*"], val)

    print(f"f(x* = {init_dict['x*']}) = {val}")

    print("\nКоэффициенты:")
    for title, values in zip(["a", "b", "c", "d"], [a, b, c, d]):
        print(f"{title}:", *[f"{el:10.5f}" for el in values])

if __name__ == "__main__":
    fire.Fire(main)


import numpy as np

np.random.seed(1234)

n_states = 5
n_steps = 50
tolerance = 1e-5

# Random transition matrix and state vector
P = np.random.rand(n_states, n_states)
p = np.random.rand(n_states)

# Normalize rows in P
P /= P.sum(axis=1)[:,np.newaxis]

# Normalize p
p /= p.sum()

# Take steps
for k in range(n_steps):
    p = P.T.dot(p)

p_50 = p
print(p_50)

# Compute stationary state
w, v = np.linalg.eig(P.T)

j_stationary = np.argmin(abs(w - 1.0))
p_stationary = v[:,j_stationary].real
p_stationary /= p_stationary.sum()
print(p_stationary)

# Compare
if all(abs(p_50 - p_stationary) < tolerance):
    print("Tolerance satisfied in infty-norm")

if np.linalg.norm(p_50 - p_stationary) < tolerance:
    print("Tolerance satisfied in 2-norm")


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
BE523 Biosystems Analysis & Design
HW3 - Problem 1. Constructing a mathematical model for penicillin clearance

Created on Sat Jan 23 21:29:34 2021
@author: eduardo
"""
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

# The penicillin concentration that will be used to find the model
P = np.array([200, 152, 118, 93, 74])
steps = len(P)
dt = 5  # time interval
t = np.linspace(0, (steps-1)*dt, steps)  # actual time vector
dP = np.zeros(steps)

# Get the decrement of penicilin in every time interval
for i in range(0, steps-1):
    dP[i] = P[i+1] - P[i]

# Plot penicillin concentration change (dP) versus penicilline concentration (Pplot)
# If the model is correct, the points should lie on a line that goes
# through the origin, so add the point (0,0) to the array
Pplot = P[:]
Pplot = np.append(Pplot, 0)
dP = np.append(dP, 0)

# Perform a linear regression with the data, the slope of the line will give us
# the constant rate of penicillin clearance in every time step (approx. 20%)
slope, intercept, r_value, p_value, std_err = stats.linregress(Pplot, dP)
print('P=', P, '\nPplot=', Pplot, '\ndP=', dP)
print("slope=", slope, "intercept=", intercept)

# # Figure 0, plotting P vs t, original data
# plt.figure(0)
# plt.title('Original data')
# plt.plot(t, P, 'kx')
# plt.legend(['data'], loc='best')
# plt.xlabel('t')
# plt.ylabel('P')

# Figure 1, plotting dP vs P
plt.figure(1)
plt.plot(Pplot, dP, 'kx', Pplot, slope*Pplot + intercept, 'b-')
plt.legend(['data', 'linear regression ($R^2$=%.2f)' % r_value**2], loc='best')
plt.xlabel('P')
plt.ylabel('dP')
# plt.savefig('p1_penicillin_linear.png', dpi=300)  # Save figure 1

# Complete the model and make a prediction
# The model has the form B(t+1) = B[0]*(slope+1)^t
Pmodel = P[0]*(slope+1)**(t/dt)

# Figure 2, plotting P (from data and model) vs t
plt.figure(2)
plt.plot(t, P, 'kx', t, Pmodel, 'r-')
plt.legend(['data', 'model prediction'], loc='best')
plt.xlabel('t (min)')
plt.ylabel('Penicillin ($\mu$ g/ml)')
# plt.savefig('p1_penicillin_model.png', dpi=300)  # Save figure 2


import numpy as np

def getCartesianPoints(rTheta, center):
    """Convert list of polar points to cartesian points

    The returned points are not rounded to the nearest point. User must do that by hand if desired.

    Parameters
    ----------
    rTheta : (N, 2) or (2,) :class:`numpy.ndarray`
        List of cartesian points to convert to polar domain

        First column is r and second column is theta
    center : (2,) :class:`numpy.ndarray`
        Center to use for conversion to cartesian domain of polar points

        Format of center is (x, y)

    Returns
    -------
    cartesianPoints : (N, 2) :class:`numpy.ndarray`
        Corresponding cartesian points from cartesian :obj:`rTheta`

        First column is x and second column is y

    See Also
    --------
    :meth:`getCartesianPoints2`
    """
    if rTheta.ndim == 2:
        x = rTheta[:, 0] * np.cos(rTheta[:, 1]) + center[0]
        y = rTheta[:, 0] * np.sin(rTheta[:, 1]) + center[1]
    else:
        x = rTheta[0] * np.cos(rTheta[1]) + center[0]
        y = rTheta[0] * np.sin(rTheta[1]) + center[1]

    return np.array([x, y]).T

def getCartesianPoints2(r, theta, center):
    """Convert list of polar points to cartesian points

    The returned points are not rounded to the nearest point. User must do that by hand if desired.

    Parameters
    ----------
    r : (N,) :class:`numpy.ndarray`
        List of polar r points to convert to cartesian domain
    theta : (N,) :class:`numpy.ndarray`
        List of polar theta points to convert to cartesian domain
    center : (2,) :class:`numpy.ndarray`
        Center to use for conversion to cartesian domain of polar points

        Format of center is (x, y)

    Returns
    -------
    x : (N,) :class:`numpy.ndarray`
        Corresponding x points from polar :obj:`r` and :obj:`theta`
    y : (N,) :class:`numpy.ndarray`
        Corresponding y points from polar :obj:`r` and :obj:`theta`

    See Also
    --------
    :meth:`getCartesianPoints`
    """
    x = r * np.cos(theta) + center[0]
    y = r * np.sin(theta) + center[1]

    return x, y

def getPolarPoints(xy, center):
    """Convert list of cartesian points to polar points

    The returned points are not rounded to the nearest point. User must do that by hand if desired.

    Parameters
    ----------
    xy : (N, 2) or (2,) :class:`numpy.ndarray`
        List of cartesian points to convert to polar domain

        First column is x and second column is y
    center : (2,) :class:`numpy.ndarray`
        Center to use for conversion to polar domain of cartesian points

        Format of center is (x, y)

    Returns
    -------
    polarPoints : (N, 2) :class:`numpy.ndarray`
        Corresponding polar points from cartesian :obj:`xy`

        First column is r and second column is theta

    See Also
    --------
    :meth:`getPolarPoints2`
    """
    if xy.ndim == 2:
        cX, cY = xy[:, 0] - center[0], xy[:, 1] - center[1]
    else:
        cX, cY = xy[0] - center[0], xy[1] - center[1]

    r = np.sqrt(cX ** 2 + cY ** 2)
    theta = np.arctan2(cY, cX)

    # Make range of theta 0 -> 2pi instead of -pi -> pi
    # According to StackOverflow, this is the fastest method:
    # https://stackoverflow.com/questions/37358016/numpy-converting-range-of-angles-from-pi-pi-to-0-2pi
    theta = np.where(theta < 0, theta + 2 * np.pi, theta)

    return np.array([r, theta]).T

def getPolarPoints2(x, y, center):
    """Convert list of cartesian points to polar points

    The returned points are not rounded to the nearest point. User must do that by hand if desired.

    Parameters
    ----------
    x : (N,) :class:`numpy.ndarray`
        List of cartesian x points to convert to polar domain
    y : (N,) :class:`numpy.ndarray`
        List of cartesian y points to convert to polar domain
    center : (2,) :class:`numpy.ndarray`
        Center to use for conversion to polar domain of cartesian points

        Format of center is (x, y)

    Returns
    -------
    r : (N,) :class:`numpy.ndarray`
        Corresponding radii points from cartesian :obj:`x` and :obj:`y`
    theta : (N,) :class:`numpy.ndarray`
        Corresponding theta points from cartesian :obj:`x` and :obj:`y`

    See Also
    --------
    :meth:`getPolarPoints`
    """
    cX, cY = x - center[0], y - center[1]

    r = np.sqrt(cX ** 2 + cY ** 2)

    theta = np.arctan2(cY, cX)

    # Make range of theta 0 -> 2pi instead of -pi -> pi
    # According to StackOverflow, this is the fastest method:
    # https://stackoverflow.com/questions/37358016/numpy-converting-range-of-angles-from-pi-pi-to-0-2pi
    theta = np.where(theta < 0, theta + 2 * np.pi, theta)

    return r, theta

def getPolarPointsImage(points, settings):
    """Convert list of cartesian points from image to polar image points based on transform metadata

    .. warning::
        Cleaner and more succinct to use :meth:`ImageTransform.getPolarPointsImage`

    .. note::
        This does **not** convert from cartesian to polar points, but rather converts pixels from cartesian image to
        pixels from polar image using :class:`ImageTransform`.

    The returned points are not rounded to the nearest point. User must do that by hand if desired.

    Parameters
    ----------
    points : (N, 2) or (2,) :class:`numpy.ndarray`
        List of cartesian points to convert to polar domain

        First column is x and second column is y
    settings : :class:`ImageTransform`
        Contains metadata for conversion from polar to cartesian domain

        Settings contains many of the arguments in :func:`convertToPolarImage` and :func:`convertToCartesianImage` and
        provides an easy way of passing these parameters along without having to specify them all again.

    Returns
    -------
    polarPoints : (N, 2) or (2,) :class:`numpy.ndarray`
        Corresponding polar points from cartesian :obj:`points` using :obj:`settings`

    See Also
    --------
    :meth:`ImageTransform.getPolarPointsImage`, :meth:`getPolarPoints`, :meth:`getPolarPoints2`
    """
    # Convert points to NumPy array
    points = np.asanyarray(points)

    # If there is only one point specified and number of dimensions is only one, then make the array a 1x2 array so that
    # points[:, 0/1] will not throw an error
    if points.ndim == 1 and points.shape[0] == 2:
        points = np.expand_dims(points, axis=0)
        needSqueeze = True
    else:
        needSqueeze = False

    # This is used to scale the result of the radius to get the appropriate Cartesian value
    scaleRadius = settings.polarImageSize[1] / (settings.finalRadius - settings.initialRadius)

    # This is used to scale the result of the angle to get the appropriate Cartesian value
    scaleAngle = settings.polarImageSize[0] / (settings.finalAngle - settings.initialAngle)

    # Take cartesian grid and convert to polar coordinates
    polarPoints = getPolarPoints(points, settings.center)

    # Offset the radius by the initial source radius
    polarPoints[:, 0] = polarPoints[:, 0] - settings.initialRadius

    # Offset the theta angle by the initial source angle
    # The theta values may go past 2pi, so they are looped back around by taking modulo with 2pi.
    # Note: This assumes initial source angle is positive
    # theta = np.mod(theta - initialAngle + 2 * np.pi, 2 * np.pi)
    polarPoints[:, 1] = np.mod(polarPoints[:, 1] - settings.initialAngle + 2 * np.pi, 2 * np.pi)

    # Scale the radius using scale factor
    # Scale the angle from radians to pixels using scale factor
    polarPoints = polarPoints * [scaleRadius, scaleAngle]

    if needSqueeze:
        return np.squeeze(polarPoints)
    else:
        return polarPoints

def getCartesianPointsImage(points, settings):
    """Convert list of polar points from image to cartesian image points based on transform metadata

    .. warning::
        Cleaner and more succinct to use :meth:`ImageTransform.getCartesianPointsImage`

    .. note::
        This does **not** convert from polar to cartesian points, but rather converts pixels from polar image to
        pixels from cartesian image using :class:`ImageTransform`.

    The returned points are not rounded to the nearest point. User must do that by hand if desired.

    Parameters
    ----------
    points : (N, 2) or (2,) :class:`numpy.ndarray`
        List of polar points to convert to cartesian domain

        First column is r and second column is theta
    settings : :class:`ImageTransform`
        Contains metadata for conversion from polar to cartesian domain

        Settings contains many of the arguments in :func:`convertToPolarImage` and :func:`convertToCartesianImage` and
        provides an easy way of passing these parameters along without having to specify them all again.

    Returns
    -------
    cartesianPoints : (N, 2) or (2,) :class:`numpy.ndarray`
        Corresponding cartesian points from polar :obj:`points` using :obj:`settings`

    See Also
    --------
    :meth:`ImageTransform.getCartesianPointsImage`, :meth:`getCartesianPoints`, :meth:`getCartesianPoints2`
    """
    # Convert points to NumPy array
    points = np.asanyarray(points)

    # If there is only one point specified and number of dimensions is only one, then make the array a 1x2 array so that
    # points[:, 0/1] will not throw an error
    if points.ndim == 1 and points.shape[0] == 2:
        points = np.expand_dims(points, axis=0)
        needSqueeze = True
    else:
        needSqueeze = False

    # This is used to scale the result of the radius to get the appropriate Cartesian value
    scaleRadius = settings.polarImageSize[1] / (settings.finalRadius - settings.initialRadius)

    # This is used to scale the result of the angle to get the appropriate Cartesian value
    scaleAngle = settings.polarImageSize[0] / (settings.finalAngle - settings.initialAngle)

    # Create a new copy of the points variable because we are going to change it and don't want the points parameter to
    # change outside of this function
    points = points.copy()

    # Scale the radius using scale factor
    # Scale the angle from radians to pixels using scale factor
    points = points / [scaleRadius, scaleAngle]

    # Offset the radius by the initial source radius
    points[:, 0] = points[:, 0] + settings.initialRadius

    # Offset the theta angle by the initial source angle
    # The theta values may go past 2pi, so they are looped back around by taking modulo with 2pi.
    # Note: This assumes initial source angle is positive
    # theta = np.mod(theta - initialAngle + 2 * np.pi, 2 * np.pi)
    points[:, 1] = np.mod(points[:, 1] + settings.initialAngle + 2 * np.pi, 2 * np.pi)

    # Take cartesian grid and convert to polar coordinates
    cartesianPoints = getCartesianPoints(points, settings.center)

    if needSqueeze:
        return np.squeeze(cartesianPoints)
    else:
        return cartesianPoints


"""
Investigate quadratic spline

Fitting a quadratic spline from one side and from the other side
(each with a support of 3) results in two different polynoms, which
are best combined by linear interpolation. The result is a cubic cardinal
spline! To me, this suggests that the Cardinal spline (with tension 0)
is the most "natural" cubic spline.
"""

import numpy as np
import visvis as vv
import pirt
from pirt import PointSet

# Input
pp = [2, 4, 3, 1]

# Interpolate1
res1 = PointSet(2)
for t in np.arange(0,1,0.01):
    c_1 = 0.5*t**2 - 0.5*t
    c0 = -t**2 + 1
    c1 = 0.5*t**2 + 0.5*t
    res1.append(t, c_1*pp[0] + c0*pp[1] + c1*pp[2])

# Interpolate2
res2 = PointSet(2)
for t in np.arange(0,1,0.01):
    c0 = 0.5*t**2 - 1.5*t + 1
    c1 = -t**2 + 2*t
    c2 = 0.5*t**2 - 0.5*t
    res2.append(t, c0*pp[1] + c1*pp[2] + c2*pp[3])

# Linearly combine
res3 = PointSet(2)
for t in np.arange(0,1,0.01):
    # NOTE: if I write this out, I'll get a cubic spline!
    c_1 = (0.5*t**2 - 0.5*t) * (1-t)
    c0 = (-t**2 + 1) * (1-t) + (0.5*t**2 - 1.5*t + 1) * t
    c1 = (0.5*t**2 + 0.5*t) * (1-t) + (-t**2 + 2*t) * t
    c2 =  (0.5*t**2 - 0.5*t) * t
    res3.append(t, c_1*pp[0] + c0*pp[1] + c1*pp[2] + c2*pp[3])

# Combine by adding
# res3 = 0.5*(res1 + res2)

# To compare, cardinal spline
resC = PointSet(2)
for t in np.arange(0,1,0.01):
    cc = pirt.get_cubic_spline_coefs(t, 0)
    resC.append(t, cc[0]*pp[0] + cc[1]*pp[1] + cc[2]*pp[2] + cc[3]*pp[3])

# Show
vv.figure(1); vv.clf()
vv.plot(res1, lc='r', lw=1)
vv.plot(res2, lc='b', lw=1)
vv.plot(res3, lc='g', lw=2)
vv.plot(resC, lc='m', lw=5, ls=':')
vv.plot([-1, 0, 1, 2],pp, lc='k', ls='--')
#
vv.legend('From the left', 'From the right', 'Combined', 'Catmull-rom')

vv.use().Run()


"""
Summation of primes
Problem 10
The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

Find the sum of all the primes below two million.
"""

import numpy as np

n = 5000000
sieve = np.array([True for _ in range(n)])
sieve[0:2] = False
upper_bound = int(np.sqrt(n))

for i in range(2, upper_bound+1):
    if sieve[i]:
        j = i * i
        counter = 0
        while j < n:
            sieve[j] = False
            j = (i * i) + (counter * i)
            counter += 1

primes = np.where(sieve == True)[0]

idx = np.where(primes < 2000000)[0]
subset = primes[idx]
solution = sum(subset)
print('solution: ', solution)

"""
142913828922
"""


#!/usr/bin/env python
# coding: utf-8

# In[2]:

# IMPORTS HERE

import numpy as np

# import matplotlib
from matplotlib import pyplot

from scipy.stats import pearsonr

# In[3]:

ageList = [23,23,27,27,39,41,47,49,50,52,54,54,56]
fatList = [9.5,26.5,7.8,17.8,31.4,25.9,27.4,27.2,31.2,34.6,42.5,28.8,33.4]

# In[4]:

ageList

# In[5]:

fatList

# In[6]:

len(ageList)

# In[7]:

len(fatList)

# In[8]:

type(ageList)

# In[9]:

npAge = np.array(ageList)

# In[10]:

npAge

# In[11]:

type(npAge)

# In[12]:

npAge.ndim

# In[13]:

npFat = np.array(fatList)

# In[14]:

npFat

# In[20]:

ageBar = npAge.sum()/len(npAge)

# In[19]:

np.sum(ageList)/len(ageList)

# In[21]:

fatBar = npFat.sum()/len(npFat)

# In[22]:

fatBar

# In[24]:

ageDif = npAge - ageBar

# In[25]:

ageDif

# In[26]:

fatDif = npFat - fatBar

# In[27]:

fatDif

# In[28]:

fatDifAgeDif = fatDif * ageDif

# In[29]:

fatDifAgeDif

# In[30]:

sumfatDifAgeDif = fatDifAgeDif.sum()

# In[31]:

sumfatDifAgeDif

# In[32]:

delA = np.sqrt(np.sum( np.square( ageDif ) ) / len(ageList))

# In[33]:

delA

# In[34]:

delB = np.sqrt(np.sum( np.square( fatDif ) ) / len(fatList))

# In[35]:

delB

# In[38]:

r = sumfatDifAgeDif / (len(ageList) * delA * delB)

# In[39]:

r

# In[42]:

scipyr,_ = pearsonr(ageList,fatList)

# In[43]:

scipyr

# In[46]:

diff = abs(r - scipyr)

# In[47]:

diff

# In[49]:

pyplot.scatter(ageList,fatList)

# In[ ]:

# In[ ]:


import numpy as np

def bottleneck0(X,Y):
    """
    Returns the dimension 0 bottleneck distance between two non-empty persistence diagrams.
    All components are assumed to be born at the beginning of the filtration,
    that is, all non-trivial points lie in the vertical axis.

    Parameters
    ----------
    X : 1D numpy array
        Non-empty array of death times for persistence diagram 1.
    Y : 1D numpy array
        Non-empty array of death times for persistence diagram 2.

    Returns
    -------
    d : float
        The bottleneck distance between X and Y.

    Authors
    --------
    Paul Samuel P. Ignacio,
    University of the Philippines Baguio,
    Governor Pack Road, Baguio City 2600, Philippines

    Jay-Anne B. Bulauan,
    University of the Philippines Baguio,
    Governor Pack Road, Baguio City 2600, Philippines

    David Uminsky,
    University of Chicago, 5801 S Ellis Ave, Chicago,IL 60637, United States

    Examples
    --------
    >>> num_points1 = 100
    >>> num_points2 = 200
    >>> X = np.random.uniform(low=0.0, high=1000.0, size=num_points1)
    >>> Y = np.random.uniform(low=0.0, high=1000.0, size=num_points2)
    >>> bottleneck0(X,Y)

    """

    #Swap if X is longer
    if len(Y) < len(X):
        X_copy = np.copy(X)
        X = Y
        Y = X_copy

    #Initialize
    X=-np.sort(-X)
    Y=-np.sort(-Y)
    d=0
    N = len(X)

    Z = abs(X-Y[0:N])
    l = np.argmax(Z)
    dtemp = Z[l]

    # Maintain an initial bijection. Systematically modify this bijection to optimize
    # the norm between matched points until the bottleneck matching is recovered.
    if N != len(Y) and dtemp < 0.5*Y[N]:
        d = 0.5*Y[N]
    elif l >= 0 and len(Z) > 1:
        while len(Z) > 1:
            k = 0.5*max(X[l],Y[l])
            if np.max(np.delete(Z,l)) <  k and k < dtemp:
                d = k
                break

            elif np.max(np.delete(Z,l)) >= k:
                if len(Z[Z>=k]) == len(np.where(np.where(Z >= k)[0] >= l)[0]):
                    d = k
                    break
                else:
                    Z=Z[0:l]
                    X=X[0:l]
                    Y=Y[0:l]
                    l=np.argmax(Z)
                    dtemp = Z[l]
                    if len(Z) == 1:
                        d = min(dtemp,0.5*max(X[l],Y[l]))
                        break
            else:
                d = dtemp
                break
    else:
        # If one of the persistence diagrams is a singleton
        d = min(dtemp,0.5*max(X[0],Y[0]))

    return d


import numpy as np
from scipy import linalg as spla
from pressio4py import logger, solvers, ode

class RosenbrockSys:
  def createResidual(self):
    return np.zeros(6)

  def createJacobian(self):
    return np.zeros((6,4))

  def residual(self, x, R):
    x1,x2,x3,x4 = x[0],x[1],x[2],x[3]
    R[0] = 10.*(x4 - x3*x3)
    R[1] = 10.*(x3 - x2*x2)
    R[2] = 10.*(x2 - x1*x1)
    R[3] = (1.-x1)
    R[4] = (1.-x2)
    R[5] = (1.-x3)

  def jacobian(self, x, J):
    x1,x2,x3 = x[0],x[1],x[2]
    J[0,2] = -20.*x3
    J[0,3] = 10.
    J[1,1] = -20.*x2
    J[1,2] = 10.
    J[2,0] = -20.*x1
    J[2,1] = 10.
    J[3,0] = -1.
    J[4,1] = -1.
    J[5,2] = -1.

class MyQRSolver:
  def computeThin(self, A):
    self.Q, self.R = np.linalg.qr(A, mode='reduced')

  def applyQTranspose(self, operand, result):
    result[:] = self.Q.T.dot(operand)

  def applyRTranspose(self, operand, result):
    result[:] = self.R.T.dot(operand)

  def solveRxb(self, b, x):
    # solve: Rx = b
    x[:] = spla.solve(self.R, b)

def test_gn_neq_rosenbrock():
  print("\n")
  logger.initialize(logger.logto.terminal)
  logger.setVerbosity([logger.loglevel.debug])

  state   = np.array([-0.05, 1.1, 1.2, 1.5])
  problem = RosenbrockSys()
  qr_s    = MyQRSolver()
  solver  = solvers.create_gauss_newton_qr(problem, state, qr_s)
  solver.setTolerance(1e-5)
  solver.solve(problem, state)
  print(state)

  gold = np.array([1.00000001567414e+00,
                   9.99999999124769e-01,
  		   9.99999996519930e-01,
                   9.99999988898883e-01])
  assert(np.allclose(gold, state))
  logger.finalize()


#!/usr/bin/python3
import sympy
import math
from prettytable import PrettyTable

def multipleRoots(x0, tol, ite):
    if (tol >= 0):
        if (ite > 0):
            tXn.append(x0)
            y0 = functionF.evalf().subs({x:x0}).evalf()
            tfXn.append("%e" % y0)
            y0p1 = functionFP1.evalf().subs({x:x0}).evalf()
            tfp1Xn.append("%e" % y0p1)
            y0p2 = functionFP2.evalf().subs({x:x0}).evalf()
            tfp2Xn.append("%e" % y0p2)
            if (y0 != 0):
                cont = 0
                error = tol + 1
                errorAbsoluto.append("")
                tIter.append(0)
                xa = x0
                while ((y0 != 0) and (y0p1 != 0) and (y0p2 != 0) and (error > tol) and (cont < ite)):
                    xn = xa - ((y0*y0p1) / ((y0p1**2) - (y0*y0p2)))
                    tXn.append(xn)
                    y0 = functionF.evalf().subs({x:xn}).evalf()
                    tfXn.append("%e" % y0)
                    y0p1 = functionFP1.evalf().subs({x:xn}).evalf()
                    tfp1Xn.append("%e" % y0p1)
                    y0p2 = functionFP2.evalf().subs({x:xn}).evalf()
                    tfp2Xn.append("%e" % y0p2)
                    error = math.fabs(xn - xa)
                    errorAbsoluto.append("%e" % error)
                    xa = xn
                    cont = cont + 1
                    tIter.append(cont)
                if (y0 == 0):
                    print (str(xa) + " is a root")
                elif (y0p1 == 0):
                    print (str(xa) + " is a root")
                elif (y0p2 == 0):
                    print (str(xa) + " is a root")
                elif (error <= tol):
                    print (str(xa) + " is an aproximate root")
                else:
                    print ("Failed the interval!")
            else:
                print (str(x0) + " is a root")
        else:
            print ("Wrong iterates!")
    else:
        print ("Tolerance < 0")
    table.add_column("n",tIter)
    table.add_column("Xn",tXn)
    table.add_column("f(Xn)",tfXn)
    table.add_column("f'(Xn)",tfp1Xn)
    table.add_column("f''(Xn)",tfp2Xn)
    table.add_column("Error",errorAbsoluto)
    print(table)

if __name__ == "__main__":
    x = sympy.Symbol('x')
    symbols = {'e':math.e,'cos':sympy.cos,'sin':sympy.sin,'ln':sympy.ln}
    functionF  = input("Enter the function f(x) = ")
    functionF = sympy.sympify(functionF,locals = symbols)
    functionFP1 = sympy.diff(functionF)
    functionFP2 = sympy.diff(functionFP1)
    x0 = float(input("Enter the initial point: "))
    tol = float(input("Enter the tolerance: "))
    ite = int(input("Enter N iteraters: "))
    table = PrettyTable()
    tIter = []
    tXn = []
    tfXn = []
    tfp1Xn = []
    tfp2Xn = []
    errorAbsoluto = []
    multipleRoots(x0, tol, ite)


import numpy as np
import scipy.ndimage
import scipy.signal

def get_freqarr_2d(nx,ny,psx, psy):
    """
       Compute frequency array for 2 D FFT transform

       Parameters
       ----------
       nx : integer
            number of samples in the x direction
       ny : integer
            number of samples in the y direction
       psx: integer
            map pixel size in the x direction
       psy: integer
            map pixel size in the y direction

       Returns
       -------
       k : float 2D numpy array
           frequency vector
    """
    kx =  np.outer(np.fft.fftfreq(nx),np.zeros(ny).T+1.0)/psx
    ky =  np.outer(np.zeros(nx).T+1.0,np.fft.fftfreq(ny))/psy
    k = np.sqrt(kx*kx + ky*ky)
    return k

def power_spectrum_2d(arr,nbins=10,psx=1,psy=1,logbins=0):
    """
    Compute 2D power spectrum of arr

    Parameters
    ----------
    arr: float 2D numpy array
         2D array for which we compute the power spectrum
    nbins: integer, optional
         number of frequency k bins (10)

    psx:  integer, optional (1)
    Returns
    -------
    kbin: float 1D numpy array
          bins in k-space
    pkbin: float 1D numpy array
          2D power spectrum for kbin
    """
    farr = np.fft.fft2(arr)/np.double(arr.size)
    nx,ny = arr.shape
    k = get_freqarr_2d(nx,ny,psx, psy)
    pk = np.double(farr * np.conj(farr))
    if logbins:
        kbinarr = np.logspace(0.0,np.log(k.max()),nbins+1)
    else:
        kbinarr = np.arange(nbins+1)/np.double(nbins)*(k.max()-k.min())
    kbin   = np.zeros(nbins+1)
    pkbin  = np.zeros(nbins+1)
    pkbins = np.zeros(nbins+1)

    for idx in range(0,nbins):
        list = np.nonzero((k > kbinarr[idx]) * (k<= kbinarr[idx+1]))
        kbin[idx+1] = np.median(k[list])
        pkbin[idx+1] = np.mean(pk[list])
        pkbins[idx+1] = np.std(pk[list])/np.sqrt(len(list[0]))
    return kbin,pkbin,pkbins

def simu_gaussian_noise(nx,ny,pk):
    """
     Simulate a 2D map assuming Gaussian noise as computed from 2D
     power spectrum

     To be DONE !!!!!
    """
    simumap = np.random.normal(0.0,1.0,[nx,ny])
    karr = get_freqarr_2d(nx,ny,psx, psy)

    return
def cross_power_spectrum_2d(arr,arr1,nbins=10,psx=1.0,psy=1.0,logbins=0):
    nx,ny = arr.shape
    nx1,ny1 = arr1.shape
    if nx1 == nx:
        if ny1 == ny:
            farr = np.fft.fft2(arr)/np.double(arr.size)
            farr1 = np.fft.fft2(arr1)/np.double(arr1.size)
            k = get_freqarr_2d(nx,ny,psx, psy)
            pk = np.double(farr * np.conj(farr1))
            if logbins:
                kbinarr = np.logspace(0.0,np.log(k.max()),nbins+1)
            else:
                kbinarr = np.arange(nbins+1)/np.double(nbins)*(k.max()-k.min())
            kbin = np.zeros(nbins+1)
            pkbin = np.zeros(nbins+1)
            for idx in range(0,nbins):
                list = np.nonzero((k > kbinarr[idx]) * (k<= kbinarr[idx+1]))
                kbin[idx+1] = np.median(k[list])
                pkbin[idx+1] = np.mean(pk[list])
                pkbins[idx+1] = np.std(pk[list])/np.sqrt(len(list[0]))
    return kbin,pkbin,pkbins

def fourier_conv_2d(arr,kernel,doshift=True):
    """
    If kernel (e.g. a Gaussian) is peaked in the center, then you
    want to have doshift=True.
    """
    farr = np.fft.fft2(arr)
    fker = np.fft.fft2(kernel)
    farr = farr * fker
    arrc = np.real(np.fft.ifft2(farr))
    if doshift:
        arrc = np.fft.fftshift(arrc)

    return arrc

def fourier_filtering_2d(arr,filt_type,par):
    farr  = np.fft.fft2(arr)
    nx,ny = arr.shape
    kx    = np.outer(np.fft.fftfreq(nx),np.zeros(ny).T+1.0)
    ky    = np.outer(np.zeros(nx).T+1.0,np.fft.fftfreq(ny))
    k     = np.sqrt(kx*kx + ky*ky)
    if filt_type == 'gauss': filter = gauss_filter_2d(k,par)
    if filt_type == 'hpcos': filter = hpcos_filter_2d(k,par)
    if filt_type == 'lpcos': filter = lpcos_filter_2d(k,par)
    if filt_type == 'bpcos': filter = bpcos_filter_2d(k,par)
    if filt_type == 'tab':   filter = table_filter_2d(k,par)
    farr    = farr * filter
    arrfilt = np.real(np.fft.ifft2(farr))
    return arrfilt

def gauss_filter_2d(k,par):
    fwhm = par
    sigma = fwhm/(2.0*np.sqrt(2.0*np.log(2)))
    filter = np.exp(-2.0*k*k*sigma*sigma*np.pi*np.pi)
    return filter

def lpcos_filter_2d(k,par):
    k1 = par[0]
    k2 = par[1]
    filter = k*0.0
    filter[k < k1]  = 1.0
    filter[k >= k1] = 0.5 * (1+np.cos(np.pi*(k[k >= k1]-k1)/(k2-k1)))
    filter[k > k2]  = 0.0
    return filter

def hpcos_filter_2d(k,par):
    k1 = par[0]
    k2 = par[1]
    filter = k*0.0
    filter[k < k1]  = 0.0
    filter[k >= k1] = 0.5 * (1-np.cos(np.pi*(k[k >= k1]-k1)/(k2-k1)))
    filter[k > k2]  = 1.0
    return filter

def bpcos_filter_2d(k,par):
    filter = hpcos_filter_2d(k,par[0:2]) * lpcos_filter_2d(k,par[2:4])
    return filter

def gauss_2d(sigma,nx,ny):
    ix =  np.outer(np.arange(nx),np.zeros(ny).T+1)-nx/2
    iy =  np.outer(np.zeros(nx)+1,np.arange(ny).T)-ny/2
    r = ix*ix+iy*iy
    fg = np.exp(-0.5*r/sigma/sigma)
    return fg

def table_filter_2d(k,par):
    from scipy import interpolate
    kbin,filterbin = par
    f = interpolate.interp1d(kbin, filterbin)
    kbin_min = kbin.min()
    kbin_max = kbin.max()

    filter = k * 0.0
    filter[(k >= kbin_min)  & (k <= kbin_max)] = f(k[(k >= kbin_min)  & (k <= kbin_max)])   # use interpolation function returned by `interp1d`
    filter[(k < kbin_min)] = filterbin[kbin == kbin_min]
    filter[(k > kbin_max)] = filterbin[kbin == kbin_max]

    return filter

def fourier_filtering_1d(arr,filt_type,par,xarr=[]):
    farr = np.fft.fft(arr)
    if len(xarr) == 0:
        nx = len(arr)         # it's strictly one dimensional!
        k  =  np.fft.fftfreq(nx)
    else:
        nx = len(arr)         # it's strictly one dimensional!
        raise Exception

        #    if filt_type == 'gauss': filter = gauss_filter_2d(k,par)
#    if filt_type == 'hpcos': filter = hpcos_filter_2d(k,par)
#    if filt_type == 'lpcos': filter = lpcos_filter_2d(k,par)
#    if filt_type == 'bpcos': filter = bpcos_filter_2d(k,par)
    if filt_type == 'tab': filter = table_filter_1d(k,par)
    farr = farr * filter
    arrfilt = np.real(np.fft.ifft(farr))
    return arrfilt

def table_filter_1d(k,par):
    from scipy import interpolate
    kbin,filterbin = par
    f = interpolate.interp1d(kbin, filterbin)
    kbin_min = kbin.min()
    kbin_max = kbin.max()

    filter = k * 0.0

    filter[(k >= kbin_min)  & (k <= kbin_max)] = f(k[(k >= kbin_min)  & (k <= kbin_max)])   # use interpolation function returned by `interp1d`
    filter[(k < kbin_min)] = filterbin[kbin == kbin_min]
    filter[(k > kbin_max)] = filterbin[kbin == kbin_max]

    return filter


import numpy as np

def versor(A,B):
    """
    Compute the unitary vector
    pointing from A to B.
    """

    # Check A and B to be of type np.array
    if type(A) != np.ndarray:
        A = np.asarray(A)
    if type(B) != np.ndarray:
        B = np.asarray(B)
    # Compute the vector pointing from A to B
    vector = B - A
    module = np.sqrt(np.sum(vector**2))
    versor = vector/module
    return versor

def versor_perp_plane(A,B,C):
    """
    Compute the unitary vector
    perpendicular to the plane
    defined by the points A, B
    and C.
    """
    # Check A, B and C to be of type np.array
    if type(A) != np.ndarray:
        A = np.asarray(A)
    if type(B) != np.ndarray:
        B = np.asarray(B)
    if type(C) != np.ndarray:
        C = np.asarray(C)
    # Vector AC
    vector1 = C - A
    # Vector AB
    vector2 = B - A
    perp_vector = np.cross(vector2, vector1)
    perp_module = np.sqrt(np.sum(perp_vector**2))
    perp_versor = perp_vector/perp_module
    return perp_versor

#if "__main__":
#   X = [0,0,0]
#   Y = [0,3,0]
#   Z = [0,0,5]
#   print(versor(X,Y))
#   print(versor_perp_plane(X,Y,Z))


"""
Source:
https://tiggerntatie.github.io/emagnet-py/offaxis/off_axis_loop.html
Used to test against implementation in this package
Included under the MIT license
"""
from scipy.special import ellipk, ellipe
from numpy import pi, sqrt, NaN

uo = 4E-7 * pi  # Permeability constant - units of H/m
Bo = lambda i, a, u=uo: i * u / 2. / a  # Central field = f(current, loop radius, perm. constant)
al = lambda r, a: r / a  # Alpha = f(radius of measurement point, radius of loop)
be = lambda x, a: x / a  # Beta = f(axial distance to meas. point, radius of loop)
ga = lambda x, r: x / r  # Gamma = f(axial distance, radius to meas. point)
Q = lambda r, x, a: (1 + al(r, a)) ** 2 + be(x, a) ** 2  #
# Q = f(radius, distance to meas. point, loop radius)
k = lambda r, x, a: sqrt(4 * al(r, a) / Q(r, x, a))  # k = f(radius, distance to meas. point, loop radius)
K = lambda k: ellipk(k ** 2.0)  # Elliptic integral, first kind, as a function of k
E = lambda k: ellipe(k ** 2.0)  # Elliptic integral, second kind, as a function of k

# On-Axis field = f(current and radius of loop, x of measurement point)
def Baxial(i, a, x, u=uo):
    if a == 0:
        if x == 0:
            return NaN
        else:
            return 0.0
    else:
        return (u * i * a ** 2) / 2.0 / (a ** 2 + x ** 2) ** 1.5

# Axial field component = f(current and radius of loop, r and x of meas. point)
def field_axial(i, a, x, r):
    if r == 0:
        if x == 0:
            return Bo(i, a)  # central field
        else:
            return Baxial(i, a, x)  # axial field
    else:  # axial component, any location
        return Bo(i, a) * \
               (E(k(r, x, a)) * ((1.0 - al(r, a) ** 2 - be(x, a) ** 2) / (Q(r, x, a) - 4 * al(r, a))) + K(k(r, x, a))) \
               / pi / sqrt(Q(r, x, a))

# Radial field component = f(current and radius of loop, r and x of meas. point)
def field_radial(i, a, x, r):
    if r == 0:
        return 0.0  # no radial component on axis!
    else:  # radial component, any location other than axis.
        return Bo(i, a) * ga(x, r) * \
               (E(k(r, x, a)) * ((1.0 + al(r, a) ** 2 + be(x, a) ** 2) / (Q(r, x, a) - 4 * al(r, a))) - K(k(r, x, a))) \
               / pi / sqrt(Q(r, x, a))


import numpy as np
import json
import math
import sys
import os
import pandas as pd

#Import a keyboard layout matrix
#parameter: layout is a .json file withthe layout defined
def import_layout(layout_file):

    layout_matrix = {}

    #Read the json file
    with open(layout_file) as data_file:
        layout_json = json.load(data_file)

    #Get the list and calculate the gaussian distribution for every key or char of the matrix
    #1. Error_Model
    for key in layout_json:
            key_neighbors = layout_json[key]
            layout_matrix[key] = gaussian_matrix(key_neighbors)

    #2. Gaussian Distribution of the Gaussian
    return layout_matrix

 #Calculate the gaussian matrix of error distribution based on a layout keyboard
def gaussian_matrix(neighbors,mean=0,variance=0.5):

    size = len(neighbors)

    result = []

    half_size = int(math.floor(size // 2))

    x = 0
    gaussian = [[0] * size for _ in range(0, size)]
    for i in range(-half_size, half_size + 1):
        y = 0
        for j in range(-half_size, half_size + 1):
            x_dist = (1 / (math.sqrt(2 * math.pi * variance))) * (
                        math.e ** ((-(i - mean) ** 2) / (2 * variance ** 2)))
            y_dist = (1 / (math.sqrt(2 * math.pi * variance))) * (
                        math.e ** ((-(j - mean) ** 2) / (2 * variance ** 2)))
            gaussian[x][y] = x_dist * y_dist
            y += 1
        x += 1

    probability = gaussian
    for i in range(0, size):
        for j in range(0, size):
            if neighbors[i][j] is not None:
                result += [(neighbors[i][j], probability[i][j])]

    total = sum(prob for neighbor, prob in result)
    normalized_result = [(neighbor, prob / total) for neighbor, prob in result]

    return normalized_result

#Check if this is correct and try to do some eperiments
def create_emission_matrix(errors_distributions):
    size = len(errors_distributions)
    epsilon=10*10**-5
    emission_matrix = np.full((size, size), epsilon, dtype=float)
    key_list = []
    keys_list = list(errors_distributions.keys())
    keys_list.sort()
    map_to_zero = list(zip(keys_list, range(0, size)))
    map_to_zero = dict(map_to_zero)

    for key in errors_distributions:
        key_list += [key]
        for letter, probability in errors_distributions[key]:
            i = map_to_zero[key]
            j = map_to_zero[letter]
            emission_matrix[i, j] = probability

    for i in range(0, size):
        emission_matrix[i] = emission_matrix[i] / sum(emission_matrix[i])

    result = np.matrix(emission_matrix)

    observations = list(errors_distributions.keys())
    observations.sort()

    return observations, result

def generate_emission_matrix(layout_file,out_file=None):

    result = import_layout(layout_file)

    for key in result:
        a = sum(n for _, n in result[key])

    observations, emission = create_emission_matrix(result)

    if(not(out_file == None)):
        np.savetxt(out_file, emission, delimiter=';')

    return observations, emission


import numpy as np  # calculations
import pathlib  # needed to create folder
import matplotlib.pyplot as plt  # needed for graphs
import sympy as sp
from sympy.abc import E, e, n, M, o

print('Program started running!')

dpisiz = 1000

def savim(dir, name):
    path = pathlib.Path(f"./{dir}")
    path.mkdir(exist_ok=True, parents=True)
    plt.savefig(f'./{dir}/{name}.png', dpi=dpisiz)
    print(f'Saved image location: ./{dir}/{name}.png')

fract = e ** n / sp.factorial(n)
func = (sp.sin(M)) ** n
dif_func = (sp.Derivative(func, (M, n - 1)))
sumo = sp.Sum(fract * dif_func, (n, 1, o))
sum3 = (sumo.subs(o, 3)).doit()
sum10 = (sumo.subs(o, 10)).doit()
E3 = sum3 + M
E10 = sum10 + M
En3_e3 = sp.trigsimp(E3.subs(e, 0.3))
En10_e3 = sp.trigsimp(E10.subs(e, 0.3))
En3_e9 = sp.trigsimp(E3.subs(e, 0.9))
En10_e9 = sp.trigsimp(E10.subs(e, 0.9))

# Use sp.lambdify to create our lambda functions
# and plot our graphs. Could have used sp.plot but I prefer having more options with matplotlib.

numberoftries = 10000
xx = np.linspace(0, 2 * np.pi, 10000)
En3_e3f = sp.lambdify(M, En3_e3)(xx)
En10_e3f = sp.lambdify(M, En10_e3)(xx)
En3_e9f = sp.lambdify(M, En3_e9)(xx)
En10_e9f = sp.lambdify(M, En10_e9)(xx)

fig = plt.figure()
ax = plt.axes()

# Import data from task 1 to compare

data = np.genfromtxt(fname="data.csv", delimiter=',')
ax.set_ylabel('E')
ax.set_xlabel('M')
ax.plot(data[:, 0], data[:, 2], label='E for e=0.3', color='tab:pink')
ax.plot(xx, En3_e3f, label='E for n=3, e=0.3', linestyle='dashed', color='tab:red')
ax.plot(xx, En10_e3f, label='E for n=10, e=0.3', linestyle='dotted', color='tab:blue')
ax.legend()
savim('pr1_task2', 'e_03')
fig1 = plt.figure()
ax1 = plt.axes()
ax1.plot(data[:, 0], data[:, 5], label='E for e=0.9', color='black')
ax1.plot(xx, En3_e9f, label='E for n=3, e=0.9', color='tan')
ax1.plot(xx, En10_e9f, label='E for n=10, e=0.9', color='fuchsia')
ax1.legend()
ax1.set_ylabel('E')
ax1.set_xlabel('M')
savim('pr1_task2', 'e_09')

print('Program Finished running!')
# As we can see from our results, for lower eccentricities both n=3 and n=10 are nearly identical
# compared to the Newton-Raphson method. However for 0.9, this is no longer the case.
# In this case there are some sinusoidal curves with small amplitude appearing except the
# middle of the curve (There are still some curvature showing at the middle,
# however it’s close to the Newton-Raphson method).


#!/usr/bin/env python
#!-*- coding: utf-8 -*-

import numpy as np

__author__ = "Irshad Ahmad Bhat"
__version__ = "1.0"
__email__ = "irshad.bhat@research.iiit.ac.in"

class Distance():

    def euclidean(self, X, Y):

	"""Returns Euclidean distance between to n-dimentional vectors."""

	X = np.asarray(X)
	Y = np.asarray(Y)

	return np.sqrt(np.sum((X-Y)**2))

    def manhattan(self, X, Y):

	"""Returns Euclidean distance between to n-dimentional vectors."""

	X = np.asarray(X)
	Y = np.asarray(Y)

	return np.sum(np.abs(X-Y))

    def cosine(self, X, Y):

	"""Returns Cosine distance between to n-dimentional vectors."""

	X = np.asarray(X)
	Y = np.asarray(Y)

	return 1 - np.sum(X*Y) / (np.sqrt(np.sum(X**2)) * np.sqrt(np.sum(Y**2)))


import numpy as np
from numpy.fft import fft, fftshift

import matplotlib.pyplot as plt
from matplotlib import cm

""" Examples """

t = np.linspace(-np.pi, np.pi, 64, endpoint=False)
dt = t[1] - t[0]
f_max = 1 / dt
y = np.sin(np.sqrt(2) * t)
y[0] = 0  # the sample corresponding to -tmax should be set zero
y = fftshift(y)  # make y start with y(t=0)
Y = fftshift(fft(y)) / 64
w = np.linspace(-np.pi * f_max, np.pi * f_max, 64, endpoint=False)
plt.figure()
plt.subplot(2, 1, 1)
plt.plot(w, np.abs(Y), lw=2)
plt.xlim([-10, 10])
plt.ylabel(r"$|Y|$", size=16)
plt.title(r"Spectrum of $\sin\left(\sqrt{2}t\right)$")
plt.grid(True)
plt.subplot(2, 1, 2)
plt.plot(w, np.angle(Y), "ro", lw=2)
plt.xlim([-10, 10])
plt.ylabel(r"Phase of $Y$", size=16)
plt.xlabel(r"$\omega$", size=16)
plt.grid(True)
plt.savefig("Assignment_09/LaTeX/eg1.png")

t1 = np.linspace(-np.pi, np.pi, 64, endpoint=False)
t2 = np.linspace(-3 * np.pi, -np.pi, 64, endpoint=False)
t3 = np.linspace(np.pi, 3 * np.pi, 64, endpoint=False)
# y = np.sin(np.sqrt(2) * t)
plt.figure()
plt.plot(t1, np.sin(np.sqrt(2) * t1), "b", lw=2)
plt.plot(t2, np.sin(np.sqrt(2) * t2), "r", lw=2)
plt.plot(t3, np.sin(np.sqrt(2) * t3), "r", lw=2)
plt.ylabel(r"$y$", size=16)
plt.xlabel(r"$t$", size=16)
plt.title(r"$\sin\left(\sqrt{2}t\right)$")
plt.grid(True)
plt.savefig("Assignment_09/LaTeX/eg2.png")

t1 = np.linspace(-np.pi, np.pi, 64, endpoint=False)
t2 = np.linspace(-3 * np.pi, -np.pi, 64, endpoint=False)
t3 = np.linspace(np.pi, 3 * np.pi, 64, endpoint=False)
y = np.sin(np.sqrt(2) * t1)
plt.figure()
plt.plot(t1, y, "bo", lw=2)
plt.plot(t2, y, "ro", lw=2)
plt.plot(t3, y, "ro", lw=2)
plt.ylabel(r"$y$", size=16)
plt.xlabel(r"$t$", size=16)
plt.title(r"$\sin\left(\sqrt{2}t\right)$ with $t$ wrapping every $2\pi$")
plt.grid(True)
plt.savefig("Assignment_09/LaTeX/eg3.png")

t = np.linspace(-np.pi, np.pi, 64, endpoint=False)
dt = t[1] - t[0]
f_max = 1 / dt
y = t
y[0] = 0  # the sample corresponding to -tmax should be set zero
y = fftshift(y)  # make y start with y(t=0)
Y = fftshift(fft(y)) / 64
w = np.linspace(-np.pi * f_max, np.pi * f_max, 64, endpoint=False)
plt.figure()
plt.semilogx(np.abs(w), 20 * np.log10(np.abs(Y)), lw=2)
plt.xlim([1, 10])
plt.ylim([-20, 0])
plt.xticks([1, 2, 5, 10], ["1", "2", "5", "10"], size=16)
plt.ylabel(r"$|Y|$ (dB)", size=16)
plt.title(r"Spectrum of a digital ramp")
plt.xlabel(r"$\omega$", size=16)
plt.grid(True)
plt.savefig("Assignment_09/LaTeX/eg4.png")

t1 = np.linspace(-np.pi, np.pi, 64, endpoint=False)
t2 = np.linspace(-3 * np.pi, -np.pi, 64, endpoint=False)
t3 = np.linspace(np.pi, 3 * np.pi, 64, endpoint=False)
n = np.arange(64)
wnd = fftshift(0.54 + 0.46 * np.cos(2 * np.pi * n / 63))
y = np.sin(np.sqrt(2) * t1) * wnd
plt.figure()
plt.plot(t1, y, "bo", lw=2)
plt.plot(t2, y, "ro", lw=2)
plt.plot(t3, y, "ro", lw=2)
plt.ylabel(r"$y$", size=16)
plt.xlabel(r"$t$", size=16)
plt.title(r"$\sin\left(\sqrt{2}t\right)\times w(t)$ with $t$ wrapping every $2\pi$")
plt.grid(True)
plt.savefig("Assignment_09/LaTeX/eg5.png")

t = np.linspace(-np.pi, np.pi, 64, endpoint=False)
dt = t[1] - t[0]
f_max = 1 / dt
n = np.arange(64)
wnd = fftshift(0.54 + 0.46 * np.cos(2 * np.pi * n / 63))
y = np.sin(np.sqrt(2) * t) * wnd
y[0] = 0  # the sample corresponding to -tmax should be set zero
y = fftshift(y)  # make y start with y(t=0)
Y = fftshift(fft(y)) / 64
w = np.linspace(-np.pi * f_max, np.pi * f_max, 64, endpoint=False)
plt.figure()
plt.subplot(2, 1, 1)
plt.plot(w, np.abs(Y), lw=2)
plt.xlim([-8, 8])
plt.ylabel(r"$|Y|$", size=16)
plt.title(r"Spectrum of $\sin\left(\sqrt{2}t\right)\times w(t)$")
plt.grid(True)
plt.subplot(2, 1, 2)
plt.plot(w, np.angle(Y), "ro", lw=2)
plt.xlim([-8, 8])
plt.ylabel(r"Phase of $Y$", size=16)
plt.xlabel(r"$\omega$", size=16)
plt.grid(True)
plt.savefig("Assignment_09/LaTeX/eg6.png")

t = np.linspace(-4 * np.pi, 4 * np.pi, 256, endpoint=False)
dt = t[1] - t[0]
f_max = 1 / dt
n = np.arange(256)
wnd = fftshift(0.54 + 0.46 * np.cos(2 * np.pi * n / 256))
y = np.sin(np.sqrt(2) * t)
y = y * wnd
y[0] = 0  # the sample corresponding to -tmax should be set zero
y = fftshift(y)  # make y start with y(t=0)
Y = fftshift(fft(y)) / 256
w = np.linspace(-np.pi * f_max, np.pi * f_max, 256, endpoint=False)
plt.figure()
plt.subplot(2, 1, 1)
plt.plot(w, np.abs(Y), lw=2)
plt.xlim([-8, 8])
plt.ylabel(r"$|Y|$", size=16)
plt.title(r"Spectrum of $\sin\left(\sqrt{2}t\right)\times w(t)$")
plt.grid(True)
plt.subplot(2, 1, 2)
plt.plot(w, np.angle(Y), "ro", lw=2)
plt.xlim([-8, 8])
plt.ylabel(r"Phase of $Y$", size=16)
plt.xlabel(r"$\omega$", size=16)
plt.grid(True)
plt.savefig("Assignment_09/LaTeX/eg7.png")

""" End of Examples """

def spectrum(f, n, lim, windowing=True, t=None):
    """Evaluates the DFT spectrum of a function f(t)."""
    if t is None:
        t, dt = np.linspace(-lim, lim, n, endpoint=False, retstep=True)
    else:
        dt = t[1] - t[0]
    f_max = 1 / dt
    w = np.linspace(-np.pi * f_max, np.pi * f_max, n, endpoint=False)
    y = f(t)
    if windowing:
        y *= fftshift(0.54 + 0.46 * np.cos(2 * np.pi * np.arange(n) / n))
    y[0] = 0  # the sample corresponding to -tmax should be set zero
    y = fftshift(y)  # make y start with y(t=0)
    Y = fftshift(fft(y)) / n

    return w, Y

def plotter(w, Y, title, lim, out, xlabel="$\omega$", ylabels=("$|Y|$", r"$\angle Y$")):
    """Plots the passed DFT spectrum."""
    plt.figure()
    plt.subplot(2, 1, 1)
    plt.title(title)
    plt.ylabel(ylabels[0])
    plt.plot(w, np.abs(Y), lw=2)
    plt.xlim(-lim, lim)
    plt.grid(True)

    plt.subplot(2, 1, 2)
    plt.xlabel(xlabel)
    plt.ylabel(ylabels[1])
    phase = np.angle(Y)
    phase[np.where(np.abs(Y) < 3e-3)] = 0
    plt.plot(w, phase, "ro", lw=2)
    plt.xlim(-lim, lim)
    plt.grid(True)

    plt.savefig("Assignment_09/LaTeX/" + out)

def estimate_params(w, Y):
    """Estimates the parameters omega and delta of cos(omega*t + delta)."""
    ii = np.where(w > 0)
    omega = np.sum(np.abs(Y[ii]) ** 2 * w[ii]) / np.sum(np.abs(Y[ii]) ** 2)
    i = np.argmin(np.abs(w - omega))
    delta = np.angle(Y[i])

    return omega, delta

w, Y = spectrum(lambda t: np.cos(0.86 * t) ** 3, 64 * 4, 4 * np.pi, False)
plotter(w, Y, "Spectrum of $\cos^3(\omega_0 t)$ without a Hamming window", 3, "q2a")

w, Y = spectrum(lambda t: np.cos(0.86 * t) ** 3, 64 * 4, 4 * np.pi)
plotter(w, Y, "Spectrum of $\cos^3(\omega_0 t)$ with a Hamming window", 3, "q2b")

w, Y = spectrum(lambda t: np.cos(1.5 * t + 0.5), 128, np.pi)
plotter(w, Y, "Spectrum of $\cos(\omega_0 t + \delta)$", 3, "q3")
print("Estimated w_0 = {:f}, delta = {:f} without noise".format(*estimate_params(w, Y)))

w, Y = spectrum(lambda t: np.cos(1.5 * t + 0.5) + np.random.randn(128) / 10, 128, np.pi)
plotter(w, Y, "Spectrum of $\cos(\omega_0 t + \delta) with noise$", 3, "q4")
print("Estimated w_0 = {:f}, delta = {:f} with noise".format(*estimate_params(w, Y)))

w, Y = spectrum(lambda t: np.cos(16 * t * (1.5 + t / (2 * np.pi))), 1024, np.pi, False)
plotter(w, Y, "Spectrum of chirped signal without a Hamming window", 60, "q5a")

w, Y = spectrum(lambda t: np.cos(16 * t * (1.5 + t / (2 * np.pi))), 1024, np.pi)
plotter(w, Y, "Spectrum of chirped signal with a Hamming window", 60, "q5b")

Y_mag = np.zeros((16, 64))
for i, t in enumerate(np.split(np.linspace(-np.pi, np.pi, 1024, endpoint=False), 16)):
    w, Y = spectrum(lambda t: np.cos(16 * t * (1.5 + t / (2 * np.pi))), 64, np.pi, False, t)
    Y_mag[i] = np.abs(Y)

fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")

t, dt = np.linspace(-np.pi, np.pi, 1024, endpoint=False, retstep=True)
f_max = 1 / dt
t = t[::64]
w = np.linspace(-f_max * np.pi, f_max * np.pi, 64, endpoint=False)
t, w = np.meshgrid(t, w)

surf = ax.plot_surface(w, t, Y_mag.T, cmap=cm.coolwarm, linewidth=0, antialiased=False)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.ylabel("Frequency ($\omega$)")
plt.xlabel("Time ($t$)")
plt.savefig("Assignment_09/LaTeX/q6")

plt.show()


#python3 steven 03/04/2020
#All found activation fuction in ML
#Reference: https://en.wikipedia.org/wiki/Activation_function
import numpy as np

def Identity(x):
    return x

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

def Binary_step(x):
    return np.where(x<0,0,1)

def Tanh(x):
    return np.tanh(x)

def SQNL(x): #https://ieeexplore.ieee.org/document/8489043
    y = np.zeros((len(x),))

    l = np.where(x > 2.0)
    if len(l) != 0:
        y[l[0]]=1
    l = np.where(x<=2.0)
    if len(l) != 0:
        y[l[0]]=x[l[0]]-x[l[0]]**2/4
    l = np.where(x<0)
    if len(l) != 0:
        y[l[0]]=x[l[0]]+x[l[0]]**2/4
    l = np.where(x<-2.0)
    if len(l) != 0:
        y[l[0]]=-1

    return y

def ArcTan(x):
    return np.arctan(x)

def ArcSinH(x):
    return np.arcsinh(x)

def Softsign(x): #http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf
    return x/(1+abs(x))

def ISRu(x,alpha=1.0): #https://arxiv.org/pdf/1710.09967.pdf
    return x/np.sqrt(1+alpha*x**2)

def ISRLu(x,alpha=1.0):#https://arxiv.org/pdf/1710.09967.pdf
    y = np.zeros((len(x),))
    l = np.where(x < 0)
    if len(l) != 0:
        y[l[0]]=ISRu(x[l[0]],alpha)

    l = np.where(x >= 0)
    if len(l) != 0:
        y[l[0]]=x[l[0]]

    return y

def PLu(x,alpha=0.1,c=1): #https://arxiv.org/pdf/1809.09534.pdf
    c = np.zeros((x.shape))+c
    return np.maximum(alpha*(x+c)-c, np.minimum(alpha*(x-c)+c, x))

def Relu(x): #https://www.cs.toronto.edu/~fritz/absps/reluICML.pdf
    return np.maximum(np.zeros((x.shape)),x)

def BReLu(x):#https://arxiv.org/pdf/1709.04054.pdf
    if len(x) % 2 ==0:
        return Relu(x)
    return -1*Relu(-1*x)

def LeakyRelu(x):#https://www.semanticscholar.org/paper/Rectifier-Nonlinearities-Improve-Neural-Network-Maas/367f2c63a6f6a10b3b64b8729d601e69337ee3cc
    return np.where(x<0,0.01*x,x)

def PRelu(x,alpha=.1): #https://arxiv.org/pdf/1502.01852.pdf
    return np.where(x<0,alpha*x,x)

def RRelu(x,alpha=.1): #https://arxiv.org/pdf/1505.00853.pdf
    return np.where(x<0,alpha*x,x)

def GELu(x):#https://arxiv.org/pdf/1606.08415.pdf   #https://github.com/hendrycks/GELUs
    return 0.5 * x * (1 + np.tanh(np.sqrt(2 / np.pi) * (x + 0.044715 * np.power(x, 3))))

def ELu(x,alpha=1.0): #https://arxiv.org/pdf/1511.07289.pdf
    return np.where(x<0, alpha*(np.exp(x)-1), x)

def SELu(x,alpha=1.67326,la=1.0507): #https://arxiv.org/pdf/1706.02515.pdf
    return la*ELu(x,alpha)

def softPlus(x): #http://proceedings.mlr.press/v15/glorot11a/glorot11a.pdf
    return np.log(1+np.exp(x))

def BentIdentity(x):
    return 0.5*(np.sqrt(x**2+1)-1)+x

def SoftExponential(x,alpha=1.0): #https://arxiv.org/pdf/1602.01321.pdf
    if alpha<0:
        return -1*(np.log(1-alpha*(x+alpha))/alpha)
    elif alpha == 0:
        return x
    else:
        return (np.exp(alpha*x)-1)/alpha + alpha

def SoftClipping(x,alpha=1.0): #https://arxiv.org/pdf/1810.11509.pdf
    return (1/alpha)*np.log((1+np.exp(alpha*x))/(1+np.exp(alpha*(x-1))))

def Squashing(x,alpha=0.5,lam=1.0,beta=1): #https://arxiv.org/pdf/1910.02486.pdf
    z1 = np.exp(beta*(x-(alpha-lam*0.5)))
    z2 = np.exp(beta*(x-(alpha+lam*0.5)))
    return (1/(lam*beta))*np.log((1+z1)/(1+z2))

def Sinusoid(x):
    return np.sin(x)

def Sinc(x):
    return np.where(x==0,1,np.sin(x)/x)

def Gaussian(x):
    return np.exp(-1*x**2)

def SQ_RBF(x):
    y = np.zeros((len(x),))
    l = np.where(abs(x) <= 1)
    if len(l) != 0:
        y[l[0]]=1-0.5*x[l[0]]**2

    l = np.where(abs(x) > 1)
    if len(l) != 0:
        y[l[0]]=0.5*(2-abs(x[l[0]]))**2

    l = np.where(abs(x) > 2)
    if len(l) != 0:
        y[l[0]]=0

    return y

def swish(x):
    return x*sigmoid(x)

def ACON_A(x, beta=1): #ActivateOrNot (ACON) ,RelU:max(x, 0)
    #https://arxiv.org/pdf/2009.04759.pdf
    #return x*sigmoid(x*beta)
    return ACON_B(x, 0, beta=beta)

def ACON_B(x, p, beta=1): #PRelU:max(x, p*x)
    #return (1-p)*x*sigmoid(beta*(1-p)*x) + p*x
    return ACON_C(x, 1, p, beta=beta)

def ACON_C(x, p1,p2, beta=1): #max(p1*x, p2*xx)
    return (p1-p2)*x*sigmoid(beta*(p1-p2)*x) + p2*x


# Operator functions
# MMultiply multiplies matrices. Written to ensure that any inbuilt optimal multiplication routines in python
# are not used and the fundamental matrix multiplication is done
# SparseDot uses the CSR format to perform sparse matrix multiplication efficiently

import numpy as np
from sparse_methods import MatrixtoCSR

def MMultiply(a, b, outer=False):
    if isinstance(a, (int, float)) and isinstance(b, (int, float)):
        return a*b

    if len(a.shape) == 1:
        if outer:
            a = a[:, np.newaxis]
        else:
            a = a[np.newaxis, :]
    if len(b.shape) == 1:
        if outer:
            b = b[np.newaxis, :]
        else:
            b = b[:, np.newaxis]

    (m, n) = np.shape(a)
    (p, q) = np.shape(b)

    if n != p:
        raise ValueError("Dimensions of a and b incompatible")

    ab = np.zeros((m, q), dtype=a.dtype)
    for i in range(m):
        for j in range(n):
            for k in range(q):
                ab[i][k] += a[i][j]*b[j][k]

    if ab.shape[1] == 1:
        ab = ab.transpose()[0]

    return ab

def SparseDot(Acsr, x, row=None):
    if row != None:
        dot = 0
        for i in range(Acsr['IA'][row], Acsr['IA'][row+1]):
            dot += Acsr['A'][i]*x[Acsr['JA'][i]]

        return dot

    m = Acsr['m']
    dot = np.zeros(m, dtype=Acsr['A'].dtype)
    for i in range(m):
        dot[i] = SparseDot(Acsr, x, i)

    return dot

# Test cases
if __name__ == "__main__":
    """
    A = np.array([[10., -1., 2., 0.],
              [-1., 11., -1., 3.],
              [2., -1., 10., -1.],
              [0.0, 3., -1., 8.]])
    """
    A = np.array([[10, 20, 0, 0, 0, 0],
                  [0, 30, 0, 40, 0, 0],
                  [0, 0, 50, 60, 70, 0],
                  [0, 0, 0, 0, 0, 80]], dtype=np.float64)

    b = np.array([6., 25., -11., 15., 0.3, -1])
    x = np.zeros_like(b)
    csr = MatrixtoCSR(A)
    print (b)
    print (x)
    print (MMultiply(A, b))
    print ("")
    print (np.dot(A, b))
    print ("")
    sd = SparseDot(csr, b)
    print (sd)


import numpy as np

def logistic(x):
    return 1.0 / (1.0 + np.exp(-x))

def logistic_derivative(x):
    return logistic(x) * (1.0 - logistic(x))

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

def tanh_derivative(x):
    return (1.0 - (tanh(x)**2))

def relu(x):
    return np.maximum(x, 0, x)

def relu_derivative(x):
    x[x <= 0] = 0
    x[x > 0] = 1
    return x

def softplus(x):
    return np.log(1.0 + np.exp(x))

def softplus_derivative(x):
    return 1.0 / (1.0 + np.exp(-x))


__all__ = ["cramers_corrected_stat"]

import numpy as np
import pandas as pd
import scipy.stats as ss

def cramers_corrected_stat(contingency_table: pd.DataFrame) -> float:
    """Calculate bias corrected cramer's V

    Parameters
    ----------
    contingency_table : pandas.DataFrame
        Contingency table of two nominal variables

    Returns
    -------
    float
        Cramer's V value for the input nominal variables

    Examples
    --------
    >>> import pandas as pd
    >>> from mymldev.eda import cramers_corrected_stat
    >>> df = pd.read_csv("titanic_train.csv")
    >>> cramers_corrected_stat(
    ...     pd.crosstab(df["Pclass"], df["Survived"])
    ... )
    0.33668387622245516

    Notes
    -----
    Cramer's V is the measure of association between two
    nominal variables, giving a value between 0 and +1
    '0' corresponds to no association
    '1' corresponds to complete association, value can reach 1
    only when two variables are equal to each other.

    References
    ----------
    .. [1] https://en.wikipedia.org/wiki/Cram%C3%A9r%27s_V
    """
    chi2 = ss.chi2_contingency(contingency_table)[0]
    n = contingency_table.sum().sum()
    phi2 = chi2 / n
    r, k = contingency_table.shape
    phi2corr = max(0, phi2 - ((k - 1) * (r - 1) / (n - 1)))
    rcorr = r - ((r - 1) ** 2) / (n - 1)
    kcorr = k - ((k - 1) ** 2) / (n - 1)
    cramers_v = np.sqrt(phi2corr / min((kcorr - 1), (rcorr - 1)))
    return cramers_v


from scipy.sparse.linalg import LinearOperator
from scipy.sparse import spmatrix
import numpy as np
import logging

def spectral_norm(A, tol=1e-8, max_iter=1000):
    """Computes the spectral norm of a linear operator A using power iteration.

    Parameters
    ===================
    - `A` (`numpy.ndarray`, `scipy.sparse.spmatrix`, or `scipy.sparse.linalg.LinearOperator`):
      the matrix for which we want to compute the spectral norm.

    Keyword parameters
    ====================
    - `tol` (float, default = `1e-8`): tolerance used to determine whether or not we
      should stop iterating. Once the estimates for the spectral norm are within distance
      `tol` of one another, we stop the power iterations and return.
    - `max_iter` (int, default = `1000`): maximum number of power iterations to do. If
      we reach this number of iterations then this function will return, but will display
      a warning that we reached the maximum number of iterations.
      - Power iteration can be extremely slow to converge, so you may need a large value
        of `max_iter` in order to find the true spectral norm.

    Return
    ====================
    - `sp_norm` (float): the estimated spectral norm of `A`.

    Code by Will Shand at the request of Stephen Becker, March 2019
    """
    if not any(issubclass(type(A),T) for T in [np.ndarray, spmatrix, LinearOperator]):
        raise ValueError("spectral_norm can only take arguments of type "
                "numpy.ndarray, scipy.sparse.spmatrix, or "
                "scipy.sparse.linalg.LinearOperator.")

    # Create an anonymous function matvec_op whose effect is equivalent to multiplying
    # the input by A'A.
    if issubclass(type(A), LinearOperator):
        matvec_op = lambda x: A.adjoint().matvec(A.matvec(x))
    else:
        matvec_op = lambda x: A.T.dot(A.dot(x))

    sp_norm = 0.
    sp_iter = np.random.normal(size = A.shape[-1])
    for ii in range(max_iter):
        Ax = matvec_op(sp_iter)
        new_sp_norm = np.linalg.norm(sp_iter)

        # Stopping condition when eigenvalue estimates get sufficiently close
        if abs(new_sp_norm - sp_norm) < tol:
            break
        else:
            sp_norm = new_sp_norm
            sp_iter = Ax / new_sp_norm

    if ii == max_iter-1:
        logging.warn(" spectral_norm ran for max_iter = %d iterations "
            "without converging. Returning..." % max_iter)

    return np.sqrt(sp_norm)

"""
TESTING
"""
if __name__ == "__main__":
    from scipy.sparse import random as sprandom

    # 1. Test on some random numpy arrays
    for ii in range(50):
        X = np.random.normal(size=(50,30))
        assert(abs(np.linalg.norm(X,2) - spectral_norm(X, max_iter=5000, tol=1e-8)) <= 1e-7)

    # 2. Test on some LinearOperator instances
    for ii in range(50):
        X1 = sprandom(50,50,density=0.2)
        X2 = np.random.normal(size=(10,50))

        # Dense representation of difference X1 - X2'X2
        A = X1 - X2.T.dot(X2)

        # LinearOperator representation of X1 - X2'X2
        mv  = lambda x: X1.dot(x) - X2.T.dot(X2.dot(x))
        rmv = lambda x: X1.T.dot(x) - X2.T.dot(X2.dot(x))
        L   = LinearOperator(X1.shape, matvec=mv, rmatvec=rmv)

        assert(abs(np.linalg.norm(A,2) - spectral_norm(L, max_iter=5000, tol=1e-8)) <= 1e-7)


# Interval for classification accuracy

#common confidence intervals
#    1.64 (90%)
#    1.96 (95%)
#    2.33 (98%)
#    2.58 (99%)

# for 50 samples
# binomial confidence interval
from math import sqrt
interval = 1.96 * sqrt( (0.2 * (1 - 0.2)) / 50)
print('%.3f' % interval)

# for 100 samples
# binomial confidence interval
interval = 1.96 * sqrt( (0.2 * (1 - 0.2)) / 100)
print('%.3f' % interval)

# for a dataset of 100 samples; 95% confidence interval with a significance of 0.05
from statsmodels.stats.proportion import proportion_confint
lower, upper = proportion_confint(88, 100, 0.05)
print('lower=%.3f, upper=%.3f' % (lower, upper))


# %% Imports
import numpy as np
import matplotlib.pyplot as plt

# %% Data
x = [100, 50, 40, 15, 5]
y = [1, 2, 3, 4, 5]

# %% Using polyfit
p = np.polyfit(x, y, 2, rcond=None, full=False, w=None, cov=False)
print(p)

# %% Showing results
def f(p, t):
    return p[0] * t ** 2 + p[1] * t + p[2]

min_x = np.min(x)
max_x = np.max(x)

t = np.linspace(min_x, max_x, 100, endpoint=True)
plt.scatter(x, y, c='r')
plt.plot(t, f(p, t))

# %% Using poly1d
f = np.poly1d(p)
t = np.linspace(min_x, max_x, 100, endpoint=True)
plt.scatter(x, y, c='r')
plt.plot(t, f(t))

# %% Visualization
x = [130, 100, 70, 60, 30, 10]
y = [0.5 , 1, 2, 3, 4, 5]
min_x = np.min(x)
max_x = np.max(x)
p = np.polyfit(x, y, 1, rcond=None, full=False, w=None, cov=False)
print(p)
f = np.poly1d(p)
t = np.linspace(min_x, max_x, 100, endpoint=True)
plt.scatter(x, y, c='r')
plt.plot(t, f(t))


from numpy import array,mean,log,exp

def nonlinear_fit(x,yo):
    n = len(x)
    y = log(yo)
    xsum = sum(x)
    ysum = sum(y)
    xmean = mean(x)
    ymean = mean(y)
    xysum = sum(x * y)
    x2sum = sum(x**2)
    A = (n * xysum - xsum * ysum)/(n * x2sum - xsum**2)
    B = ymean - A * xmean
    print('A = %8.4f B = %8.4f' % (A, B))
    b = exp(B)
    a = A
    return a,b

def f(a,b,x):
    return b * exp(a * x)

x = array([0, 1, 2, 4])
yo = array([2, 4, 8, 15])
a,b = nonlinear_fit(x,yo)

print('a = %8.4f b = %8.4f' % (a,b))
print("y = %8.4f exp(%8.4f x)" % (b,a))


"""
https://projecteuler.net/problem=205

Peter has nine four-sided (pyramidal) dice, each with faces numbered 1, 2, 3, 4.
Colin has six six-sided (cubic) dice, each with faces numbered 1, 2, 3, 4, 5, 6.

Peter and Colin roll their dice and compare totals: the highest total wins. The result is a draw if the totals are equal.

What is the probability that Pyramidal Pete beats Cubic Colin? Give your answer rounded to seven decimal places in the form 0.abcdefg
"""
import numpy as np

def calculate_pdf_dice(nr_side_of_dice, nr_dice):
    """"
    Help function that calculates the PDF of one dice player
    """
    max_score = nr_dice*nr_side_of_dice
    nr_possible_combinations = nr_side_of_dice**nr_dice

    outcome_frequency = np.zeros(max_score)
    dice_outcome_vector = np.ones(nr_dice)

    # Loop over all possible combination of dice to calculate the outcome frequency
    for i in range(0, nr_possible_combinations):
        outcome_result = dice_outcome_vector.sum()
        outcome_frequency[int(outcome_result - 1)] = outcome_frequency[int(outcome_result - 1)] + 1
        # Used to have a flexible way to have nested for-loops [decided by number of dice and side of dice]
        for dice_nr in range(0, nr_dice):
            updated_other_dice = False

            # Criteria to see if wone of the dice to the right shall have an updated value
            criteria_1 = dice_outcome_vector[0:dice_nr+1].sum() == nr_side_of_dice*(dice_nr+1)
            if dice_nr+1 < nr_dice:
                criteria_2 = dice_outcome_vector[dice_nr+1] != nr_side_of_dice
            else:
                criteria_2 = True

            # update dice to the right if all the dice to the left have maximum value (see criteria above)
            if criteria_1 and criteria_2 and i < nr_possible_combinations-1:
                dice_outcome_vector[0:dice_nr + 1] = 1
                dice_outcome_vector[dice_nr + 1] = dice_outcome_vector[dice_nr + 1] + 1
                updated_other_dice = True
                break
        # if not update dice to the right - update dice to the left
        if not updated_other_dice:
            dice_outcome_vector[0] = dice_outcome_vector[0] + 1

    # calculate the PDF funciton by taking the frequency/number of possible outcomes
    pdf_vector = outcome_frequency/outcome_frequency.sum()

    return pdf_vector

if __name__ == '__main__':
    peter_pdf = calculate_pdf_dice(nr_side_of_dice=4, nr_dice=9)
    colin_pdf = calculate_pdf_dice(nr_side_of_dice=6, nr_dice=6)

    # calculate probability that peter wins using conditional probabilities
    culumtative_win_peter = 0
    for i in range(0, len(peter_pdf)):
        culumtative_win_peter += colin_pdf[0:i].sum() * peter_pdf[i]

    print("probability win peter: {}".format(culumtative_win_peter))


import numpy as np
import matplotlib.pylab as plt

print("######")

def mean_squared_error(y, t):
    return 0.5 * np.sum((y - t) ** 2)

def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)

    batch_size = y.shape[0]
    delta = 1e-7
    # return -np.sum(t * np.log(y + delta)) / batch_size
    return -np.sum(np.log(y[np.arange(batch_size), t] + delta)) / batch_size

t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
y1 = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
y2 = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
print(mean_squared_error(np.array(y1), np.array(t)))
print(mean_squared_error(np.array(y2), np.array(t)))

print("######")
print(cross_entropy_error(np.array(y1), np.array(t)))
print(cross_entropy_error(np.array(y2), np.array(t)))

print("######")

# numerical differentiation

def numerical_diff(f, x):
    # h = 10e-50 # => 0.000 error
    # return (f(x+h) - f(x)) / h
    h = 10e-4  # => 0.0001
    return (f(x + h) - f(x - h)) / (h * 2)

def fn_example1(x):
    return 0.01 * x ** 2 + 0.1 * x

x = np.arange(0.0, 20.0, 0.1)
y = fn_example1(x)
plt.xlabel("x")
plt.ylabel("f(x)")
plt.plot(x, y)
plt.show()

print(numerical_diff(fn_example1, 5))
print(numerical_diff(fn_example1, 10))
print("######")

def tangent_line(f, x):
    d = numerical_diff(f, x)
    print(d)
    y = f(x) - d * x
    return lambda t: d * t + y

tf2 = tangent_line(fn_example1, 5)
tf3 = tangent_line(fn_example1, 10)
y2 = tf2(x)
y3 = tf3(x)

plt.plot(x, y)
plt.plot(x, y2)
plt.plot(x, y3)
plt.show()

print("######")
# Partial differentiation

def fn_example2(x):
    return x[0] ** 2 + x[1] ** 2
    # return np.sum(x**2)

def fn_tmp1(x0):
    return x0 * x0 + 4 ** 2

def fn_tmp2(x1):
    return 3 ** 2 + x1 * x1

print(numerical_diff(fn_tmp1, 3))
print(numerical_diff(fn_tmp2, 4))


import numpy as np

def householder_compute (x):
  s = np.dot(x,x)
  alpha = -np.sign(x[0])*np.sqrt(s)
  x[0] -= alpha
  x /= np.sqrt(np.dot(x,x))
  return alpha

def householder_apply (u,x):
  n = x.shape
  s = np.dot(u,x)
  for i in range(0,n[0]):
    x[i] -= 2*s*u[i]

def householder_qr (A):
  (m,n) = A.shape
  D = np.zeros(n)
  for k in range(0,n-1):
    D[k] = householder_compute(A[k:m,k])
    for i in range (k+1,n):
      householder_apply(A[k:m,k],A[k:m,i])
  return D

def householder_solve (QR,D,b)
  (m,n) = QR.shape
  for k in range (0,n-1):
    householder_apply(QR[k:m,k],b[k:m])
  x = np.zeros(n)
  for k in range(n-1,-1,-1):
    x[k] = b[k]
    for j in range(k+1,n):
      x[k] -= A[k,j]*x[j]
    x[k] /= D[k]
  return x

x = np.array([3.,4.,5.])
print (x.shape)
u = np.copy(x)
print(x)
a = householder_compute(u)
print(x)
print(u)
print(a)

householder_apply (u,x)
print(x)

print("QR")
A = np.array([[2.,-1.,0.],[-1.,2.,-1.],[0.,-1.,2.]])
diag = householder_qr(A)
print(A)
print(diag)


import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from sklearn import linear_model
import matplotlib.animation as animation
import os
import subprocess

# apply gradient descent algorithm to optimiza cost function of several variables

def cost(x):
	"""Cost function of linear regression (LR) model with coefficient x"""
	m = A.shape[0]
	return .5/m *np.linalg.norm(A.dot(x)-b,2)**2

def grad(x):
	"""Gradient function of cost function"""
	m = A.shape[0]
	return 1/m *A.T.dot(A.dot(x)-b)

def numerical_grad(x, cost):
	"""Calculating numerical gradient with coefficient x to check whether our grad function is correct or not"""
	eps = 1e-4
	g = np.zeros_like(x)
	for i in range(len(x)):
		x_p = x.copy()
		x_n = x.copy()
		x_p[i] += eps
		x_n[i] -= eps
		g[i] = (cost(x_p) - cost(x_n))/(2*eps)
	return g

def check_grad(x, cost, grad):
	"""Check grad function by comparing actual gradient value and numerical gradient (estimation)"""
	x = np.random.rand(x.shape[0], x.shape[1])
	grad1 = grad(x)
	grad2 = numerical_grad(x, cost)
	return True if np.linalg.norm(grad1 - grad2) < 1e-6 else False

def gradient_descent(x_init, grad, alpha):
	"""
	Running gradient descent with initial value x_init, grad function, learning rate alpha
	This function return x: list of solution after each iteration and iteration: last iteration it has gone through
	"""
	m = len(x_init)
	x = [x_init]
	for iteration in range(itr):
		x_new = x[-1] - alpha*grad(x[-1])
		if np.linalg.norm(grad(x_new))/m < 1e-3: #Stop gradient descent when grad value is too small.
			break
		x.append(x_new)
	return (x, iteration)

############### Main ####################

# create random data
b = np.array([[2,5,7,9,11,16,19,23,22,29,29,35,37,40,46,42,39,31,30,28,20,15,10,6]]).T
A = np.array([[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]]).T

ax = plt.axes(xlim=(-10, 50), ylim=(-10, 50)) #restrict the figure showing only values in specified range

#Visualize data
plt.plot(A,b,'ro', label='_nolegend_') # plot data points
fig1 = plt.figure(1)
# append column ones to matrix A
ones = np.ones((A.shape[0],1), dtype=np.int8)
A = np.concatenate((ones,A), axis=1)

## append x^2 to A
x_square = np.array([A[:,1]**2]).T
A = np.concatenate((A,x_square), axis=1)

line, = ax.plot([], [], color = 'blue') # plot function used in animation

# plot solution found by scikit learn
A_dagger = np.linalg.inv(A.transpose().dot(A)).dot(A.transpose())
x_formula = A_dagger.dot(b)

x0_gd = np.linspace(1,46,10000)
y0_sklearn = x_formula[0][0] + x_formula[1][0]*x0_gd + x_formula[2][0]*x0_gd*x0_gd
plt.plot(x0_gd, y0_sklearn, color='green')

# apply gradient descent
itr = 101
learning_rate = .000001 #.0001
x_init = np.array([[1], [1], [-1]])
x_init = np.array([[ 1.05455731],
       [ 3],
       [-0.01216413]])

print('Checking gradient...', check_grad(np.random.rand(3, 1), cost, grad))

# running gradient descent
myGD = gradient_descent(x_init, grad, learning_rate)

# plot x_init (black line)
x0_gd = np.linspace(1,46,10000)
y0_init = x_init[0][0] + x_init[1][0]*x0_gd + x_init[2][0]*x0_gd*x0_gd

plt.plot(x0_gd, y0_init, color = 'black')

# plot lines in each iteration
def update(i):
	x_gd = myGD[0][i]
	y0_gd = x_gd[0][0] + x_gd[1][0]*x0_gd + x_gd[2][0]*x0_gd*x0_gd
	line.set_data(x0_gd,y0_gd)
	# print(i)
	# print(round(np.linalg.norm(grad(myGD[0][i]))/3, 3))
	plt.xlabel('Iteration: {}/{}, |grad|={}'.format(i, myGD[1],round(np.linalg.norm(grad(myGD[0][i]))/3, 3)))
	return line,

# legend for graph
plt.legend(('Value in each GD iteration', 'Solution by formular', 'Inital value for GD'), loc=(0.52, 0.01))
ltext = plt.gca().get_legend().get_texts()
plt.setp(ltext[0], fontsize=10)
plt.setp(ltext[1], fontsize=10)
plt.setp(ltext[2], fontsize=10)

# save animation to mp4 file using ffmpeg
Writer = animation.writers['ffmpeg']
writer = Writer(fps=15, metadata=dict(artist='Me'), bitrate=1800)

line_ani = animation.FuncAnimation(fig1, update, myGD[1]+1, interval=50, blit=True)
line_ani.save('100iteration.mp4', writer='ffmpeg')

# https://stackoverflow.com/questions/11269575/how-to-hide-output-of-subprocess-in-python-2-7
# FNULL = open(os.devnull, 'w')
# subprocess.call(['ffmpeg', '-i', '50iter.mp4', '50iter.gif'], stdout=FNULL, stderr=subprocess.STDOUT) # Execute command line to convert .mp4 to .gif using ffmpeg and hide output of command line to terminal

plt.show()


from lega.legendre_basis import legendre_function, mass_matrix,\
    stiffness_matrix, legendre_basis
from scipy.linalg import eigh
from sympy.plotting import plot
from sympy import Symbol
from math import sqrt
import numpy as np

# Visualize the eigenfunctions of -u'' = lmnda u in (-1, 1) with u'(-1)=u'(1)=0

n = 10
basis = legendre_basis(10)

# Solve the eigenvalue problem to get coeffs of the new basis
A = stiffness_matrix(n)
M = mass_matrix(n)

lmbda1, V1 = eigh(A.toarray()[1:, 1:], M.toarray()[1:, 1:])
lmbdas = np.concatenate([np.array([0]), lmbda1])
V = np.eye(n)/sqrt(2.)
V[1:, 1:] = V1

# Make the new basis
Abasis = [legendre_function(v) for v in V.T]

print 'eigenvalues', lmbdas

# Plot the basis for comparison
x = Symbol('x')
f_fA = iter(zip(basis, Abasis))

f, fA = next(f_fA)
p = plot(f, (x, -1, 1), show=False)
p[0].line_color = 'red'
p_ = plot(fA, (x, -1, 1), show=False)
p_[0].line_color = 'blue'
p.append(p_[0])

for f, fA in f_fA:
    p_ = plot(f, (x, -1, 1), show=False)
    p_[0].line_color = 'red'
    p.append(p_[0])

    p_ = plot(fA, (x, -1, 1), show=False)
    p_[0].line_color = 'blue'
    p.append(p_[0])

p.show()

# Some questions, what are the approximation properties of Abasis? And how does
# the transformation between function and its series look? And, is there a
# clever way to get the eigenvalues and eigenvectors


import numpy as np

def Mahalanobis_distance(x, mu, M):
    """
    Calculating the Mahalanobis distance between x and mu, MD(x,mu), in a space with metric M.

    ------------PARAMETERS------------
    @param simul : Number of simulations

    @param x : First vector
    @param mu : Second vector, usually containing the expected values
    @param M : The inverse of the covariance matrix
    @returns : The Mahalanobis distance between x and mu MD(x,mu)
    ----------------------------------
    """

    delta = np.array(x)-np.array(mu)
    #MD(x,mu) = (delta*M*delta)^{1/2}
    return np.sqrt(np.dot(np.dot(delta,M),delta))

def multivariate_hypergeometric_Mahalanobis_distance(x, mu, m):
    """
    Calculating the Mahalanobis distance between x and mu, MD(x,mu), in a metric space defined by a multivariate hypergeometric distribution defined using the vector m.

    ------------PARAMETERS------------
    @param simul : Number of simulations

    @param x : First vector
    @param mu : Second vector, usually containing the expected values
    @param m : Vector containing the number of items in each category
    @returns : The MD(x,mu) and a vector containg the contributions to the square of the MD(x,mu)
    ----------------------------------
    """
    MD=[]
    N = sum(m)
    n = sum(x)
    #if n!=sum(mu):
    #    print("ERROR: The numer of element in each ranking vector must be the same")
    #    print("Please correct")
    #    return None
    gamma = n*(N-n)/(N-1)/N/N

    for i in range(len(x)):
        MD.append(pow((x-mu)[i],2)/N/m[i])

    return np.sqrt(sum(MD)/gamma), np.array(MD)/gamma