from scipy import optimize
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from random import uniform
import evaluation_functions as ef

def rosenbrock(x, y):
    return (x-1)**2 + 100*(y-x**2)**2;

def beale(x, y):
    return (x*y + 1.5 - x)**2 + (x * (y**2) + 2.5 - x)**2 + (x * (y**3) + 2.625 - x)

def booth(x, y):
    return (x + 2 * y - 7)**2 + (2*x  + y - 5)**2

def matyas(x, y):
    return 0.26*(x**2 + y**2) - 0.48*(x*y)

def plot_rosenbrock():
    step = .15
    X = np.arange(-2, 2, step)
    Y = np.arange(-1, 3, step)
    X, Y = np.meshgrid(X, Y)

    Z = rosenbrock(X, Y)

    fig = plt.figure(figsize=(15, 10))
    ax = fig.gca(projection='3d')
    surface = ax.plot_surface(X, Y, Z, cmap=cm.gist_heat_r, linewidth=0)
    ax.set_zlim(0, 2000)
    fig.colorbar(surface, shrink=0.5, aspect=10)
    plt.show()

def bfgs_rosenbrock2d(minValue, maxValue):
    answerList = []
    answerValuesList = []
    for i in range(30):
        print('\nInteration:',i)
        x0 = [uniform(minValue, maxValue), uniform(minValue, maxValue)]
        print('Initial Point:', x0)
        answer = optimize.minimize(optimize.rosen, x0, method='BFGS', jac = optimize.rosen_der,
                                   options={'disp':True, 'return_all':True})
        print('Rosenbrock Minimized Value:',answer.x)
        answerList.append(answer)
        answerValuesList.append(answer.x)
    return answerList, answerValuesList

def bfgs_rosenbrock30d(minValue, maxValue):
    answerList = []
    answerValuesList = []
    for i in range(30):
        print('\nInteration:',i)
        x0 = []
        for j in range(30):
            x0.append(uniform(minValue, maxValue))
        print('Initial Point:', x0)
        answer = optimize.minimize(optimize.rosen, x0, method='BFGS', jac = optimize.rosen_der,
                                   options={'disp':True, 'return_all':True})
        print('Rosenbrock Minimized Value:',answer.x)
        answerList.append(answer)
        answerValuesList.append(answer.x)
    return answerList, answerValuesList

#plot_rosenbrock()
result2dList, result2dValueList = bfgs_rosenbrock2d(-1,1)
minimum2dInterationResult = ef.minimum_iterations(result2dList)
minimum2dInterationConvergeResult = ef.minimum_iterations_converge(result2dList)
ef.evaluate_method(result2dValueList, 'Rosenbrock 2D')

result30dList, result30dValueList = bfgs_rosenbrock30d(-1, 1)
minimum30dInterationResult = ef.minimum_iterations(result30dList)
minimum30dInterationConvergeResult = ef.minimum_iterations_converge(result30dList)
ef.evaluate_method(result30dValueList , 'Rosenbrock 30D')


import numpy as np
import matplotlib.pyplot as plt

t = np.linspace(0, 20, 1001)
noise = np.random.randn(1001)

T = np.pi  # period

# Fourier series coefficients
a_0 = 1.

a_1 = 1.
a_2 = 2.
a_3 = 3.

b_1 = 4.
b_2 = 5.
b_3 = 6.

timeseries = a_0 \
    + a_1*np.cos(1*np.pi*t/T) \
    + a_2*np.cos(2*np.pi*t/T) \
    + a_3*np.cos(3*np.pi*t/T) \
    + b_1*np.sin(1*np.pi*t/T) \
    + b_2*np.sin(2*np.pi*t/T) \
    + b_3*np.sin(3*np.pi*t/T)

noisy_timeseries = timeseries + noise

plt.plot(t, timeseries)
plt.scatter(t, noisy_timeseries)
plt.show()

# data = np.vstack((t, timeseries)).T
# noisy_data = np.vstack((t, noisy_timeseries)).T

# np.savetxt("test_timeseries.csv", data, delimiter=",")
# np.savetxt("test_timeseries_noisy.csv", noisy_data, delimiter=",")


import numpy as np
import random

from numpy.core.fromnumeric import transpose

# 1.Matrix Creation
dim = int(input("Enter Dimension of matrix :"))
matrix = np.random.randint(10, size=(dim, dim))

# 2.Matrix inversion
inverse = np.linalg.inv(matrix)
print ("Inverse matrix : %s" %inverse)

# 3.dot Product won't exactly yield I
I = np.dot(matrix, inverse)
print(" Dot product of matrix and its inverse is I: %s" %np.dot(matrix, inverse))

# 4.Verification of the identity matrix
EPS = 1e-8
r = np.all(np.abs(I - np.eye(dim)) < EPS)
print(r)

# 5.Trace of matrix
print(" Trace of matrix : %s" %matrix.trace())

# Random matrices with fixed dimension
A = np.random.randint(10, size=(2, 3))
B = np.random.randint(10, size=(3, 2))

# 6.cross product
print("cross product of %s and %s is %s" %(A, B, np.outer(A, B)))

# 7.transpose of matrix
print("Transpose of matris is %s" %np.transpose(matrix))

# 8.norm of matrix
print("Norm of matrix is : %s" %np.linalg.norm(matrix))

# 9. Range of matrix
print('Range of the matrix is : %s' %np.ptp(matrix))

# 9. Rank of matrix
print('Rank of the matrix is : %s' %np.linalg.matrix_rank(matrix))


import numpy as np
import matplotlib.pyplot as plt

def jointhist(i, j, bins=256):
    """Calculate the joint histogram of two grayscale images of the same size"""
    li, lj = np.ravel(i), np.ravel(j)  # unravel ndarrays into lists
    assert len(li) == len(lj), "images have different sizes, please scale your data first!"

    nrows = min(int(np.ceil(max(li))), 255)
    ncols = min(int(np.ceil(max(lj))), 255)

    H = np.zeros((bins, bins))  # initially black everywhere, (0~255) = (black~white)
    x_bin_width = (nrows + 1) / bins
    y_bin_width = (ncols + 1) / bins

    for index in range(len(li)):
        x_value, y_value = int(li[index]), int(lj[index])  # grayscale intensity
        x_bin_id = int(x_value / x_bin_width)
        y_bin_id = int(y_value / y_bin_width)
        H[x_bin_id, y_bin_id] += 1

    return H

def test(i_vec, j_vec):
    """Test the joint histogram against the numpy built-in function"""
    fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(16, 11))
    fig.suptitle("Numpy built-in Joint histograms of (I1,J1) ~ (I6,J6)", fontsize=24)

    for index in range(6):
        H, _, _ = np.histogram2d(np.ravel(i_vec[index]), np.ravel(j_vec[index]), bins=256)

        axis = (index // 3, index % 3)  # axes(subplot) index
        ax[axis].imshow(np.log(H + 0.000001), origin='low')
        ax[axis].set_xlabel(f"I{index + 1}")
        ax[axis].set_ylabel(f"J{index + 1}")

    fig.subplots_adjust(top=1)
    fig.tight_layout()
    plt.show()

def run(i_vec, j_vec):
    """Verify the number of pixels and draw the joint histograms"""
    fig, ax = plt.subplots(nrows=2, ncols=3, figsize=(16, 11))
    fig.suptitle("Joint histograms of (I1,J1) ~ (I6,J6)", fontsize=24)

    for index in range(6):
        nrows, ncols = i_vec[index].shape
        print(f"I{index + 1}.shape = J{index + 1}.shape = {i_vec[index].shape}")
        print(f"{nrows} * {ncols} = {nrows * ncols}")

        H = jointhist(i_vec[index], j_vec[index])  # calculate histogram
        H_sum = H.sum()
        print(f"Joint histogram's total sum is H.sum() = {H_sum}")
        print("---------------------------------------------------")
        assert H_sum == nrows * ncols, "verification failed..."

        axis = (index // 3, index % 3)  # axes(subplot) index
        ax[axis].imshow(np.log(H + 0.000001), origin='low')
        ax[axis].set_xlabel(f"I{index + 1}")
        ax[axis].set_ylabel(f"J{index + 1}")

    fig.subplots_adjust(top=1)
    fig.tight_layout()
    plt.show()


#
# Points and weights for Gaussian quadrature
#
# by Alberto Costa Nogueira Jr. (Matlab and Python versions)
#    Renato Cantao (Python version)
#
import numpy
from math import gamma
from jacobi_p import jacobi_p
from djacobi_p import djacobi_p
from jacobi_roots import jacobi_roots
from simulation_data import QuadratureNodes

class JacobiGaussQuad:
    """Points and weights for Gaussian quadrature based on Jacobi polynomials"""
    def __init__(self, sim_data):
        # Sets parameters to obtain quadrature points from Legendre polynomials
        # Legendre == Jacobi(0,0)
        alpha = 0.0
        beta  = 0.0
        nip = sim_data.nip()

        # Case 1: Gauss-Legendre quadrature
        if sim_data.node_dist == QuadratureNodes.GL:
            self.xi, self.w = self._gl(nip, alpha, beta)
        # Case 2: Gauss-Legendre-Lobato quadrature
        elif sim_data.node_dist == QuadratureNodes.GLL:
            self.xi, self.w = self._gll(nip, alpha, beta)
        else:
            raise AssertionError("Unknown quadrature type!")

    # Case 1: Gauss-Legendre quadrature
    def _gl(self, nip, alpha, beta):
        xi = jacobi_roots(nip, alpha, beta)

        C1 = (2.0**(alpha+beta+1.0))*gamma(alpha+nip+1.0)*gamma(beta+nip+1.0)
        C2 = gamma(nip+1.0)*gamma(alpha+beta+nip+1.0)*(1.0-xi**2 )

        DPm = djacobi_p(xi, nip, alpha, beta)

        w = C1*DPm**(-2)/C2

        return xi, w

    # Case 2: Gauss-Legendre-Lobato quadrature
    def _gll(self, nip, alpha, beta):
        r = jacobi_roots(nip-2, alpha+1.0, beta+1.0)
        xi = numpy.empty(r.shape[0]+2)
        xi[0] = -1.0
        xi[1:-1] = r
        xi[-1] = 1.0

        C1 = (2.0**(alpha+beta+1.0))*gamma(alpha+nip)*gamma(beta+nip)
        C2 = (nip-1)*gamma(nip)*gamma(alpha+beta+nip+1.0)

        Pm = jacobi_p(xi, nip-1, alpha, beta)

        w = C1*Pm**(-2)/C2

        w[ 0] = w[ 0]*(beta+1.0)
        w[-1] = w[-1]*(alpha+1.0)

        return xi, w

    def n(self):
        """Number of integration points / weights."""
        return self.xi.shape[0]

#-- jacobi_gauss_quad.py -------------------------------------------------------


"""Functions for working with vectors and polar coordinates."""

import numpy as np

def cart_to_pol(x, y):
    """
    Convert vector from cartesian/xy notation to polar notation.

    Parameters
    ------
    x: int or float
        The x component of a vector
    y: int or float
        The y component of a vector

    Returns
    -------
    phi: float
        The direction of the vector
    rho: float
        The magnitude of the vector
    """
    rho = np.sqrt(x ** 2 + y ** 2)
    phi = np.arctan2(y, x)
    return (phi, rho)

def pol_to_cart(phi, rho=1):
    """
    Convert vector from polar notation to cartesian/xy notation.

    Parameters
    -------
    phi: float
        The direction of the vector
    rho: float
        The magnitude of the vector.
        If ommitted, the default value is 1 (unit vector).

    Returns
    ------
    x: int or float
        The x component of a vector
    y: int or float
        The y component of a vector
    """
    x = rho * np.cos(phi)
    y = rho * np.sin(phi)
    return (x, y)

def points_to_angle(p, q):
    """
    Finds the polar angle (phi) between the vector from the origin
    along the positive x-axis and the line defined by two points p,q.

    Parameters
    -----
    p: tuple of ints/floats. (x,y)
    q: tuple of ints/floats. (x,y)

    Returns
    ------
    phi: float
        the angle of the line in radians, between -pi and pi.
    """
    phi = np.arctan2(q[0] - p[0], q[1] - p[1])
    return phi

def wrap_to_pi(x):
    """
    Wrap a value between -pi and pi in polar coordinate space.
        e.g. if x = 2*pi, x_wrapped = 0
        e.g. if x = 3*pi, x_wrapped = pi

    Parameters
    ------
    x: an int or float

    Returns
    -------
    x_wrapped: float between -pi and pi
    """
    x_wrapped = (x + np.pi) % (2 * np.pi) - np.pi
    return x_wrapped


"""
A linear regression learning algorithm example using TensorFlow library.

Author: Aymeric Damien
Project: https://github.com/aymericdamien/TensorFlow-Examples/
"""

from __future__ import print_function

import tensorflow as tf
import numpy

rng = numpy.random

# Set seeds for consistent results
numpy.random.seed(1)
try:
    tf.random.set_seed(1)
except:
    tf.set_random_seed(1)

# Parameters
learning_rate = 0.01
training_epochs = 100
display_step = 50

# Training Data
train_X = numpy.asarray(
    [
        3.3,
        4.4,
        5.5,
        6.71,
        6.93,
        4.168,
        9.779,
        6.182,
        7.59,
        2.167,
        7.042,
        10.791,
        5.313,
        7.997,
        5.654,
        9.27,
        3.1,
    ]
)
train_Y = numpy.asarray(
    [
        1.7,
        2.76,
        2.09,
        3.19,
        1.694,
        1.573,
        3.366,
        2.596,
        2.53,
        1.221,
        2.827,
        3.465,
        1.65,
        2.904,
        2.42,
        2.94,
        1.3,
    ]
)
n_samples = train_X.shape[0]

# tf Graph Input
X = tf.placeholder("float")
Y = tf.placeholder("float")

# Set model weights
W = tf.Variable(rng.randn(), name="weight")
b = tf.Variable(rng.randn(), name="bias")

# Construct a linear model
pred = tf.add(tf.multiply(X, W), b)

# Mean squared error
cost = tf.reduce_sum(tf.pow(pred - Y, 2)) / (2 * n_samples)
# Gradient descent
#  Note, minimize() knows to modify W and b because Variable objects are trainable=True by default
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)

# Initialize the variables (i.e. assign their default value)
init = tf.global_variables_initializer()

# Start training
with tf.Session() as sess:

    # Run the initializer
    sess.run(init)

    # Fit all training data
    for epoch in range(training_epochs):
        for (x, y) in zip(train_X, train_Y):
            sess.run(optimizer, feed_dict={X: x, Y: y})

        # Display logs per epoch step
        if (epoch + 1) % display_step == 0:
            c = sess.run(cost, feed_dict={X: train_X, Y: train_Y})
            print(
                "Epoch:",
                "%04d" % (epoch + 1),
                "cost=",
                "{:.9f}".format(c),
                "W=",
                sess.run(W),
                "b=",
                sess.run(b),
            )

    print("Optimization Finished!")
    training_cost = sess.run(cost, feed_dict={X: train_X, Y: train_Y})
    print("Training cost=", training_cost, "W=", sess.run(W), "b=", sess.run(b), "\n")


"""
When you roll two regular six-sided dice, the total number of pips that can come up ranges from 2 (if both dice show 1)
to 12 (if both dice show 6), but as all experienced gamblers know, some numbers are more likely than others. In fact,
the most likely number to come up is 7, with a probability of 1/6. By contrast, the probability of 12 showing is only
1/36, so it is six times more likely that the dice will show 7 than it is that they will show 12.

The reason for this is of course that there are more ways that two dice can sum to 7. In fact, there are exactly six
ways two dice can sum to 7: the first die can show 1 and the second 6, the first 2 and the second 5, the first 3 and
the second 4, the first 4 and the second 3, the first 5 and the second 2, and finally the first die can show 6 and the
second 1. Given that there are a total of 6*6 = 36 different ways the dice can land, this gives us the probability:
6/36 = 1/6. In contrast, there is only one way two dice can form 12, by throwing two sixes.

Define a function f(d, n) that gives the number of ways d six-sided dice can be thrown to show the number n. So, in the
previous example, f(2,7) = 6. Here are a few other values of that function:
f(1,n) = 1 (for 1≤n≤6, 0 otherwise)
f(2,7) = 6
f(2,10) = 3
f(2,12) = 1
f(3,10) = 27
f(5,20) = 651
f(7,30) = 12117
f(10,50) = 85228
Find f(20, 100)

Note: the answer fits into a 64-bit integer

Bonus: Find f(1100, 5000) mod 107
"""

import itertools
from scipy import convolve

def f(d, n):
    """
    my itertools solution. too slow for final solution
    """
    dice = '123456'
    comb = itertools.product(dice, repeat=d)
    perm_list = []

    def sum_check(x, n):
        return sum(x) == n

    for c in comb:
        intd = list(map(int, c))
        if sum_check(intd, n):
            perm_list.append(intd)
    return len(perm_list)

def crawphish(d, n):
    """
    Recursive solution from /u/crawphish ported to python by me. too slow for final solution
    """
    out = 0
    for i in range(1, 6+1):
        if d:
            out += crawphish(d - 1, n - i)
        else:
            if n:
                return 0
            else:
                return 1
    return out

def ttl(d, n, m=10**7):
    """
    /u/ttl's solution. Mathematical solution, no idea of how it works but it returns the solution and bonus solution
    very quickly.
    """
    p = q = [1]*6+[0]
    i = 1
    while i < d:
        q, i = (convolve(q, q) % m, i*2) if 2*i < d else (convolve(q, p) % m, i+1)
    return q[-n-1]

def main():
    # print(f(20,100))
    # print(crawphish(20, 100))
    print(ttl(1100, 5000))

if __name__ == "__main__":
    main()


"""
Content under Creative Commons Attribution license CC-BY 4.0,
code under MIT license (c)2018 Sergio Rojas (srojas@usb.ve)

http://en.wikipedia.org/wiki/MIT_License
http://creativecommons.org/licenses/by/4.0/

Created on april, 2018
Last Modified on: may 15, 2018

  This program finds the solution of the equation
     7 = x + 9
"""
from sympy import symbols, Eq, solveset
x  = symbols('x')

LHS = 7
RHS = x + 9

thesol = list( solveset( Eq(LHS, RHS), x) )
print('thesol =', thesol)

newLHS = LHS - RHS #rearrange the equation to read: LHS - RHS = 0
print('newLHS =', newLHS)

newLHS = newLHS.subs(x, thesol[0])
if newLHS.simplify() == 0:
    print('The solution of {0} = {1}, is x = {2}'.format(LHS,RHS,thesol[0]))


import numpy as np
import time

#implementation of Gauss-Jordan Elimination for square matrices
test1 = [[ 0,  2,  1],
         [ 1, -2, -3],
         [-1,  1,  2]]

test2 = [[1, -2, 1],
        [0, 2, -8],
        [-4, 5, 9]]

test3 = [[1, 1, -2, 1, 3, -1],
         [2, -1, 1, 2, 1, -3],
         [1, 3, -3, -1, 2, 1],
         [5, 2, -1, -1, 2, 1],
         [-3, -1, 2, 3, 1, 3],
         [4, 3, 1, -6, -3, -2]]

another = [[1, 2, 3],
           [4, 5, 6],
           [7, 8, 9]]

test_vector1 = [-8, 0, 3]
test2_vector = [0, 8, -9]
test3_vector = [4, 20, -15, -3, 16, -27]

numpy_matrix = np.array(test3)
numpy_vector = np.array([test3_vector])
numpy_vector = np.transpose(numpy_vector)

start1 = time.time()
solution = np.linalg.solve(numpy_matrix, numpy_vector)
end1 = time.time()
numpy_time = end1 - start1

#switches the rows in the case when there is a vector with zero in the first place
def switch_the_rows(mat, vector):
    for i in range(len(list_)):
        if mat[i][0] != mat[0][0] and mat[i][0] != 0:
            temp1 = mat[i]
            temp2 = vector[i]
            mat[i] = mat[0]
            vector[i] = vector[0]
            mat[0] = temp1
            vector[0] = temp2
            break
    return mat, vector

#row reduces the matrix, approaches to lower triangular matrix
#one row operation each time
def lower_row_reduction(mat, pivot_index, vector):
    pivot = mat[pivot_index]
    for i in range(pivot_index, len(mat)):
        if i+1 == len(mat): break
        if mat[i+1][i] != 0:
            piv_multiple = [-x * mat[i+1][pivot_index]/pivot[pivot_index] for x in pivot]
            vect_multiple = -vector[pivot_index]*mat[i+1][pivot_index]/pivot[pivot_index]
            mat[i+1][:] = [x+y for x, y in zip(piv_multiple, mat[i+1])]
            vector[i+1] = vect_multiple+vector[i+1]
    return mat, vector

#creation of lower triangular matrix
def lower_triangular(mat, vector):
    for i in range(len(mat)):
        mat, vector = lower_row_reduction(mat, i, vector)
    return mat, vector

#row reduces the matrix, approaches to identity matrix
#one row operation each time
def upper_row_reduction(mat, pivot_index, vector):
    pivot = mat[pivot_index]
    vector[pivot_index] /= pivot[pivot_index]
    mat[pivot_index][:] = [x/pivot[pivot_index] for x in pivot]
    pivot = mat[pivot_index]
    for i in range(pivot_index, -1, -1):
        if i == 0: break
        if mat[i][i] != 0:
            temp = [-x*mat[i-1][pivot_index] for x in pivot]
            temp_vector = -vector[pivot_index]*mat[i-1][pivot_index]
            mat[i-1][:] = [y+x for x, y in zip(mat[i-1], temp)]
            vector[i-1] = temp_vector+vector[i-1]
    return mat, vector

#creation of upper triangular matrix
def upper_triangular(mat, vector):
    for i in range(len(mat)-1, -1, -1):
        mat, vector = upper_row_reduction(mat, i, vector)
    return mat, vector

#merge the functions
def gauss_jordan(mat, vector):
    if mat[0][0] == 0: mat, vector = switch_the_rows(mat, vector)
    mat, vector = lower_triangular(mat, vector)
    mat, vector = upper_triangular(mat, vector)
    return mat, vector

start = time.time()
M, sol = gauss_jordan(test3, test3_vector)
end = time.time()

my_time = end - start

sol = [round(x, 2) for x in sol]                #round each element in the vector up to 2 decimal places
print(sol)

print("Numpy implementation: " + str(numpy_time))
print("My implementation: " + str(my_time))
print("Difference: " + str(my_time - numpy_time))


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

# Raivo Laanemets
# rlaanemt@ut.ee

# A note: getA1() is used to transform matrix row into array.

import sys
import random
import numpy
import time
import math

# Solves linear system Kx = b.
# when is_unit is set to True then the
# procedure expects lower triangular matrix as L
# otherwise it expects lower unit triangular matrix as L.
# Might destructively update input matrix!

def solveL(L, b, is_unit=False):
    # If unit triangular matrix is assumed, set 1's in
    # the matrix main diagonal.
    if is_unit:
        L += numpy.diag(numpy.matrix(-L.diagonal() + 1).getA1())
    # Solve with forward subsitution.
    x = numpy.array(numpy.zeros(len(b), dtype=float))
    x[0] = b[0] / L[0, 0]
    for i in xrange(1, len(b)):
        x[i] = (b[i] - sum((L[i, 0:i]).getA1() * x[0:i])) / L[i, i]
    return x

# Solves linear system Kx = b.
# Expects upper triangular matrix as L.

def solveU(L, b):
    # Transforms the matrix L into suitable form to use with solveL.
    # Might be inefficient.
    # [::-1] reverses the array.
    return solveL(numpy.fliplr(numpy.flipud(L)), b[::-1])[::-1]

# Taken from pseudoalgorithm:
# http://www.math.vt.edu/people/wapperom/class_home/4445/alg_ludoolittle.pdf

# Compared to one on our lecture slides:
# 1. It gives name of the algorithm (Doolittle's) so
# I can ask someone about it.
# 2. Checks if factorization is possible at all
# instead of quitely producing bogus results.
# 3. Gives L and U matrixes I actually know how to use.

# Returns a three tuple (L, U) as the decomposition result.
# Modifies right side vector b as well.

def gauss_decomp(a, b, pivoting=False):
    n = len(a)
    l = numpy.matrix(numpy.zeros((n, n), dtype=float))
    u = numpy.matrix(numpy.zeros((n, n), dtype=float))
    for i in xrange(n): # iterates over rows

        max_a = abs(a[i, i])
        max_i = i

        # Row pivoting.
        # Find best pivot (manually).
        if pivoting:
            for j in xrange(i, n):
                if (abs(a[j, i]) > max_a):
                    max_a = abs(a[j, i])
                    max_i = j

        if max_i != i:

            # Swaps rows manually.
            # Tracking row permutations was too complex for me.
            # This might be inefficient but could be easily
            # implemented in C or Fortran and then use
            # that implementation through some Python
            # native interface.

            interchange(a, i, max_i);
            interchange(l, i, max_i);

            # Also does swapping for right-hand side vector.

            tmp = b[i]
            b[i] = b[max_i]
            b[max_i] = tmp

        if a[i, i] == 0:
            raise Exception("Factorization not possible");
        l[i, i] = 1.0
        for j in xrange(i, n):
            u[i, j] = a[i, j]
            for k in xrange(i):
                u[i, j] = u[i, j] - l[i, k] * u[k, j]
        for j in xrange(i + 1, n):
            l[j, i] = a[j, i]
            for k in xrange(i):
                l[j, i] = l[j, i] - l[j, k] * u[k, i]
            l[j, i] = l[j, i] / float(u[i, i])

    return (l, u)

def interchange(M, r1, r2):
    for j in xrange(len(M)):
        tmp = M[r1, j]
        M[r1, j] = M[r2, j]
        M[r2, j] = tmp

def solve_single(A, b, pivoting=True):
    (L, U) = gauss_decomp(A, b, pivoting)
    return solve_lu(L, U, b);

def solve_lu(L, U, b):
    y = solveL(L, b)
    x = numpy.matrix(solveU(U, y))
    # Consistent with numpy.linalg.solve output.
    x.shape = (len(b), 1)
    return numpy.matrix(x)

def main(argv):
    # Testing with the example from http://en.wikipedia.org/wiki/System_of_linear_equations
    A = numpy.matrix([[2, -2, 4], [3, 2, -1], [-1, 0.5, -1]], dtype=float)
    b = numpy.array([-2, 1, 0], dtype=float)
    print "A\n", A
    print "b\n", b
    print "solve\n", solve_single(A, b, True)

    # Calculating errors for large matrices.
    m = 40
    size = 25
    errors = []
    errors_pivoting = []
    for i in xrange(m):
        Aarr = (numpy.random.rand(size * size) - 0.5) * 1000000000
        Aarr.shape = (size, size)
        A = numpy.matrix(Aarr)
        b = numpy.random.random(size)
        A1 = A.copy()
        b1 = b.copy()
        x1 = solve_single(A1, b1, False)
        errors.append(numpy.sum(numpy.square(b1 - (A1 * x1).getA1())))
        A2 = A.copy()
        b2 = b.copy()
        x2 = solve_single(A2, b2, True)
        errors_pivoting.append(numpy.sum(numpy.square(b2 - (A2 * x2).getA1())))

    print "Average error without pivoting :", numpy.average(errors)
    print "Average error with pivoting :", numpy.average(errors_pivoting)

if __name__ == "__main__":
    main(sys.argv[1:])


#ZADANIE 1
#Napisz funkcje tsin(x), tcos(x), texp(x) i ttan(x) realizujace takie same operacje jak funkcje biblioteczne:
#numpy.sin(x), numpy.cos(x), numpy.exp(x) i numpy.tan(x).
#We wlasnych funkcjach wykorzystaj rozwiniecie w szereg Taylora (https://en.wikipedia.org/wiki/Taylor_series).
#W celu poprawnego rozwiazania zadania nalezy dodatkowo napisac funkcje realizujaca n! (silnia).

import numpy as np

def tbernoulli(n):
    if n<0 and n>20:
        return 0
    else:
        temp=[1, 1/2, 1/6, 0, -1/30, 0, 1/42, 0, -1/30, 0, 5/66, 0, -691/2730, 0, 7/6, 0, -3617/510, 0, 43867/798, 0, -174611/330]
        return temp[n]

def silnia(x):
    sil=1
    while x>0:
        sil=sil*x
        x =x-1
    return sil

def tsin(x):
    sum_sin=0
    for i in range(0,6):
        sum_sin=sum_sin+((-1)**i)*(x**(2*i+1))/float(silnia(2*i+1))
    return sum_sin

def tcos(x):
    sum_cos=0
    for i in range(0,6):
        sum_cos=sum_cos+((-1)**i)*(x**(2*i))/float(silnia(2*i))
    return sum_cos

def texp(x):
    sum_exp=0
    for i in range(0,6):
        sum_exp=sum_exp+(x**i)/float(silnia(i))
    return sum_exp

def ttan(x):
    sum_tan=0
    for i in range(0,6):
        sum_tan=sum_tan+tbernoulli(2*i)*((-4)**i)*(1-(4**i))*(x**(2*i-1))/float(silnia(2*i))
    return sum_tan

x=np.pi/3

print('sin(%.2f)=%.12f' % (x,tsin(x)))
print('cos(%.2f)=%.12f' % (x,tcos(x)))
print('exp(%.2f)=%.12f' % (x,texp(x)))
print('tan(%.2f)=%.12f' % (x,ttan(x)))


# -*- coding: utf-8 -*-
"""
Created on Tue Sep 21 00:58:09 2021

@author: Mahfuz_Shazol
"""

import numpy as np

X=np.array([
            [1,2,4],
            [2,-1,3],
            [0,5,1]
          ])

det_x_result=np.linalg.det(X)
print(det_x_result)

lambdas,v=np.linalg.eig(X)
product_of_eigon_result=np.product(lambdas)
print(product_of_eigon_result)


import numpy as np
import math

# Compute the intersection distance between histograms x and y
# Return 1 - hist_intersection, so smaller values correspond to more similar histograms
# Check that the distance range in [0,1]

def dist_intersect(x,y):

    #... (your code here)

# Compute the L2 distance between x and y histograms
# Check that the distance range in [0,sqrt(2)]

def dist_l2(x,y):

    #... (your code here)

# Compute chi2 distance between x and y
# Check that the distance range in [0,Inf]
# Add a minimum score to each cell of the histograms (e.g. 1) to avoid division by 0

def dist_chi2(x,y):

    #... (your code here)

def get_dist_by_name(x, y, dist_name):
  if dist_name == 'chi2':
    return dist_chi2(x,y)
  elif dist_name == 'intersect':
    return dist_intersect(x,y)
  elif dist_name == 'l2':
    return dist_l2(x,y)
  else:
    assert False, 'unknown distance: %s'%dist_name


## 2. The Mean ##

distribution = [0,2,3,3,3,4,13]

mean = 4
center =False
equal_distances = True

## 3. The Mean as a Balance Point ##

from numpy.random import randint, seed

equal_distances = 0

for i in range(5000):
    seed(i)
    distribution = randint(0,1000,10)
    mean = sum(distribution)/len(distribution)

    above_mean = []
    below_mean = []
    for value in distribution:
        if value == mean:
            continue
        if value < mean:
            below_mean.append(mean - value)
        if value > mean:
            above_mean.append(value -mean)

    sum_above = round(sum(above_mean),1)
    sum_below =round(sum(below_mean),1)
    if (sum_above==sum_below):
        equal_distances+=1

print(equal_distances)

## 4. Defining the Mean Algebraically ##

one = False

two = False

three =  False

## 5. An Alternative Definition ##

distribution_1 = [42, 24, 32, 11]
distribution_2 = [102, 32, 74, 15, 38, 45, 22]
distribution_3 = [3, 12, 7, 2, 15, 1, 21]

def mean(distribution):
    sum_distribution = 0
    for value in distribution:
        sum_distribution += value

    return sum_distribution / len(distribution)

mean_1 = mean(distribution_1)
mean_2 = mean(distribution_2)
mean_3 =  mean(distribution_3)

print(mean_1)
print(mean_2)
print(mean_3)

## 6. Introducing the Data ##

import pandas as pd

houses = pd.read_table('AmesHousing_1.txt', sep = '\t')
print(houses.head())

one =  True

two = False

three = True

## 7. Mean House Prices ##

def mean(distribution):
    sum_distribution = 0
    for value in distribution:
        sum_distribution += value

    return sum_distribution / len(distribution)

function_mean = mean(houses['SalePrice'])

pandas_mean =  houses['SalePrice'].mean()
means_are_equal = function_mean ==  pandas_mean

print(function_mean ,pandas_mean, means_are_equal)

## 8. Estimating the Population Mean ##

parameter = houses['SalePrice'].mean()

sample_size = 5

sample_sizes = []
sampling_errors = []

for i in range(101):
    sample = houses['SalePrice'].sample(sample_size, random_state = i)

    statistic = sample.mean()
    sampling_error = parameter - statistic
    sampling_errors.append(sampling_error)
    sample_sizes.append(sample_size)
    sample_size +=29

import matplotlib.pyplot as plt

plt.scatter(sample_sizes, sampling_errors)
plt.axhline(0)
plt.axvline(2930)
plt.xlabel('Sample size')
plt.ylabel('Sampling error')

## 9. Estimates from Low-Sized Samples ##

means = []

for i in range(10000):
    sample = houses['SalePrice'].sample(100, random_state = i)
    means.append(sample.mean())

plt.hist(means)
plt.axvline(houses['SalePrice'].mean())
plt.xlabel('Sample mean')
plt.ylabel('Frequency')
plt.xlim(0,500000)

## 11. The Sample Mean as an Unbiased Estimator ##

population = [3, 7, 2]
samples = [[3, 7], [3, 2],
           [7, 2], [7, 3],
           [2, 3], [2, 7]
          ]

sample_means = []
for sample in samples:
    sample_means.append(sum(sample) / len(sample))

population_mean = sum(population) / len(population)
mean_of_sample_means = sum(sample_means) / len(sample_means)

unbiased = (population_mean == mean_of_sample_means)
print(population_mean)
print(sample_means)
print(mean_of_sample_means)
print(unbiased)

5. Probability and Statistics/statistics-intermediate/The Mean-305.py


# -*- coding: utf-8 -*-
"""
-----------------------------------------------------------------------------
Ejercicio 2: Integración - Fórmulas de cuadratura compuestas.
-----------------------------------------------------------------------------
"""
import numpy as np
import sympy as sym

# Cálculo de la integral exacta de la función f(x) = exp(x) en [0,3]
#---------------------------------------------------------------------
x = sym.Symbol('x', real=True)            # definimos la variable x simbólica
f = sym.exp(x)            # definimos la función f simbólica
I_exacta = sym.integrate(f,(x,0,3))
I_exacta = float(I_exacta)
print ('El valor exacto es: ',I_exacta)

"""
Ejercicio 2a: Integración - Fórmula del punto medio compuesta.
-----------------------------------------------------------------------------
Función punto_medio_comp: Halla la integral aproximada utilizando la fórmula del
punto medio compuesta para una función f en un intervalo [a,b].

Argumentos de entrada:
    f:  función integrando (función lambda).
    a:  extremo inferior del intervalo de integración (número real).
    b:  extremo superior del intervalo de integración (número real).
    n:  número de subintervalos (número entero).

Argumentos de salida:
    I:  integral aproximada con la fórmula del punto medio compuesta de la función
        f en [a,b] (número real).

Ejemplos:
    f = lambda x : x**2
    I = punto_medio_comp(f,0,2,4)
    print('Ejemplo de prueba con punto medio compuesta =', I)
    Salida:
        Ejemplo de prueba con punto medio compuesta = 2.625
"""

# Función punto_medio_comp
#--------------------------------------
def punto_medio_comp(f,a,b,n):
    h = (b-a)/float(n)              # longitud de los subintervalos
    x = np.arange(a,b+h,h) # vector que contiene los puntos medios de los subintervalos
    I = 0.0
    for i in range(1,n+1):
        I += f((x[i-1]+x[i])/2.0)
    I = h*I       # fórmula del punto medio compuesta
    return I

#--------------------------------------
# Ejemplos
#--------------------------------------

# Ejemplo de prueba
f = lambda x : x**2
I = punto_medio_comp(f,0,2,4)
print('Ejemplo de prueba con punto medio compuesta =', I)

#--------------------------------------
# Ejercicio 2a
#--------------------------------------

# Cálculo de la integral aproximada
#---------------------------------------
f = lambda x :np.exp(x)
a = 0
b = 3
n = 5
Ipmc = punto_medio_comp(f,a,b,n)

print ('El valor aproximado con punto medio compuesta es:', Ipmc)

"""
Ejercicio 2b: Integración - Fórmula del trapecio compuesta.
-----------------------------------------------------------------------------
Función trapecio_comp: Halla la integral aproximada utilizando la fórmula del
trapecio compuesta para una función f en un intervalo [a,b].

Argumentos de entrada:
    f:  función integrando (función lambda).
    a:  extremo inferior del intervalo de integración (número real).
    b:  extremo superior del intervalo de integración (número real).
    n:  número de subintervalos (número entero).

Argumentos de salida:
    I:  integral aproximada con la fórmula del trapecio compuesta de la función
        f en [a,b] (número real).

Ejemplos:
    f = lambda x : x**2
    I = trapecio_comp(f,0,2,4)
    print('Ejemplo de prueba con trapecio compuesta =', I)
    Salida:
        Ejemplo de prueba con trapecio compuesta = 2.75
"""

# Función trapecio_comp
#--------------------------------------
def trapecio_comp(f,a,b,n):
    h = (b-a)/float(n)            # longitud del intervalo
    x = np.arange(a,b+h,h) # vector que contiene los nodos intermedios
    I = 0.0
    for i in range(1,n):
        I += f(x[i])
    I = (h/2.0)*(f(a)+f(b)) + h*I           # fórmula del trapecio compuesta
    return I

#--------------------------------------
# Ejemplos
#--------------------------------------

# Ejemplo de prueba
f = lambda x : x**2
I = trapecio_comp(f,0,2,4)
print('Ejemplo de prueba con trapecio compuesta =', I)

#--------------------------------------
# Ejercicio 2b
#--------------------------------------

# Cálculo de la integral aproximada
#---------------------------------------
f = lambda x :np.exp(x)
a = 0
b = 3
n = 4
Itc = trapecio_comp(f,a,b,n)

print ('El valor aproximado con trapecio compuesta es:', Itc)

"""
Ejercicio 2c: Integración - Fórmula de Simpson compuesta.
-----------------------------------------------------------------------------
Función simpson_comp: Halla la integral aproximada utilizando la fórmula de
Simpson compuesta para una función f en un intervalo [a,b].

Argumentos de entrada:
    f:  función integrando (función lambda).
    a:  extremo inferior del intervalo de integración (número real).
    b:  extremo superior del intervalo de integración (número real).
    n:  número de subintervalos (número entero).

Argumentos de salida:
    I:  integral aproximada con la fórmula de Simpson compuesta de la función
        f en [a,b] (número real).

Ejemplos:
    f = lambda x : x**2
    I = simpson_comp(f,0,2,6)
    print('Ejemplo de prueba con Simpson compuesta =', I)
    Salida:
        Ejemplo de prueba con Simpson compuesta = 2.6666666666666665
"""

# Función simpson_comp
#--------------------------------------
def simpson_comp(f,a,b,n):
    h = (b-a)/float(n)                                 # longitud de los subintervalos
    x1 = np.arange(a,b+h,h) # nodos que separan los subintervalos
    I = 0.0                                 # fórmula de Simpson compuesta
    for i in range(1,n+1,1):
        I += f(x1[i-1]) + 4.0*f((x1[i-1]+x1[i])/2.0) + f(x1[i])
    I = (h/6.0)*I
    return I

#--------------------------------------
# Ejemplos
#--------------------------------------

# Ejemplo de prueba
f = lambda x : x**2
I = simpson_comp(f,0,2,6)
print('Ejemplo de prueba con Simpson compuesta =', I)

#--------------------------------------
# Ejercicio 2c
#--------------------------------------

# Cálculo de la integral aproximada
#---------------------------------------
f = lambda x :np.exp(x)
a = 0
b = 3
n = 4
Its = simpson_comp(f,a,b,n)

print ('El valor aproximado con Simpson compuesta es:', Its)


import numpy as np
from numpy import linalg as linAlg
import math
import pandas as pd
from random import shuffle
from matplotlib import pyplot as plt
import matplotlib.pyplot as plt
import matplotlib.pyplot as pause
from mpl_toolkits.mplot3d import Axes3D
from time import sleep
import matplotlib.animation as animation
import sys

def plotPoints(plotOutFunction, fy=[], fx=[],tau=-1):
	x = []
	y = []

	for i in range(len(xyPoints)):
		x.append(xyPoints[i][0])
		y.append(xyPoints[i][len(xyPoints[0])-1])

	if tau == -1:
		plt.title("XY points and predicted function for Linear Regression")
	else:
		plt.title("XY points and predicted function for weighted Regression with tau = " + str(tau))
	plt.scatter(x,y,color='blue',label='Original Plot')
	if (plotOutFunction == 1):
		plt.scatter(fx,fy,color='red',label='Predicted Plot')

	plt.xlabel("Input Data")
	plt.ylabel("Output Data")
	plt.legend()

	plt.show()

def readPoints(fileX,fileY):
	noOfPoints = 0
	xyPoints = []

	f1 = open(fileX, "r")
	f2 = open(fileY, "r")

	xPoint = f1.read().splitlines()
	yPoint = f2.read().splitlines()

	for i in range(len(xPoint)):
		xy1Point = []
		xy1Point.append(float(xPoint[i]))
		xy1Point.append(1.0)			# This is the value corresponding to theta0 (since theta0 is the intercept)
		xy1Point.append(float(yPoint[i]))

		xyPoints.append(xy1Point)
		noOfPoints = noOfPoints + 1

	f1.close()
	f2.close()

	return xyPoints, noOfPoints

def normalize(xyPoints, mean, var):
	for i in range(len(xyPoints[0])):
		if (i == len(xyPoints[0])-2):		# Ignore the second last col and last col. Second last col is 1.0 that denotes intercept
			break

		x = []
		for j in range(len(xyPoints)):
			x.append(xyPoints[j][i])

		mean[i]=(np.mean(x))
		var[i]=(np.std(x))

		for j in range(len(xyPoints)):
			xyPoints[j][i] = (xyPoints[j][i] - mean[i]) / var[i]

	return xyPoints,mean,var

def getPredictedY(xyPoints, thetaVec):
	fy = []
	y = [0] * len(xyPoints)

	for k in range(len(xyPoints)):
		fy1 = 0.0
		for i in range(len(thetaVec)):
			fy1 = fy1 + thetaVec[i] * xyPoints[k][i]

		fy.append(fy1)
		y[k] = xyPoints[k][len(xyPoints[0])-1]

	return fy

def unormalize(xyPoints, mean, var, pfx=[], isFxAvailable=False):
	fx = pfx
	if isFxAvailable == False:
		fx = [0] * len(xyPoints)

	for i in range(len(xyPoints[0])):
		if (i == len(xyPoints[0])-2):
			break

		for j in range(len(xyPoints)):
			xyPoints[j][i] = (xyPoints[j][i] * var[i]) + mean[i]

			if isFxAvailable == True:
				fx[j] = (fx[j] * var[i]) + mean[i]
			else:
				fx[j] = xyPoints[j][i]

	return xyPoints, fx

def calculateTheta(xyPoints, thetaVec, weights, isWeightedLinearReg):
	X = np.zeros((len(xyPoints), 2))
	Xt = np.zeros((2, len(xyPoints)))
	Y = np.zeros((len(xyPoints), 1))
	W = np.zeros((len(xyPoints), len(xyPoints)))

	for i in range(len(xyPoints)):
		for j in range(len(xyPoints[i])-1):
			X[i][j] = xyPoints[i][j]
			Xt[j][i] = xyPoints[i][j]

	for i in range(len(weights)):
		W[i][i] = weights[i]

	for i in range(len(xyPoints)):
		Y[i][0] = xyPoints[i][len(xyPoints[0])-1]

	thetaVec = linAlg.inv(Xt @ X) @ Xt @ Y
	if isWeightedLinearReg == True:
		thetaVec = linAlg.inv(Xt @ W @ X) @ Xt @ W @ Y

	thetaVecRet = [0] * (len(thetaVec))
	for i in range(len(thetaVec)):
		thetaVecRet[i] = thetaVec[i][0]

	return thetaVecRet

def getWeights(xyPoints, noOfPoints, pointToProcess, weights, tau):
	for i in range(noOfPoints):
		diff = 0.0
		for j in range(len(xyPoints[i])-1):
			diff = diff + (pointToProcess[j] - xyPoints[i][j]) * (pointToProcess[j] - xyPoints[i][j])

		weights[i] = math.exp(-1 * (diff / (2 * tau * tau)))

	return weights

def linearRegression(xyPoints, noOfPoints, pointToProcess, isWeightedLinearReg, tau = 0):
	thetaVec = [0] * (len(xyPoints[0]) - 1)		# Last col is y so we will subtract that col in thetaVec and last theta is O0 which we will add a column in theta Vec
	weights = [1] * (noOfPoints)

	if isWeightedLinearReg == True:
		weights = getWeights(xyPoints, noOfPoints, pointToProcess, weights, tau)

	thetaVec = calculateTheta(xyPoints, thetaVec, weights, isWeightedLinearReg)
	fy = getPredictedY(xyPoints, thetaVec)

	return fy,thetaVec

def weightedLinearRegression(xyPoints, noOfPoints, tau):
	fyFinal = [1] * (noOfPoints)
	xFinal = [1] * (noOfPoints)
	cntr = 0

	minEle = 100000
	maxEle = -100000
	for i in range(len(xyPoints)):
		if minEle > xyPoints[i][0]:
			minEle = xyPoints[i][0]
		if maxEle < xyPoints[i][0]:
			maxEle = xyPoints[i][0]
	points = np.linspace(minEle, maxEle, noOfPoints)
	#for i in range(len(xyPoints)):
	#	points[i] = xyPoints[i][0]

	while cntr < noOfPoints:
		pointToProcess = [1] * (len(xyPoints[0])-1)
		pointToProcess[0] = points[cntr]

		fy,thetaVec = linearRegression(xyPoints, noOfPoints, pointToProcess, True, tau)		# True - Is weighted linear regression

		predictedPointToProcess = 0.0
		for j in range(len(thetaVec)):
			predictedPointToProcess = predictedPointToProcess + thetaVec[j] * pointToProcess[j]

		fyFinal[cntr] = predictedPointToProcess
		xFinal[cntr] = pointToProcess[0]

		cntr = cntr + 1

	return fyFinal,xFinal

fileX = sys.argv[1] # prints python_script.py
fileY = sys.argv[2] # prints var1
tau = float(sys.argv[3]) # prints var2

xyPoints,noOfPoints = readPoints(fileX, fileY)

mean = [0] * len(xyPoints[0])
var = [0] * len(xyPoints[0])

######### (a)
xyPoints,mean,var = normalize(xyPoints, mean, var)

fy,thetaVec = linearRegression(xyPoints, noOfPoints, [], False)					# False - Is not weighted linear regression

xyPoints,fx = unormalize(xyPoints, mean, var, [], False)
plotPoints(1,fy,fx)

######### (b)
xyPoints,mean,var = normalize(xyPoints, mean, var)

#tau =0.8
fy,fx = weightedLinearRegression(xyPoints, noOfPoints, tau)

xyPoints,fx = unormalize(xyPoints, mean, var, fx, True)
plotPoints(1,fy, fx,tau)

######### (c)
tauList = [0.1, 0.3, 2, 10]
for i in range(len(tauList)):
	xyPoints,mean,var = normalize(xyPoints, mean, var)

	tau = tauList[i]
	fy,fx = weightedLinearRegression(xyPoints, noOfPoints, tau)

	xyPoints,fx = unormalize(xyPoints, mean, var, fx, True)
	plotPoints(1,fy,fx,tau)


#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Jérôme Eberhardt 2016-2020
# Unrolr
#
# Principal Component Analysis
# Author: Jérôme Eberhardt <qksoneo@gmail.com>
#
# License: MIT

from __future__ import division
from __future__ import print_function
from __future__ import absolute_import

import numpy as np
from scipy import linalg

__author__ = "Jérôme Eberhardt"
__copyright__ = "Copyright 2020, Jérôme Eberhardt"

__lience__ = "MIT"
__maintainer__ = "Jérôme Eberhardt"
__email__ = "qksoneo@gmail.com"

class PCA:

    def __init__(self, n_components=None):
        """Create DihedralPCa object

        Args:
            n_components (int, None): Number of components to keep. if n_components is not set all components are kept.

        """
        self._n_components = n_components
        self.components = None
        self.singular_values = None

    def fit_transform(self, X):
        """Fit the model with X and apply the dimensionality reduction on X.

        Args:
            X (ndarray): array-like, shape (n_samples, n_features)

        Returns:
            ndarray: final embedding (n_samples, n_components)

        """
        # Centering the data
        X -= np.mean(X, axis=0)
        # Compute covariance matrix
        cov = np.cov(X, rowvar=False)
        # PCA!!!
        singular_values , components = linalg.eigh(cov)

        # Sort by singular values
        idx = np.argsort(singular_values)[::-1]
        self.components = components[:, idx].T
        self.singular_values = singular_values[idx]

        if self._n_components is None:
            embedding = np.dot(X, self.components)
        else:
            embedding = np.dot(X, self.components[:int(self._n_components)].T)

        return embedding


"""
This file represents an abstract activation function and many well-known activation functions
"""

from abc import ABC, abstractmethod
import math

import numpy as np

class AbstractActivation(ABC):
    @abstractmethod
    def get_value(self, x: np.array):
        """
        The value of the activation on the array (element wise operation)
        """

    @abstractmethod
    def get_derivative(self, x: np.array, value_at_x: np.array = None):
        """
        Get the derivative of the activation function on x (element wise operation)
        """

    def get_approximate_derivative(self, x: np.array, eps: float = math.pow(10, -7)):
        """
        :param x: the array on which we want to compute the approximate derivative (element wise)
        :param eps: the epsilon used for the approximation (we recommend to not change it)
        :return: the approximate derivative
        """
        return (self.get_value(x + eps) - self.get_value(x - eps)) / (2 * eps)

class Sigmoid(AbstractActivation):
    def get_value(self, x: np.array) -> np.array:

        return 1 / (1 + np.exp(-x))

    def get_derivative(self, x: np.array, value_at_x: np.array = None) -> np.array:

        # The derivative on x is equal to sigmoid(x) * (1 - sigmoid(x))
        if value_at_x is None:
            sigmoid_value = self.get_value(x)
        else:
            sigmoid_value = value_at_x

        return sigmoid_value * (1 - sigmoid_value)

class Relu(AbstractActivation):
    def get_value(self, x: np.array) -> np.array:

        return np.maximum(x, 0)

    def get_derivative(self, x: np.array, value_at_x: np.array = None) -> np.array:

        # The derivative of relu is 0 when value is less than 0 else 1
        # Mathematically speaking, there is no derivative on 0, but we will consider that it is
        # equal to 1

        return x >= 0

    def get_approximate_derivative(self, x: np.array, eps: float = math.pow(10, -7)):

        # We highly do not recommend to use the approxilate derivative when using a relu function
        raise Exception("Do not use derivative approximate on Relu")

class Tanh(AbstractActivation):
    def get_value(self, x: np.array) -> np.array:

        return np.tanh(x)

    def get_derivative(self, x: np.array, value_at_x: np.array = None) -> np.array:

        # The derivative on x is equal to 1 + tanh^2
        if value_at_x is None:
            tanh_value = self.get_value(x)
        else:
            tanh_value = value_at_x
        return 1 - np.power(tanh_value, 2)


# ポアソン分布

# 利用するライブラリ
import numpy as np
from scipy.stats import poisson # ポアソン分布
from scipy.special import gamma, loggamma # ガンマ関数, 対数ガンマ関数
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

#%%

### 確率の計算

# パラメータを指定
lmd = 4.0

# 確率変数の値を指定
x = 2.0

# 定義式により確率を計算
prob = lmd**x / gamma(x + 1.0) * np.exp(-lmd)
print(prob)

# 対数をとった定義式により確率を計算
log_prob = x * np.log(lmd) - loggamma(x + 1.0) - lmd
prob = np.exp(log_prob)
print(prob, log_prob)

# ポアソン分布の関数により確率を計算
prob = poisson.pmf(k=x, mu=lmd)
print(prob)

# ポアソン分布の対数をとった関数により確率を計算
log_prob = poisson.logpmf(k=x, mu=lmd)
prob = np.exp(log_prob)
print(prob, log_prob)

#%%

### 統計量の計算

# パラメータを指定
lmd = 4.0

# 計算式により平均を計算
E_x = lmd
print(E_x)

# 計算式により分散を計算
V_x = lmd
print(V_x)

# ポアソン分布の関数により平均を計算
E_x = poisson.mean(mu=lmd)
print(E_x)

# ポアソン分布の関数により分散を計算
V_x = poisson.var(mu=lmd)
print(V_x)

#%%

### 分布の可視化

## 分布の計算

# パラメータを指定
lmd = 4.0

# 作図用のxの点を作成
x_vals = np.arange(np.ceil(lmd) * 4.0)

# ポアソン分布を計算
probability = poisson.pmf(k=x_vals, mu=lmd)

#%%

## 分布の作図

# ポアソン分布を作図
plt.figure(figsize=(12, 9)) # 図の設定
plt.bar(x=x_vals, height=probability, color='#00A968') # 棒グラフ
plt.xlabel('x') # x軸ラベル
plt.ylabel('probability') # y軸ラベル
plt.suptitle('Poisson Distribution', fontsize=20) # 全体のタイトル
plt.title('$\lambda=' + str(lmd) + '$', loc='left') # タイトル
plt.xticks(ticks=x_vals) # x軸目盛
plt.grid() # グリッド線
plt.show() # 描画

#%%

# 統計量を計算
E_x = lmd
s_x = np.sqrt(lmd)

# 統計量を重ねたポアソン分布を作図
plt.figure(figsize=(12, 9)) # 図の設定
plt.bar(x=x_vals, height=probability, color='#00A968') # 分布
plt.vlines(x=E_x, ymin=0.0, ymax=probability.max(), color='orange', linewidth=2.5, linestyle='--', label='$E[x]$') # 平均
plt.vlines(x=E_x - s_x, ymin=0.0, ymax=probability.max(), color='orange', linewidth=2.5, linestyle=':', label='$E[x] \pm \\sqrt{V[x]}$') # 平均 - 標準偏差
plt.vlines(x=E_x + s_x, ymin=0.0, ymax=probability.max(), color='orange', linewidth=2.5, linestyle=':') # 平均 + 標準偏差
plt.xlabel('x') # x軸ラベル
plt.ylabel('probability') # y軸ラベル
plt.suptitle('Poisson Distribution', fontsize=20)# 全体のタイトル
plt.title('$\lambda=' + str(lmd) + '$', loc='left') # タイトル
plt.xticks(ticks=x_vals) # x軸目盛
plt.legend() # 凡例
plt.grid() # グリッド線
plt.show() # 描画

#%%

### パラメータと分布の形状の関係

# lambdaとして利用する値を指定
lambda_vals = np.arange(start=0.0, stop=10.1, step=0.1)
print(len(lambda_vals)) # フレーム数

# 作図用のxの点を作成
x_vals = np.arange(np.ceil(lambda_vals.max()) * 2.0)

# y軸(確率)の最大値を設定
prob_max = np.max(poisson.pmf(k=x_vals, mu=lambda_vals.min())) + 0.1
#prob_max = 0.5

# 図を初期化
fig = plt.figure(figsize=(12, 9)) # 図の設定
fig.suptitle('Poisson Distribution', fontsize=20)# 全体のタイトル

# 作図処理を関数として定義
def update(i):
    # 前フレームのグラフを初期化
    plt.cla()

    # i回目のパラメータを取得
    lmd = lambda_vals[i]

    # ポアソン分布を計算
    probability = poisson.pmf(k=x_vals, mu=lmd)

    # ポアソン分布を作図
    plt.bar(x=x_vals, height=probability, color='#00A968') # 棒グラフ
    plt.xlabel('x') # x軸ラベル
    plt.ylabel('probability') # y軸ラベル
    plt.title('$\lambda=' + str(np.round(lmd, 1)) + '$', loc='left') # タイトル
    plt.xticks(ticks=x_vals) # x軸目盛
    plt.grid() # グリッド線
    plt.ylim(ymin=0.0, ymax=prob_max) # y軸の表示範囲

# gif画像を作成
anime_prob = FuncAnimation(fig, update, frames=len(lambda_vals), interval=100)

# gif画像を保存
anime_prob.save('ProbabilityDistribution/Poisson_prob.gif')

#%%

### 乱数の生成

## 乱数の生成

# パラメータを指定
lmd = 4.0

# データ数(サンプルサイズ)を指定
N = 1000

# ポアソン分布に従う乱数を生成
x_n = np.random.poisson(lam=lmd, size=N)

# 作図用のxの点を作成
x_vals = np.arange(x_n.max() + 5.0)

# 乱数を集計
frequency = np.array([np.sum(x_n == m) for m in x_vals])

# ポアソン分布を計算
probability = poisson.pmf(k=x_vals, mu=lmd)

#%%

## 乱数の可視化

# サンプルのヒストグラムを作成
plt.figure(figsize=(12, 9)) # 図の設定
plt.bar(x=x_vals, height=frequency, color='#00A968') # ヒストグラム
plt.xlabel('x') # x軸ラベル
plt.ylabel('frequency') # y軸ラベル
plt.suptitle('Poisson Distribution', fontsize=20)# 全体のタイトル
plt.title('$\lambda=' + str(lmd) + ', N=' + str(N) +
          '=(' + ', '.join([str(f) for f in frequency]) + ')$', loc='left') # タイトル
plt.xticks(ticks=x_vals) # x軸目盛
plt.grid() # グリッド線
plt.show() # 描画

#%%

# サンプルの構成比を作図
plt.figure(figsize=(12, 9)) # 図の設定
plt.bar(x=x_vals, height=probability, color='white', edgecolor='green', linestyle='--') # 元の分布
plt.bar(x=x_vals, height=frequency / N, color='#00A968', alpha=0.8) # 構成比
plt.xlabel('x') # x軸ラベル
plt.ylabel('proportion') # y軸ラベル
plt.suptitle('Poisson Distribution', fontsize=20)# 全体のタイトル
plt.title('$\lambda=' + str(lmd) + ', N=' + str(N) +
          '=(' + ', '.join([str(f) for f in frequency]) + ')$', loc='left') # タイトル
plt.xticks(ticks=x_vals) # x軸目盛
plt.grid() # グリッド線
plt.show() # 描画

#%%

## アニメーションによる可視化:(頻度)

# フレーム数を指定
N_frame = 100

# 図を初期化
fig = plt.figure(figsize=(12, 9)) # 図の設定
fig.suptitle('Poisson Distribution', fontsize=20)# 全体のタイトル

# y軸(頻度)の最大値を設定
freq_max = np.max([np.sum(x_n[:N_frame] == m) for m in x_vals]) + 1.0

# 作図処理を関数として定義
def update(n):
    # 前フレームのグラフを初期化
    plt.cla()

    # n個の乱数を集計
    frequency = np.array([np.sum(x_n[:(n+1)] == m) for m in x_vals])

    # サンプルのヒストグラムを作成
    plt.bar(x=x_vals, height=frequency, color='#00A968', zorder=1) # ヒストグラム
    plt.scatter(x=x_n[n], y=0.0, s=100, c='orange', zorder=2) # サンプル
    plt.xlabel('x') # x軸ラベル
    plt.ylabel('frequency') # y軸ラベル
    plt.title('$\lambda=' + str(lmd) + ', N=' + str(n + 1) +
              '=(' + ', '.join([str(f) for f in frequency]) + ')$', loc='left') # タイトル
    plt.xticks(ticks=x_vals) # x軸目盛
    plt.grid() # グリッド線
    plt.ylim(ymin=-0.5, ymax=freq_max) # y軸の表示範囲

# gif画像を作成
anime_freq = FuncAnimation(fig, update, frames=N_frame, interval=100)

# gif画像を保存
anime_freq.save('ProbabilityDistribution/Poisson_freq.gif')

#%%

## アニメーションによる可視化:(構成比)

# フレーム数を指定
N_frame = 100

# 図を初期化
fig = plt.figure(figsize=(12, 9)) # 図の設定
fig.suptitle('Poisson Distribution', fontsize=20)# 全体のタイトル

# y軸(割合)の最大値を設定
prop_max = np.max([np.sum(x_n[:N_frame] == m) for m in x_vals]) / N_frame + 0.1

# 作図処理を関数として定義
def update(n):
    # 前フレームのグラフを初期化
    plt.cla()

    # n個の乱数を集計
    frequency = np.array([np.sum(x_n[:(n+1)] == m) for m in x_vals])

    # サンプルのヒストグラムを作成
    plt.bar(x=x_vals, height=probability, color='white', edgecolor='green', linestyle='--', zorder=1) # 元の分布
    plt.bar(x=x_vals, height=frequency / (n + 1), color='#00A968', alpha=0.8, zorder=2) # 構成比
    plt.scatter(x=x_n[n], y=0.0, s=100, c='orange', zorder=3) # サンプル
    plt.xlabel('x') # x軸ラベル
    plt.ylabel('proportion') # y軸ラベル
    plt.title('$\lambda=' + str(lmd) + ', N=' + str(n + 1) +
              '=(' + ', '.join([str(f) for f in frequency]) + ')$', loc='left') # タイトル
    plt.xticks(ticks=x_vals) # x軸目盛
    plt.grid() # グリッド線
    plt.ylim(ymin=-0.01, ymax=prop_max) # y軸の表示範囲

# gif画像を作成
anime_prop = FuncAnimation(fig, update, frames=N_frame, interval=100)

# gif画像を保存
anime_prop.save('ProbabilityDistribution/Poisson_prop.gif')

#%%


import numpy as np
n_array = np.array([[1, 2, 3],
                    [4, 5, 6],
                    [7, 8, 9]])
print("Numpy Matrix is:")
trace = np.trace(n_array)
print("\nTrace of given 3X3 matrix:")
print(trace)

#15 (trace-sum of diagonal elements)


# encoding: utf-8
import numpy as np

# x = np.array([1.0,2.0,3.0])
# print(x)
# type(x)

x = np.array([1.0, 2.0, 3.0])
y = np.array([2.0, 4.0, 6.0])
print(x + y)
print(x - y)
print(x * y)
print(x / y)
print(x / 2)
# x 和 y 的元素个数要相同，不然会报错

# Numpy的N维数组
A = np.array([[1, 2], [3, 4]])
print(A)
print(A.shape)  # 矩阵的形状
print(A.dtype)  # 矩阵元素的数据类型

B = np.array([[3, 0], [0, 6]])
print(A + B)
print(A * B)
print(A * 10)
# Numpy数据可以生成N维数组
# 数学上将一维数组称为向量，二维数组称为矩阵
# 张量 tensor

# 广播
# 形状不同的数组之间也可以进行运算
C = np.array([[1, 2], [3, 4]])
D = np.array([10, 20])
C * D

# 访问元素
# 元素的索引从0开始
E = np.array([[51, 55], [14, 19], [0, 4]])
print('E')
print(E)
print(E[0])
print(E[0][1])
for row in E:
    print('row ：', row)
E = E.flatten()  # 将E转化为一维数组
print(E)
print(E[np.array([0, 2, 4])])  # 获取索引为0，2，4的元素
print(E > 15)  # [ True  True False  True False False]
print(E[E > 15])  # [51 55 19]


import os
import math
import csv
from scipy import stats
from itertools import combinations
import time

def ttest(writer, combo, a, b):
    sigFlag = 0
#    print("Combo of", combo[0], "and", combo[1])
    sumA = float(sum(a))
    sumB = float(sum(b))

    sumAsq = sumA ** 2
    sumBsq = sumB ** 2

    avgA = sumA/len(a)
    avgB = sumB/len(b)

    ssqA = sum(map(lambda x: x ** 2, a))
    ssqB = sum(map(lambda x: x ** 2, b))
    df = len(a) + len(b) - 2

    t = (avgA - avgB)/math.sqrt((((ssqA - sumAsq/len(a))+(ssqB - sumBsq/len(b)))/df)*(1.0/len(a)+1.0/len(b)))
#    print("T value ->", t)

    pval = stats.t.sf(abs(t), df)*2
#    print("2 Tailed P value ->", pval)

    if(pval < 0.05):
        sigFlag = 1
    res = [combo[0], combo[1], round(t, 5), df, round(pval, 6), sigFlag]
    writer.writerow(res)
#    print(res)

def main():
    ctr = 0
    path = os.getcwd()
    start = time.time()
    results = open(path + '\\results.csv', 'wt', newline='')
    writer = csv.writer(results, delimiter = ',')
    head = ['var_1', 'var_2', 't_value', 'degrees_of_freedom', 'p_value', 'significant']
    writer.writerow(head)
    rstart = time.time()
    csvFile = path + "\\data\\NMttest.csv"
    with open(csvFile, newline='') as fp:
        reader = csv.DictReader(fp)
        data = {}
        for row in reader:
            for header, value in row.items():
                try:
                    data[header].append(value)
                except KeyError:
                    data[header] = [value]
        for key, value in data.items():
            data[key] = list(filter(None, data[key]))
            data[key] = list(map(lambda x: float(x), data[key]))
        featureCombos = (list(combinations(data.keys(),2)))
        print("Time to read file ->", round(time.time() - rstart, 3), "seconds.", end = '\n')
        print("Total Combinations ->", len(featureCombos))
        for elem in featureCombos:
            ctr += 1
            sampleA = data[elem[0]]
            sampleB = data[elem[1]]
            ttest(writer, elem, sampleA, sampleB)
            print('Write success. Combination number ->', ctr, end = '\n')
#        print(data)
#    csvFile.close()
    results.close()
    fin = time.time() - start
    print("Total Time Elapsed ->", round(fin, 3), "seconds." ,end = '\n')
if __name__ == '__main__':
    main()


"""
2차원 Convolution(합성곱) 연산
"""
import numpy as np

def convolution_2d(x, w):
    """x, w: 2d ndarray. x의 shape이 w.shape와 같다.
        x와 w의 교차 상관 연산 결과를 return
    """
    xh, xw = x.shape[0], x.shape[1]

    # 2d 배열 w의 가로(width) ww,  세로(height) wh
    wh, ww = w.shape[0], w.shape[1]
    row_num = xh - wh + 1
    col_num = xw - ww + 1
    result = []
    for i in range(row_num):
        for j in range(col_num):
            x_sub = x[i:wh + i, j:ww + j]
            fma = np.sum(x_sub * w)
            result.append(fma)
    conv_ = np.array(result).reshape((row_num, col_num))
    return conv_

if __name__ == '__main__':
    np.random.seed(113)
    x = np.arange(1, 10).reshape((3, 3))
    print(x)
    w = np.array([[2, 0],
                  [0, 0]])
    print(w)

    # 2d 배열 x의 가로(width) xw 2,  세로(height) xh 2
    xh, xw = x.shape[0], x.shape[1]

    # 2d 배열 w의 가로(width) ww 2,  세로(height) wh 2
    wh, ww = w.shape[0], w.shape[1]

    x_sub1 = x[0:wh, 0:ww]
    print('x_sub1:', x_sub1)
    fma1 = np.sum(x_sub1 * w)
    print('fma1:', fma1)
    x_sub2 = x[0:wh, 1:1 + ww]
    print('x_sub2:', x_sub2)
    fma2 = np.sum(x_sub2 * w)
    print('fam2:', fma2)

    x_sub3 = x[1:1 + wh, 0:ww]
    print('x_sub3:', x_sub3)
    fma3 = np.sum(x_sub3 * w)
    print('fam3:', fma3)

    x_sub4 = x[1:1 + wh, 1:1 + ww]
    print('x_sub4:', x_sub4)
    fma4 = np.sum(x_sub4 * w)
    print('fam4:', fma4)

    conv = np.array([fma1, fma2, fma3, fma4]).reshape((2, 2))
    print('conv:', conv)

    x_result = convolution_2d(x, w)
    print(x_result)

    x = np.random.randint(10, size=(5, 5))
    w = np.random.randint(5, size=(3, 3))
    x_result = convolution_2d(x, w)
    print('x:', x)
    print('w:', w)
    print('result:', x_result)


import numpy as np
import warnings

#	returns the Mean Percentage Error between two Numpy Arrays. The two lists must be of the same size and greater than 0.
def mpe(prediction, actual):

	try:
		return np.mean((prediction - actual) / actual)
	except:
		return 'NA'

#	returns the Coefficient of Variation between two Numpy Arrays. The two lists must be of the same size and greater than 0.
def cv(prediction, actual):
	return rmse(prediction, actual)/np.mean(actual)

#   returns the Root-Mean-Square Error between two Numpy Arrays. The two lists must be of the same size and greater than 0.
def rmse(prediction, actual):
	return np.sqrt(((prediction - actual) ** 2).mean())

#   returns the Mean Absolute Percentage Error between two Numpy Arrays. The two lists must be of the same size and no values of 0 in Actual list.
def mape(prediction, actual):
	try:
		return np.mean(np.abs((actual - prediction) / actual))
	except:
		return 'NA'

def MAPE_pos(prediction,actual):
    eva = np.abs(actual) > (0.05 * np.abs(np.mean(actual)))
    return np.mean(np.abs((actual[eva] - prediction[eva]) / actual[eva]))

def cv_pos(prediction,actual):
    eva = np.abs(actual) > (0.05 * np.mean(np.abs(actual)))
    return np.sqrt(np.mean((prediction[eva]-actual[eva])**2))/np.mean(actual[eva])

def rmse_pos(prediction,actual):
    eva = np.abs(actual) > (0.05 * np.mean(np.abs(actual)))
    if sum(eva) == 0: # If the actual is always zero, then evaluate on the prediction
        eva = np.abs(prediction) > (0.05 * np.mean(np.abs(prediction)))
    return np.sqrt(np.mean((prediction[eva]-actual[eva])**2))

def mpe_pos(prediction,actual):
    eva = np.abs(actual) > (0.05 * np.abs(np.mean(actual)))
    return mpe(prediction[eva],actual[eva])

def getErrors(prediction, actual):

	mpe_err = mpe(prediction, actual)
	mape_err = mape(prediction,actual)
	cv_err = cv(prediction,actual)

	print("MPE is",mpe_err)
	print("MAPE is",mape_err)
	print("CV is",cv_err)
	# print("RMSE is",rmse_err)

	mpe_err = str(mpe_err)[0:10]
	mape_err = str(mape_err)[0:10]
	cv_err = str(cv_err)[0:10]

	# print(mpe_err, type(mpe_err))

	return [mpe_err,mape_err,cv_err]


import numpy as np
import matplotlib.pyplot as plt

mean = 1
stdev = 0.5

x = np.random.normal(loc=mean, scale=stdev,size=(10000))

plt.figure()
plt.title("Normal Distribution (mean= "+ str(mean)+ ", stdev= "+ str(stdev)+ ")")
plt.hist(x)

####################################################################################
n = 10
p = 0.5

y = np.random.binomial(n=n, p=p, size=1000)

plt.figure()
plt.title("Binomial Distribution (n= "+ str(n) + ", p= "+ str(p)+ ")")
plt.hist(y)


import numpy as np
import random
import math
from scipy.spatial.transform import Rotation as scipyR

# Math
def euclidean_dist(p1, p2):
    return math.sqrt(sum([(a - b)** 2 for a, b in zip(p1, p2)]))

def vec(p1, p2):
    """ vector from p1 to p2 """
    if type(p1) != np.ndarray:
        p1 = np.array(p1)
    if type(p2) != np.ndarray:
        p2 = np.array(p2)
    return p2 - p1

def proj(vec1, vec2, scalar=False):
    # Project vec1 onto vec2. Returns a vector in the direction of vec2.
    scale = np.dot(vec1, vec2) / np.linalg.norm(vec2)
    if scalar:
        return scale
    else:
        return vec2 * scale

def R_x(th):
    return np.array([
        1, 0, 0, 0,
        0, np.cos(th), -np.sin(th), 0,
        0, np.sin(th), np.cos(th), 0,
        0, 0, 0, 1
    ]).reshape(4,4)

def R_y(th):
    return np.array([
        np.cos(th), 0, np.sin(th), 0,
        0, 1, 0, 0,
        -np.sin(th), 0, np.cos(th), 0,
        0, 0, 0, 1
    ]).reshape(4,4)

def R_z(th):
    return np.array([
        np.cos(th), -np.sin(th), 0, 0,
        np.sin(th), np.cos(th), 0, 0,
        0, 0, 1, 0,
        0, 0, 0, 1
    ]).reshape(4,4)

def T(dx, dy, dz):
    return np.array([
        1, 0, 0, dx,
        0, 1, 0, dy,
        0, 0, 1, dz,
        0, 0, 0, 1
    ]).reshape(4,4)

def to_radians(th):
    return th*np.pi / 180

def to_degrees(th):
    return th*180 / np.pi

def R_between(v1, v2):
    if len(v1) != 3 or len(v2) != 3:
        raise ValueError("Only applicable to 3D vectors!")
    v = np.cross(v1, v2)
    c = np.dot(v1, v2)
    s = np.linalg.norm(v)
    I = np.identity(3)

    vX = np.array([
        0, -v[2], v[1],
        v[2], 0, -v[0],
        -v[1], v[0], 0
    ]).reshape(3,3)
    R = I + vX + np.matmul(vX,vX) * ((1-c)/(s**2))
    return R

def R_euler(thx, thy, thz, affine=False):
    """
    Obtain the rotation matrix of Rz(thx) * Ry(thy) * Rx(thz); euler angles
    """
    R = scipyR.from_euler("xyz", [thx, thy, thz], degrees=True)
    if affine:
        aR = np.zeros((4,4), dtype=float)
        aR[:3,:3] = R.as_dcm()
        aR[3,3] = 1
        R = aR
    return R

def R_quat(x, y, z, w, affine=False):
    R = scipyR.from_quat([x,y,z,w])
    if affine:
        aR = np.zeros((4,4), dtype=float)
        aR[:3,:3] = R.as_dcm()
        aR[3,3] = 1
        R = aR
    return R

def R_to_euler(R):
    """
    Obtain the thx,thy,thz angles that result in the rotation matrix Rz(thx) * Ry(thy) * Rx(thz)
    Reference: http://planning.cs.uiuc.edu/node103.html
    """
    return R.as_euler('xyz', degrees=True)
    # # To prevent numerical errors, avoid super small values.
    # epsilon = 1e-9
    # matrix[abs(matrix - 0.0) < epsilon] = 0.0
    # thz = to_degrees(math.atan2(matrix[1,0], matrix[0,0]))
    # thy = to_degrees(math.atan2(-matrix[2,0], math.sqrt(matrix[2,1]**2 + matrix[2,2]**2)))
    # thx = to_degrees(math.atan2(matrix[2,1], matrix[2,2]))
    # return thx, thy, thz

def R_to_quat(R):
    return R.as_quat()

def euler_to_quat(thx, thy, thz):
    return scipyR.from_euler("xyz", [thx, thy, thz], degrees=True).as_quat()

def quat_to_euler(x, y, z, w):
    return scipyR.from_quat([x,y,z,w]).as_euler("xyz", degrees=True)

def approx_equal(v1, v2, epsilon=1e-6):
    if len(v1) != len(v2):
        return False
    for i in range(len(v1)):
        if abs(v1[i] - v2[i]) > epsilon:
            return False
    return True


import numpy as np

# function that takes as input a list of numbers, and returns
# the list of values given by the softmax function.
def softmax(L):
    eL = np.exp(L)
    return np.divide(eL, eL.sum())

def cross_entropy(Y, P):
    Y = np.float_(Y)
    P = np.float_(P)
    return -np.sum(Y * np.log(P) + (1 - Y) * np.log(1 - P))


'''
Equivalence of AR(1) and MA(infinity)

To better understand the relationship between MA models and AR models, you will demonstrate that an AR(1) model is equivalent to an MA(∞
∞
) model with the appropriate parameters.

You will simulate an MA model with parameters 0.8,0.82,0.83,…
0.8
,
0.8
2
,
0.8
3
,
…
 for a large number (30) lags and show that it has the same Autocorrelation Function as an AR(1) model with ϕ=0.8
ϕ
=
0.8
.

INSTRUCTIONS
100XP
Import the modules for simulating data and plotting the ACF from statsmodels
Use a list comprehension to build a list with exponentially decaying MA parameters: 1,0.8,0.82,0.83,…
1
,
0.8
,
0.8
2
,
0.8
3
,
…
Simulate 5000 observations of the MA(30) model
Plot the ACF of the simulated series
'''

# import the modules for simulating data and plotting the ACF
from statsmodels.tsa.arima_process import ArmaProcess
from statsmodels.graphics.tsaplots import plot_acf

# Build a list MA parameters
ma = [0.8**i for i in range(30)]

# Simulate the MA(30) model
ar = np.array([1])
AR_object = ArmaProcess(ar, ma)
simulated_data = AR_object.generate_sample(nsample=5000)

# Plot the ACF
plot_acf(simulated_data, lags=30)
plt.show()


from matplotlib import pyplot as plt
import numpy as np
from skimage import io, color
from math import sqrt, exp

def distance(point1,point2):
    return sqrt((point1[0]-point2[0])**2 + (point1[1]-point2[1])**2)

def butterworthLP(lin, col, D0, n):
    base = np.zeros((lin,col))
    center = (lin/2,col/2)
    for x in range(lin):
        for y in range(col):
            base[y,x] = 1/(1+(distance((y,x),center)/D0)**(2*n))
    return base

def butterworthHP(lin, col, D0, n):
    base = butterworthLP(lin, col, D0, n)
    base = 1 - base
    return base

def gaussianLP(lin, col, D0):
    base = np.zeros((lin,col))
    center = (lin/2,col/2)
    for x in range(col):
        for y in range(lin):
            base[y,x] = exp(((-distance((y,x),center)**2)/(2*(D0**2))))
    return base

def gaussianHP(lin, col, D0):
    base = gaussianLP(lin, col, D0)
    base = 1 - base
    return base

im = io.imread('Lenna.png')

im2 = color.rgb2gray(im)
im2 = (im2 * 255).astype('uint8')

lin,col = im2.shape

#f1 = butterworthLP(51,51,7,2)
#f2 = butterworthHP(51,51,7,2)
#f3 = gaussianLP(51,51,7)
#f4 = gaussianHP(51,51,7)

f1 = butterworthLP(lin, col, 20, 2)
f2 = butterworthHP(lin, col, 120, 2)
f3 = gaussianLP(lin, col, 20)
f4 = gaussianHP(lin, col, 120)

plt.figure()
plt.subplot(221)
plt.imshow(f1)
plt.subplot(222)
plt.imshow(f2)
plt.subplot(223)
plt.imshow(f3)
plt.subplot(224)
plt.imshow(f4).

imft2 = np.fft.fft2(im2)
fshift2 = np.fft.fftshift(imft2)

blur1 = fshift2 * f1
bordas1 = fshift2 * f2
blur2 = fshift2 * f3
bordas2 = fshift2 * f4

blur1 = np.fft.ifft2(np.fft.ifftshift(blur1))
bordas1 = np.fft.ifft2(np.fft.ifftshift(bordas1))
blur2 = np.fft.ifft2(np.fft.ifftshift(blur2))
bordas2 = np.fft.ifft2(np.fft.ifftshift(bordas2))

plt.figure()
plt.subplot(221)
plt.imshow(np.abs(blur1), cmap='gray')
plt.subplot(222)
plt.imshow(np.abs(bordas1), cmap='gray')
plt.subplot(223)
plt.imshow(np.abs(blur2), cmap='gray')
plt.subplot(224)
plt.imshow(np.abs(bordas2), cmap='gray')


import numpy as np
import pandas as pd

from sklearn.decomposition import NMF
from sklearn.metrics import mean_squared_error

import ast

DATA_ROOT = "../data/"

class NMFactorizer:

    def __init__(self):
        pass

    def train(self, V, start_rank=3, max_iter=1000, rtol=1e-4, max_rank=np.inf, verbose=False):
        """Train a Nonnegative matrix factorization on the nonnegative matrix V.
        This progressively increases the rank of the factorization if it does not meet the relative
        tolerance standard. The results are stored as members of the class"""

        #This is very similar to the lab code we used for problem 5
        rank = start_rank
        nmf = NMF(init='random', max_iter=max_iter)
        benchmark = np.linalg.norm(V)*rtol

        if verbose:
            print(f"Attempting to converge to residual less than {benchmark:.6f}")

        done = False
        success = False
        while not done:
            nmf.set_params(n_components=rank)
            W = nmf.fit_transform(V)
            H = nmf.components_
            Vhat = W@H
            rmse = np.sqrt(mean_squared_error(V, Vhat))
            if verbose:
                print(f"Rank={rank} factorization rmse={rmse}")

            if rmse < benchmark:
                done = True
                success = True
            else:
                rank += 1

            if rank > max_rank:
                done = True
                success = False

        print(f"Found a tolerable NMF factorization with rank={rank}")
        #save results to the object
        self.success = success
        self.nmf = nmf
        self.W = W
        self.H = H
        self.Vhat = Vhat
        self.rank = rank
        #Mask out positive values of V which have "already been seen"
        #Allowing us to make good recommendations
        self.masked_Vhat = Vhat * (V == 0)

        return success

class NMFRecommender:

    def __init__(self):
        self.talk_nmf = NMFactorizer()
        self.speaker_nmf = NMFactorizer()
        pass

    def load_data(self, min_talks=2, csv_file="caleb_merged_topics.csv"):
        """Load the topic and speaker data for the top topics and speakers"""
        talk_data = pd.read_csv(DATA_ROOT + csv_file, index_col=0)
        #Drop talks which don't have topics
        talk_data.dropna(subset=["Topics"], inplace=True)
        #Map the stringified topic lists to python lists; keep dtype as object
        talk_data["Topics"] = talk_data["Topics"].map(ast.literal_eval)

        #Find unique topics and topic counts (in case we want to filter to only popular topics
        self.topic_count = {}
        for topics in talk_data["Topics"]:
            for topic in topics:
                if topic in self.topic_count:
                    self.topic_count[topic] += 1
                else:
                    self.topic_count[topic] = 1

        self.topic_indices = {topic:i for i, topic in enumerate(self.topic_count)}
        self.topic_lookup = {i:topic for i, topic in enumerate(self.topic_count)}
        talk_ids = []

        #Create a nonnegative matrix with talks as rows representing talk-choices as features
        #and topics as columns representing potential users interested in those topics
        nrows = len(talk_data.index)
        ncols = len(self.topic_indices)
        self.V_talks = np.zeros((nrows, ncols))
        self.talk_ids = np.empty(nrows, dtype=int)

        for row, (talk_id, topics) in enumerate(zip(talk_data.index, talk_data["Topics"])):
            self.talk_ids[row] = talk_id

            for topic in topics:
                topic_col = self.topic_indices[topic]
                self.V_talks[row, topic_col] = 1

        # I want to include my favorite Japanese General authority
        #Elder Kazuhiko Yamashita who has only given 2 talks. I don't think adding
        #speakers who have spoken few times wil affect the factorization/recommendations to other
        #speakers very much and could provide some useful information. However predictions on speakers
        #with less talks will be less reliable.
        speakers = talk_data["Speaker"].value_counts()
        top_speakers = speakers[speakers >= min_talks]

        #Create a nonnegative matrix with speakers as columns and topics as rows

        nrows = len(self.topic_count)
        ncols = len(top_speakers.index)

        self.V_speakers = np.zeros((nrows, ncols))

        self.speaker_indices = {speaker:i for i, speaker in enumerate(top_speakers.index)}
        self.speaker_lookup = {i:speaker for i, speaker in enumerate(top_speakers.index)}
        self.speaker_topics = {}

        for i, speaker in enumerate(top_speakers.index):
            sp_topic_counts = {topic:0 for topic in self.topic_count}
            #Count the number of times the speaker has talked on a given topic
            for topics in talk_data.loc[talk_data["Speaker"] == speaker, "Topics"]:
                for topic in topics:
                    sp_topic_counts[topic] += 1

            #Store the aggregate topic counts for the speaker in the nonnegative matrix
            for topic in sp_topic_counts:
                topic_row = self.topic_indices[topic]
                self.V_speakers[topic_row, i] = sp_topic_counts[topic]

            #We might be interested in what topics they've spoken on in the past
            self.speaker_topics[speaker] = sp_topic_counts

        #return talk_data for later lookup
        return talk_data

    def train_topics_vs_talks(self, **kwargs):
        return self.talk_nmf.train(self.V_talks, **kwargs)

    def train_speakers_vs_topics(self, **kwargs):
        return self.speaker_nmf.train(self.V_speakers, **kwargs)

    def recommend_talks(self, topic, n_talks=10):
        """
        Recommend the top n_talks talks from the Nonnegative Matrix Factorization.

        Returns:
            top_talk_ids (list) a list of tuples, n_talks long, containing the ID of the recommended talk
        """
        topic_index = self.topic_indices[topic]
        top_indices = self.talk_nmf.masked_Vhat[:, topic_index].argsort()[::-1][:n_talks]
        return [self.talk_ids[index] for index in top_indices]

    def recommend_topics_to_speaker(self, speaker, n_topics=10):
        speaker_index = self.speaker_indices[speaker]
        top_indices = self.speaker_nmf.masked_Vhat[:, speaker_index].argsort()[::-1][:n_topics]
        return [self.topic_lookup[index] for index in top_indices]

    #def recommend_speakers_from_topic()


import numpy as np

""" Here I implemented the scoring functions.
    MAE, MSE, RMSE, RMSLE are included.

    Those are used for calculating differences between
    predicted values and actual values.

    Metrics are slightly differentiated. Sometimes squared, rooted,
    even log is used.

    Using log and roots can be perceived as tools for penalizing big
    errors. However, using appropriate metrics depends on the situations,
    and types of data
"""

# Mean Absolute Error
def mae(predict, actual):
    """
    Examples(rounded for precision):
    >>> actual = [1,2,3];predict = [1,4,3]
    >>> np.around(mae(predict,actual),decimals = 2)
    0.67

    >>> actual = [1,1,1];predict = [1,1,1]
    >>> mae(predict,actual)
    0.0
    """
    predict = np.array(predict)
    actual = np.array(actual)

    difference = abs(predict - actual)
    return difference.mean()

# Mean Squared Error
def mse(predict, actual):
    """
    Examples(rounded for precision):
    >>> actual = [1,2,3];predict = [1,4,3]
    >>> np.around(mse(predict,actual),decimals = 2)
    1.33

    >>> actual = [1,1,1];predict = [1,1,1]
    >>> mse(predict,actual)
    0.0
    """
    predict = np.array(predict)
    actual = np.array(actual)

    difference = predict - actual
    square_diff = np.square(difference)

    return square_diff.mean()

# Root Mean Squared Error
def rmse(predict, actual):
    """
    Examples(rounded for precision):
    >>> actual = [1,2,3];predict = [1,4,3]
    >>> np.around(rmse(predict,actual),decimals = 2)
    1.15

    >>> actual = [1,1,1];predict = [1,1,1]
    >>> rmse(predict,actual)
    0.0
    """
    predict = np.array(predict)
    actual = np.array(actual)

    difference = predict - actual
    square_diff = np.square(difference)
    mean_square_diff = square_diff.mean()
    return np.sqrt(mean_square_diff)

# Root Mean Square Logarithmic Error
def rmsle(predict, actual):
    """
    Examples(rounded for precision):
    >>> actual = [10,10,30];predict = [10,2,30]
    >>> np.around(rmsle(predict,actual),decimals = 2)
    0.75

    >>> actual = [1,1,1];predict = [1,1,1]
    >>> rmsle(predict,actual)
    0.0
    """
    predict = np.array(predict)
    actual = np.array(actual)

    log_predict = np.log(predict + 1)
    log_actual = np.log(actual + 1)

    difference = log_predict - log_actual
    square_diff = np.square(difference)
    mean_square_diff = square_diff.mean()

    return np.sqrt(mean_square_diff)

# Mean Bias Deviation
def mbd(predict, actual):
    """
    This value is Negative, if the model underpredicts,
    positive, if it overpredicts.

    Example(rounded for precision):

    Here the model overpredicts
    >>> actual = [1,2,3];predict = [2,3,4]
    >>> np.around(mbd(predict,actual),decimals = 2)
    50.0

    Here the model underpredicts
    >>> actual = [1,2,3];predict = [0,1,1]
    >>> np.around(mbd(predict,actual),decimals = 2)
    -66.67
    """
    predict = np.array(predict)
    actual = np.array(actual)

    difference = predict - actual
    numerator = np.sum(difference) / len(predict)
    denumerator = np.sum(actual) / len(predict)
    # print(numerator, denumerator)
    score = float(numerator) / denumerator * 100

    return score


import numpy as np
from pytest import approx

from fastats.linear_algebra import det

def test_determinant_wikihow():
    """
    2x2 matrix determinant example, taken from:
    https://www.wikihow.com/Find-the-Determinant-of-a-2x2-Matrix
    """
    A = np.array([[9, 8], [-7, 6]])
    assert det(A) == 110
    assert det(A) == approx(np.linalg.det(A))

def test_determinant_wikipedia():
    """
    3x3 matrix determinant example, taken from:
    https://en.wikipedia.org/wiki/Determinant
    """
    A = np.array([[-2, 2, -3], [-1, 1, 3], [2, 0, -1]])
    assert det(A) == 18
    assert det(A) == approx(np.linalg.det(A))

def test_determinant_mathworks():
    """
    3x3 matrix determinant example, taken from:
    https://uk.mathworks.com/help/matlab/ref/det.html
    """
    A = np.array([[1, -2, 4], [-5, 2, 0], [1, 0, 3]])
    assert det(A) == -32
    assert det(A) == approx(np.linalg.det(A))

def test_determinant_1x1():
    """
    1x1 matrix special case where det returns the single
    matrix element
    """
    A = np.array([5]).reshape(1, 1)
    output = det(A)
    assert output == 5

if __name__ == '__main__':
    import pytest
    pytest.main([__file__])


import numpy as np
import matplotlib.pyplot as plt

'''
La siguiente función retorna el integrando de la función de Bessel J_m(x). Sus parámetros son m, x, y la variable de integración t.
'''
def bessel_integrand(m, x, t):
    return 1.0/np.pi * np.cos(m*t - x*np.sin(t))

'''
La siguiente función realiza la integral entre a y b de la función f para un número de pasos N utilizando la regla de Simpson. Los parámetros m y x son los correspondientes a J_m(x).
'''
def simpson(f, a, b, N, m, x):
    if N%2 == 1:
        N += 1
    h = (b-a)/N
    result = f(m,x,a) + f(m,x,b)
    for i in range(1, N, 2):
        result += 4*f(m,x,a + i*h)
    for i in range(2, N-1, 2):
        result += 2*f(m,x,a + i*h)
    result *= h/3.0
    return result

'''
Note que una integral corresponde a un punto de las gráficas que se quieren obtener. Entonces, la siguiente función realiza el procedimiento varias veces, generando arreglos para el eje X y el eje Y de las gráficas
'''
def plot_bessel(m):
    X = np.linspace(0,20,41)
    Y =np.zeros(41)
    for i in list(range(len(X))):
        Y[i]=simpson(bessel_integrand, 0.0, np.pi, 1000, m, X[i])

    plt.plot(X,Y)
    plt.xlabel("$x$", fontsize = "15")
    plt.ylabel("$J_m(x)$", fontsize = "15")
    plt.title("$m = $"+str(m), fontsize="15")
    plt.show()
    plt.close()

'''
Ahora sólo queda llamar esta función para cada m.
'''
plot_bessel(0)
plot_bessel(1)
plot_bessel(2)


import numpy
from matplotlib import pyplot

def trapezoidal(f, a, b, N):
    x, dx = numpy.linspace(a, b, N+1, retstep=True)
    fx = f(x)
    return dx * ( (fx[0] + fx[-1])/2 + numpy.sum(fx[1:-1]) )

def simpsons(f, a, b, N):
    x, dx = numpy.linspace(a, b, N+1, retstep=True)
    fx = f(x)
    return dx/3 * ( (fx[0] + fx[-1]) + \
        2*numpy.sum(fx[2:-1:2]) + 4*numpy.sum(fx[1:-1:2]) )

def richardson(f, a, b, N):
    I_h = simpsons(f, a, b, N)
    I_2h = simpsons(f, a, b, N//2)
    return (2**4*I_h - I_2h) / (2**4 - 1)

if __name__=="__main__":
    print("Trapezoidal rule")
    print(trapezoidal(numpy.sin, 0, numpy.pi/2, 2))
    print(trapezoidal(numpy.sin, 0, numpy.pi/2, 4))
    Npoints = 2**numpy.arange(1,20)
    dx_all = numpy.pi/2/Npoints
    errors = numpy.zeros_like(dx_all)
    for i, N in enumerate(Npoints):
        I = trapezoidal(numpy.sin, 0, numpy.pi/2, N)
        errors[i] = abs(I - 1)
    pyplot.loglog(dx_all, errors, 'kx')
    pyplot.loglog(dx_all, errors[0]*(dx_all/dx_all[0])**2, 'b-',
                  label=r"$\propto \Delta x^2$")
    pyplot.legend(loc='upper left')
    pyplot.xlabel(r"$\Delta x$")
    pyplot.ylabel("Error")
    pyplot.show()

    print("Simpson's rule")
    print(simpsons(numpy.sin, 0, numpy.pi/2, 2))
    print(simpsons(numpy.sin, 0, numpy.pi/2, 4))
    Npoints = 2**numpy.arange(1,20)
    dx_all = numpy.pi/2/Npoints
    errors = numpy.zeros_like(dx_all)
    for i, N in enumerate(Npoints):
        I = simpsons(numpy.sin, 0, numpy.pi/2, N)
        errors[i] = abs(I - 1)
    pyplot.loglog(dx_all, errors, 'kx')
    pyplot.loglog(dx_all, errors[0]*(dx_all/dx_all[0])**4, 'b-',
                  label=r"$\propto \Delta x^4$")
    pyplot.legend(loc='upper left')
    pyplot.xlabel(r"$\Delta x$")
    pyplot.ylabel("Error")
    pyplot.show()

    print("Richardson extrapolation")
    print(richardson(numpy.sin, 0, numpy.pi/2, 4))
    print(richardson(numpy.sin, 0, numpy.pi/2, 8))
    Npoints = 2**numpy.arange(2, 10)
    dx_all = numpy.pi/2/Npoints
    errors = numpy.zeros_like(dx_all)
    for i, N in enumerate(Npoints):
        I = richardson(numpy.sin, 0, numpy.pi/2, N)
        errors[i] = abs(I - 1)
    pyplot.loglog(dx_all, errors, 'kx')
    pyplot.loglog(dx_all, errors[0]*(dx_all/dx_all[0])**6, 'b-',
                  label=r"$\propto \Delta x^6$")
    pyplot.legend(loc='upper left')
    pyplot.xlabel(r"$\Delta x$")
    pyplot.ylabel("Error")
    pyplot.show()


import math
import numpy as np
from common.constant import *

def MinkowskiDistance(vector_1 : np.array, vector_2 : np.array, p = 2) -> float:
    """
    计算两点的闵可夫斯基距离 \n
    p = 1 时为曼哈顿距离 \n
    p = 2 时为欧式距离 \n
    p = ∞ 时为切比雪夫距离 \n
    """

    temp = np.abs(vector_1 - vector_2)
    return np.sum(temp ** p) ** (1 / p)

def Mahalanobis_distance(vector_1 : np.ndarray, vector_2 : np.ndarray, S_inv : np.ndarray) -> float:
    """
    计算两点的马哈拉诺比斯距离 \n
    :param S_inv: 协方差矩阵的逆矩阵 \n
    """
    temp_vector = vector_1 - vector_2
    temp_vector = temp_vector.reshape((-1, 1))

    dot_product = np.dot(temp_vector.T, np.dot(S_inv, temp_vector))
    if dot_product < 0:
        raise Exception('The number to calculate the square root is negative.')
    dis = math.sqrt(dot_product)
    return dis

def get_EuclideanDistance_matrix(X : np.ndarray, V : np.ndarray) -> np.ndarray:
    c = V.shape[MatrixShapeIndex.column]
    n = X.shape[MatrixShapeIndex.column]

    distance_matrix = np.zeros((n, c))

    for i in range(n):
        for j in range(c):
            distance_matrix[i][j] = MinkowskiDistance(X[:, i], V[:, j])

    return distance_matrix

if __name__ == '__main__':
    a = np.array([1, 2])
    b = np.array([4, 6])
    print(MinkowskiDistance(a, b, 1))


import numpy as np
import tensornetwork as tn

def schmidt_decomposition_numpy(bipartitepurestate_tensor):
    """ Calculate the Schmidt decomposition of the given discrete bipartite quantum system

    This is called by :func:`schmidt_decomposition`. This runs numpy.

    :param bipartitepurestate_tensor: tensor describing the bi-partitite states, with each elements the coefficients for :math:`|ij\\rangle`
    :return: list of tuples containing the Schmidt coefficient, eigenmode for first subsystem, and eigenmode for second subsystem
    :type bipartitepurestate_tensor: numpy.ndarray
    :rtype: list
    """
    state_dims = bipartitepurestate_tensor.shape
    mindim = np.min(state_dims)

    vecs1, diags, vecs2_h = np.linalg.svd(bipartitepurestate_tensor)
    vecs2 = vecs2_h.transpose()

    decomposition = [(diags[k], vecs1[:, k], vecs2[:, k])
                     for k in range(mindim)]

    decomposition = sorted(decomposition, key=lambda dec: dec[0], reverse=True)

    return decomposition

def schmidt_decomposition_tensornetwork(bipartitepurestate_tensor):
    """ Calculate the Schmidt decomposition of the given discrete bipartite quantum system

    This is called by :func:`schmidt_decomposition`. This runs tensornetwork.

    :param bipartitepurestate_tensor: tensor describing the bi-partitite states, with each elements the coefficients for :math:`|ij\\rangle`
    :return: list of tuples containing the Schmidt coefficient, eigenmode for first subsystem, and eigenmode for second subsystem
    :type bipartitepurestate_tensor: numpy.ndarray
    :rtype: list
    """
    state_dims = bipartitepurestate_tensor.shape
    mindim = np.min(state_dims)

    node = tn.Node(bipartitepurestate_tensor)
    vecs1, diags, vecs2_h, _ = tn.split_node_full_svd(node, [node[0]], [node[1]])

    decomposition = [(diags.tensor[k, k], vecs1.tensor[:, k], vecs2_h.tensor[k, :])
                     for k in range(mindim)]

    decomposition = sorted(decomposition, key=lambda dec: dec[0], reverse=True)

    return decomposition

def schmidt_decomposition(bipartitepurestate_tensor, approach='tensornetwork'):
    """Calculate the Schmidt decomposition of the given discrete bipartite quantum system

    Given a discrete normalized quantum system, given in terms of 2-D numpy array ``bipartitepurestate_tensor``,
    each element of ``bipartitepurestate_tensor[i, j]`` is the coefficient of the ket :math:`|ij\\rangle`,
    calculate its Schmidt decomposition, returned as a list of tuples, where each tuple contains
    the Schmidt coefficient, the vector of eigenmode of first subsystem, and the vector of the eigenmode of
    second subsystem.

    :param bipartitepurestate_tensor: tensor describing the bi-partitite states, with each elements the coefficients for :math:`|ij\\rangle`
    :param approach: using `numpy` or `tensornetwork` in computation. (default: `tensornetwork`)
    :return: list of tuples containing the Schmidt coefficient, eigenmode for first subsystem, and eigenmode for second subsystem
    :type bipartitepurestate_tensor: numpy.ndarray
    :type approach: str
    :rtype: list
    :raise: ValueError
    """
    if approach == 'numpy':
        return schmidt_decomposition_numpy(bipartitepurestate_tensor)
    elif approach == 'tensornetwork':
        return schmidt_decomposition_tensornetwork(bipartitepurestate_tensor)
    else:
        raise ValueError("Approach is either 'numpy' or 'tensorflow', not {}.".format(approach))


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

from pearsonLinearCorrelationCoefficient import pearson_linear_correlation_coefficient

def linear_regression(filename: str):
    df = pd.read_csv(filename, delimiter=',')
    number_of_rows = df.shape[0]
    df_hat = df.sum() / number_of_rows
    x_hat = df_hat[0]
    y_hat = df_hat[1]
    df['xi-x_hat'] = df.iloc[:, 0] - x_hat
    df['yi(xi-x_hat)'] = df['xi-x_hat'] * df.iloc[:, 1]
    df['(xi-x_hat)2'] = df['xi-x_hat'] ** 2
    df_sum = df.sum()
    a = df_sum['yi(xi-x_hat)'] / df_sum['(xi-x_hat)2']
    b = y_hat - x_hat * a
    return a, b

def draw_linear_regression(a: float, b: float, filename: str):
    df = pd.read_csv(filename, delimiter=',')
    column_names = df.columns
    df.plot(x=column_names[0], y=column_names[1], style='o', color='k')
    minX = df.iloc[:, 0].min()
    minX -= 0.1 * minX
    maxX = df.iloc[:, 0].max()
    maxX += 0.1 * maxX
    step = (maxX - minX) / 10
    regressionX = np.arange(minX, maxX, step)
    regressionY = a * regressionX + b
    plt.grid()
    plt.plot(regressionX, regressionY, 'r', linewidth=2)
    plt.xlabel(column_names[0])
    plt.ylabel(column_names[1])
    plt.legend(['y=f(x)', 'regression line'])
    fig = plt.gcf()
    fig.set_size_inches(5, 3.8)
    fig.tight_layout()
    plt.savefig('temp_regression_chart.png',  dpi=100)
    # plt.show()

print("Algorithm loaded: Linear regression")

"""
filename = '../data/pearsonLinearCorrelationCoefficient.csv'
r = pearson_linear_correlation_coefficient(filename)
print(f"Correlation coefficient: {r}")

if abs(r) < 0.5:
    print("Correlation coefficient should be less than |0.5|")
    exit(0)

a, b = linear_regression(filename)
print(f"a: {a}")
print(f"b: {b}")
draw_linear_regression(a, b, filename)
"""


"""
A number chain is created by continuously adding the square of the digits in a number to form a new number until it has been seen before.
For example,
44 > 32 > 13 > 10 > 1 > 1
85 > 89 > 145 > 42 > 20 > 4 > 16 > 37 > 58 > 89
Therefore any chain that arrives at 1 or 89 will become stuck in an endless loop. What is most amazing is that EVERY starting number will eventually arrive at 1 or 89.
How many starting numbers below ten million will arrive at 89?
"""

import numpy as np

def create_next(x):
	tmp_sum = 0
	while x > 0:
		tmp_sum += (x % 10)**2
		x /= 10
	return tmp_sum

def create_chain(x):
	chain = []
	next_num = x
	while 1:
		if next_num == 89:
			return True
		elif next_num == 1:
			return False
		elif next_num in chain:
			return False
		chain.append(next_num)
		next_num = create_next(next_num)

total_found = 0
for x in xrange(1,10000000):
	if x % 10000 == 0:
		print(x)
	if create_chain(x):
		total_found += 1

print("Found %d" % total_found) # 8581146


import numpy as np
from scipy.optimize import minimize

#ref for inequality constraint example syntax https://stackoverflow.com/questions/21765794/python-constrained-non-linear-optimization

'''
This is scipy kicking Google ORs a**.  Not only does it handle the linear version, it also
handles a nonlinear objective function with ease.  There must be a downside somewhere. Maybe not
as performant at scale? But so far so good...
'''

def objective(x):
    #linear objective
    return - ( np.dot(x, v) ) # x[1]*v[1] + ...x[n]*v[n]

    #non linear objective
    # return -( np.dot(x, v) + x[1]*v[1]*x[2]*v[2] )

def constraint1(x):
    return 20.0 -(np.dot(x, w)) # x[1]*w[1] + ...x[n]*w[n]

n = 3
x0 = np.array([1, 1, 5]) # initial guesses
w = np.array([1,4,1]) # weights
v = np.array([3,5,2]) # values

# show initial objective
print('Initial SSE Objective: ' + str(objective(x0)))

# optimize
bnds = ((1.0, 3.0), (1.0, 5.0), (10.0, 20.0))
con1 = {'type': 'ineq', 'fun': constraint1}
cons = ([con1])
solution = minimize(objective,x0,method='SLSQP',\
                    bounds=bnds,constraints=cons)
x = solution.x

# show final objective
print('Final SSE Objective: ' + str(round(objective(x))*(-1)))

#debug:check weight constraint is working. this number should be close to zero or going over weight
print('Overweight: ', str(20-(x[0]*w[0]+x[1]*w[1]+x[2]*w[2]) ))

# print solution
print('Solution')
print('x1 = ' + str(round(x[0])))
print('x2 = ' + str(round(x[1])))
print('x3 = ' + str(round(x[2])))


# coding: utf-8

# # Function iagaussian

# ## Synopse

# Generate a d-dimensional Gaussian image.
#
# - **g = gaussian(s, mu, cov)**
#
#   - **g**: Image.
#
#
#   - **s**: Image shape. (rows columns)
#   - **mu**: Image. Mean vector. n-D point. Point of maximum value.
#   - **cov**: Covariance matrix (symmetric and square).

# In[3]:

import numpy as np

def gaussian(s, mu, cov):
    d = len(s)  # dimension
    n = np.prod(s) # n. of samples (pixels)
    x = np.indices(s).reshape( (d, n))
    xc = x - mu
    k = 1. * xc * np.dot(np.linalg.inv(cov), xc)
    k = np.sum(k,axis=0) #the sum is only applied to the rows
    g = (1./((2 * np.pi)**(d/2.) * np.sqrt(np.linalg.det(cov)))) * np.exp(-1./2 * k)
    return g.reshape(s)

# ## Description

# A n-dimensional Gaussian image is an image with a Gaussian distribution. It can be used to generate
# test patterns or Gaussian filters both for spatial and frequency domain. The integral of the gaussian function is 1.0.

# ## Examples

# In[1]:

testing = (__name__ == "__main__")
if testing:
    get_ipython().system(' jupyter nbconvert --to python gaussian.ipynb')
    import numpy as np
    import sys,os
    ea979path = os.path.abspath('../../')
    if ea979path not in sys.path:
        sys.path.append(ea979path)
    import ea979.src as ia

    get_ipython().magic('matplotlib inline')
    import matplotlib.pyplot as plt

# ### Example 1 - Numeric 2-dimensional

# In[2]:

if testing:
    f = ia.gaussian((8, 4), np.transpose([[3, 1]]), [[1, 0], [0, 1]])
    print('f=\n', np.array2string(f, precision=4, suppress_small=1))
    g = ia.normalize(f, [0, 255]).astype(np.uint8)
    print('g=\n', g)

# ## Example 2 - one dimensional signal

# In[3]:

# note that for 1-D case, the tuple has extra ,
# and the covariance matrix must be 2-D
if testing:
    f = ia.gaussian( (100,), 50, [[10*10]])
    g = ia.normalize(f, [0,1])
    plt.plot(g)
    plt.show()

# ### Example 3 - two-dimensional image

# In[4]:

if testing:
    f = ia.gaussian((150,250), np.transpose([[75,100]]), [[40*40,0],[0,30*30]])
    g = ia.normalize(f, [0,255]).astype(np.uint8)
    ia.adshow(g)

# ## Example 4 - Numeric 3-dimensional

# In[6]:

if testing:
    f = ia.gaussian((3,4,5), np.transpose([[1,2,3]]), [[1,0,0],[0,4,0],[0,0,9]])
    print('f=\n', np.array2string(f, precision=4, suppress_small=1))
    g = ia.normalize(f, [0,255]).astype(np.uint8)
    print('g=\n', g)

# ## Equation

# $$    f(x) = \frac{1}{\sqrt{2 \pi} \sigma} exp\left[ -\frac{1}{2} \left( \frac{x - \mu}{\sigma} \right)^2 \right]
# $$
#
# $$ f({\bf x}) = \frac{1}{(2 \pi)^{d/2}|\Sigma|^{1/2}} exp\left[ -\frac{1}{2}\left({\bf x} - \mu \right)^t\Sigma^{-1}\left({\bf x} - \mu \right)\right]
# $$


# coding=utf-8
import numpy as np

# Data type	Description
# bool_	Boolean (True or False) stored as a byte
# int_	Default integer type (same as C long; normally either int64 or int32)
# intc	Identical to C int (normally int32 or int64)
# intp	Integer used for indexing (same as C ssize_t; normally either int32 or int64)
# int8	Byte (-128 to 127)
# int16	Integer (-32768 to 32767)
# int32	Integer (-2147483648 to 2147483647)
# int64	Integer (-9223372036854775808 to 9223372036854775807)
# uint8	Unsigned integer (0 to 255)
# uint16	Unsigned integer (0 to 65535)
# uint32	Unsigned integer (0 to 4294967295)
# uint64	Unsigned integer (0 to 18446744073709551615)
# float_	Shorthand for float64.
# float16	Half precision float: sign bit, 5 bits exponent, 10 bits mantissa
# float32	Single precision float: sign bit, 8 bits exponent, 23 bits mantissa
# float64	Double precision float: sign bit, 11 bits exponent, 52 bits mantissa
# complex_	Shorthand for complex128.
# complex64	Complex number, represented by two 32-bit floats (real and imaginary components)
# complex128	Complex number, represented by two 64-bit floats (real and imaginary components)

x = np.float32(1.0)
y = np.int_([1, 2, 4])
z = np.arange(3, dtype=np.uint8)
np.array([1, 2, 3], dtype='f')

z.astype(float)
np.int8(z)
assert z.dtype == np.dtype('uint8')

d = np.dtype(int)
assert np.issubdtype(d, int)
assert not np.issubdtype(d, float)

# Converting Python array_like Objects to Numpy Arrays
x = np.array([2, 3, 1, 0])
x = np.array([2, 3, 1, 0])
x = np.array([[1, 2.0], [0, 0], (1 + 1j, 3.)])
x = np.array([[1. + 0.j, 2. + 0.j], [0. + 0.j, 0. + 0.j], [1. + 1.j, 3. + 0.j]])

# Intrinsic Numpy Array Creation
np.arange(10)
np.arange(2, 10, dtype=np.float)
np.arange(2, 3, 0.1)
np.linspace(1., 4., 6)
np.indices((3, 3))

# Reading Arrays From Disk¶


from scipy.misc import comb
import math

def ensemble_error(n_classifier, error):
    k_start = int(math.ceil(n_classifier / 2.))
    probs = [comb(n_classifier, k) * error ** k * (1 - error) ** (n_classifier - k)
             for k in range(k_start, n_classifier + 1)]
    return sum(probs)

import numpy as np

error_range = np.arange(0.0, 1.01, 0.01)
ens_errors = [ensemble_error(n_classifier=11, error=error)
              for error in error_range]

import matplotlib.pyplot as plt

plt.plot(error_range,
         ens_errors,
         label='Ensemble error',
         linewidth=2)

plt.plot(error_range,
         error_range,
         linestyle='--',
         label='Base error',
         linewidth=2)

plt.xlabel('Base error')
plt.ylabel('Base/Ensemble error')
plt.legend(loc='upper left')
plt.grid(alpha=0.5)
plt.show()


# -*- coding: utf-8 -*-
from math import *
from scipy.stats import norm
from scipy.optimize import fmin_bfgs

# Black Sholes Function
def price(S, K, T, r, v, callPutFlag = 'c'):
    d1 = (log(S / K) + (r + 0.5 * v**2) * T) / (v * sqrt(T))
    d2 = d1 - v * sqrt(T)
    if (callPutFlag == 'c') or (callPutFlag == 'C'):
        return S * norm.cdf(d1) - K * exp(-r * T) * norm.cdf(d2)
    else:
        return K * exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)

# Calc Implied volatility
def implied_volatility(price_, S, K, T, r, callPutFlag = 'c'):
    Objective = lambda x: (price_ - price(S, K, T, r, x, callPutFlag))**2
    return fmin_bfgs(Objective, 1, disp=False)[0]

# test
if __name__ == '__main__':
    import time
    time_start = time.clock()
    # correct : call 3.68
    print(price(49.0, 50.0, 1.0, 0.01, 0.2, 'C'))
    time_elapsed = time.clock() - time_start
    print('time elapsed: %2f seconds' % time_elapsed)

    time_start = time.clock()
    # correct : put 4.18
    print(price(49.0, 50.0, 1.0, 0.01, 0.2, 'P'))
    time_elapsed = time.clock() - time_start
    print('time elapsed: %2f seconds' % time_elapsed)

    time_start = time.clock()
    # correct : 0.2
    print(implied_volatility(3.68, 49.0, 50.0, 1.0, 0.01, 'C'))
    time_elapsed = time.clock() - time_start
    print('time elapsed: %2f seconds' % time_elapsed)

    time_start = time.clock()
    # correct : 0.2
    print(implied_volatility(4.18, 49.0, 50.0, 1.0, 0.01, 'P'))
    time_elapsed = time.clock() - time_start
    print('time elapsed: %2f seconds' % time_elapsed)