# Bench mark function 12
# Generalized Penalized Function No.01
# HW dimension: 30
# Min = 0
# Range [-50,50]
# Reference: https://al-roomi.org/benchmarks/unconstrained/n-dimensions/172-generalized-penalized-function-no-1

import math
import numpy as np

name = "F12"
l_bound = -50
u_bound = 50
dim = 30
opt = 0

def u(u_X, a, k, m):
    X = u_X.copy()
    for index in range(X.size):
        element = X[index]
        if element > a:
            X[index] = k * (element - a)**m
        elif element < -1 * a:
            X[index] = k * (-1 * element - a)**m
        else:
            X[index] = 0
    return X

def func(X):
    Y = 1 + (X+1)/4
    f_term = 10 * math.sin(math.pi*Y[0])**2
    m_1 = (Y[0:-1] - 1)**2
    m_2 = 1 + 10 * np.sin(math.pi*Y[1:])**2
    m_term = np.sum(np.multiply(m_1, m_2))
    l_term = (Y[-1]-1)**2
    front = math.pi * (f_term + m_term + l_term) / X.size
    end = np.sum(u(X, 10, 100, 4))
    result = front + end
    return result

if __name__ == '__main__':
    X = np.arange(10)
    X = X * 0.3
    print(X)
    result = func(X)
    print(result)


################################################################################
#                                                                              #
#	UJJWAL KHANDELWAL                                                      #
#	CSO (CUCKOO SEARCH OPTIMIZATION)                                       #
#	PYTHON 3.7.10                                                          #
#                                                                              #
################################################################################

#######################   IMPORT DEPENDENCIES   ################################

import numpy as np

######################## FITNESS FUNCTION 1 ######################################

def fitness_1(X):

    '''

    X: POSITION (EITHER CURRENT, LOCAL BEST OR GLOBAL BEST) OF SIZE (n,)

    2-DIMENSIONAL VECTORS (X = (x,y))

    #################################################################################

    HIMMELBLAU'S FUNCTION

    MINIMIZE f(x) = (x^2 + y - 11)^2 + (x + y^2 - 7)^2

    OPTIMUM SOLUTION IS x* = 3 AND y* = 2

    REPLACE 'f' BELOW WITH THIS TO TEST EXAMPLE-1

    f = (x**2 + y - 11)**2 + (x + y**2 - 7)**2

    '''
    X = np.array(X).reshape(-1,1)
    x, y = X[0][0], X[1][0]
    f = (x**2 + y - 11)**2 + (x + y**2 - 7)**2
    return f

######################## FITNESS FUNCTION 2 ######################################

def fitness_2(X):

    '''

    X: POSITION (EITHER CURRENT, LOCAL BEST OR GLOBAL BEST) OF SIZE (n,)

    2-DIMENSIONAL VECTORS (X = (x,y))

    #################################################################################

    BOOTH'S FUNCTION

    MINIMIZE f(x) = (x + 2y - 7)^2 + (2x + y - 5)^2

    OPTIMUM SOLUTION IS x* = 1 AND y* = 3

    REPLACE 'f' BELOW WITH THIS TO TEST EXAMPLE-2

    f = (x + 2*y - 7)**2 + (2*x + y - 5)**2

    '''
    X = np.array(X).reshape(-1,1)
    x, y = X[0][0], X[1][0]
    f = (x + 2*y - 7)**2 + (2*x + y - 5)**2
    return f

######################## FITNESS FUNCTION 3 ######################################

def fitness_3(X):

    '''

    X: POSITION (EITHER CURRENT, LOCAL BEST OR GLOBAL BEST) OF SIZE (n,)

    2-DIMENSIONAL VECTORS (X = (x,y))

    #################################################################################

    BEALE'S FUNCTION

    MINIMIZE f(x) = (1.5 - x - xy)^2 + (2.25 - x + xy^2)^2 + (2.625 - x + xy^3)^2

    OPTIMUM SOLUTION IS x* = 3 AND y* = 0.5

    REPLACE 'f' BELOW WITH THIS TO TEST EXAMPLE-3

    f = (1.5 - x + x*y)**2 + (2.25 - x + x*(y**2))**2 + (2.625 - x + x*(y**3))**2

    #################################################################################

    '''
    X = np.array(X).reshape(-1,1)
    x, y = X[0][0], X[1][0]
    f = (1.5 - x + x*y)**2 + (2.25 - x + x*(y**2))**2 + (2.625 - x + x*(y**3))**2
    return f

def fitness_4(X):

    '''

    X: POSITION (EITHER CURRENT, LOCAL BEST OR GLOBAL BEST) OF SIZE (n,)

    2-DIMENSIONAL VECTORS (X = (x,y))

    #################################################################################

    MAXIMIZE f(x) = 2xy + 2x - x^2 - 2y^2

    OPTIMUM SOLUTION IS x* = 2 AND y* = 1

    REPLACE 'f' BELOW WITH THIS TO TEST fitness_4

    f = 2*x*y + 2*x - x**2 - 2*(y**2)

    #################################################################################

    '''
    X = np.array(X).reshape(-1,1)
    x, y = X[0][0], X[1][0]
    f = 2*x*y + 2*x - x**2 - 2*(y**2)
    return f

def fitness_5(X):

    '''

    X: POSITION (EITHER CURRENT, LOCAL BEST OR GLOBAL BEST) OF SIZE (n,)

    2-DIMENSIONAL VECTORS (X = (x,y))

    #################################################################################

    BIVARIATE MICHAELWICZ FUNCTION

    MINIMIZE f(x) = -sin(x)*(sin(x^2/π)^2m) - sin(y)*(sin(2y^2/π)^2m)

    OPTIMUM SOLUTION IS x* = 2.20319, AND y* = 1.57049

    REPLACE 'f' BELOW WITH THIS TO TEST EXAMPLE-5

    f = -np.sin(x)*(np.sin(x*x/np.pi)**(2*m))-np.sin(y)*(np.sin(2*y*y/np.pi)**(2*m))

    '''
    X = np.array(X).reshape(-1,1)
    m = 10
    x, y = X[0][0], X[1][0]
    f = -np.sin(x)*(np.sin(x*x/np.pi)**(2*m))-np.sin(y)*(np.sin(2*y*y/np.pi)**(2*m))
    return f


#!/usr/bin/env python3
"""
Optimization Module
"""
import numpy as np

def normalization_constants(X):
    """
    Calculates the normalization (standardization) constants of a matrix

    X is the numpy.ndarray of shape (m, nx) to normalize
        m is the number of data points
        nx is the number of features

    Returns: the mean and standard deviation of each feature, respectively
    """
    mean = np.sum(X, axis=0) / X.shape[0]
    vrnc = np.sum((X - mean) ** 2, axis=0) / X.shape[0]
    stdv = np.sqrt(vrnc)
    return mean, stdv


# -*- coding: utf-8 -*-
" We solve the numerical integral in this pyfile. Newton-Cotes integral rule, Composite Newton-Cotes integral rule are mentioned "

import numpy as np

""" Input data Instance:
data = np.array([[0,3],
                 [1,5],
                 [2,6],
                 [3,8]])

"""

def trapezium(data,a,b):
    " Integral from ath data to bth data "
    #dim = b-a
    x = data[a-1,0]
    y = data[b-1,0]
    fx = data[a-1,1]
    fy = data[b-1,1]
    return (y-x)/2*(fx+fy)

# trapezium(data,1,2)

def sinpson(data,a,b):
    " Integral from ath data to bth data "
    dim = b-a
    if dim%2 != 0:
        return "Error"
    else:
        x = data[a-1,0]
        #xy = data[(b+a)/2-1,0]
        y = data[b-1,0]
        fx = data[a-1,0]
        fy = data[b-1,0]
        fxy = data[(b+a)/2-1,0]
        return (y-x)/6*(fx+4*fxy+fy)

"""
data = np.array([[0,1],
                 [0.125,0.997398],
                 [0.25,0.989688],
                 [0.375,0.976727],
                 [0.5,0.958851],
                 [0.625,0.936156],
                 [0.75,0.908858],
                 [0.875,0.877193],
                 [1,0.841471]])
"""

def com_trapezium(data):
    dim = data.shape[0]
    a = data[0,0]
    b = data[dim-1,0]
    h = (b-a)/(dim-1)
    result = data[0,1]+data[dim-1,1]
    for index in range(1,dim-1):
        result = result + 2*data[index,1]
    return result*h/2

def com_sinpson(data):
    dim = data.shape[0]
    a = data[0,0]
    b = data[dim-1,0]
    h = (b-a)/(dim-1)*2
    result = data[0,1]+data[dim-1,1]
    #times = (dim-1)/2
    for index in range(1,dim-1):
        if index%2 != 0:
            result = result + 4*data[index,1]
        else:
            result = result + 2*data[index,1]
    return result*h/6

#com_trapezium(data)
#com_sinpson(data)


import matplotlib.pyplot as plt
import numpy as np
import sympy as sp
from sympy.abc import x

def get_integrated_tanh_sympy():
    return sp.integrate(sp.tanh(x), x)

def get_integrated_sigmoid_sympy():
    sigmoid = get_sigmoid_function_sympy()
    return sp.integrate(sigmoid, x)

def get_sigmoid_function_sympy():
    sigmoid = 1 / (1 + sp.exp(-x))
    return sigmoid

def proc_sympy_function(x_array, expression, label, lib='numpy'):
    # Numeric Computation, Sympy documentation, 2016, [Online] Available
    # http://docs.sympy.org/dev/modules/numeric-computation.html
    f = sp.lambdify(x, expression, lib)
    y_f = f(x_array)
    plt.plot(x_array, y_f, label=label)

def step(z):
    """
    return an array of same size as z.
    For elements of z larger than zero, return one.
    Otherwise zero.

    :type z: Any
    :param z: input. preferrably a ndarray
    :return:
    """
    result = np.zeros_like(z)
    result[z > 0] = 1.0
    return result

def ReLU(x_array):
    result = np.zeros_like(x_array)
    result[0 < x_array] = x_array[0 < x_array]
    return result

def main(min_x=-8, max_x=8):
    min_x, max_x = sorted([min_x, max_x])
    x_array = np.linspace(min_x, max_x, 101)

    x_array_step = get_x_step_array(min_x, max_x)

    symbols_to_be_processed_list = [
        {'label': 'sigmoid', 'f': get_sigmoid_function_sympy()},
        {'label': 'integrated sigmoid', 'f': get_integrated_sigmoid_sympy()},
    ]

    for fmt in ('pdf', 'png'):
        plt.clf()

        for d in symbols_to_be_processed_list:
            proc_sympy_function(x_array, d['f'], d['label'])

        y_ReLU = ReLU(x_array)
        plt.plot(x_array, y_ReLU, label='ReLU')

        y_step = step(x_array_step)
        plt.plot(x_array_step, y_step, label='step')

        plt.grid(True)
        plt.legend(loc=0)
        plt.axis('equal')
        plt.savefig('activation.%s' % fmt)

def get_x_step_array(min_x, max_x):
    if 0 > min_x * max_x:
        # if min_x and max_x have different signs
        x_array_step = np.array([min_x, 0.0, 1e-10, max_x])
    elif 0 < min_x * max_x:
        # if min_x and max_x have same signs
        x_array_step = np.array([min_x, max_x])
    elif 0 == min_x:
        x_array_step = np.array([min_x, 1e-10, max_x])
    elif 0 == max_x:
        x_array_step = np.array([min_x, 0, 1e-10])
    else:
        raise ValueError('Unable to decide x array')

    return x_array_step

if __name__ == '__main__':
    main()


import numpy as np
import matplotlib.pyplot as plt

# generate 2D mesh grid
nx, ny = (100, 100)

x = np.linspace(0, 10, nx)
y = np.linspace(0, 10, ny)

xv, yv = np.meshgrid(x, y)

# define function to plot
def f(x, y):
    return x * (y ** 2)

# calculate Z value for each X,Y point
z = f(xv, yv)

"""
Now that we have our mesh grid and have calculated f(x,y) for all points on the mesh
grid,we can visualize the results! The z points on the graph will be represented using
a colormap.
"""

# Make a Color plot to display the data
plt.figure(figsize=(14, 12))
plt.pcolor(xv, yv, z)
plt.title('2D Color Plot of f(x,y)=xy^2')
plt.colorbar()
# plt.show()

# generate 2D mesh grid for Gradient
nx, ny = (10, 10)
x = np.linspace(0, 10, nx)
y = np.linspace(0, 10, ny)
xg, yg = np.meshgrid(x, y)

# calculate the gradient of f(x,y)
# Note: numpy returns answer in rows (y), columns (x) format
# Gy, Gx = np.gradient(f(xg, yg))

# calculate the gradient by formula for f(x, y) = x*y^2

def ddx(x, y):
    return y ** 2

def ddy(x, y):
    return 2 * x * y

Gx = ddx(xg, yg)
Gy = ddy(xg, yg)

# Make a Color plot to display the data
fig = plt.figure(figsize=(14, 12))
plt.pcolor(xv, yv, z)
plt.colorbar()
plt.quiver(xg, yg, Gx, Gy, scale=1000, color='w')
plt.title('Gradient of f(x,y) = xy^2')
plt.savefig('gradient.png')
plt.close(fig)


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

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import datasets

def hypo(X, theta):
    return theta * X[:,0]

def costFunc(X, y, theta, h=hypo):
    m = np.shape(X)[0]
    diff = h(X, theta) - y
    cost_list = np.power(diff, 2)
    return np.sum(cost_list) / (2 * float(m))

# gradient descent
def gradientDescent(X, y, alpa=0.1, h=hypo):
    m = np.shape(X)[0]
    theta = 0.0
    thetaArr = []
    maxCycles = 1000
    for k in range(maxCycles):
        theta = theta - alpa * ( np.sum((h(X, theta) - y) * X[:, 0]) / float(m) )
        thetaArr.append(theta)
    return theta, thetaArr

def showData(X, y):
    plt.title('x-y data')
    plt.scatter(X[:, 0], y)
    plt.show()

def showTheta_Cost(theta_list, cFunc=costFunc):
    cost_list = []
    for theta in theta_list:
        cost = cFunc(X, y, theta, h=hypo)
        cost_list.append(cost)
    plt.title('theta - cost')
    plt.scatter(theta_list, cost_list)
    plt.show()

# generate data
np.random.seed(314)
X, y = datasets.make_regression(n_samples=100, n_features=1, noise=10)
showData(X, y)

# plot the cost with different theta (model parameter)
cost_list = []
theta_list = np.arange(0, 50, 1)
for theta in theta_list:
    cost = costFunc(X, y, theta, h=hypo)
    cost_list.append(cost)
showTheta_Cost(theta_list, cFunc=costFunc)

# optimize cost-function by using gradient descent algorithm
theta, thetaArr = gradientDescent(X, y)
showTheta_Cost(thetaArr, cFunc=costFunc)

# plot the final result (best model paramter)
plt.title('best regression model')
plt.scatter(X[:, 0], y, c='b')
plt.plot(X[:, 0], hypo(X, theta), 'r')


import numpy as np

# https://stackoverflow.com/questions/34968722/how-to-implement-the-softmax-function-in-python
def np_softmax(x):
    """Compute softmax values for each sets of scores in x."""
    e_x = np.exp(x - np.max(x, axis=1, keepdims=True))
    return e_x / e_x.sum(axis=1, keepdims=True)

def np_sigmoid(x):
    return 1 / (1 + np.exp(-x))


from numpy import linspace, sin, cos, pi, absolute, real, imag, arctan, arctan2
from numpy.fft import fft, fftfreq, fftshift
import matplotlib.pyplot as plt

def dft(x):
    N = x.size
    n = np.arange(N)
    k = n.reshape((N, 1))
    e = np.exp(-2j * np.pi * k * n / N)
    return np.dot(e, x)

##
## Exercício 1
##
def exercicio1():

	# Sampling rate
	fs = 32  # Hz

	# Time is from 0 to 1 seconds, but leave off the endpoint, so
	# that 1.0 seconds is the first sample of the *next* chunk
	length = 1  # second
	N = fs * length
	t = linspace(0, length, num=N, endpoint=False)

	# Generate a sinusoid at frequency f
	f1 = 8  # Hz
	a = 3.0 * sin(2 * pi * f1 * t)

	# Plot signal, showing how endpoints wrap from one chunk to the next
	plt.subplot(3, 1, 1)
	plt.plot(t, a, '.-')
	plt.plot(t, a, 'r.')  # first sample of next chunk
	plt.margins(0.1, 0.1)
	plt.xlabel('Time [s]')

	## DFT
	ffta = fft(a)

	## normalized amplitude
	ampl = 2 * 1/N * abs(ffta)

	## real and imaginary part
	re = real(ffta)
	im = imag(ffta)

	# FFT frequency bins
	freqs = fftfreq(N, 1/fs)

	# Plot shifted data on a shifted axis
	plt.subplot(3, 1, 2)
	plt.stem(fftshift(freqs), fftshift(ampl))
	plt.margins(0.1, 0.1)
	plt.xlabel('Frequency [Hz]')

	plt.subplot(3, 1, 3)
	plt.stem(fftshift(freqs), fftshift(arctan2(im, re)*180/pi))
	plt.margins(0.1, 0.1)
	plt.xlabel('Frequency [Hz]')
	plt.tight_layout()
	plt.show()

##
## Exercício 2
##
def exercicio2():

	# Sampling rate
	fs = 64  # Hz

	# Time is from 0 to 1 seconds, but leave off the endpoint, so
	# that 1.0 seconds is the first sample of the *next* chunk
	length = 1  # second
	N = fs * length
	t = linspace(0, length, num=N, endpoint=False)

	# Generate a sinusoids
	f1 = 8   # Hz
	f2 = 12  # Hz
	f3 = 20  # Hz
	a = 3.0 * sin(2 * pi * f1 * t) + 1.5 * cos(2 * pi * f2 * t) + 0.5 * sin(2 * pi * f3 * t)

	# Plot signal, showing how endpoints wrap from one chunk to the next
	plt.subplot(3, 1, 1)
	plt.plot(t, a, '.-')
	plt.plot(t, a, 'r.')  # first sample of next chunk
	plt.margins(0.1, 0.1)
	plt.xlabel('Time [s]')

	## DFT
	ffta = fft(a)

	## normalized amplitude
	ampl = 2 * 1/N * abs(ffta)

	## real and imaginary part
	re = real(ffta)
	im = imag(ffta)

	# FFT frequency bins
	freqs = fftfreq(N, 1/fs)

	# Plot shifted data on a shifted axis
	plt.subplot(3, 1, 2)
	plt.stem(fftshift(freqs), fftshift(ampl))
	plt.margins(0.1, 0.1)
	plt.xlabel('Frequency [Hz]')

	plt.subplot(3, 1, 3)
	plt.stem(fftshift(freqs), fftshift(arctan2(im, re)*180/pi))
	plt.margins(0.1, 0.1)
	plt.xlabel('Frequency [Hz]')
	plt.tight_layout()
	plt.show()


"""
Script to create metaballs structures encoded as arrays.
Metaballs structures used for background generation.
"""

import numpy as np

def norm(x,y,p):
    """
    Normalise x and y. Raises x and y to power p sum them and then take
    root to the power 1/p.
    Since this value can be used as divisor, a small constant is added
    to ensure it is never zero
    :param x: value to be normalized
    :param y: value to be normalized
    :param p: normalization factor
    :return: sum of normalized values raised to 1/p
    """
    #the constant factor is to ensure that norm is never 0 as it is used
    # as divisor
    n = np.power(np.power(np.abs(x),p) + np.power(np.abs(y),p), 1./p)+1e-08
    return n

class ball:
    """
    Class representing a 2D ball, with a center, radius and normalization
    factor. Provides function to calculate inverse distance to a point
    relative to the radius.
    :param radius: radius of the ball
    :param x0: x coordinate of the center
    :param y0: y coordinate of the center
    :param norm: normalisation factor
    """
    def __init__(self, radius, x0, y0, norm):
        self.radius = radius
        self.x0 = x0
        self.y0 = y0
        self.norm = norm

    def inverse_distance(self, x, y):
        """
        Calcutes the inverse distance from a point to the sphere center
        :param x: x coordinate of the point
        :param y: y coordinate of the point
        :return: inverse distance to the point scaled by the radius
        """
        return self.radius/norm(x-self.x0, y-self.y0, self.norm)

def sum_inverse_distance(x,y,balls):
    """
    For a given ball and array of points calculates the inverse distance
    of each point to each ball and sums values for each point together. This
    produce an array of the same size as the input x,y arrays
    :param x: array of x coordinates of individual points
    :param y: array of y coordinates of individual points
    :balls: array of ball class instances
    :return f: array of sums of inverse distances of each point to all balls
        respectively (e.g. f[0] is sum of all inverse distances of
        point x[0],y[0])
    """
    if(x.shape!=y.shape):
        raise IndexError("The x and y parameters don't have the same shape")

    f = np.zeros(x.shape)
    for ball in balls:
        f += ball.inverse_distance(x,y)
    return f

def metaball(rows, cols, balls, thres):
    """
    For a 2D array of given number of rows and collumns, it calculates
    the inverse distance to all balls. Creates a boolean array of same size
    where True, if the points sum of inverse distances is bigger than given
    treshold.
    :param rows: int number of rows
    :param cols: int number of collumns
    :param balls: array of ball class instances
    :param thres: threshold for the inverse distance
    :return filled: boolean array of the specified size with True for entries
        which coordinate representation inverse distance was larger than
        treshold
    """
    # create arrays of X,Y coordinates
    Y = np.linspace(0,rows-1,rows)
    Y = np.reshape(Y,(rows,1))
    Ystack = []
    for i in range(cols):
        Ystack.append(Y)
    Y = np.hstack(Ystack)

    X = np.linspace(0,cols-1,cols)
    Xstack = []
    for i in range(rows):
        Xstack.append(X)
    X = np.vstack(Xstack)

    # compute the sum_inverse_distance over the coordinates, using numpy matrix operations
    f = sum_inverse_distance(X,Y,balls)
    filled = f > thres
    return filled

def random_metaball(row, col, n_balls, size):
    """
    Returns a metaball images with specified size (row, col), number of
    balls present. The amount of metaball features present can be controlled
    through the n_balls and size (threshold for pixel being included in the
    metaball)
    :param row: number of rows of returned image
    :param col: number of collumns of returned image
    :param n_balls: number of balls to generate
    :param size: treshold for point being included in a metaball
    :return metaball: returns a row*col array image of metaball features
    """
    centre_x = np.random.randint(0,col)
    centre_y = np.random.randint(0,row)
    sigma_x = np.round(col/10.0)
    sigma_y = np.round(row/10.0)
    min_ball_radius = col/(15*n_balls)
    max_ball_radius = col/(10*n_balls)

    # generate balls
    Balls = []
    for i in range(n_balls):
        x = np.round(np.random.normal(centre_x, sigma_x))
        y = np.round(np.random.normal(centre_y, sigma_y))
        x = min(max(x,0),col-1)
        y = min(max(y,0),row-1)
        radius = np.random.uniform(min_ball_radius, max_ball_radius)

        norm = np.random.randint(1,3)

        Balls.append(ball(radius, x, y, norm))

    return metaball(row, col, Balls, size)


import numpy as np
from scipy.integrate import quad
from scipy.special import gamma as Gamma

def integrand(phi, l, i):
    """Integrand in the q^l_i expression."""
    sin = np.sin(phi)
    cos = np.cos(phi)
    return (
        np.sign(sin) ** i * (1 - cos) ** (l - i / 2) * (1 + cos) ** (i / 2)
    ) / (2 * np.pi)

def qli_numerical(l, i):
    """Integration of q^l_i by quadrature."""
    return quad(integrand, -np.pi, np.pi, args=(l, i))[0]

def qli_closed_form(l, i):
    """Closed form solution forq^l_i."""
    return (
        2 ** l
        / np.pi
        * Gamma(0.5 * (1 + i))
        * Gamma(l + 0.5 * (1 - i))
        / Gamma(l + 1)
    )

def test_qli(lmax=10):
    """
    Show that our closed form expression for the integral is correct.
    """
    for l in range(lmax + 1):
        for i in range(0, 2 * l + 1, 2):
            assert np.allclose(qli_closed_form(l, i), qli_numerical(l, i))


import numpy as np

def qeq(a, b, c):
    """
    Solve quadratic equation.
    """
    d = np.sqrt(b**2 - 4 * a * c)
    return ((-b + d) / (2 * a)), ((-b - d)/ (2 * a))

def qeq2(a, b, c):
    """
    Solve quadratic equation with less error.
    """
    d = np.sqrt(b**2 - 4 * a * c)
    alpha = (-b - np.sign(b) * d) / (2 * a)
    beta = c / (a * alpha)
    return alpha, beta


import math
import numpy as np

def dotproduct(v1, v2):
	return sum((a*b) for a, b in zip(v1, v2))

def length(v):
	return math.sqrt(dotproduct(v, v))

def getRotateAngle(v1, v2):
	return math.acos(np.clip(dotproduct(v1, v2) / (length(v1) * length(v2)), -1, 1))

def distanceEuclidean(a, b):
	return np.linalg.norm(sum(x1 - x2 for x1, x2 in zip(a, b)))

def mean(numbers):
	return float(sum(numbers)) / max(len(numbers), 1)

def RMSE(v1, v2):
	return mean([distanceEuclidean(a, b) for a, b in zip(v1, v2)])

def rotateCore(point, rad):
	x = math.cos(rad)*point[0] - math.sin(rad)*point[1]
	y = math.sin(rad)*point[0] + math.cos(rad)*point[1]
	return [x, y]

def rotatePoint(point, rad):
	return rotateCore(point, rad)

def rotatePointArray(points, rad):
	# print (points)
	points = [rotateCore(p, rad) for p in points]
	return points

def minIndex(data):
	pairs = [(i, v) for i, v in enumerate(data)]
	return min(pairs, key = lambda p : p[1])[0]

def getBestMatchAngle(ref, points):
	rads = [getRotateAngle(ref[0], points[i]) for i in range(len(points))]
	rads = rads + [-rad for rad in rads]
	errors = [RMSE(ref, rotatePointArray(points, rad)) for rad in rads]
	return rads[minIndex(errors)]

def testDriver():
	angles = [math.pi * (0.2 + i / 12.0)  for i in range(12)]
	points = [[math.cos(angle), math.sin(angle)] for angle in angles]
	ref = rotatePointArray(points, math.pi * 0.35)

	rad = getBestMatchAngle(ref, points)
	print (rad)

if __name__ == '__main__':
	testDriver()


import numpy as np
import matplotlib.pyplot as plt
# %matplotlib inline
import pymesh
#https://pymesh.readthedocs.io/en/latest/basic.html
import time
import multiprocessing
import numexpr as ne
import meshplot
# for display of meshes
#https://skoch9.github.io/meshplot/tutorial/

#Mesh Methods

# compute the volume of the tetrahedron formed from face with index iface
# and the origin
def vol_i(mesh,iface):
    f = mesh.faces
    v = mesh.vertices
    iv1 = f[iface,0]  # indexes of the 3 vertices
    iv2 = f[iface,1]
    iv3 = f[iface,2]
    #print(iv1,iv2,iv3)
    v1 = v[iv1]  # the 3 vertices
    v2 = v[iv2]
    v3 = v[iv3]
    #print(v1,v2,v3)
    mat = np.array([v1,v2,v3])
    # the volume is equal to 1/6 determinant of the matrix formed with the three vertices
    # https://en.wikipedia.org/wiki/Tetrahedron
    #print(mat)
    vol = np.linalg.det(mat)/6.0  # compute determinant
    return vol

# compute the volume of the mesh by looping over all tetrahedrons formed from the faces
# we assume that the body is convex
def volume_mesh(mesh):
    f = mesh.faces
    nf = len(f)
    vol = 0.0
    for iface in range(nf):
        vol += vol_i(mesh,iface)
    return vol

# if vol equ radius is 1  the volume should be equal to 4*np.pi/3 which is 4.1888

# tests
#vi = vol_i(squannit,1)
#print(vi)
#vtot = volume_mesh(squannit)
#print(vtot)

# correct all the radii so that the volume becomes that of a sphere with radius 1
# return a new mesh
def cor_volume(mesh):
    vol = volume_mesh(mesh)
    print('Volume {:.4f}'.format(vol))
    rad = pow(vol*3/(4*np.pi),1.0/3.0)
    print('radius of vol equ sphere {:.4f}'.format(rad))
    f = mesh.faces
    v = np.copy(mesh.vertices)
    v /= rad
    newmesh = pymesh.form_mesh(v, f)
    newmesh.add_attribute("face_area")
    newmesh.add_attribute("face_normal")
    newmesh.add_attribute("face_centroid")
    vol = volume_mesh(newmesh)
    print('new Volume {:.3f}'.format(vol))
    return newmesh

def nf_mesh(mesh):
    f = mesh.faces
    print('number of faces ',len(f))

def get_nf_mesh(mesh):
    f = mesh.faces
    return len(f)


# EMAHelperFunctions.py

#################################################################

## Libraries

import matplotlib.pyplot as plt
import numpy as np

################################################################

## Exponential Moving Average (EMA) Functions

# Calculate the alpha value for a desired period.
def calculateAlpha(ema_period):
    alpha = 2.0 / (ema_period + 1)
    return alpha

# Returns the denominator
def getDenominator(number_of_terms):
    # bottom = 1 + (1-a) + (1-a)^2 + (1-a)^3 + ...
    a = calculateAlpha(number_of_terms)
    i = 0
    total = 0
    while i < number_of_terms:
        term = (1-a)**i
        total = total + term
        i = i + 1
    return total

# Returns the numerator
def getNumerator(price_data, price_data_index, number_of_terms):
    # top = p1 + (1-a)*p2 + (1-a)^2*p3 + (1-a)^3*p4 + ...
    a = calculateAlpha(number_of_terms)
    i = 0
    total = 0
    while i < number_of_terms:
        price = price_data[price_data_index - i]
        cof = (1-a)**i
        term = price * cof
        total = total + term
        i = i + 1
    return total

# Returns a single Exponential Moving Average value.
def getEMA(price_data, price_data_index, number_of_terms):
    if (number_of_terms - price_data_index) > 1:
        # There are too many terms for the given index.
        return 0
    else:
        top = getNumerator(price_data, price_data_index, number_of_terms)
        bottom = getDenominator(number_of_terms)
        EMA = np.array([top / bottom])
        return EMA

# Returns a list of all EMA values.
def getEMAdataset(price_data, number_of_terms):
    ema_data = np.zeros(np.size(price_data))
    i = 0
    while i < np.size(price_data):
        datum = getEMA(price_data, i, number_of_terms)
        ema_data[i] = datum
        i = i + 1
    return ema_data

####################################################################

## Plotting Function

# Plots 3 lines: raw data, EMA(period_1), EMA(period_2)
def calculateAndPlotEMA(data, ema_period_1, ema_period_2):
    ema_1 = getEMAdataset(data, ema_period_1)
    ema_2 = getEMAdataset(data, ema_period_2)
    x = np.arange(len(data))
    plt.plot(x, data)
    plt.plot(x, ema_1)
    plt.plot(x, ema_2)
    ema_legend_text_1 = "EMA(" + str(ema_period_1) + ")"
    ema_legend_text_2 = "EMA(" + str(ema_period_2) + ")"
    plt.legend(['Value', ema_legend_text_1, ema_legend_text_2])
    plt.title("Exponential Moving Averages")
    plt.grid(b=True, which='major', color='gray', linestyle=':')
    plt.show()

########################################################################

## Sine Wave Function

# Generates a sine wave.
def generateSineWave(period, amplitude, sigma, end):
    # Equations
    alpha = amplitude / 2.0
    beta = 2.0 * np.pi / period
    frequency = 1.0 / period
    x = np.arange(end + 1)

    # Formula
    y = alpha * np.sin(beta * x) + sigma
    return y


import sys
sys.path.append("..")
import argparse

import numpy as np
from robopy import *
from numpy.linalg import inv
from packages.rotations import *

def rotation_calc(alpha, beta, gama):
  rot_alpha = rotationz(alpha)
  rot_beta = rotationy(beta)
  rot_gama = rotationx(gama)
  return np.dot(np.dot(rot_alpha, rot_beta), rot_gama)

def reverse_euler_calc(r):
  beta = arcsin(-r[2, 0])
  alpha = arccos(r[0,0]/cos(beta))
  gama = arccos(r[2,2]/cos(beta))
  return alpha, beta, gama

def main():
  parser = argparse.ArgumentParser(description='Exercise 2A algorithms')

  parser.add_argument('-n', dest='exercise_num', default='a',
                      type=str, nargs='?',
                      help='Exercise Number')

  args = parser.parse_args()

  assert args.exercise_num in ['a', 'b', 'c', 'd'], 'exercise number is not valid'
  if args.exercise_num == 'a':
    print('solution i: ', rotation_calc(10, 20, 30))
    print('solution ii: ', rotation_calc(30, 90, -55))
    st = np.allclose(inv(rotation_calc(10, 20, 30)),rotation_calc(10, 20, 30).T)
    print('Are Rba == Rab-1 == Rab.T : ', str(st))

  elif args.exercise_num == 'b':
    print('10_20_30(alpha,beta,gama) angle rotated then reversed: ', reverse_euler_calc(rotation_calc(10, 20, 30)))
    print('30_90_-55(alpha,beta,gama) angle rotated then reversed: ', reverse_euler_calc(rotation_calc(30, 90, -55)))
  elif args.exercise_num == 'c':
    p = [1, 0, 1]
    print('P_A', np.dot(rotationy(20), p))
  elif args.exercise_num == 'd':
    print('Is my implemented rotationx calculation correct: ',
          str(np.allclose(rotationx(10), rotx(10, "deg"))))
    print('Is my implemented rotationy calculation correct: ',
          str(np.allclose(rotationy(20), roty(20, "deg"))))
    print('Is my implemented rotationz calculation correct: ',
          str(np.allclose(rotationz(30), rotz(30, "deg"))))
    print('Is my implemented homogeneouse transformation matrix calculation correct: ',
          str(np.allclose(rotation_calc(10, 20, 30), rpy2tr([30, 20, 10], unit='deg')[:3,:3])))
    print('Is my implemented reverse euler matrix calculation correct: ',
          str(np.allclose(reverse_euler_calc(rotation_calc(10, 20, 30)), tr2rpy(rotation_calc(10, 20, 30), 'deg')[0, ::-1])))

if __name__ == '__main__':
  main()


import cv2
import math
import numpy as np

def sort_left(points):
    """sort list of points by x-axis
    Ref:
    - https://stackoverflow.com/questions/2706605/sorting-a-2d-numpy-array-by-multiple-axes
    """
    a = np.asarray(points)
    ind = np.lexsort((a[:,1], a[:,0]))
    return a[ind]

def get_midpoint(edge, b=0.5):
    """Get a point that lies on edge. Returns center point and angle of projection.
    Args:
        edge: list of points [p0, p1], where each point is np.array in format [x, y]
        b: distance of point along edge, default = 0.5 (midpoint)
    """

    # p0, p1 = sort_left(edge)
    p0, p1 = edge
    c = p1 - p0
    c = p0 + c * b
    c = c.astype(np.int)

    # note -- y-axis is reversed p1_y - p2_y as origin is top-left in image.
    angle = math.atan((p0[1]-p1[1])/(p1[0]-p0[0]))
    return c, angle

def project_point(point, w, theta):
    """project from point at angle theta, along distance w"""

    # y axis inverted because image origin is top left
    proj = np.asarray([w * math.cos(theta), -w * math.sin(theta)])
    proj += point
    proj = proj.astype(np.int)
    return proj

def get_rotated_rect(center, theta, b=22, w=70):
    """Get 4 coords of rectangle rotated around center with
    width 2 * b and length 2 * w, with rotation angle theta in radians.

    References:
    - https://math.stackexchange.com/questions/2518607/how-to-find-vertices-of-a-rectangle-when-center-coordinates-and-angle-of-tilt-is
    """

    xs = [[-1, -1], [1, -1], [1, 1], [-1, 1]]
    xs = np.dot(xs, [[w * math.cos(theta)], [b * math.sin(theta)]])

    # note: reversed y axis since image starts at top-left
    ys = [[1, -1], [-1, -1], [-1, 1], [1, 1]]
    ys = np.dot(ys, [[w * math.sin(theta)], [b * math.cos(theta)]])

    rect = np.concatenate([xs, ys], axis=1)
    rect = rect.astype(np.int)
    rect = rect + center
    return rect

def perpendicular_point(p1, p2, p3):
    """Get point P, on line (p1, p2) such that (P, p3) is perpendicular to (p1, p2)
    Args:
        p1, p2, p3: point coords in np.array in format [x, y]
    """
    det = np.sum(np.square(p2 - p1))
    a = np.sum((p3 - p1) * (p2 - p1)) / det
    p = p1 + a * (p2 - p1)
    p = p.astype(np.int)
    return p


import numpy as np
import warnings
warnings.filterwarnings("ignore")
import sys
from PIL import Image, ImageDraw, ImageFilter

def koch_line(start, end, factor):
    """
    Segments a line to Koch line, creating fractals.

    :param tuple start:  (x, y) coordinates of the starting point
    :param tuple end: (x, y) coordinates of the end point
    :param float factor: the multiple of sixty degrees to rotate
    :returns tuple: tuple of all points of segmentation
    """

    # coordinates of the start
    x1, y1 = start[0], start[1]

    # coordinates of the end
    x2, y2 = end[0], end[1]

    # the length of the line
    l = np.sqrt((x2 - x1 )**2 + (y2 - y1 )**2)

    # first point: same as the start
    a = (x1, y1)

    # second point: one third in each direction from the first point
    b = (x1 + (x2 - x1 ) /3., y1 + (y2 - y1 ) /3.)

    # third point: rotation for multiple of 60 degrees
    c = (b[0] + l/ 3. * np.cos(factor * np.pi / 3.), b[1] + l / 3. * np.sin(factor * np.pi / 3.))

    # fourth point: two thirds in each direction from the first point
    d = (x1 + 2. * (x2 - x1) / 3., y1 + 2. * (y2 - y1) / 3.)

    # the last point
    e = end

    return {'a': a, 'b': b, 'c': c, 'd': d, 'e': e, 'factor': factor}

def koch_snowflake(degree, s=5.0):
    """Generates all lines for a Koch Snowflake with a given degree.

    :param int degree: how deep to go in the branching process
    :param float s: the length of the initial equilateral triangle
    :returns list: list of all lines that form the snowflake
    """
    # all lines of the snowflake
    lines = []

    # we rotate in multiples of 60 degrees
    sixty_degrees = np.pi / 3.

    # vertices of the initial equilateral triangle
    A = (0., 0.)
    B = (s, 0.)
    C = (s * np.cos(sixty_degrees), s * np.sin(sixty_degrees))

    # set the initial lines
    if degree == 0:
        lines.append(koch_line(A, B, 0))
        lines.append(koch_line(B, C, 2))
        lines.append(koch_line(C, A, 4))
    else:
        lines.append(koch_line(A, B, 5))
        lines.append(koch_line(B, C, 1))
        lines.append(koch_line(C, A, 3))

    for i in range(1, degree):
        # every lines produce 4 more lines
        for _ in range( 3 * 4**(i - 1)):
            line = lines.pop(0)
            factor = line['factor']

            lines.append(koch_line(line['a'], line['b'], factor % 6))  # a to b
            lines.append(koch_line(line['b'], line['c'], (factor - 1) % 6))  # b to c
            lines.append(koch_line(line['c'], line['d'], (factor + 1) % 6))  # d to c
            lines.append(koch_line(line['d'], line['e'], factor % 6))  # d to e

    return lines

def image_from_koch(degree, flake_size=5, image_size=(256, 256), blur_radius=3):
    base = Image.new("L", image_size)
    lines = koch_snowflake(degree, flake_size)
    x, y = [], []
    for l in lines:
        x.extend([l['a'][0], l['b'][0], l['c'][0], l['d'][0], l['e'][0]])
        y.extend([l['a'][1], l['b'][1], l['c'][1], l['d'][1], l['e'][1]])
    x = np.array(x) + image_size[1] / 2 - flake_size / 2
    y = np.array(y) + image_size[0] / 2 - flake_size / np.sqrt(3) / 2
    draw = ImageDraw.Draw(base)
    draw.polygon(list(zip(x, y)), fill=256)
    return np.asarray(base.filter(ImageFilter.BoxBlur(blur_radius))) / 256

def plot_koch():
    import matplotlib.pyplot as plt

    max_degree = 10
    fig, axs = plt.subplots(1, max_degree, figsize=(5*max_degree, 5), subplot_kw={'aspect': 'equal'})
    colors = ['#661D98', '#2CBDFE', '#47DBCD', '#F5B14C', '#960019', '#661D98', '#2CBDFE', '#47DBCD', '#F5B14C', '#960019']

    for d in range(max_degree):
        lines = koch_snowflake(degree=d)

        # extract the line coordinates
        x, y = [], []
        for l in lines:
            x.extend([l['a'][0], l['b'][0], l['c'][0], l['d'][0], l['e'][0]])
            y.extend([l['a'][1], l['b'][1], l['c'][1], l['d'][1], l['e'][1]])

        # remove all ticks and axes
        axs[d].set_xticks([], [])
        axs[d].set_yticks([], [])
        axs[d].spines['right'].set_visible(False)
        axs[d].spines['left'].set_visible(False)
        axs[d].spines['top'].set_visible(False)
        axs[d].spines['bottom'].set_visible(False)

        # fill the polygons
        axs[d].fill(x, y, facecolor=colors[d], edgecolor='black', lw=1)

    plt.show()

    plt.gcf().text(0.1, 0.15, 'by Vladimir Ilievski', fontsize=28, fontfamily='Verdana')
    plt.savefig('snowflakes_0_to_4.png', dpi=300, bbox_inches='tight')

if __name__ == '__main__':
    data = image_from_koch(4, 100)
    import matplotlib.pyplot as plt
    max_degree = 10
    fig, axs = plt.subplots(1, 1, subplot_kw={'aspect': 'equal'})
    plt.imshow(data)

    fig.show()
    pass


import pylab
import numpy
import math

# simple example of removing a frequency component from a
# two-frequency sine wave signal

# Since our input data is real, the negative frequency components
# don't include any new information, and are not interesting to us.
# The rfft routines understand this, and rfft takes n real points and
# returns n/2+1 complex output points.  The corresponding inverse
# knows this, and acts accordingly.
#
# these are the routines we want for real valued data

# note that the scipy version of rfft returns that data differently

# M. Zingale (2013-02-28)

def twoFreqSine(npts):

    # a pure sine with no phase shift will result in pure imaginary
    # signal
    f_0 = 0.2
    f_1 = 0.5

    xmax = 10.0/f_0

    # we call with endpoint=False -- if we include the endpoint, then for
    # a periodic function, the first and last point are identical -- this
    # shows up as a signal in the FFT.
    xx = numpy.linspace(0.0, xmax, npts, endpoint=False)

    # input frequency
    f_0 = 0.2

    f = 0.5*(numpy.sin(2.0*math.pi*f_0*xx) + numpy.sin(2.0*math.pi*f_1*xx))

    return xx, f

npts = 256

xx, f = twoFreqSine(npts)

# Forward transform: f(x) -> F(k)

# normalization factor: the 2 here comes from the fact that we neglect
# the negative portion of frequency space because our input function
# is real
norm = 2.0/npts
fk = norm*numpy.fft.rfft(f)

ofk_r = fk.real.copy()
ofk_i = fk.imag.copy()

# the fftfreq returns the postive and negative (and 0) frequencies
# the newer versions of numpy (>=1.8) have an rfftfreq() function
# that really does what we want.
k = numpy.fft.fftfreq(len(xx))[range(0,npts/2+1)]

# the last element is negative, because of the symmetry, but should
# be positive (see http://docs.scipy.org/doc/numpy-dev/reference/generated/numpy.fft.rfftfreq.html)
k[-1] *= -1

# since we don't include the endpoint in xx, to normalize things, we need
# max(xx) + dx to get the true range
kfreq = k*npts/(max(xx) + xx[1])

# filter all frequencies > 0.4
fk[kfreq > 0.4] = 0.0

# element 0 of fk is the DC component
fk_r = fk.real
fk_i = fk.imag

# Inverse transform: F(k) -> f(x)
fkinv = numpy.fft.irfft(fk/norm)

# PLOT
pylab.rc("font", size=9)

pylab.subplot(411)

pylab.plot(xx, f)
pylab.xlabel("x")
pylab.ylabel("f(x)")

pylab.subplot(412)

pylab.plot(kfreq, ofk_r)
pylab.plot(kfreq, ofk_i, ls=":")
pylab.xlabel(r"$\nu_k$")
pylab.ylabel("original F(k)")

#pylab.xlim(0,1)

pylab.subplot(413)

pylab.plot(kfreq, fk_r)
pylab.plot(kfreq, fk_i, ls=":")
pylab.xlabel(r"$\nu_k$")
pylab.ylabel("filtered F(k)")

pylab.subplot(414)

pylab.plot(xx, fkinv.real)
pylab.xlabel("x")
pylab.ylabel(r"inverse filtered F(k)")

pylab.tight_layout()

f = pylab.gcf()
f.set_size_inches(9.0,8.0)

pylab.savefig("simple-filter.png", bbox_inches='tight', pad_inches=0.33)


# %% [markdown]
# # Bayesian Linear Regression
# In this post I talk about reformulating linear regression in a Bayesian framework.
# This gives us the notion of epistemic uncertainty which allows us to generate probabilistic model predictions.
# I formulate a model class which can perform linear regression via Bayes rule updates.
# We show the results are the same as from the `statsmodels` library.
# I will also show some of the benefits of the sequential bayesian approach.
# %%
import pandas as pd
import numpy as np
import statsmodels.api as sm
import time
from scipy.stats import norm
import matplotlib.pyplot as plt

plt.style.use("seaborn-whitegrid")
# %% [markdown]
# ## Generate some dummy data
# We generate some ideal data for a linear regression model so that we know the true coefficients for this example.
# %%
n = 10000
m = 2
np.random.seed(3)

noise_std = 2

x = np.random.uniform(-1, 1, size=(n, m))
x = np.hstack([np.ones(shape=(n, 1)), x])
w = np.random.uniform(-1, 1, size=(m + 1, 1))
y_true = x @ w
y = y_true + np.random.normal(loc=0, scale=noise_std, size=(n, 1))

print("True coefficients:\n", w)
# %% [markdown]
# ## Fit a linear regression with `statsmodels`
# The implementation of linear regression in `statsmodels` returns the standard error
# of the fitted coefficients.
# %%
results = sm.OLS(y, x).fit()
print(results.summary())

# extract coefficient distributions
w_sm_mu = results.params
w_sm_std = np.sqrt(np.diag(results.normalized_cov_params))
# %% [markdown]
# If we received extra data we would have no choice but to retrain the model from scratch.
# In the following we train the model with an increasing fraction of the data and time each instance.
# %%
idx = np.floor(np.linspace(0, x.shape[0], num=50))[1:]
time_iter = []

params_mu = []
params_std = []
for end_idx in idx:
    t0 = time.process_time()
    results = sm.OLS(y[: int(end_idx)], x[: int(end_idx)]).fit()
    time_iter.append(time.process_time() - t0)

    params_mu.append(results.params)
    params_std.append(np.sqrt(np.diag(results.normalized_cov_params)))

params_mu = pd.DataFrame(params_mu, index=idx)
params_std = pd.DataFrame(params_std, index=idx, columns=params_mu.columns)
# %% [markdown]
# As expected, we can see that training the model with increasing lengths of data causes an increasing in fitting time.
# %%
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(idx, time_iter, label="statsmodels")
ax.set_ylabel("Time taken (s)")
ax.set_xlabel("No. training rows")
plt.legend()
plt.show()
# %% [markdown]
# We can also show that with increasing data our estimates of the coefficients become more confident
# as the standard error shrinks.
# This is a measure of our epistemic (model) uncertainty.
# %%
fig, ax = plt.subplots(ncols=2, figsize=(10, 6))
params_mu.plot(ax=ax[0])
params_std.plot(ax=ax[1])
ax[0].set_xlabel("No. training rows")
ax[0].set_ylabel("Coefficient means")
ax[1].set_ylabel("Coefficient standard dev.")
plt.show()
# %% [markdown]
# ## Sequential bayesian regression
# Another way of approaching this problem is with sequential Bayesian regression.
# This method follows Bayes theorem, where we have a prior distribution or estimates of our regression coefficients.
# We then update those prior distribution with data we observe to get a posterior distribution.
# We can then consider those posterior distributions as our new prior distributions and repeat the process.
#
# Linear regression produces a multivariate normal distribution over the resulting coefficient estimates.
# The conjugate prior to this is also a multivariate normal distribution prior.
# As such we can formulate an analytical expression for the Bayes rule posterior update.
#
# The update rules I used were taken from:
# [https://cedar.buffalo.edu/~srihari/CSE574/Chap3/3.4-BayesianRegression.pdf](https://cedar.buffalo.edu/~srihari/CSE574/Chap3/3.4-BayesianRegression.pdf)
#
# ### Model definition
# We can build this as a class withi a similar API to sklearn models:
# %%
class BayesLinearRegressor:
    def __init__(
        self, number_of_features, mean=None, cov=None, alpha=1e6, beta=1
    ):
        # prior distribution on weights
        if mean is None:
            self.mean = np.array([[0] * (number_of_features)], dtype=np.float).T

        if cov is None:
            self.cov = alpha * np.identity(number_of_features)
            self.cov_inv = np.linalg.inv(self.cov)

        self.beta = beta  # process noise

    def fit(self, x, y):
        return self.update(x, y)

    def update(self, x, y):
        """
        Perform a bayesian update step
        """
        if len(x.shape) == 1:
            x = x[np.newaxis, :]
        if len(y.shape) == 1:
            y = y[:, np.newaxis]

        # update state of covariance and means
        cov_n_inv = self.cov_inv + self.beta * x.T @ x
        cov_n = np.linalg.inv(cov_n_inv)
        mean_n = cov_n @ (self.cov_inv @ self.mean + self.beta * x.T @ y)

        self.cov_inv = cov_n_inv
        self.cov = cov_n
        self.mean = mean_n

    def predict(self, x):
        mean = x @ self.mean
        scale = np.sqrt(np.sum(x @ self.cov @ x.T, axis=1))
        return mean, scale

    @property
    def coef_(self):
        return self.mean

    @property
    def scale_(self):
        return np.sqrt(np.diag(self.cov))

# %% [markdown]
# We can train the model as follows.
# We use `numpy` testing to confirm the coefficient we get are equal to those of `statsmodels`.
# %%
bayes_linear_regression = BayesLinearRegressor(x.shape[1])
bayes_linear_regression.fit(x, y)
np.testing.assert_array_almost_equal(
    bayes_linear_regression.coef_, params_mu.tail(1).transpose().to_numpy()
)
np.testing.assert_array_almost_equal(
    bayes_linear_regression.scale_, params_std.tail(1).to_numpy().flatten()
)
# %% [markdown]
# ### Sequential training
# We can now train the model with chunks of data.
# We will time the models fitting and track the coefficients with extra data.
# %%
bayes_linear_regression = BayesLinearRegressor(x.shape[1])

time_iter_seq = []
params_mu_seq = []
params_std_seq = []
for i, end_idx in enumerate(idx):
    t0 = time.process_time()
    if i > 0:
        start_idx = int(idx[i - 1])
    else:
        start_idx = 0
    bayes_linear_regression.update(
        x[start_idx : int(end_idx)],
        y[start_idx : int(end_idx)],
    )
    time_iter_seq.append(time.process_time() - t0)

    params_mu_seq.append(bayes_linear_regression.coef_.flatten())
    params_std_seq.append(bayes_linear_regression.scale_)

params_mu_seq = pd.DataFrame(
    params_mu_seq, index=idx, columns=params_mu.columns
)
params_std_seq = pd.DataFrame(
    params_std_seq, index=idx, columns=params_mu.columns
)
# %% [markdown]
# The time taken to train with each chunk is approximately the same.
# As such, we can fit an initial model and continue to update it as an alternative to fitting a single large model.
# %%
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(idx, time_iter, label="statsmodels")
ax.plot(idx, time_iter_seq, label="sequential")
# ax.plot(idx, np.cumsum(time_iter_seq), label="cumulative_sequential")
ax.set_ylabel("Time taken (s)")
ax.set_xlabel("No. training rows")
plt.legend()
plt.show()
# %% [markdown]
# The model coefficients behave as before.
# E.g. we can similarly show that the standard deviation of the coefficients reduces with data length.
# %%
fig, ax = plt.subplots(ncols=2, figsize=(10, 6))
params_mu_seq.plot(ax=ax[0])
params_std_seq.plot(ax=ax[1])
ax[0].set_xlabel("No. training rows")
ax[0].set_ylabel("Coefficient means")
ax[1].set_ylabel("Coefficient standard dev.")
plt.show()
# %% [markdown]
# ### Posteriors vs Priors
# One of the benefits of using bayesian linear regression is the ability to apply prior distributions
# on the model coefficients.
# To demonstrate this we use a prior with a much smaller variance, as such it is no longer uninformed.
# We fit the model and plot the pdf of the prior and posterior.
# The posteriors evidently converge to the true coefficients and have a tight distribution.
# %%
bayes_linear_regression = BayesLinearRegressor(x.shape[1], alpha=0.5)
prior_mu = bayes_linear_regression.coef_
prior_std = bayes_linear_regression.scale_
bayes_linear_regression.fit(x, y)

def norm_max(x):
    return x / x.max()

x_range = np.linspace(-3, 3, num=1000)
fig, ax = plt.subplots(nrows=m + 1, figsize=(10, 6))
for idx in range(m + 1):
    ax[idx].plot(
        x_range,
        norm_max(norm.pdf(x_range, loc=prior_mu[idx], scale=prior_std[idx])),
    )
    ax[idx].plot(
        x_range,
        norm_max(
            norm.pdf(
                x_range,
                loc=params_mu_seq.iloc[-1, idx],
                scale=params_std_seq.iloc[-1, idx],
            )
        ),
    )
    ax[idx].set_ylabel(f"$~P(z_{idx})$")
# %% [markdown]
# ### Prediction uncertainty
# The distribution of our coefficients gives us a distribution for our model predictions as well.
#
# The predict method of the `BayesLinearRegressor` class returns a standard deviation for each point.
# We can then plot a few of those points with this confidence shaded.
# This only represent epistemic uncertainty - i.e. uncertainty from our model coefficients,
# not uncertainty from the data generating process.
# %%
bayes_linear_regression = BayesLinearRegressor(x.shape[1])
bayes_linear_regression.fit(x, y)
pred_mu, pred_scale = bayes_linear_regression.predict(x[:100])

sort_id = np.argsort(pred_mu.flatten())

fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(pred_mu[sort_id].flatten(), ".")

ax.fill_between(
    np.arange(100),
    pred_mu[sort_id].flatten() - pred_scale[sort_id],
    pred_mu[sort_id].flatten() + pred_scale[sort_id],
    alpha=0.3,
)
# %% [markdown]
# ### Adaptive learning
# By updating sequential with data as it appears we can learn from data that may not be stationary.
# A sequential model can do some form of tracking if the coefficients need to change with time.
#
# More on this to come...

import numpy,from scipy,import statsmodels


# -*- coding: utf-8 -*-
"""
Created on Mon Oct 18 08:28:29 2021

@author: Ezra
"""

import numpy as np
import matplotlib.pyplot as plt

def f(x):
    #return x*x*np.log(x)
    return np.sin(x)

def trap(a,b,n):
    '''
    Trapazoidal method of integration

    Parameters
    ----------
    a : TYPE
        DESCRIPTION.
    b : TYPE
        DESCRIPTION.
    n : TYPE
        DESCRIPTION.

    Returns
    -------
    xi : TYPE
        DESCRIPTION.

    '''
    h = (b-a)/n
    xi0=f(a) + f(b)
    for i in range(1,n):
        x = a + i*h
        xi0 = xi0 + 2*f(x)
    xi = (h*xi0)/2
    return xi

def simp(a,b,n):
    '''
    simpsons method

    Parameters
    ----------
    a : left limit of integration
    b : right limit of integration
    n : number of subdivision for composite (even).

    Returns
    -------
    None.

    '''
    h = (b-a)/float(n)
    xi0 = f(a) + f(b)
    xi1 = 0
    xi2 = 0
    for i in range(1,n):
        x=a+i*h
        if i%2==0:
            xi2=xi2+f(x)
        else:
            xi1=xi1+f(x)
    xi=h*(xi0+2*xi2+4*xi1)/3
    return xi

def romT4(a,b,n):
    return((4*trap(a,b,n)-trap(a,b,n))/3)

def romT6(a,b,n):
    return((16*romT4(a,b,2*n)-romT4(a,b,n))/15)

def mid(a,b,n):
    h=(b-a)/(n+2)
    xi0=0
    for i in range(int(n//2)+1):
        x=a+(2*i+1)*h
        xi0=xi0+f(x)
    xi=2*h*xi0
    return xi

a=0
b=2
soln=np.cos(a)-np.cos(b)

def err(x,y):
    z = abs(x-y)/y
    return z

est1 = trap(0,2,10)
est2 = simp(0,2,10)
est3 = mid(0,2,10)
est4 = romT4(0,2,10)
est5 = romT6(0,2,10)
print(est1)
print(est2)
print(est3)
print(est4)
print(est5)

trapEst = []
midEst = []
simEst = []
rombT4Est = []
rombT6Est = []

n=[2,10,40,50,60,100,200]

for i in range(len(n)):
    trapEst.append(err(trap(a,b,n[i]),soln))
    midEst.append(err(mid(a,b,n[i]),soln))
    simEst.append(err(simp(a,b,n[i]),soln))
    rombT4Est.append(err(romT4(a,b,n[i]),soln))
    rombT6Est.append(err(romT6(a,b,n[i]),soln))

# print((f(1.5)+f(1))/2*.5)

plt.figure(0)
plt.semilogy(n,trapEst,label = 'Trapezoid')
plt.semilogy(n,midEst,label = 'Midpoint')
plt.semilogy(n,simEst,label = 'Simpson')
plt.semilogy(n,rombT4Est,label = 'Romber Trap 4')
plt.semilogy(n,rombT6Est,label= 'Romber Trap 6')


import superimport

import numpy as np
import matplotlib.pyplot as plt

ts = np.arange(100)
tis = np.array([25, 50, 75])
lr_list = []
lr0 = 1
gamma = 0.9
for t in ts:
    passed_num_thresholds = sum(t > tis)
    lr = lr0 * np.power(gamma, passed_num_thresholds)
    lr_list.append(lr)

plt.figure()
plt.plot(lr_list)
plt.title('piecewise constant')
pml.savefig('lr_piecewise_constant.pdf')
plt.show()

ts = np.arange(100)
lam = 0.999
lr0 = 1
lr_list = lr0 * np.exp(-lam*ts)

plt.figure()
plt.plot(lr_list)
plt.title('exponential decay')
plt.savefig('lr_exp_decay.pdf')
plt.show()

ts = np.arange(100)
alpha = 0.5
beta = 1
lr0 = 1
lr_list = lr0 * np.power(beta*ts + 1, -alpha)

plt.figure()
plt.plot(lr_list)
plt.title('polynomial decay')
pml.savefig('lr_poly_decay.pdf')
plt.show()


'''
Blum Blum Shub (B.B.S.) is a pseudorandom number generator proposed in 1986 by Lenore Blum,
Manuel Blum and Michael Shub[1] that is derived from Michael O. Rabin's one-way function.
Pseudorandom number generator (source: https://en.wikipedia.org/wiki/Blum_Blum_Shub)
'''
from sympy import isprime
import random

def BBSgenerator(nbits=8):
    '''
    BBS also called CSPRG (source: https://blog.csdn.net/android_jiangjun/article/details/80648184).
    @param nbits: number of bits of the number. e.g., 8-bits: 0~255
    '''

    def generatePQ(start=None):
        '''
        Get the big prime number p and q.
        In BBS algorithm, p ≡ q ≡ 3(mod 4)
        @param start: start of finding big prime,
                    default 1,000,000 (1 million)
        '''
        x = 1000000 if start is None else start
        p = q = None
        while (True):
            if isprime(x) and (x % 4) == 3:
                if p is None:
                    p = x
                elif q is None:
                    q = x
                else:
                    break
            x += 1
        return p, q

    # initialize p and q
    p, q = generatePQ()
    n = p * q
    s = p
    while (s % p) == 0 or (s % q) == 0:
        s = random.SystemRandom().randint(p+q, p+p+q+q)
    x = (s * s) % n
    num = 0
    for i in range(nbits):
        x = (x*x) % n
        num = num * 2 + (x % 2)
    return num

if __name__ == "__main__":
    print("Testing BBS generator...")
    # test: generate 10 random integers
    for i in range(10):
        print(BBSgenerator(16))


import numpy as np
from numba import jit

@jit(nopython=True, nogil=True, cache=True)
def soft_thresh(lam, x):  # pragma: no cover
    r"""

    soft_thresh(lam, x)

    Soft thresholding operator.  Takes a numpy ndarray of floats and returns and element-wise soft-thesholded version.

    Element-wise, the soft-thresholding operator :math:`S_\lambda(x)` is given by:

    .. math::

        S_\lambda(x) =
            \begin{cases}
                x + \lambda, & \text{if} \quad x < -\lambda \\
                0          , & \text{if} \quad -\lambda < x < \lambda \\
                x - \lambda, & \text{if} \quad x > \lambda
            \end{cases}

    where :math:`\lambda` is a scalar tresholding parameter.

    Args:
        lam (float): threshold value
        x (numpy.ndarray): array of floats to be soft thresholded

    Returns:
        numpy.ndarray: soft thresholded array of floats
    """
    if lam == 0.0:
        return x
    else:
        return np.sign(x) * np.maximum(np.abs(x) - lam, 0)


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

import sympy as sp
from numpy import exp
from trapezoidal import trapezoidal
from midpoint import midpoint
from simpsons import simpson
from gaussian import gauss
from scipy.integrate import fixed_quad

def f(y):
    return exp(-y**2)

a = 0
b = 2
print('    n        midpoint          trapezoidal          simpson          gaussian')
for i in range(1, 16):
    n = 2**i
    m = midpoint(f, a, b, n)
    t = trapezoidal(f, a, b, n)
    s = simpson(f, a, b, n)
    #g = gauss(f, a, b, n)
    g = fixed_quad(f,a,b,n=n)[0]
    print('%7d %.16f %.16f %.16f %.16f' % (n, m, t, s, g))

def g(x):
    return x*(x-1)

a = 2;  b = 6;
n = 100

numerical_trap = trapezoidal(g, a, b, n)
numerical_mid  = midpoint(g, a, b, n)

# Compute exact integral by sympy
x = sp.symbols('x')
F = sp.integrate(g(x))
exact = F.subs(x, b) - F.subs(x, a)
exact = exact.evalf()

error_trap = abs(numerical_trap - exact)
error_mid  = abs(numerical_mid - exact)

print('For n = %d, we get:' % (n))
print('Numerical trapezoid: %g , Error: %g' % \
                                 (numerical_trap,error_trap))
print('Numerical midpoint: %g , Error: %g' % \
                                 (numerical_mid,error_mid))


import numpy as np
import pytest

import tbats.transformation as transformation

class TestBoxCox(object):

    @pytest.mark.parametrize(
        "y, lam, expected_y",
        [
            [  # lambda is zero, expect logarithm
                [np.e, np.e ** 2, np.e ** 3],
                0,
                [1., 2., 3.],
            ],
            [  # lambda is 1, expect simple addition
                [-2, -1, 0, 1, 2, 3],
                1,
                [-3, -2, -1, 0, 1, 2],
            ],
            [  # lambda is 0.5, expect sqrt
                [4, 9, 16, -4, -9],
                0.5,
                [(2 - 1) / 0.5, (3 - 1) / 0.5, (4 - 1) / 0.5, -(2 + 1) / 0.5, -(3 + 1) / 0.5],
            ],
            [  # lambda is -2, expect inversion and power of 2
                [0.1, 1, 3],
                -2,
                [(100 - 1) / (-2), 0, (1 / 9 - 1) / (-2)],
            ],
        ]
    )
    def test_transformations(self, y, lam, expected_y):
        y_transformed = transformation.boxcox(y, lam)
        assert np.allclose(expected_y, y_transformed)
        y_back_transformed = transformation.inv_boxcox(y_transformed, lam)
        assert np.allclose(y, y_back_transformed)

    def test_lambda_finding(self):
        np.random.seed(49385)
        y = np.exp(
            np.random.uniform(size=100) + np.array(range(40, 140)) / 20
        )
        lam = transformation.find_box_cox_lambda(y, bounds=(0, 1))
        assert np.isclose(0.031759, lam, atol=1e-4)

    def test_lambda_finding_2(self):
        np.random.seed(49385)
        y = (np.random.uniform(size=105) + np.array(range(40, 145)) / 20) ** 2
        lam = transformation.find_box_cox_lambda(y, bounds=(0, 1))
        assert np.isclose(0.4139901, lam, atol=1e-4)

    def test_lambda_finding_with_seasonality(self):
        np.random.seed(3423)
        t = np.array(range(0, 160))
        y = 5 * np.sin(t * 2 * np.pi / 14) + ((t / 20) ** 1.5 + np.random.normal(size=160) * t / 50) + 10

        lam = transformation.find_box_cox_lambda(y, seasonal_periods=[9, 14], bounds=(0, 1))
        assert np.isclose(0.690025, lam, atol=1e-4)


import numpy as np
import numpy.linalg as LA

def ssh_hamiltonian(k, t1, t2, real_basis=True):
    """ Returns the SSH Hamiltonian at k with hopping amplitudes t1 and t2.

    Args:
        k (float): point in momentum space.
        t1 (float): hopping parameter.
        t2 (float): hopping paramter.
        real_basis (bool): if True, returns Hamiltonian in real basis. Else, use complex basis.

    Returns:
        np.array: the SSH Hamiltonian.
    """
    if real_basis:
        hamiltonian = np.zeros((2, 2), dtype=np.double)
        hamiltonian[0, 0] = t2 * np.sin(k)
        hamiltonian[1, 1] = -t2 * np.sin(k)
        hamiltonian[0, 1] = t1 + t2 * np.cos(k)
        hamiltonian[1, 0] = t1 + t2 * np.cos(k)
        return hamiltonian
    else:
        j = complex(0, 1)
        hamiltonian = np.zeros((2, 2), dtype=np.cdouble)
        hamiltonian[0, 1] = t1 + t2 * np.cos(k) - j * t2 * np.sin(k)
        hamiltonian[1, 0] = t1 + t2 * np.cos(k) + j * t2 * np.sin(k)
        return hamiltonian

def get_state(hamiltonian, idx_list):
    """Return energy eigenstates of hamiltonian for band index in the idx_list

    Args:
        Hamiltonian (np.array): the Hamiltonian matrix
        idx_list (list): list of band indices, the lowest energy band being 0

    Returns:
        np.array: energy eigenstates (column vectors) arragned according to idx_list
    """
    eigval, eigvec = LA.eigh(hamiltonian)
    return eigvec[:, idx_list]

def distance(state1, state2):
    """Return the quantum distance between state1 and state2.

    Args:
        state1 (np.array): a quantum state
        state2 (np.array): a quantum state
    Returns:
        float: quantum distance between state1 and state2, sqrt(1-abs(<state1|state2>)**2)
    """
    return np.sqrt(abs(1.0 - abs(state1.conjugate().transpose() @ state2).item()**2))

def get_state_list(t1, t2, idx_list, mesh_size):
    """ Returns list of states
    Args:
        t1, t2 (float): parameters in the Hamiltonian
        idx_list (list): list of indices for which we create the state list
        mesh_size: number of k points (uniform mesh)

    Returns:
        list: list of states  (in idx_list) for each k point
    """
    state_list = []
    k_mesh = np.linspace(0, 2. * np.pi, num=mesh_size, endpoint=False)
    for k in k_mesh:
        state_list.append(get_state(ssh_hamiltonian(k, t1, t2), idx_list))
    return state_list


'''
Find the minimum aggregate area for a square and a circle formed by cutting a wire in two pieces.
'''

import math
from sympy import Derivative, symbols, solve, sympify
from collections import namedtuple

Pieces = namedtuple( 'Pieces', [ 'circumference', 'side'] )

def cut_wire( l ):
	# Side, Circumference
	s, c = symbols( 's, c' )
	# V = s^2 ( square ) + pi * ( c / 2pi )^2
	A = ( s / 4 ) ** 2 + c**2 / ( 4 * math.pi )

	# c + s = l
	L = c + s - l

	# Solve for c in terms of s
	sC = solve( L, s )[ 0 ]

	# A1 = area in terms of a single variable
	A1 = A.subs( s, sC )

	# Now single variable, take The derivitave with respect to c.
	dA = Derivative( A1, c ).doit()
	slns = solve( dA )

	min_c = slns[ 0 ]
	min_s = l - min_c

	return Pieces( circumference = min_c, side = min_s )

def area_sqare( s ):
	return s**2

def area_circle( c ):
	return c**2 / ( 4 * math.pi )

if __name__ == '__main__':

	try:
		l = float( input( 'Enter the length of the wire to cut: ') )
	except ValueError:
		print( 'Error parsing values' )
	else:
		print( 'wire length: {0}\n'.format( l ) )

		pieces = cut_wire( l )
		area_circle = area_circle( pieces.circumference )
		area_sqare = area_sqare( pieces.side )

		print( 'Mimimum Area: {0}'.format( area_circle + area_sqare ) )
		print( 'Circle Area: {0}'.format( area_circle ) )
		print( 'Square Area: {0}'.format( area_sqare ) )


import random
import jax.numpy as jnp
from jax.scipy import stats as jsps
from jax import grad, vmap, jit
import matplotlib.pyplot as plt
import numpy as np
import scipy as sp

def mvn_pdf(x, mu, sigma):
    k = len(mu)

    term1 = (2*jnp.pi)**(-k/2)
    term2 = 1./jnp.sqrt(jnp.linalg.det(sigma))
    term3 = jnp.exp(-1./2 * (x - mu).T @ jnp.linalg.inv(sigma) @ (x - mu))

    return term1 * term2 * term3

def mvn_pdf_vectorized(x, mu, sigma):
    """
    assumes x is a num_samples x num_dimensions array.
    performs the density computations in a vectorized manner
    """
    k = len(mu)

    demeaned_x = x - mu

    first_prod = jnp.linalg.inv(sigma) @ demeaned_x.T

    second_prod = demeaned_x * first_prod.T

    reduction = np.sum(second_prod, axis=1).flatten()

    term1 = (2*jnp.pi)**(-k/2)
    term2 = 1./jnp.sqrt(jnp.linalg.det(sigma))
    term3 = jnp.exp(-1./2 * reduction)

    return term1 * term2 * term3

"""
For the below functions:
weights: the weight on each mode. Sum cannot exceed 1
mus: list of means
sigmas: list of covariance matrices
* weights, mus and sigmas must have same length
"""
# Outputs function for the gmm PDF
def gmm_pdf(weights, mus, sigmas):
    def p(x):

        pdfval = 0

        for weight, mu, sigma in zip(weights, mus, sigmas):
            pdfval = pdfval + weight * mvn_pdf(x, mu, sigma)

        return pdfval

    return p

# Vectorized version of gmm pdf
def gmm_pdf_vectorized(weights, mus, sigmas):
    def p(x):

        pdfval = 0

        for weight, mu, sigma in zip(weights, mus, sigmas):
            pdfval = pdfval + weight * mvn_pdf_vectorized(x, mu, sigma)

        return pdfval

    return p

# Finite differences function to check the analytic GLD
def finite_diff(g, h, weights, mus, sigmas):
    def f(x):
        return (g(x + h, weights, mus, sigmas) - g(x, weights, mus, sigmas))/h

    return f

# Outputs function for log of the PDF
def log_gmm_pdf(weights, mus, sigmas):
    p = gmm_pdf(weights, mus, sigmas)

    def logp(x):
        return jnp.log(p(x))

    return logp

# Vectorized version of log gmm pdf
def log_gmm_pdf_vectorized(weights, mus, sigmas):
    p = gmm_pdf_vectorized(weights, mus, sigmas)

    def logp(x):
        return jnp.log(p(x))

    return logp

# Outputs log likelihood of gmm
def log_lik_gmm(weights, mus, sigmas ):

    p = gmm_pdf_vectorized(weights, mus, sigmas)

    def log_lik(x):
        return jnp.sum(jnp.log(p(x)))

    return log_lik

# Produces analytic gradient log density for gmm
def gmm_gld(weights, mus, sigmas):

    logp = log_gmm_pdf(weights, mus, sigmas)

    return jit(vmap(grad(logp)))

# Produces samples from gmm
def sample_gmm(num_samples, weights, mus, sigmas):

    num_pdfs = len(weights)

    result = []
    for i in range(num_samples):
        # choose distribution
        idx = np.random.choice(range(num_pdfs), p=weights)

        mu = mus[idx]
        sigma = sigmas[idx]

        # sample from distribution
        sample = np.random.multivariate_normal(mu, sigma)

        result.append(sample)

    return np.array(result)

import numpy,import scipy,import jax,from jax


import numpy as np

import matplotlib.pyplot as plt

from utils import sigmoid

def cost_1(z):
    return -np.log(sigmoid(z))

def cost_0(z):
    return -np.log(1 - sigmoid(z))

def cost_function_visualize():
    z = np.arange(-10, 10, 0.1)
    phi_z = sigmoid(z)
    c1 = [cost_1(x) for x in z]
    plt.plot(phi_z, c1, label='J(w) if y=1')
    c0 = [cost_0(x) for x in z]
    plt.plot(phi_z, c0, linestyle='--', label='J(w) if y=0')
    plt.ylim(0.0, 5.1)
    plt.xlim([0, 1])
    plt.xlabel('$\phi$(z)')
    plt.ylabel('J(w)')
    plt.legend(loc='upper left')
    plt.tight_layout()
    plt.show()


import numpy as np
from math import *
from scipy import optimize
import matplotlib.pyplot as plt
import base64
import io
import json

def rungekutta4(f,y0,h,a,b):
    n = int(np.floor((b-a)/h))
    x = np.zeros(n)
    y = np.zeros((y0.shape[0],n))
    x[0] = a
    y[:,0] = y0
    for i in range(n-1):
        x[i+1] = x[i]+h
        k1 = f(x[i],y[:,i])
        k2 = f(x[i]+h/2,y[:,i]+h*k1/2)
        k3 = f(x[i]+h/2,y[:,i]+h*k2/2)
        k4 = f(x[i]+h,y[:,i]+h*k3)
        y[:,i+1] = y[:,i] + h*(k1+2*k2+2*k3+k4)/6
    return x, y

def rungekutta(paras):
    def f(x, y):
        loc = {'ret': None, 'x': x, 'y': y}
        exec(paras['f'], globals(), loc)
        return loc['ret']
    y0 = np.array(paras['data'])
    h  = float(paras['h'])
    a  = float(paras['a'])
    b  = float(paras['b'])

    x,y = rungekutta4(f,y0,h,a,b)
    fig = plt.Figure()
    ax = fig.subplots()
    for index in range(len(y)):
        ax.plot(x,y[index],label="y"+str(index+1))
    ax.legend()
    buf = io.BytesIO()
    fig.savefig(buf, format="png")
    # Embed the result in the html output.
    img = base64.b64encode(buf.getbuffer()).decode("ascii")
    return {'img': img, 'x': x, 'y': y}

if __name__ == "__main__":
    paras = {'f': '''
dy = np.zeros(3)
dy[0] = y[1]*y[2]
dy[1] = -y[0]+y[2]
dy[2] = -0.51*y[0]*y[1]
ret = dy
''', 'data': [1,1,3], 'h': "0.15", 'a': 0, 'b': 15}

    ret = rungekutta(paras)
    print(ret['x'])
    print(ret['y'])
    img = open('./rungekutta.png', 'w')
    img.write(ret['img'])
    img.close()


import numpy as np
import matplotlib.pyplot as plt

def train(X, T):
    # Standardize input data (X)

    # Calculate mean and std.
    means = X.mean(axis = 0)
    std = X.std(axis = 0)

    Xs = (X - means) / std

    # Tack a column of 1s
    Xs = np.insert(Xs, 0, 1, 1)

    # Use Xs to generate model (w)
    w = np.linalg.lstsq(Xs.T @ Xs, Xs.T @ T, rcond = None)[0]

    # Return as a dictionary
    dict = {'means': means, 'stds': std, 'w': w}
    return dict

def use(model, X):
    # Use model and input X to predict.
    means = model['means']
    std = model['stds']
    w = model['w']

    # Standardize X
    Xs = (X - means) / std

    # Tack column of 1s
    Xs = np.insert(Xs, 0, 1, 1)

    # Predict
    predict = Xs @ w
    #print(Xs.shape)
    #print(w.shape)
    return predict

def rmse(predict, T):
    rmerr = np.sqrt(np.mean((T - predict) ** 2))
    return rmerr

def trainSGD(X, T, learningRate, numberOfIterations):
    # Standardize inputs X.
    means = X.mean(axis = 0)
    std = X.std(axis = 0)
    Xs = (X - means) / std

    nSamples = Xs.shape[0]
    ncolsT = T.shape[1]

    # Tack a column of 1s
    Xs = np.insert(Xs, 0, 1, 1)
    ncolsX = Xs.shape[1]
    # Initialize weights to zero.
    w = np.zeros((ncolsX, ncolsT))

    for i in range(numberOfIterations):
        for n in range(nSamples):
            predicted = Xs[n:n+1, :] @ w
            w += learningRate * Xs[n:n+1, :].T * (T[n:n+1, :] - predicted)

    dict = {'means': means, 'stds': std, 'w': w}
    return dict

if __name__ == '__main__':
	X = np.array([[0,1,2],[3,4,5], [5,6,7]])
	T = np.array([[1,2,3]])
	T = np.transpose(T)

	model = train(X, T)
	predict = use(model, X)
	r = rmse(predict, T)

	model2 = trainSGD(X, T, 0.1, 100)
	print(model2)


# =============================================================================
#
# Finite Difference Method Code for Forward, Backward, and Central Difference
# Schemes for single points and user-defined functions
# User must provide exact solution for derivative
# Generates plots and calculates slope showing order of each method
# Written by: Cameron Armstrong (2021)
# Institution: Virginia Commonwealth University
# =============================================================================

# Required Modules
import numpy as np
from matplotlib import pyplot as plt
import scipy
from scipy.stats import linregress

# Difference Schemes Functions
# f is function input
# x is point input
# h is stepsize

def FDS(f,x,h):
    return (f(x+h)-f(x))/h

def BDS(f,x,h):
    return (f(x)-f(x-h))/h

def CDS(f,x,h):
    return (f(x+h)-f(x-h))/(2*h)

def ourFunc(x):
    return 4*x**3 - 5*x**2 +6*x -1

# Variable Definitions
x = 1                                           # point to analyze
dx = .01                                        # initial step-size
numiter = 4                                     # number of iterations
factor = 10                                     # stepsize factor - default is 10

# function calls
dfdt_FDS = round(FDS(ourFunc,x,dx),1)
dfdt_BDS = round(BDS(ourFunc,x,dx),1)
dfdt_CDS = round(CDS(ourFunc,x,dx),1)

exact = 12*x**2 - 10*x + 6                      # exact solution

# prints single point derivative approximations at initial stepsize
# comment these out if you just want to run the loop below
print('Forward Difference Scheme = %s' %(dfdt_FDS))
print('Backward Difference Scheme = %s' %(dfdt_BDS))
print('Central Difference Scheme = %s' %(dfdt_CDS))
print('Exact Solution = %s' %(exact))

# error arrays and stepsize array initialization
error_FDS = np.zeros(numiter)
error_BDS = np.zeros(numiter)
error_CDS = np.zeros(numiter)
dxarray = np.zeros(numiter)

# loop for going through incrementally smaller step sizes
for i in range(numiter):
    # function calls
    dfdt_FDS = FDS(ourFunc,x,dx)
    dfdt_BDS = BDS(ourFunc,x,dx)
    dfdt_CDS = CDS(ourFunc,x,dx)
    # calculating error
    error_FDS[i] = abs(dfdt_FDS-exact)
    error_BDS[i] = abs(dfdt_BDS-exact)
    error_CDS[i] = abs(dfdt_CDS-exact)
    # storing current stepsize
    dxarray[i] = dx
    # update stepsize
    dx = dx/factor

# plotting of log(error) vs log(stepsize)
plt.figure()
plt.loglog(dxarray,error_FDS,label='Forward')
plt.loglog(dxarray,error_BDS,label='Backward')
plt.loglog(dxarray,error_CDS,label='Central')
plt.xlabel('log(stepsize)')
plt.ylabel('log(error)')
plt.legend()

# calculating log of errors and stepsize
logerror_FDS = np.log(error_FDS)
logerror_BDS = np.log(error_BDS)
logerror_CDS = np.log(error_CDS)
logdx = np.log(dxarray)

# linear regression on log-log data
# returns approxmate order of each method rounded to neareast integer
order_FDS = scipy.stats.linregress(logdx,logerror_FDS)
order_FDS = round(order_FDS.slope,0)
order_BDS = scipy.stats.linregress(logdx,logerror_BDS)
order_BDS = round(order_BDS.slope,0)
order_CDS = scipy.stats.linregress(logdx,logerror_CDS)
order_CDS = round(order_CDS.slope,0)

# prints apprimxate scheme orders
print('Order of FDS = %s' %(order_FDS))
print('Order of BDS = %s' %(order_BDS))
print('Order of CDS = %s' %(order_CDS))


'''
Created on Apr 24, 2017

@author: Leo Zhong
'''

import numpy as np
from astropy.units import Ybarn
import math

def computeCorrelation(X, Y):
    xBar = np.mean(X)
    yBar = np.mean(Y)
    SSR = 0
    varX = 0
    varY = 0
    for i in range(0 , len(X)):
        diffXXBar = X[i] - xBar
        diffYYBar = Y[i] - yBar
        SSR += (diffXXBar * diffYYBar)
        varX +=  diffXXBar**2
        varY += diffYYBar**2

    SST = math.sqrt(varX * varY)
    return SSR / SST

def polyfit(x,y,degree):
    result={}

    coffs = np.polyfit(x, y, degree)

    #polynomial cofficient
    result['polynomial']=coffs.tolist()

    #r-squared
    p=np.poly1d(coffs)

    yhat=p(x)
    ybar=np.sum(y)/len(y)
    ssreg=np.sum((yhat-ybar)**2)
    sstot=np.sum((y-ybar)**2)
    result['determination']=ssreg/sstot

    return result

testX = [1, 3, 8, 7, 9]
testY = [10, 12, 24, 21, 34]

print (computeCorrelation(testX, testY))
print (polyfit(testX, testY, 1))


"""
Lecture 3: Fast-Fourier Transform
---------------------------------
Topics covered:
- Recursion
- Divide and conquer

"""

import numpy as np
import math

def add(A, B):
  """
  Add two vetors (tuple of numbers)
  that represent polynomials as a
  coefficient

  if A = a_0 + x * a_1 + (x ** 2) * a_2 + ...
  and B = b_0 + x * b_1 + ...

  Then this function returns their sum
  expressed as a coefficient vector

  Complexity: O(n) where n is the highest degree term in the sum

  """
  n_A = len(A)
  n_B = len(B)
  n = max(n_A, n_B)
  C = [None for _ in range(n)]
  for i in range(n):
    c_i = 0
    if i < n_A:
      c_i += A[i]
    if i < n_B:
      c_i += B[i]
    C[i] = c_i
  return tuple(C)

def discrete_fourier_transform(A):
  """
  Recursive discrete Fourier transform on
  a polynomial, A, for this algorithm
  let's assume A has a length that
  is a power of 2

  Complexity: O(n * log(n))

  """
  n = len(A)
  if n == 1:
    return A
  omega = 1
  omega_n = np.exp(complex(0, 2 * math.pi / n))
  A_0 = []
  A_1 = []
  for i in range(n):
    if i % 2:
      A_1.append(A[i])
    else:
      A_0.append(A[i])
  A_0 = discrete_fourier_transform(A_0)
  A_1 = discrete_fourier_transform(A_1)
  A_hat = [0 for _ in range(n)]
  for i in range(n / 2):
    A_hat[i] = A_0[i] + (omega * A_1[i])
    A_hat[i + (n / 2)] = A_0[i] - (omega * A_1[i])
    omega *= omega_n
  return tuple(A_hat)

def inv_discrete_fourier_transform(A_hat):
  """
  Recursive inverse discrete Fourier transform on
  a transformed polynomial, A_hat

  Complexity: O(n * log(n))

  """
  m = len(A_hat)
  def recurse_inv_dft(L_hat):
    n = len(L_hat)
    if n == 1:
      return L_hat
    omega = 1
    omega_n = np.exp(complex(0, -2 * math.pi / n))
    L_0 = []
    L_1 = []
    for i in range(n):
      if i % 2:
        L_1.append(L_hat[i])
      else:
        L_0.append(L_hat[i])
    L_0 = recurse_inv_dft(L_0)
    L_1 = recurse_inv_dft(L_1)
    L = [0 for _ in range(n)]
    for i in range(n / 2):
      L[i] = L_0[i] + (omega * L_1[i])
      L[i + (n / 2)] = L_0[i] - (omega * L_1[i])
      omega *= omega_n
    return tuple(L)
  return tuple([float(a) / m for a in recurse_inv_dft(A_hat)])

def fast_polynomial_multiplication(A, B):
  """
  Fast polynomial multiplication which uses
  DFT, given a tuple of polynomial coefficients.
  This algorithm assumes the tuples have a length
  that is an even power of two

  Complexity: O(n * log(n))

  """
  if not A or not B: # Covers None and empty case
    return ()
  n_A = len(A)
  n_B = len(B)
  n = n_A + n_B
  A = [A[i] if i < n_A else 0 for i in range(n)]
  B = [B[i] if i < n_B else 0 for i in range(n)]
  C_star = [0 for _ in range(n)]
  A_star = discrete_fourier_transform(A)
  B_star = discrete_fourier_transform(B)
  for i in range(n):
    c_i = A_star[i]
    c_i *= B_star[i]
    C_star[i] = c_i
  return tuple(inv_discrete_fourier_transform(C_star))


#%%
import numpy as np
a = np.array([1, 2, 3])
print(a, type(a), type(np.ndarray), type(type))

angles = np.array([0, 30, 45, 60, 90])
print(angles)

print(np.sin(angles))
print(np.sin(angles))

# convert in radians

angles_radians = angles * np.pi/180
print(angles_radians)
print(np.sin(angles_radians))
print(np.radians(angles))
print(np.degrees(angles_radians))

print(np.mean(angles))
print(np.median(angles))

# statistics
salaries = np.genfromtxt('data/salary.csv')
print(salaries)
np.mean(salaries)
np.median(salaries)
np.std(salaries)
salaries.shape
np.var(salaries)
a = np.arange(11) ** 2
a[-2]
a[3:5]
a[:7]
a[:11:2]
a[::-1]  # reverse an array

students = np.array([['Alice', 'Balice', 'Calice ', ' Dalice '], [54, 56, 232, 22], [34, 343, 11, 343]])
print(students)

#%%
students[0]

#%%
students[1]

#%%
students[2]

#%%
students[0:2, 2:4]

#%%
students[:,1:2]

#%%
students[:,1:3]

#%%
students[-1,:]

#%%
students[0,...]

#%%
for i in students:
    print("i =:",i)

#%%
for element in students.flatten():
    print(element)

#%%
for elem in students.flatten(order="F"):
    print(elem)

#%%
x = np.arange(12).reshape(3,4)
x

#%%
for i in np.nditer(x):
    print(i)

for i in np.nditer(x, order="F"):
    print(i)

#%%
for arr in np.nditer(x, op_flags = ["readwrite"]):
    arr[...] = arr * arr
x

#%%
a = np.array([['Germany', 'Frane', 'Hungary', "Austria"],
            ['Berlin', 'Paris','Budapest', 'Vienna']])

a

#%%
a.shape

#%%
a.ravel() #copy made if needed

#%%
a.T # transposed Matrix

#%%
a.T.ravel()

#%%
a.reshape(2,4)

#%%
np.arange(15).reshape(3,5)

#%%
np.arange(15).reshape(5,3)

#%%
a.reshape(-1, 2) # -1 special vlaue signified we do ont know rows

#%%
#splitting arrays
arr = np.arange(20)
arr

#%%
np.split(arr, [1, 7])

#%%
p1, p2 = np.hsplit(arr, 2)

#%%
print(p1, p2)

#%% [markdown]
# # Image Manipulation

#%%
from scipy import ndimage
from scipy import misc

#%%
f = misc.face()
f

#%%
f.shape
print(type(f))

#%%
import matplotlib.pyplot as plt
plt.imshow(f)

#%%
plt.imshow(f[100:450,500:1000])

#%%
s1, s2 = np.split(f, 2)
plt.imshow(s1)

#%%
plt.imshow(s2)

#%%
b1 , b2 = (np.split(f, 2,axis=1))
plt.imshow(b1)

#%%
plt.imshow(b2)

#%%
plt.imshow(np.concatenate((b1, b2)))

#%%
plt.imshow(np.concatenate((b1, b2), axis=1))

#%%
# shallow copy of arrays edit will refelect in origional array
fruits = np.array(['Apple', 'Mango', 'WaterMelon', 'Guava'])
f_1 = fruits.view()
f_2 = fruits.view()
print(f_1)
print(f_2)

#%%
id(f_1)

#%%
id(f_2)

#%%
f_1 is fruits

#%%
f_2[2]="Strawberry"
fruits
print(f_1)

#%%
f_1 = np.array(["Chikoo", "papaya"])

#%%
fruits

#%%
np.append(f_1, "New Fruit1")
np.append(f_2, "New Fruit2")

#%%
fruits

#%%
f_2.reshape(2,2)

#%%
# Deep copy
basket = fruits.copy()

#%%
#deep copied
basket
basket.base is fruits

#%% [markdown]
# # Complex Indexing Using Numpy

#%%
import csv

#%%
a = np.arange(12)**2
a

#%%
indx_1 = [2, 6, 8]

#%%
a[indx_1]

#%%
indx_2 = np.array([[2,4], [8,10]])
indx_2

#%%
a[indx_2] # resulting array is shape is index array

#%%
import pandas as pd

gdp_16 = pd.read_csv("data/gdp_pc.csv")["2016"].values
type(gdp_16)

#%%
gdp_16.shape

#%%
plt.plot(gdp_16)
plt.show()

#%%
np.median(gdp_16)

#%%
gdp_16

#%%
gdp_16 = gdp_16[~np.isnan(gdp_16)] #not nan

#%%
gdp_16

#%%
np.median(gdp_16)

#%%
np.sort(gdp_16)

#%%
np.count_nonzero(gdp_16[gdp_16 > 40000])

#%%
print(np.mean(gdp_16))

#%%
# Indexing withh Boolean arrays

#%%
a = np.arange(16).reshape(4,4)
a

#%%
indx_bool = a > 9

#%%
indx_bool

#%%
a[indx_bool]

#%%
a[indx_bool][0:1]

#%%
np.count_nonzero(a >  6)

#%%
np.sum(a < 6)

#%%
np.sum(a < 6, axis=1)

#%%
np.sum(a < 6, axis=0)

#%%
np.any(a > 8)

#%%
np.all(a < 10)

#%%
np.all(a < 100)

#%%
# indexing structure data
name = ["Alice", "Beth", "Cathy", "Dorothy"]
student_Id =  [1,2, 3,4]
score = [85.4, 90.4, 87.66,78.9 ]

#%%
student_data = np.zeros(4, dtype = {'names':('name', 'studentId','score'),
                                   'formats':('U10', 'i4', 'f8')})

#%%
student_data

#%%
student_data['name'] = name
student_data['studentId'] = student_Id
student_data['score'] = score

#%%
student_data

#%%
student_data[1]

#%%
student_data['name']

#%%
student_data[student_data['score'] > 90]

#%%
# Broadcasting Scalers
# Array multiplying with scaler


'''
计数排序法，对序列比较集中，重复值较多时对的排序非常有效，：
1.知道或统计出待排序数组的元素的最大值和最小值
2.创建一个最大值和最小值差+1的数组，从小到大的统计每个值出现的次数
3.迭代每个值，及重复的次数放到一个新数组中，就完成了排序

'''
import numpy as np

class CountingSort:
    def sort(self, x, min, max):
        l = len(x)
        b = [0 for i in range(max - min + 1)]
        for i in range(l):
            j = x[i] - min
            b[j] += 1
        c = [0 for i in range(l)]
        ji = 0
        for k in range(len(b)):
            for bIndex in range(b[k]):
                c[ji] = min + k
                ji += 1
        return c

def main():
    min, max = 0, 100
    x = np.random.randint(min, max, 20)
    print(x)
    re = CountingSort().sort(x, min, max)
    print('After sort: ', re)

if __name__ == '__main__':
    main()


"""
Implementation of Hill Cipher!

Important notation:
K = Matrix which is our 'Secret Key'
P = Vector of plaintext (that has been mapped to numbers)
C = Vector of Ciphered text (in numbers)

C = E(K,P) = K*P (mod X) -- X is length of alphabet used
P = D(K,C) = inv(K)*C (mod X)  -- X is length of alphabet used

Programmed by Aladdin Persson <aladdin.persson at hotmail dot com>
*  2019-11-09 Initial programming
"""

import numpy as np
from egcd import egcd  # pip install egcd

alphabet = "abcdefghijklmnopqrstuvwxyz"

letter_to_index = dict(zip(alphabet, range(len(alphabet))))
index_to_letter = dict(zip(range(len(alphabet)), alphabet))

def matrix_mod_inv(matrix, modulus):
    """We find the matrix modulus inverse by
    Step 1) Find determinant
    Step 2) Find determinant value in a specific modulus (usually length of alphabet)
    Step 3) Take that det_inv times the det*inverted matrix (this will then be the adjoint) in mod 26
    """

    det = int(np.round(np.linalg.det(matrix)))  # Step 1)
    det_inv = egcd(det, modulus)[1] % modulus  # Step 2)
    matrix_modulus_inv = (
        det_inv * np.round(det * np.linalg.inv(matrix)).astype(int) % modulus
    )  # Step 3)

    return matrix_modulus_inv

def encrypt(message, K):
    encrypted = ""
    message_in_numbers = []

    for letter in message:
        message_in_numbers.append(letter_to_index[letter])

    split_P = [
        message_in_numbers[i : i + int(K.shape[0])]
        for i in range(0, len(message_in_numbers), int(K.shape[0]))
    ]

    for P in split_P:
        P = np.transpose(np.asarray(P))[:, np.newaxis]

        while P.shape[0] != K.shape[0]:
            P = np.append(P, letter_to_index[" "])[:, np.newaxis]

        numbers = np.dot(K, P) % len(alphabet)
        n = numbers.shape[0]  # length of encrypted message (in numbers)

        # Map back to get encrypted text
        for idx in range(n):
            number = int(numbers[idx, 0])
            encrypted += index_to_letter[number]

    return encrypted

def decrypt(cipher, Kinv):
    decrypted = ""
    cipher_in_numbers = []

    for letter in cipher:
        cipher_in_numbers.append(letter_to_index[letter])

    split_C = [
        cipher_in_numbers[i : i + int(Kinv.shape[0])]
        for i in range(0, len(cipher_in_numbers), int(Kinv.shape[0]))
    ]

    for C in split_C:
        C = np.transpose(np.asarray(C))[:, np.newaxis]
        numbers = np.dot(Kinv, C) % len(alphabet)
        n = numbers.shape[0]

        for idx in range(n):
            number = int(numbers[idx, 0])
            decrypted += index_to_letter[number]

    return decrypted

def main():
    # message = 'my life is potato'
    message = "help"

    K = np.matrix([[3, 3], [2, 5]])
    # K = np.matrix([[6, 24, 1], [13,16,10], [20,17,15]]) # for length of alphabet = 26
    # K = np.matrix([[3,10,20],[20,19,17], [23,78,17]]) # for length of alphabet = 27
    Kinv = matrix_mod_inv(K, len(alphabet))

    encrypted_message = encrypt(message, K)
    decrypted_message = decrypt(encrypted_message, Kinv)

    print("Original message: " + message)
    print("Encrypted message: " + encrypted_message)
    print("Decrypted message: " + decrypted_message)

main()


#!/usr/bin/env python3
"""
3-posterior.py
"""
import numpy as np

def likelihood(x, n, P):
    """
    function that calculates the likelihood of obtaining the data
    given various hypothetical probabilities of developing severe side effects
    """

    if not isinstance(P, np.ndarray) or P.ndim != 1:
        raise TypeError("P must be a 1D numpy.ndarray")
    if not isinstance(n, int) or n < 1:
        raise ValueError("n must be a positive integer")
    if not isinstance(x, int) or x < 0:
        err = "x must be an integer that is greater than or equal to 0"
        raise ValueError(err)
    if x > n:
        raise ValueError("x cannot be greater than n")
    if not all(P >= 0) or not all(P <= 1):
        raise ValueError("All values in P must be in the range [0, 1]")

    # Product of probabilities for the data:
    A = (P ** x) * ((1 - P) ** (n - x))
    # Factorials to be accounted for:
    B = np.math.factorial(x) * np.math.factorial(n - x) / np.math.factorial(n)
    L = A / B

    return L

def intersection(x, n, P, Pr):
    """
    function that calculates the intersection of obtaining this data
    with the various hypothetical probabilities
    """

    if not isinstance(n, int) or n < 1:
        raise ValueError("n must be a positive integer")
    if not isinstance(x, int) or x < 0:
        err = "x must be an integer that is greater than or equal to 0"
        raise ValueError(err)
    if x > n:
        raise ValueError("x cannot be greater than n")
    if not isinstance(P, np.ndarray) or P.ndim != 1:
        raise TypeError("P must be a 1D numpy.ndarray")
    if not isinstance(Pr, np.ndarray) or P.shape != Pr.shape:
        raise TypeError("Pr must be a numpy.ndarray with the same shape as P")
    if not all(P >= 0) or not all(P <= 1):
        raise ValueError("All values in P must be in the range [0, 1]")
    if not all(Pr >= 0) or not all(Pr <= 1):
        raise ValueError("All values in Pr must be in the range [0, 1]")
    if not np.isclose([np.sum(Pr)], [1])[0]:
        raise ValueError("Pr must sum to 1")

    # Intersection is the product of likelihood and probability of prior:
    L = likelihood(x, n, P)
    IN = L * Pr

    return IN

def marginal(x, n, P, Pr):
    """
    function that calculates the marginal probability of obtaining the data
    """

    # Calculate the marginal probability by summing over
    # all the possible conditions (here, the probabilities P)
    IN = intersection(x, n, P, Pr)
    M = np.sum(IN)

    return M

def posterior(x, n, P, Pr):
    """
    function that calculates the posterior probability for the various
    hypothetical probabilities of developing severe side effects given the data
    """

    IN = intersection(x, n, P, Pr)
    M = marginal(x, n, P, Pr)
    P = IN / M

    return P


# Question @Aman Mathur U20:

# 1 question hai kaafi simple hai par accha lga merko,
# Dekho ki tumhe 1 list de rkha hai n numbers ka , sab different hai , ab tum uska max nikalna hai using this algorithm,
# Set max as -infinity(minimum possible value)
# Traverse through the list
# If the current element > max
# max = current element,
# Is algorithm se list me 1 baari traverse krke hum max element nikaal skte hai , ab question ye hai ki find the expected number of times the if statement is satisfied for n elements

# For example agar n= 2 hai to expected value is 1.5,
# Aise  2 possible combinations ho skte hai
# 1 ,2  or 2,1,
# 1,2 me to baari if condition satisfy hogi , 2,1 me 1 baari,
# To ans is( 2+1)/2 = 1.5

import numpy as np, itertools

def max_calc(rec_list):
    sum_of_ifs = 0

    permut_list = itertools.permutations(rec_list)

    for i in permut_list:
        max = -np.inf
        for j in i:
            if int(j) > max:
                max = int(j)
                sum_of_ifs += 1

    ans = sum_of_ifs / np.math.factorial(len(rec_list))
    return ans

if __name__ == "__main__":
    ans = max_calc(input().split( ))
    print(ans)

# 1, 2, 3 -> 3
# 1, 3, 2 -> 2
# 2, 1, 3 -> 2
# 2, 3, 1 -> 2
# 3, 1, 2 -> 1
# 3, 2, 1 -> 1


from __future__ import division
import sys
import numpy as np

print(sys.version)
# 2.7.11 | 64-bit | (default, Jun 11 2016, 10:32:30)
# [GCC 4.1.2 20080704 (Red Hat 4.1.2-55)]

print(5/2)
# 2.5
# for python 2.7 prints 2
# for python 3.* prints 2.5
# importing division from future fix this

arr1 = np.array([[1,2,3,4],[6,7,8,9]])
print(arr1)
'''
[[1 2 3 4]
 [6 7 8 9]]
'''

print(arr1 * arr1)
'''
[[ 1  4  9 16]
 [36 49 64 81]]
'''

print(arr1 - arr1)
'''
[[0 0 0 0]
 [0 0 0 0]]
'''

# scalars
print(1 / arr1)
'''
[[ 1.          0.5         0.33333333  0.25      ]
 [ 0.16666667  0.14285714  0.125       0.11111111]]
'''

print(arr1 * 2)
'''
[[ 2  4  6  8]
 [12 14 16 18]]
'''

# exponential
print(arr1 ** 3)
'''
[[  1   8  27  64]
 [216 343 512 729]]
'''


import numpy as np
import matplotlib.pyplot as plt

# Ejercicio 1

def FD(f, x, h):
    return (f(x+h)-f(x))/h

def CD(f, x, h):
    return (f(x+h/2)-f(x-h/2))/h

def ED(f, x, h):
    return (4*CD(f, x, h/2)-CD(f, x, h))/3.0

def get_error(f, deriva_f_analitica, deriva_f_numerica, x):
    h_range = np.logspace(-15,-1, 200)
    analitica = deriva_f_analitica(x)
    error_range = np.abs((deriva_f_numerica(f, x, h_range) - analitica)/analitica)
    return h_range, error_range

def minus_sin(x):
    return -np.sin(x)

plt.figure(figsize=(15,10))

i = 1
ff = [np.exp, np.cos]
gg = [np.exp, minus_sin]
names = ["exp(x)", "cos(x)"]
xx = [0.1, 1.0, 100.0]

for f, g, n, in zip(ff, gg, names):
    for x in xx:
        plt.subplot(2,3,i)

        h, e = get_error(f, g, FD, x); plt.plot(h, e, label="FD", alpha=1.0)
        h, e = get_error(f, g, CD, x); plt.plot(h, e, label="CD", alpha=1.0)
        h, e = get_error(f, g, ED, x); plt.plot(h, e, label="ED", alpha=1.0)

        plt.title("f(x)={}, x={:.1f}".format(n,x))
        plt.xlim([1E-15,1E-1])
        plt.ylim([1E-15,1E-1])
        plt.loglog()
        plt.legend()
        plt.grid()
        plt.xlabel("h")
        plt.ylabel("|error primera derivada|")
        i += 1

plt.tight_layout()
plt.savefig("primera_derivada.png", bbox_inches='tight')


"""Module to do some awesome scientific simulations."""

import argparse
import numpy as np
from compute_pi_cpp import compute_pi_cpp

__all__ = ["compute_pi"]

parser = argparse.ArgumentParser(
    description="run_simulation -n number_of_samples")
parser.add_argument('-n', '--number', required=True, type=int,
                    help="Number of samples")
parser.add_argument(
    '-m', '--mode', choices=["numpy", "cpp"], default="numpy")

def main():
    """Call an awesome scientific package."""
    # read the command line arguments
    args = parser.parse_args()
    samples = args.number
    mode = args.mode
    # perform the simulation
    print(f'Do some awesome science in {mode}!')
    if mode == "numpy":
        serial_pi = compute_pi(samples)
        print(f"Pi Numpy calculation: {serial_pi:0.8f}")
    else:
        parallel_pi = compute_pi_cpp(samples)
        print(f"Pi C++ calculation: {parallel_pi:0.8f}")

def compute_pi(samples: int) -> float:
    """Compute the pi number using the Monte-Carlo method.

    Measure  the ratio between points that are inside a circle of radius 1
    and a square of size 1.
    """
    # Take random x and y cartesian coordinates
    xs = np.random.uniform(size=samples)
    ys = np.random.uniform(size=samples)

    # Count the points inside the circle
    rs = np.sqrt(xs**2 + ys**2)
    inside = rs[rs < 1.0]

    # compute pi
    approx_pi = (float(inside.size) / samples) * 4

    return approx_pi

if __name__ == "__main__":
    main()


import numpy as np

# x = np.array([0.1, 0.8, 0.05, 0.05])
# t = np.array([0.0, 0.1, 0.0, 0.0])    # target probability distribution

# x = np.array([0.2, 0.5, 0.2, 0.1])
# t = np.array([0.0, 0.0, 0.1, 0.0])    # target probability distribution

# x = np.array([0.05, 0.05, 0.8, 0.1])
# t = np.array([0.0, 0.0, 0.0, 0.1])    # target probability distribution

x = np.array([0.5, 0.1, 0.1, 0.3])
# target probability distribution
t = np.array([0.1, 0.0, 0.0, 0.0])

# Function definitions

def softmax(v):
    exps = np.exp(v)
    sum = np.sum(exps)
    return exps / sum

def cross_entropy(inps, targets):
    return np.sum(-targets * np.log(inps))

def cross_entropy_derivatives(inps, targets):
    return -targets / inps

def softmax_derivatives(softmax):
    return softmax * (1 - softmax)

# [0.10650698, 0.10650698, 0.78698604]
soft = softmax(x)
print(soft)

print(cross_entropy(soft, t))                           # 2.2395447662218846

# [-0.       , -9.3890561, -0.       ]
cross_der = cross_entropy_derivatives(soft, t)
print(cross_der)

# [0.09516324, 0.09516324, 0.16763901]
soft_der = softmax_derivatives(soft)
print(soft_der)

print(cross_der * soft_der)
print(soft - t)

# ## Derivative using chain rule
# cross_der * soft_der              # [-0.        , -0.89349302, -0.        ]
#
#
# ## Derivative using analytical derivation
#
# soft - t                          # [ 0.10650698, -0.89349302,  0.78698604]


# example of gradient descent with momentum for a one-dimensional function
from numpy import asarray
from numpy.random import rand
from numpy.random import seed

# objective function
def objective(x):
	return x**2.0

# derivative of objective function
def derivative(x):
	return x * 2.0

# gradient descent algorithm
def gradient_descent(objective, derivative, bounds, n_iter, step_size, momentum):
	# generate an initial point
	solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
	# keep track of the change
	change = 0.0
	# run the gradient descent
	for i in range(n_iter):
		# calculate gradient
		gradient = derivative(solution)
		# calculate update
		new_change = step_size * gradient + momentum * change
		# take a step
		solution = solution - new_change
		# save the change
		change = new_change
		# evaluate candidate point
		solution_eval = objective(solution)
		# report progress
		print('>%d f(%s) = %.5f' % (i, solution, solution_eval))
	return [solution, solution_eval]

# seed the pseudo random number generator
seed(4)
# define range for input
bounds = asarray([[-1.0, 1.0]])
# define the total iterations
n_iter = 30
# define the step size
step_size = 0.1
# define momentum
momentum = 0.3
# perform the gradient descent search with momentum
best, score = gradient_descent(objective, derivative, bounds, n_iter, step_size, momentum)
print('Done!')
print('f(%s) = %f' % (best, score))


"""
Eigenvalue demonstration

The revolving red hand is the input vector and the blue hand is the linearly
transformed vector.

Four times every revolution the two hands are parallel (or anti-parallel), twice
to each eigenvector of the matrix A.  The ratio of lengths, blue hand over
red hand, is the corresponding eigenvalue.  The eigenvalue will be negative
if the hands are anti-parallel.

"""

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from math import pi, sin, cos

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

e, x = np.linalg.eig(A)
print(e)
print(x)

print(f"λ1 = {e[0]:.3f}, x1 = {np.real(x[:,0].flatten())}")
print(f"λ2 = {e[1]:.3f}, x2 = {np.real(x[:,1].flatten())}")

s = np.max(np.abs(e))

fig, ax = plt.subplots()
plt.axis([-s, s, -s, s])
plt.grid(True)
plt.title('Eigenvector demonstration')
plt.xlabel('x');
plt.ylabel('y');
plt.axis('equal')
plt.xlim(-s, s)
plt.ylim(-s, s)
ax.set_aspect('equal')

l1, = plt.plot([0, 0], [0, 0], color='r', linewidth=1.5)  # input vector
l2, = plt.plot([0, 0], [0, 0], color='b', linewidth=1.5)  # transformed vector

plt.legend(['$x$', r'${\bf A} x$'])

def animate(theta):

    x = np.r_[cos(theta), sin(theta)]
    y = A @ x

    l1.set_xdata([0, x[0]])
    l1.set_ydata([0, x[1]])

    l2.set_xdata([0, y[0]])
    l2.set_ydata([0, y[1]])

    return l1, l2

myAnimation = animation.FuncAnimation(fig, animate, frames=np.linspace(0, 2 * pi, 400), blit=True, interval=20, repeat=True)

plt.show(block=True)


"""

https://en.wikipedia.org/wiki/Bernstein_polynomial

"""

from sympy import *
from sympy.abc import *
import sys
import os

def bernstein(v, n):
    return expand(binomial(n, v) * x**v * (1-x)**(n-v))

def bernstein_derivative(v, n):
    return n*(bernstein(v-1, n-1) - bernstein(v, n-1))

def bernstein_integral(v, n):
    s = 0
    for j in range(v+1, n+2):
        s += bernstein(j, n+1)
    return s/(n+1)

if len(sys.argv) < 3:
    print("usage: v n")
    sys.exit()

v = int(sys.argv[1])
n = int(sys.argv[2])

print("Bernstein(v={}, n={})".format(v, n))
print(bernstein(v, n))
print()
print("Derivative(v={}, n={})".format(v, n))
print(bernstein_derivative(v, n))
print()
print("Integral(v={}, n={})".format(v, n))
print(bernstein_integral(v, n))