# Implementation of Sammon's nonlinear mapping stress, a quality measure for NLDR embeddings.
# For more details on the measure, see Sammon, J. W. (1969).
# A nonlinear mapping for data structure analysis. IEEE Transactions on computers, 100(5), 401-409.
# This implementation has been written by Adrien Bibal (University of Namur).

import numpy as np
from scipy.spatial.distance import pdist
from sklearn.preprocessing import scale

# Compute the stress function of NLM (the focus of this stress is on the input space)
# data = high dimensional data
# visu = low dimensional data
# return the NLM stress between data and visu
# The higher the score, the worst is the visualization.
def compute(data, visu):
	# DV = Distance Vector
	DV1 = scale(pdist(data, 'euclidean'))
	DV2 = scale(pdist(visu, 'euclidean'))

	stress = 0
	for i in range(len(DV1)):
		stress += ((DV1[i] - DV2[i])**2) / DV1[i]

	stress *= 1 / np.sum(DV1)

	return stress


"""
author: "Kelly Rivera"
title: "QR Algorithm"
"""

##Import Python Libraries
import numpy as npy
import scipy.linalg as spl  # SciPy Linear Algebra Library

## Householder transformation method
def qr_Algorithm_HH(x, converge_range):
    m, n = x.shape
    Q_last = npy.identity(n)
    diff = 1

    lamb, u = spl.eig(x)
    lamb = max(npy.abs(lamb))

    # QR Algo using
    while diff > converge_range:
        Q, R = npy.linalg.qr(x)
        # This update matrix A, by dot product of reverse QR
        x = npy.dot(R, Q)

        eigenvalue = npy.diag(x)  #outputs only the values on the main diaginal
        eigenvalue = max(npy.abs(eigenvalue))

        diff = npy.abs(lamb - eigenvalue)

        eigenvectors = npy.dot(Q_last, Q)
        Q_last = eigenvectors

    eigenvalues = npy.diag(x)  #outputs only the values on the main diaginal

    return eigenvectors, eigenvalues

## Gram-Schmidt Process
def qr_GS(x):
    m, n = x.shape
    Q = npy.zeros((m, n)) # Q is all zero
    R = npy.zeros((n, n))

    for j in range(n): #range (3) = {0,1,2}
        v = x[:, j] # x[:,0] returns the first* column* of x, x[:,1] reutrns the second column etc

        for i in range(j):

            Q1 = Q[:, i] #when we are here for the the first time, q =
            R[i, j] = npy.dot(Q1, v)
            v = v - R[i, j] * Q1

        vNorm = npy.linalg.norm(v)
        R[j, j] = vNorm
        Q[:, j] = v / vNorm

    return Q, R

def qr_Algorithm_GS(x, converge_range):
    m, n = x.shape
    Q_last = npy.identity(n)
    diff = 1

    lamb, u = spl.eig(x)
    lamb = max(npy.abs(lamb))

    while diff > converge_range:
        Q, R = qr_GS(x)
        # This update matrix A, by dot product of reverse QR
        x = npy.dot(R, Q)

        eigenvalue = npy.diag(x)  #outputs only the values on the main diaginal
        eigenvalue = max(npy.abs(eigenvalue))

        diff = npy.abs(lamb - eigenvalue)

        eigenvectors = npy.dot(Q_last, Q)
        Q_last = eigenvectors

    eigenvalues = npy.diag(x)  #outputs only the values on the main diaginal

    return eigenvectors, eigenvalues

## QR with Shift using the Gram-Schmidt precess
def shiftedQR_Algorithm(x, converge_range):
    m, n = x.shape
    I = npy.identity(n)
    Q_last = npy.identity(n)
    diff = 1

    lamb, u = spl.eig(x)
    lamb = max(npy.abs(lamb))

    while diff > converge_range:
        μ = x[[n-1],[n-1]]         # shift: μ = a_nn
        Q, R = qr_GS((x - (μ*I)))
        # This update matrix A, by dot product of reverse QR
        x = npy.dot(R, Q) + (μ*I)   # Updates matrix, by dot product of reverse QR and adding back the shift

        eigenvalue = npy.diag(x)  #outputs only the values on the main diaginal
        eigenvalue = max(npy.abs(eigenvalue))

        diff = npy.abs(lamb - eigenvalue)

        eigenvectors = npy.dot(Q_last, Q)
        Q_last = eigenvectors

    eigenvalues = npy.diag(x)  #outputs only the values on the main diaginal

    return eigenvectors, eigenvalues


# Hit or miss
# Monte Carlo Integration Method

import numpy as np
import random as rn
N = 1000000
xr = np.random.uniform(1,2,N)
yr = np.random.uniform(0,15,N)
count = 0.
area = 1*15.

for i in range(N):
    if yr[i] <= xr[i]**4. - 2.*xr[i] + 1.:
        count += 1.

integ = count*area/N

print integ


from numba import jit
import numpy as np

@jit
def laplacian_1d(n):
    return np.diag(2 * np.ones(n - 2)) + \
           np.diag(-np.ones(n - 3), 1) + \
           np.diag(-np.ones(n - 3), -1)

@jit
def laplacian_2d(n):
    return np.kron(np.eye(n - 2), laplacian_1d(n)) + \
           np.kron(laplacian_1d(n), np.eye(n - 2))

# from scipy.sparse import diags, kron, eye

# @jit
# def laplacian_1d(n):
#     return diags([2 * np.ones(n - 2), -np.ones(n - 3), -np.ones(n - 3)], [0, 1, -1])

# @jit
# def laplacian_2d(n):
#     return kron(eye(n - 2), laplacian_1d(n)) + \
#            kron(laplacian_1d(n), eye(n - 2))


import numpy as np

def geometric_mean(A: float, B: float) -> float:
    return np.sqrt(A * B)

def arithmetic_mean(A: float, B: float) -> float:
    return 0.5 * (A + B)

def Lorentz_Berthelot(params1, params2) -> tuple:
    """
    Lorentz-Berthelot mixing rules to compute epsilon and sigma parameters of different site types

    Parameters
    ----------

    eps1 : float
        epsilon parameter of site 1

    eps2 : float
        epsilon parameter of site 2

    sig1 : float
        sigma parameter of site 1

    sig2 : float
        sigma parameter of site 2

    Returns
    -------
    eps : float
    Mixed epsilon parameter
    sig : float
    Mixed sigma parameter
    """
    eps1, sig1 = params1
    eps2, sig2 = params2
    eps = geometric_mean(eps1, eps2)
    sig = arithmetic_mean(sig1, sig2)
    return eps, sig

def AB_mixing(A_1: float, A_2: float, B_1: float, B_2: float) -> float:

    A = geometric_mean(A_1, A_2)
    B = geometric_mean(B_1, B_2)
    return A, B


import numpy as np
import math
import matplotlib.pylab as pl
import random

"""
NumRep Exercises 1 and 2
Simon McLaren
"""

# Class for a gaussian function
class MyGaussianPdf:

    # Constructor
    def __init__(self, mean, width):
        self.mean = mean
        self.width = width

    # Return Gaussian width
    def getWidth(self):
        return self.width

    # Return Gaussian mean
    def getMean(self):
        return self.mean

    # Return a random value of x with Gaussian distribution
    def next(self, minx, maxx):
        fmax = 1.
        y2 = 10.
        y1 = 1.
        while y2>y1:
            randomx = minx + (maxx-minx)*random.random()
            y1 = self.evaluate(randomx)
            y2 = fmax*random.random()
        return randomx

    # Evaluate the Gaussian at point x
    def evaluate(self, x):
        return math.exp(-((x-self.mean)**2)/2*self.width**2)

    # Calculate the integral of the gaussian between -inf and inf
    def integralAnalytic(self):
        return self.width*math.sqrt(2*math.pi)

    # Numerical integration by the 0th order rectangle method
    def integralNumericRectangle0thOrder(self, numofrectangles):
        minx = -5*self.width
        maxx = 5*self.width
        rectanglewidth = (maxx-minx)/numofrectangles
        integral = 0.
        evalxpoint = minx + rectanglewidth*0.5 # Midpoint of rectangle
        for i in range(numofrectangles):
            integral += self.evaluate(evalxpoint) * rectanglewidth
            evalxpoint += rectanglewidth
        return integral

    # Numerical integration by the 1st order rectangle method
    def integralNumericRectangle1stOrder(self, numofrectangles):
        minx = -5 * self.width
        maxx = 5 * self.width
        rectanglewidth = (maxx - minx) / numofrectangles
        integral = 0.
        lowerxbound = minx
        higherxbound = minx + rectanglewidth
        for i in range(numofrectangles):
            integral += rectanglewidth * self.evaluate(lowerxbound) + \
                        0.5 * abs(self.evaluate(higherxbound) - self.evaluate(lowerxbound)) * rectanglewidth
            lowerxbound += rectanglewidth
            higherxbound += rectanglewidth
        return integral

if __name__ == "__main__":
    gaussianfunction = MyGaussianPdf(0.,1.)
    # gaussiansampledata = []
    # for i in range(10000):
    #     gaussiansampledata.append(gaussianfunction.next(-4.,4.))
    # pl.hist(gaussiansampledata[:], bins = 50, range = [-4.,4.])
    # pl.savefig("gaussianhist.png")
    # pl.show()
    # data = np.random.normal(0.,1.,10000)
    # pl.hist(data[:], bins = 50, range = [-4.,4.])
    # pl.savefig("numpygaussianhist.png")
    # pl.show()
    integralanalytic = float(gaussianfunction.integralAnalytic())
    integralnumeric = float(gaussianfunction.integralNumericRectangle1stOrder(10000))
    integraldifference = abs(integralanalytic-integralnumeric)
    percentdifference = float(100*integraldifference/integralanalytic)
    print "The analytic integral is %f.  The numeric integral is %f.  The percentage difference between them is %.5f." \
          % (integralanalytic, integralnumeric, percentdifference)


import numpy as np
from scipy.ndimage import interpolation

# нахождеение центра масс изображения
def moments(image):
    # создание сетки
    c0, c1 = np.mgrid[:image.shape[0], :image.shape[1]]
    # сумма пикселей
    total_image = np.sum(image)
    # mu_x - момент по x
    m0 = np.sum(c0 * image) / total_image
    # mu_y - момент по y
    m1 = np.sum(c1 * image) / total_image
    # var(x) - вариация по x
    m00 = np.sum((c0 - m0)**2 * image) / total_image
    # var(y) - вариация по y
    m11 = np.sum((c1 - m1)**2 * image) / total_image
    # covariance(x,y) - ковариация
    m01 = np.sum((c0 - m0) * (c1 - m1) * image) / total_image
    # вектор центов масс - mu_x, mu_y соответственно
    mu_vector = np.array([m0, m1])
    # наблюдается ли схожесть в ковариационных матрицах
    covariance_matrix = np.array([[m00,m01],[m01,m11]])

    return mu_vector, covariance_matrix

# выравнивание
def deskew(image):
    # нахождение моментов
    c, v = moments(image)
    # нахождение коэффициента альфа для матрицы выравнивания
    alpha = v[0, 1] / v[0, 0]
    # матрица выравнивания
    affine = np.array([[1, 0], [alpha, 1]])
    # новый центр масс
    ocenter = np.array(image.shape)/2.0
    # центрирование
    offset = c - np.dot(affine, ocenter)
    # трансформация
    img = interpolation.affine_transform(image, affine, offset=offset)
    return (img - img.min()) / (img.max() - img.min())

# для применени к датасету MNIST из библиотеки TensorFlow
def apply_deskew(data):
    """
	Применение метда deskew (выравивание цифр) ко входным данным.
	:param data: входные данные.
	:return: преобразованные данные.
	"""
    # пустой тензор результатов
    result = np.zeros(data.shape)
    # цикл по каждой записи (картинке с цифрой)
    for i in range(data.shape[0]):
        image = data[i,...].astype('float32') / 255.
        # применение deskew
        processed_image = deskew(image)
        # хапись результатов
        result[i] = processed_image

    return result.reshape(result.shape[0], -1)


import numpy as np
import scipy.stats

def linconfband(xx, yy, a, b, conf=0.95, x_grid=None, need_eps=False):
    """
    Confidence bands for linear regression line

    adopted from
    1. https://gist.github.com/rsnemmen/f2c03beb391db809c90f
    2. https://gist.github.com/rsnemmen/0eb32832c657c19e4d39
    3. https://en.wikipedia.org/wiki/Simple_linear_regression
    """
    alpha = 1.0 - conf  # significance
    N = xx.size      # data sample size

    x_grid = np.linspace(xx.min(), xx.max(), 100) if x_grid is None else x_grid
    y_grid = a*x_grid + b

    eps = yy - (a*xx + b)
    sd = np.sqrt(1/(N-2) * np.sum(eps**2))

    sxx = np.sum((xx - xx.mean())**2)
    sx  = (x_grid - xx.mean())**2

    # Quantile of Student's t distribution for p=1-alpha/2
    alpha = alpha/N  # bonferroni correction?
    q = scipy.stats.t.ppf(1.-alpha/2., N-2)
    dy = q * sd * np.sqrt(1./N + sx/sxx)

    ucb = y_grid + dy  # Upper confidence band
    lcb = y_grid - dy  # Lower confidence band
    res = [lcb, ucb]
    if need_eps:
        res.append(eps)
    return res


import numpy as np

# addition of vector with scalar
one_dim_array = np.array([11, 21, 31, 41]) #create an array
# array([11, 21, 31, 41])

one_dim_array + 1 # element wise addition
# array([12, 22, 32, 42])

one_dim_array ** 2 # element wise exponent
# array([ 121,  441,  961, 1681], dtype=int32)

one_dim_array - 1 # element wise subtraction
# array([10, 20, 30, 40])

# matrix multiplication

matrix1 = np.diag([1,2,3,4])
""" array([[1, 0, 0, 0],
       [0, 2, 0, 0],
       [0, 0, 3, 0],
       [0, 0, 0, 4]]) """

# way 1
matrix1 * matrix1
""" array([[ 1,  0,  0,  0],
       [ 0,  4,  0,  0],
       [ 0,  0,  9,  0],
       [ 0,  0,  0, 16]]) """

# way 2
matrix1.dot(matrix1)
""" array([[ 1,  0,  0,  0],
       [ 0,  4,  0,  0],
       [ 0,  0,  9,  0],
       [ 0,  0,  0, 16]]) """


import numpy as np
from functions import sigmoid, sigmoid_derivative

class GradientDescentAlgorithm(object):
    def __init__(self,eta=3.0,topology=[]):
        self.eta = eta
        self.topology = topology
        pass

    def finalize_epoch(self):
        pass

    def gradient_descent(self, num_of_examples, deltas, weights, activations, biases):
        new_weights = np.zeros(len(weights)).tolist()
        new_biases = np.zeros(len(biases)).tolist()
        scalar = float(self.eta)/num_of_examples

        for layer, output in reversed(list(enumerate(deltas))):
            new_weights[layer] = weights[layer] - scalar * np.dot(deltas[layer].T, activations[layer]).T
            new_biases[layer] = biases[layer] - scalar * np.sum(deltas[layer], axis=0)

        return new_weights, new_biases

    # calculate initial error and back_propagate
    def calculate_deltas(self, activations, outputs, weights, labels):
        deltas = np.zeros(len(outputs)).tolist()
        for layer, output in reversed(list(enumerate(outputs))):
            if layer == (len(outputs) - 1):
                first_term = activations[-1] - labels
            else:
                first_term = np.dot(deltas[layer+1], weights[layer+1].T)

            second_term = sigmoid_derivative(output)

            deltas[layer] = np.multiply(first_term, second_term)

        return deltas

    def feed_forward(self, weights, biases, data, labels):
        # Add data as first layer for activations
        new_activations = [data]
        new_outputs = []
        number_of_labels = labels.shape[0]

        for idx, weight in enumerate(weights):
            outputs, activations = self.feed_forward_layer(idx,weight,new_activations[idx],biases[idx])
            new_outputs.append(outputs)
            new_activations.append( activations )

        return new_activations, new_outputs

    def feed_forward_layer(self,layer,weight,inputs,bias):
        outputs = self.calculate_outputs(layer,inputs,weight,bias)
        activations = self.calculate_activations(layer,outputs)

        return outputs, activations

    def calculate_outputs(self,layer, inputs,weight,bias):
        outputs = np.dot(inputs, weight) + bias

        return outputs

    def calculate_activations(self,layer,outputs):
        return sigmoid(outputs)


import numpy as np

def standardize(X):
    mean = np.mean(X, axis=0)
    std = np.std(X, axis=0)
    std[np.where(std == 0.0)[0]] = 1.0
    return (X - mean) / std

def SVD(X):
    X -= np.mean(X, axis = 0) # zero-center the data (important)
    cov = np.dot(X.T, X) / X.shape[0] # get the data covariance matrix
    U, S, V = np.linalg.svd(cov)
    return U, S, V

def PCA(X, num_retained=1000):
    U,S,V = SVD(X)
    Xrot_reduced = np.dot(X, U[:,:100]) # Xrot_reduced becomes [N x 100]
    return Xrot_reduced

def whiten(X, num_retained=1000):
    U,S,V = SVD(X)
    Xrot = np.dot(X, U) # decorrelate the data
    Xwhite = Xrot / np.sqrt(S + 1e-5)
    return Xwhite


"""
Tool module
===========

Contains some useful numerical tools
"""

import numpy as np

def rotate_towards(vi, vf, theta):
    """
    Rotate a vector `vi` towards another vector `vf` by angle `theta`.
    Return the rotated vector.
    """
    x = np.cross(vi, vf)
    _x_ = np.linalg.norm(x)
    if _x_ < 1e-15:
        return vi
    else:
        x /= _x_
    A = np.array([[ 0, -x[2], x[1] ],
                  [ x[2], 0, -x[0] ],
                  [ -x[1], x[0], 0 ]])
    c, s = np.cos(theta), np.sin(theta)
    R = np.eye(3) + s * A + (1-c) * A.dot(A)

    return R.dot(vi)

def cart2sphere(v):
    """
    Return the spherical angles `theta` and `phi` associated with a unit vector `v`.
    """
    # v needs to be a unit vector
    x,y,z = v
    theta = np.arccos(np.clip(z,-1,1))
    phi = np.arctan2(x,y)

    return theta, phi

def sphere2cart(theta, phi):
    """
    Return the unit vector `v` associated with angles `theta` and `phi`.
    Adjusts `theta` and `phi` such that the transformation is valid
    """
    if theta < 0:
        theta = np.pi + theta
        phi += np.pi
    elif theta > np.pi:
        theta = theta - np.pi
        phi += np.pi
    st, sp = np.sin(theta), np.sin(phi)
    ct, cp = np.cos(theta), np.cos(phi)
    x = st * sp
    y = st * cp
    z = ct

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

if __name__=="__main__":

    v = np.array([1.,0,0])

    th, ph = cart2sphere(v)
    print(th, ph)

    v_ = sphere2cart(th,ph)

    print(v, v_)


#import time
import numpy as np
#from scipy.special import eval_legendre as lp
import matplotlib.pyplot as plt
from rt_002_polleg import polleg
#==============================================================================
#
if __name__ == "__main__":
#   scattering angle & cosine
    sca = np.linspace(0.0, 180.0, 181)
    x = np.cos(np.radians(sca))
#   Rayleigh phase function
    r = 0.75*(1.0 + x*x)
#   expansion moments for the Rayleigh phase function: 2k+1 is INCLUDED
    xk_r = np.array([1.0, 0.0, 0.5])
    nk = len(xk_r)
#   restore Rayleigh phase function from moments: 3 different options
    pk = polleg(x, nk-1)   # recall, k = 0,1,2 hence nk-1;   not sure if the built-in eval_legendre is better
    rx_opt1 = np.dot(xk_r, pk)  # this looks nice, but NOT efficient because ...
#
    rx_opt2 = np.zeros_like(rx_opt1)
    for ik in range(nk):          # we ALREADY HAVE this loop in polleg!
        for ix in range(len(x)):  # we ALREADY HAVE this loop in polleg AS WELL!!
            rx_opt2[ix] += xk_r[ik]*pk[ik,ix]
#
#   Less nice, a bit harder to understand, but efficient way is:
#      compute Legendre polynomials "on the go"
    rx_opt3 = np.zeros_like(rx_opt1)
    for ix in range(len(x)):
        xi = x[ix]              # avoids addressing to an array
        rxi = 1.0               # xk[k=0]*Pk[k=0] + xk[1]*Pk[k=1] = 1*1 + 0*x
        p0 = 1.0                # for Pk-recurrence
        p1 = xi                 # for Pk-recurrence
        for ik in range(2, nk): #
            p2 = (2.0 - 1.0/ik)*xi*p1 - (1.0 - 1.0/ik)*p0 # recurrence
            rxi += xk_r[ik]*p2                            # accumulation - can not be fully vectorized :(
            p0 = p1             # for Pk-recurrence
            p1 = p2             # for Pk-recurrence
        rx_opt3[ix] = rxi       # avoids addressing to an array inside the ik-loop
#
    plt.figure()
    plt.plot(sca, r, 'k', sca[0::10], rx_opt1[0::10], 'ro',\
       sca[2::10], rx_opt2[2::10], 'go', sca[4::10], rx_opt3[4::10], 'bo')
    plt.title('Rayleigh phase function')
    plt.xlabel('scattering angle, deg.')
    plt.legend(['explicit formula', 'from moments, xk: opt.1', 'from moments, xk: opt.2', 'from moments, xk: opt.3'])
    plt.grid(True)


#!/usr/bin/env python3

import numpy as np

def recoverData(Z, U, K):
    #RECOVERDATA Recovers an approximation of the original data when using the
    #projected data
    #   X_rec = RECOVERDATA(Z, U, K) recovers an approximation the
    #   original data that has been reduced to K dimensions. It returns the
    #   approximate reconstruction in X_rec.
    #

    # You need to return the following variables correctly.
    #X_rec = zeros(size(Z, 1), size(U, 1))

    # ====================== YOUR CODE HERE ======================
    # Instructions: Compute the approximation of the data by projecting back
    #               onto the original space using the top K eigenvectors in U.
    #
    #               For the i-th example Z(i,:), the (approximate)
    #               recovered data for dimension j is given as follows:
    #                    v = Z(i, :)'
    #                    recovered_j = v' * U(j, 1:K)'
    #
    #               Notice that U(j, 1:K) is a row vector.
    #

    X_rec = np.dot(Z, U[:, :K].T)

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

    return X_rec
    #end


from sympy import *

# Verify SymTrace in MultiBspline.hpp

# The first part of this script verifies the expression for the trace of the product of a
# symmetric matrix (H) and a general matrix (G).

# The second part creates body of the SymTrace test in test_multi_spline.cpp.

G = MatrixSymbol('G', 3, 3)
H = MatrixSymbol('H', 3, 3)

h1 = Matrix(H)
print 'H = ',h1
# Symmetrize H
h1 = h1.subs(H[1,0], H[0,1])
h1 = h1.subs(H[2,1], H[1,2])
h1 = h1.subs(H[2,0], H[0,2])
print 'Symmetrized H = ',h1
print

e =  Trace(h1*Matrix(G)).doit()
print 'Trace = ',e

h00 = Symbol('h00')
h01 = Symbol('h01')
h02 = Symbol('h02')
h11 = Symbol('h11')
h12 = Symbol('h12')
h22 = Symbol('h22')
print
e = e.subs(H[0,0], h00)
e = e.subs(H[0,1], h01)
e = e.subs(H[0,2], h02)
e = e.subs(H[1,1], h11)
e = e.subs(H[1,2], h12)
e = e.subs(H[2,2], h22)
print 'Trace = ',e
print
e2 =  e.collect([h00,h01,h02,h12,h11,h22])
print 'Trace =',e2

g = IndexedBase('g')
e2 = e2.subs(G[0,0], g[0])
e2 = e2.subs(G[0,1]+G[1,0], g[1])
e2 = e2.subs(G[0,2]+G[2,0], g[2])
e2 = e2.subs(G[1,1], g[1])
e2 = e2.subs(G[1,2]+G[2,1], g[4])
e2 = e2.subs(G[2,2], g[5])
print
print 'Replace with symmetrized G'
print 'Trace =',e2

vH = Matrix([[1.0, 2.0, 3.0],
             [2.0, 4.4, 1.1],
             [3.0, 1.1, 0.9]])
vG = Matrix([[0.1, 0.2, 0.3],
             [1.4, 2.3, 8.0],
             [0.9, 1.4, 2.3]])

tr = Trace(vH*vG).doit()
print 'Trace = ',tr

print
print 'Concrete values for unit test'
print '// Code from here to the end of the function generate by gen_trace.py'
print
print '  double h00 = %g;'%vH[0,0]
print '  double h01 = %g;'%vH[0,1]
print '  double h02 = %g;'%vH[0,2]
print '  double h11 = %g;'%vH[1,1]
print '  double h12 = %g;'%vH[1,2]
print '  double h22 = %g;'%vH[2,2]
print
print '  double gg[6] = {%g, %g, %g, %g, %g, %g};'%(vG[0,0], vG[0,1] + vG[1,0], vG[0,2] + vG[2,0], vG[1,1], vG[1,2] + vG[2,1], vG[2,2])
print
print '  double tr = SymTrace(h00, h01, h02, h11, h12, h22, gg);'
print '  REQUIRE(tr == Approx(%g));'%tr
print


#!/usr/bin/env python

# Software License Agreement (MIT License)
#
# Copyright (c) 2020, tri_star
# All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Author: Meiying Qin, Jake Brawer

# https://github.com/christophhagen/averaging-quaternions

import numpy
import numpy.matlib as npm

# Q is a Nx4 numpy matrix and contains the quaternions to average in the rows.
# The quaternions are arranged as (w,x,y,z), with w being the scalar
# The result will be the average quaternion of the input. Note that the signs
# of the output quaternion can be reversed, since q and -q describe the same orientation
def averageQuaternions(Q):
    # Number of quaternions to average
    M = Q.shape[0]
    A = npm.zeros(shape=(4,4))

    for i in range(0,M):
        q = Q[i,:]
        # multiply q with its transposed version q' and add A
        A = numpy.outer(q,q) + A

    # scale
    A = (1.0/M)*A
    # compute eigenvalues and -vectors
    eigenValues, eigenVectors = numpy.linalg.eig(A)
    # Sort by largest eigenvalue
    eigenVectors = eigenVectors[:,eigenValues.argsort()[::-1]]
    # return the real part of the largest eigenvector (has only real part)
    return numpy.real(eigenVectors[:,0].A1)

# Average multiple quaternions with specific weights
# The weight vector w must be of the same length as the number of rows in the
# quaternion maxtrix Q
def weightedAverageQuaternions(Q, w):
    # Number of quaternions to average
    M = Q.shape[0]
    A = npm.zeros(shape=(4,4))
    weightSum = 0

    for i in range(0,M):
        q = Q[i,:]
        A = w[i] * numpy.outer(q,q) + A
        weightSum += w[i]

    # scale
    A = (1.0/weightSum) * A

    # compute eigenvalues and -vectors
    eigenValues, eigenVectors = numpy.linalg.eig(A)

    # Sort by largest eigenvalue
    eigenVectors = eigenVectors[:,eigenValues.argsort()[::-1]]

    # return the real part of the largest eigenvector (has only real part)
    return numpy.real(eigenVectors[:,0].A1)


import numpy

def rk_butcher_4():
    A = numpy.array([[0,0,0,0],[.5,0,0,0],[0,.5,0,0],[0,0,1,0]])
    b = numpy.array([1/6, 1/3, 1/3, 1/6])
    return A, b

def ode_rkexplicit(f, u0, butcher=None, tfinal=1, h=.1):

    if butcher is None:
        A, b = rk_butcher_4()
    else:
        A, b = butcher
    c = numpy.sum(A, axis=1)
    s = len(c)
    u = u0.copy()
    t = 0
    hist = [(t,u0)]

    while t < tfinal:
        if tfinal - t < 1.01*h:
            h = tfinal - t
            tnext = tfinal
        else:
            tnext = t + h
        h = min(h, tfinal - t)

        fY = numpy.zeros((len(u0), s))
        for i in range(s):
            Yi = u.copy()
            for j in range(i):
                Yi += h * A[i,j] * fY[:,j]
            fY[:,i] = f(t + h*c[i], Yi)
        u += h * fY @ b
        t = tnext
        hist.append((t, u.copy()))
    return hist

limiters = []

def limappend(lim):
    limiters.append(lim)
    return lim

@limappend
def limit_zero(r):
    return 0*r

@limappend
def limit_none(r):
    return 0*r+1

@limappend
def limit_minmod(r):
    return numpy.maximum(numpy.minimum(2*r, 2*(1-r)), 0)

@limappend
def limit_sin(r):
    return numpy.where(numpy.all((0 < r, r < 1), axis=0),
                      numpy.sin(numpy.pi*r),
                      0)

@limappend
def limit_vl(r):
    return numpy.maximum(4*r*(1-r), 0)

@limappend
def limit_bj(r):
    return numpy.clip(numpy.minimum(4*r, 4*(1-r)), 0, 1)


# CELL 1
# Import necessary library functions
import numpy as np
import pandas as pd

# CELL 2
# Create Two numpy array of size 3 X 2 and 2 X 3.
# Randomly Initalize that array.
narray1 = np.random.randint(100, size=(3,2))
narray2 = np.random.randint(100, size=(2,3))
print(narray1)
print()
print(narray2)

# CELL 3
# Perform matrix multiplication
mul_mat = np.matmul(narray1,narray2)
print(mul_mat)

# CELL 4
# Perform elementwise matrix multiplication
ew_matmul1 = narray1 * narray1
ew_matmul2 = narray2 * 5
print(ew_matmul1)
print()
print(ew_matmul2)

# CELL 5
# Find mean of first matrix
mean_narray1 = np.mean(narray1)
print(mean_narray1)

# CELL 6
mtcars = pd.read_csv('/mtcars.csv')
print(mtcars)

# CELL 7
# Convert Numeric entries(columns) of mtcars.csv to Mean Centered Version
num_col_list = ['mpg','cyl','disp','hp','drat','wt','qsec','vs','am','gear','carb']
num_cols = pd.read_csv('/mtcars.csv', usecols=num_col_list)
meanByCols = np.mean(num_cols, axis=0)
print('Mean:')
print(meanByCols)
print()
print('Mean Centered Version')
for i in num_col_list:
  print(i + ':')
  for j,k in zip(num_cols[i], range(len(meanByCols))):
    print(j - meanByCols[i])
  print()


import numpy as np
from scipy.special import expit

hidden_size=2
input_size=2
classes=1
X=np.array(([[0, 0],[0, 1],[1, 0],[1, 1]]))
Wh=np.random.randn(hidden_size,input_size)
bh=np.random.randn(hidden_size,1)
Wo=np.random.randn(1,hidden_size)
bo=np.random.randn(classes,1)

T=np.array(([[0],[1],[1],[0]]))

def lossFunc():

	loss=0;

	dbo=np.zeros_like(bo)
	dWo=np.zeros_like(Wo)
	hg12=np.zeros_like(bh)
	dbh=np.zeros_like(bh)
	dh12tmp=np.zeros_like(bh)
	dh12=np.zeros_like(bh)
	dWh=np.zeros_like(Wh)

	for i in xrange(4):

		#forward propogation
		h12 = np.dot(Wh, X[i,:][np.newaxis].T) + bh
		hg=expit(h12)
		h3=np.dot(Wo,hg) + bo
		hg3=expit(h3)
		y=hg3
		loss+=0.5*(T[i]-y)*(T[i]-y)

		#backward propogation
		de=-(T[i]-y)
		dhg3=hg3*(1-hg3)
		dy=dhg3*de
		dbo+=dy
		dWo+=np.dot(dy,hg.T)
		dh12=np.dot(Wo.T,dy)
		dh12tmp=hg*(1-hg)*dh12
		dbh+=dh12tmp
		xsub=X[i,:]
		xsub=np.matrix(xsub)
		dWh+=np.dot(dh12tmp, xsub)

	#np.clip(dWh,-2,2,dWh)
	#np.clip(dWo,-2,2,dWo)
	#np.clip(dbh,-2,2,dbh)
	#np.clip(dbo,-2,2,dbo)
	return loss,dWh,dWo,dbh,dbo

learning_rate=0.2
f2=open("./log_data/sig_0.2.dat",'w')

for ep in xrange(2000):
	loss,dWh,dWo,dbh,dbo=lossFunc()

	Wh+=-learning_rate*dWh
	Wo+=-learning_rate*dWo
	bh+=-learning_rate*dbh
	bo+=-learning_rate*dbo

	if(ep%100==0):
		print 'Loss is %f' %(loss)

		f2.write(str(ep))
		f2.write("\t")
		tmp=str(loss).strip('[]')
		f2.write(str(tmp))
		f2.write("\n")

f2.close()

for i in xrange(4):
		#forward propogation
		h12 = np.dot(Wh, X[i,:][np.newaxis].T) + bh
		hg=expit(h12)
		#print hg
		h3=np.dot(Wo,hg) + bo
		hg3=expit(h3)
		print hg3


import numpy as np
import os

class FilterbankShape(object):

    def lin_tri_filter_shape(self, nfilt=20, nfft=512, samplerate=16000, lowfreq=0, highfreq=None):
        """Compute a linear-filterbank. The filters are stored in the rows, the columns correspond
        to fft bins. The filters are returned as an array of size nfilt * (nfft/2 + 1)
        :param nfilt: the number of filters in the filterbank, default 20.
        :param nfft: the FFT size. Default is 512.
        :param samplerate: the samplerate of the signal we are working with. Affects mel spacing.
        :param lowfreq: lowest band edge of mel filters, default 0 Hz
        :param highfreq: highest band edge of mel filters, default samplerate/2
        :returns: A numpy array of size nfilt * (nfft/2 + 1) containing filterbank. Each row holds 1 filter.
        """
        highfreq = highfreq or samplerate/2
        assert highfreq <= samplerate/2, "highfreq is greater than samplerate/2"

        # compute points evenly spaced in mels
        #lowmel = self.hz2mel(lowfreq)
        #highmel = self.hz2mel(highfreq)
        #melpoints = np.linspace(lowmel,highmel,nfilt+2)
        hzpoints = np.linspace(lowfreq,highfreq,nfilt+2)
        # our points are in Hz, but we use fft bins, so we have to convert
        #  from Hz to fft bin number
        bin = np.floor((nfft+1)*hzpoints/samplerate)

        fbank = np.zeros([nfilt,nfft//2+1])
        for j in range(0,nfilt):
            for i in range(int(bin[j]), int(bin[j+1])):
                fbank[j,i] = (i - bin[j]) / (bin[j+1]-bin[j])
            for i in range(int(bin[j+1]), int(bin[j+2])):
                fbank[j,i] = (bin[j+2]-i) / (bin[j+2]-bin[j+1])
        fbank = np.transpose(fbank)
        fbank.astype(np.float32)
        return fbank


import numpy as np

def normalize_vec(vals, minval=None, maxval=None):
    """Normalize values in vec to 0-1 range"""
    minval = vals.min()   if minval is None else minval
    maxval = vals.max()+1 if maxval is None else maxval
    return (vals-minval) / (maxval-minval)

def general_heatmat(xvec, yvec, xsize=100, ysize=100,
            xmin=None, xmax=None, ymin=None, ymax=None):
    """Create a 2D heatmap showing densities of x-y combinations"""
    mask = np.isfinite(xvec) & np.isfinite(yvec)
    xvec = xvec[mask]
    yvec = yvec[mask]
    xint = normalize_vec(xvec, xmin, xmax)
    yint = normalize_vec(yvec, ymin, ymax)
    mask = (xint>=0) & (xint<=1) & (yint>=0) & (yint<=1)
    xint = (xint[mask] * (xsize-1)).astype(int)
    yint = (yint[mask] * (ysize-1)).astype(int)
    ijvec = np.ravel_multi_index((xint,yint),(xsize,ysize))
    return np.bincount(ijvec, minlength=xsize*ysize).reshape(xsize,ysize).T

def heatmat(df, imax=None, jmax=None):
    """Create a 2D heatmap showing densities of x-y combinations"""
    xint = df.xpos.astype(np.int32)
    yint = df.ypos.astype(np.int32)
    if imax is None:
        if hasattr(df, "imax"):
            imax = df.imax
        else:
            imax = xint.max()+1
    if jmax is None:
        if hasattr(df, "jmax"):
            jmax = df.jmax
        else:
            jmax = yint.max()+1
    ijvec = np.ravel_multi_index((xint,yint),(imax,jmax))
    return np.bincount(ijvec, minlength=imax*jmax).reshape(imax,jmax).T

def trajs_to_grid(df, col_name, imax=None, jmax=None, data_source=None):
    """Create a 2D heatmap showing densities of x-y combinations"""
    xint = df.xpos.astype(np.int32)
    yint = df.ypos.astype(np.int32)
    if imax is None:
        if hasattr(df, "imax"):
            imax = df.imax
        else:
            imax = xint.max()+1
    if jmax is None:
        if hasattr(df, "jmax"):
            jmax = df.jmax
        else:
            jmax = yint.max()+1
    ijvec = np.ravel_multi_index((xint,yint),(imax,jmax))

    sum = np.bincount(ijvec, weights=df[col_name], minlength=imax*jmax)
    cnt = np.bincount(ijvec, minlength=imax*jmax)
    return (sum/cnt).reshape(imax,jmax).T


# Setting up program
import cv2
import numpy as np
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import multivariate_normal
from matplotlib.patches import Ellipse

# Setting seed for reproducibility
UBIT = 'damirtha'
np.random.seed(sum([ord(c) for c in UBIT]))

# Function to apply GMM clustering given X, Mu, Sigma, K and Pi
def GMMclustering(Mu, Sigma, Pi, K,  X, data = 'X', itr = 5):
    c=0
    for j in range(itr):
        pXgivenC = []
        for i in range(K):
            pXgivenC.append(multivariate_normal.pdf(X, mean = Mu[i], cov = Sigma[i]))
        pXgivenC = np.transpose(np.array(pXgivenC))
        pX = np.array(np.sum(np.multiply(pXgivenC,Pi), axis= 1))
        pCgivenX = np.multiply(np.transpose(np.multiply(pXgivenC,Pi)),pX ** -1)
        for i in range(K):
            Mu[i] = np.average(X, axis = 0, weights = pCgivenX[i])
            Sigma[i] = np.cov(X, rowvar = 0, aweights = pCgivenX[i], ddof = 0)
        Pi = np.sum(pCgivenX, axis = 1)/len(X)
        if data == 'faithful':
            plt.figure()
            plt.plot(X[:,0], X[:,1], 'bo', markersize = 3)
            color = ['r','g','b']
            # Plot a transparent 3 standard deviation covariance ellipse

            for i in range(K):
                plot_cov_ellipse(pos = Mu[i], cov = Sigma[i], nstd=3, alpha=0.5, color= color[i])

            plt.savefig('Results/task3_gmm_iter'+str(j+1)+'.jpg')
        c+=1
    return Mu, Sigma, Pi, c

def plot_cov_ellipse(cov, pos, nstd=2, ax=None, **kwargs):
    """
    Plots an `nstd` sigma error ellipse based on the specified covariance
    matrix (`cov`). Additional keyword arguments are passed on to the
    ellipse patch artist.
    Parameters
    ----------
        cov : The 2x2 covariance matrix to base the ellipse on
        pos : The location of the center of the ellipse. Expects a 2-element
            sequence of [x0, y0].
        nstd : The radius of the ellipse in numbers of standard deviations.
            Defaults to 2 standard deviations.
        ax : The axis that the ellipse will be plotted on. Defaults to the
            current axis.
        Additional keyword arguments are pass on to the ellipse patch.
    Returns
    -------
        A matplotlib ellipse artist
    """
    def eigsorted(cov):
        vals, vecs = np.linalg.eigh(cov)
        order = vals.argsort()[::-1]
        return vals[order], vecs[:,order]

    if ax is None:
        ax = plt.gca()

    vals, vecs = eigsorted(cov)
    theta = np.degrees(np.arctan2(*vecs[:,0][::-1]))

    # Width and height are "full" widths, not radius
    width, height = 2 * nstd * np.sqrt(vals)
    ellip = Ellipse(xy=pos, width=width, height=height, angle=theta, **kwargs)

    ax.add_artist(ellip)
    return ellip

# Initializing GMM parameters
X = np.array([[5.9,3.2],[4.6,2.9],[6.2,2.8],[4.7,3.2],[5.5,4.2],[5.0,3.0],[4.9,3.1],[6.7,3.1],[5.1,3.8],[6.0,3.0]])
K = 3
Mu = np.array([[6.2,3.2],[6.6,3.7],[6.5,3.0]])
Sigma = np.array([[[0.5, 0], [0, 0.5]]]*3)
Pi = np.array([1/3, 1/3, 1/3])

# Computing EM algorithm to get soft clusters
Mu, Sigma, Pi, c = GMMclustering(Mu, Sigma, Pi, K,  X, 'X', 1)
print('Mu for 3.5a:')
print(Mu)

# Bonus task 3.5 b, opening dataset and initializing GMM parameters
file = open('data/faithful.dat','r')
c=0; data=[]
for line in file:
    c+=1
    if c > 26:
        data.append(np.array(line.split()[1:3]))
data = np.array(data)
data = data.astype(np.float)
K = 3
Mu = np.array([[4.0,81],[2.0,57],[4.0, 71]])
Sigma = np.array([[[1.3, 13.98], [13.98, 184.82]]]*K)
Pi = np.array([1/3]*K)

# Computing EM algorithm to get soft clusters
Mu, Sigma, Pi, c = GMMclustering(Mu, Sigma, Pi, K,  data, 'faithful', 5)


from numpy import *
from matplotlib import *
from pylab import *
import matplotlib.lines as mlines

if __name__ == "__main__":
    rc('text', usetex=True)
    rc('font', family='serif')
    fs = 20
    ### Example 1
    x = arange(-5,5,0.1)

    # r > 0
    fig= figure(1)
    ax = fig.add_subplot(313)
    frame1 = plt.gca()
    hold
    r = 10
    xdot = r*x - x**3
    ax.plot(x,xdot,'b-')
    ylim([min(xdot),max(xdot)+3])
    xlim([min(x),max(x)])
    ax.plot(x,zeros_like(x),'k-')
    ax.plot(sqrt(r),0,'bo',fillstyle='full',mec='b')
    ax.plot(-sqrt(r),0,'bo',fillstyle='full',mec='b')
    ax.plot(0,0,'bo',mfc='none',mec='b')
    ax.set_title(r'$r > 0$')
    frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)

    ax.annotate('', xy=(-2, 0), xytext=(-1, 0),
             arrowprops=dict(facecolor='black', shrink=0.04, width=1),
             )
    ax.annotate('', xy=(2, 0), xytext=(1, 0),
             arrowprops=dict(facecolor='black', shrink=0.04, width=1),
             )

    # lft = mlines.Line2D.fillStyles
    # r = 0
    ax = fig.add_subplot(312)
    frame1 = plt.gca()
    r = 0
    xdot = r*x - x**3
    ax.plot(x,xdot,'b-')
    ax.plot(0,0,'bo',fillstyle='full',mec='b')
    ylim([min(xdot),max(xdot)+3])
    xlim([min(x),max(x)])
    ax.plot(x,zeros_like(x),'k-')
    ax.set_title(r'$r = 0$')
    frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)

    ax.annotate('', xy=(-2, 0), xytext=(-3, 0),
             arrowprops=dict(facecolor='black', shrink=0.04, width=1),
             )
    ax.annotate('', xy=(2, 0), xytext=(3, 0),
                arrowprops=dict(facecolor='black', shrink=0.04, width=1),
                )

    # r < 0
    ax = fig.add_subplot(311)
    frame1 = plt.gca()
    r = -5
    xdot = r*x - x**3
    ax.plot(x,xdot,'b-')
    ax.plot(0,0,'bo',fillstyle='full',mec='b')
    ax.plot(r,0,'bo', mfc='none',mec='b')
    ylim([min(xdot)-1,max(xdot)+3])
    xlim([min(x),max(x)])
    ax.plot(x,zeros_like(x),'k-')
    ax.set_title(r'$r < 0$')
    xlabel(r'$x$',fontsize=fs)
    ylabel(r'$\dot{x}$',fontsize=fs)
    frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)

    ax.annotate('', xy=(-2, 0), xytext=(-3, 0),
             arrowprops=dict(facecolor='black', shrink=0.04, width=1),
             )
    ax.annotate('', xy=(2, 0), xytext=(3, 0),
                arrowprops=dict(facecolor='black', shrink=0.04, width=1),
                )

    # bifurcation diagram
    x = arange(-5,5,0.1)
    fig= figure(2)
    ax = fig.add_subplot(111)
    frame1 = plt.gca()
    hold
    rpp = sqrt(arange(0,5,0.1))
    rpn = -1*sqrt(arange(0,5,0.1))
    rn = zeros_like(arange(-5,0,0.1))
    rzp = zeros_like(arange(0,5,0.1))
    rzn = zeros_like(arange(-5,0,0.1))
    ax.plot(arange(-5,0,0.1),rzn,'b-')
    ax.plot(arange(0,5,0.1),rzp,'b--')
    ax.plot(arange(0,5,0.1),rpp,'b-')
    ax.plot(arange(0,5,0.1),rpn,'b-')
    axvline(x=0,color='k')
    ax.set_title(r'$x^* = 0$')
    frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)

    # subcritical

    # bifurcation diagram
    x = arange(-5,5,0.1)
    fig= figure(3)
    ax = fig.add_subplot(111)
    frame1 = plt.gca()
    hold
    rpp = sqrt(arange(0,5,0.1))
    rpn = -1*sqrt(arange(0,5,0.1))
    rn = zeros_like(arange(-5,0,0.1))
    rzp = zeros_like(arange(0,5,0.1))
    rzn = zeros_like(arange(-5,0,0.1))
    ax.plot(arange(-5,0,0.1),rzn,'b-')
    ax.plot(arange(0,5,0.1),rzp,'b--')
    ax.plot(arange(-5,0,0.1),rpp[::-1],'b--')
    ax.plot(arange(-5,0,0.1),rpn[::-1],'b--')
    axvline(x=0,color='k')
    ax.set_title(r'$x^* = 0$')
    frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)

    # stabilize
    x = arange(-5,5,0.1)
    fig= figure(4)
    ax = fig.add_subplot(111)
    frame1 = plt.gca()
    hold
    rpp = sqrt(arange(0,5,0.1))
    rpn = -1*sqrt(arange(0,5,0.1))
    rn = zeros_like(arange(-8,0,0.1))
    rzp = zeros_like(arange(0,5,0.1))
    rzn = zeros_like(arange(-8,0,0.1))
    rps = sqrt(arange(0,10,0.1)) + rpp[-1]
    rpns = -1*sqrt(arange(0,10,0.1)) + rpn[-1]

    ax.plot(arange(-8,0,0.1),rzn,'b-')
    ax.plot(arange(0,5,0.1),rzp,'b--')
    ax.plot(arange(-5,0,0.1),rpp[::-1],'b--')
    ax.plot(arange(-5,0,0.1),rpn[::-1],'b--')

    ax.plot(arange(-5,5,0.1),rps,'b-')
    ax.plot(arange(-5,5,0.1),rpns,'b-')
    axvline(x=0,color='k')
    ax.set_title(r'$x^* = 0$')
    frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)

    show()


import numpy as np
from fft import dft,fft,inv_dft,inv_fft
import time
mat_size = 512
upper_limit = 255
lower_limit=0
matrix = np.random.randint(lower_limit,upper_limit,size=(mat_size,mat_size))

def twodfft(matrix):
    # intialize two matrix of same size of orginially generated random matrix
    # one matrix to store the result of FFT of row vectors
    # another one to store the result of FFT of column vectors of the matrix generated in the previous step
    z_rows = np.zeros((mat_size,mat_size),dtype=complex)
    z_cols = np.zeros((mat_size,mat_size),dtype=complex)
    # print(z_rows)
    # print(z_cols)
    # store the FFT of row vectors in z_rows
    # every row of z_rows contains FFT of row vector of "matrix"
    for i in range(len(matrix)):
        z_rows[i] = fft(matrix[i])

    # apply FFT on column vectors and store the resultant column vector in z_cols as columns
    # every column of z_cols contains the FFT of column vectors of z_rows
    for i in range(len(z_rows[0])):
        z_cols[:,i] = fft(z_rows[:,i])
    return z_cols

#print(z_cols)
def inv_2dfft(z_cols):
    i_rows = np.zeros((mat_size,mat_size),dtype=complex)
    i_cols = np.zeros((mat_size,mat_size),dtype=complex)

    for i in range(len(z_cols[0])):
        i_rows[i] = inv_fft(z_cols[i])
    for i in range(len(z_cols[0])):
        i_cols[:,i] = inv_fft(i_rows[:,i])
    return i_cols

#driver program
z_cols = twodfft(matrix)
i_cols = inv_2dfft(z_cols)
start_time = time.time()
if(np.allclose(z_cols, np.fft.fft2(matrix))):
    print("The output of the 2D fft matches the numpy function's output for the 2D fft")

if(np.allclose(i_cols, np.fft.ifft2(z_cols))):
    print("The output of the 2D fft matches the numpy function's output for the 2D fft")
print(time.time() - start_time)


from __future__ import print_function
import time
import numpy as np
import pandas as pd
from sklearn.datasets import fetch_openml
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import seaborn as sns

# MNIST data
mnist = fetch_openml("mnist_784")
X = mnist.data / 255.0
y = mnist.target

feat_cols = [ 'pixel'+str(i) for i in range(X.shape[1]) ]
df = pd.DataFrame(X,columns=feat_cols)
df['y'] = y
df['label'] = df['y'].apply(lambda i: str(i))
X, y = None, None
print('Size of the dataframe: {}'.format(df.shape))

# For reproducability of the results
np.random.seed(42)
rndperm = np.random.permutation(df.shape[0])

# plt.gray()
fig = plt.figure( figsize=(16,7) )
for i in range(0,15):
    ax = fig.add_subplot(3,5,i+1, title="Digit: {}".format(str(df.loc[rndperm[i],'label'])) )
    ax.matshow(df.loc[rndperm[i],feat_cols].values.reshape((28,28)).astype(float), cmap=plt.cm.binary)
plt.show()

# PCA
pca = PCA(n_components=3)
pca_result = pca.fit_transform(df[feat_cols].values)
df['pca-one'] = pca_result[:,0]
df['pca-two'] = pca_result[:,1]
df['pca-three'] = pca_result[:,2]
print('Explained variation per principal component: {}'.format(pca.explained_variance_ratio_))

# 2D of PCA
plt.figure(figsize=(16,10))
sns.scatterplot(
    x="pca-one", y="pca-two",
    hue="y",
    palette=sns.color_palette("hls", 10),
    data=df.loc[rndperm,:],
    legend="full",
    alpha=0.3
)
plt.show()

# 3D of PCA
# ax = plt.figure(figsize=(16,10)).gca(projection='3d')
# ax.scatter(
#     xs=df.loc[rndperm,:]["pca-one"],
#     ys=df.loc[rndperm,:]["pca-two"],
#     zs=df.loc[rndperm,:]["pca-three"],
#     # c=df.loc[rndperm,:]["y"],
#     cmap='tab10'
# )
# ax.set_xlabel('pca-one')
# ax.set_ylabel('pca-two')
# ax.set_zlabel('pca-three')
# plt.show()

# t-SNE
N = 10000
df_subset = df.loc[rndperm[:N],:].copy()
data_subset = df_subset[feat_cols].values
pca = PCA(n_components=3)
pca_result = pca.fit_transform(data_subset)
df_subset['pca-one'] = pca_result[:,0]
df_subset['pca-two'] = pca_result[:,1]
df_subset['pca-three'] = pca_result[:,2]
print('Explained variation per principal component: {}'.format(pca.explained_variance_ratio_))

time_start = time.time()
tsne = TSNE(n_components=2, verbose=1, perplexity=40, n_iter=300)
tsne_results = tsne.fit_transform(data_subset)
print('t-SNE done! Time elapsed: {} seconds'.format(time.time()-time_start))

df_subset['tsne-2d-one'] = tsne_results[:,0]
df_subset['tsne-2d-two'] = tsne_results[:,1]
plt.figure(figsize=(16,10))
sns.scatterplot(
    x="tsne-2d-one", y="tsne-2d-two",
    hue="y",
    palette=sns.color_palette("hls", 10),
    data=df_subset,
    legend="full",
    alpha=0.3
)
plt.show()


"""
lineshapes1d.py One-dimensional lineshape functions and classes
"""

import numpy as np
import scipy.special    # needed for complex error function (wo
pi = np.pi

####################################
# 1D lineshape simulator functions #
####################################

# Gaussian (normal) lineshape simulator functions
def sim_gauss_sigma(x, x0, sigma):
    """
    Simulate a Gaussian (normal) lineshape with unit height at the center.

    Simulate discrete points of a continuous Gaussian (normal) distribution
    with unit height at the center.  Sigma (the standard deviation of the
    distribution) is used as the distribution scale parameter.

    Functional form:

        f(x; x0, sigma) = exp(-(x-x0)^2  / (2 * sigma^2))

    Parameters:

    * x     Array of values at which to evaluate distribution.
    * x0    Center (mean) of Gaussian distribution.
    * sigma Scale (variance) of the Gaussian distribution.

    """
    return np.exp(-(x-x0)**2 / (2.0*sigma**2) )

def sim_gauss_fwhm(x, x0, fwhm):
    """
    Simulate a Gaussian (normal) lineshape with unit height at the center.

    Simulate discrete points of a continuous Gaussian (normal) distribution
    with unit height at the center.  FWHM (full-width at half-maximum ) is used
    as the distribution scale parameter.

    Functional form:

        f(x; x0, fwhm) = exp( -(x-x0)^2 * 4 * ln(2)  / (fwhm^2))

    Parameters:

    * x     Array of values at which to evaluate distribution.
    * x0    Center (mean) of Gaussian distribution.
    * fwhm  Full-width at half-maximum of distribution.

    """
    return np.exp(-(x-x0)**2 * 4 * np.log(2) / (fwhm**2))

# Lorentzian lineshape simulator functions
def sim_lorentz_gamma(x, x0, gamma):
    """
    Simulate a Lorentzian lineshape with unit height at the center.

    Simulates discrete points of the continuous Cauchy-Lorentz (Breit-Wigner)
    distribution with unit height at the center.  Gamma (the half-width at
    half-maximum, HWHM) is used as the scale parameter.

    Functional form:

        f(x; x0, gamma) = g^2 / ((x-x0)^2 + g^2)

    Parameters:

    * x     Array of values at which to evaluate distribution.
    * x0    Center of the distribution.
    * gamma Scale parameter, half-width at half-maximum, of distribution.

    """
    return gamma**2 / (gamma**2 + (x-x0)**2)

def sim_lorentz_fwhm(x, x0, fwhm):
    """
    Simulate a Lorentzian lineshape with unit height at the center.

    Simulates discrete points of the continuous Cauchy-Lorentz (Breit-Wigner)
    distribution with unit height at the center.  FWHM (full-width at
    half-maximum) is used as the scale parameter.

    Functional form:

        f(x; x0, fwhm) = (0.5 * fwhm)^2 / ((x-x0)^2 + (0.5 * fwhm)^2)

    Parameters:

    * x     Array of values at which to evaluate distribution.
    * x0    Center of the distribution.
    * fwhm  Full-width at half-maximum of distribution.

    """
    return (0.5 * fwhm)**2 / ((0.5 * fwhm)**2 + (x-x0)**2)

# Voigt lineshape simulator functions

def sim_voigt_fwhm(x, x0, fwhm_g, fwhm_l):
    """
    Simulate a Voigt lineshape with unit height at the center.

    Simulates discrete points of the continuous Voigt profile with unit height
    at the center.  Full-width at half-maximum (FWHM) of each component are used
    as the scale parameters for the Gaussian and Lorentzian distribution.

    Functional Form:

        f(x; x0, fwhm_g, fwhm_l) = Re[w(z)] / Re[(w(z0)]

    Where:

        z = sqrt(ln(2)) * (2 * (x - x0) + 1j * fwhm_l) / fwhm_g
        z0 = sqrt(ln(2)) * 1j * fwhm_l / fwhm_g
        w(z) is the complex error function of z

    Parameters

    * x         Array of values at which to evalutate distribution.
    * x0        Center of the distribution.
    * fwhm_g    Full-width at half-maximum of the Gaussian component.
    * fwhm_l    Full-width at half-maximum of the Lorentzian component.

    """
    z = np.sqrt(np.log(2)) * (2.0 * (x - x0) + 1.j * fwhm_l) / fwhm_g
    z0 = np.sqrt(np.log(2)) * 1.j *  fwhm_l / fwhm_g
    return scipy.special.wofz(z).real / scipy.special.wofz(z0).real

def sim_voigt_sigmagamma(x, x0, sigma, gamma):
    """
    Simulate a Voigt lineshape with unit height at the center.

    Simulates discrete points of the continuous Voigt profile with unit height
    at the center.  Sigma and gamma are used as the Gaussian and Lorentzian
    scaler parameters.

    Functional Form:

        f(x; x0, sigma, gamma) = Re[w(z)] / Re[(w(z0)]

    Where:

        z = ((x - x0) + 1j * gamma) / (sigma * sqrt(2))
        z0 = (1j * gamma) / (sigma * sqrt(2))
        w(z) is the complex error function of z

    Parameters

    * x     Array of values at which to evalutate distribution.
    * x0    Center of the distribution
    * sigma Gaussian scale component of Voigt profile.  Variance of the Gaussian
            distribution.
    * gamma Lorentzian scale component of Voigt profile.  Half-width at
            half-maximum of the Lorentzian component.

    """
    z = (x - x0 + 1j * gamma) / ( sigma * np.sqrt(2))
    z0 = (1j * gamma) / (sigma * np.sqrt(2))
    return scipy.special.wofz(z).real / scipy.special.wofz(z0).real

# Pseudo Voigt linehspae simulator functions
def sim_pvoigt_fwhm(x, x0, fwhm, eta):
    """
    Simulate a Pseudo Voigt lineshape with unit height at the center.

    Simulates discrete points of the continuous Pseudo Voigt profile with unit
    heigh at the center.  Full-width at half-maximum (FWHM) of the Gaussian and
    Lorentzian distribution are used as the scale parameter as well as eta, the
    mixing factor.

    Functional Form:

        f(x; x0, fwhm, eta) = (1-eta) * G(x; x0, fwhm) + eta * L(x; x0, fwhm)

    Where:

        G(x; x0, fwhm) = exp( -(x-x0)^2 * 4 * ln(2)  / (fwhm^2))
        L(x; x0, fwhm) = (0.5 * fwhm)^2 / ((x-x0)^2 + (0.5 * fwhm)^2)

    Parameters

    * x     Array of values at which to evalutate distribution.
    * x0    Center of the distribution.
    * fwhm  Full-width at half-maximum of the Pseudo Voigt profile.
    * eta   Lorentzian/Gaussian mixing parameter.

    """
    G = sim_gauss_fwhm(x, x0, fwhm)
    L = sim_lorentz_fwhm(x, x0, fwhm)
    return (1.0 - eta) * G + eta * L

########################
# 1D Lineshape classes #
########################

# A lineshape class defines methods used to fit and simulate one dimensional
# lineshapes, which can be used to build multidimensinal lineshapes.  These
# classes should have the following 6 methods:

# sim(self, M, p)   - Using parameters in p simulate a lineshape of length M.
# nparams(self, M)  - Determind the number of parameters needed for a length M
#                     lineshape.
# guessp(self, sig) - Estimate parameters of signal sig, these should be
#                     parameter which might be used for initial least-squares
#                     fitting.
# pnames(self, M)   - Give names to the parameters of a lineshape of length M.
#
# add_edge(self, p, (min,max))  - take into account region limits at min,max
#                                 for parameters in p.
# remove_edge(self, p, (min,max))   - remove the effects of region limits
#                                   min, max for parameters in p.

# location-scale lineshapes

class location_scale():
    """
    Class for building a 2 parameter location scale lineshape class
    """
    def nparam(self,M):
        return 2

    def add_edge(self,p,(min,max)):
        if p[0] is None:
            return p
        return p[0]-min,p[1]

    def remove_edge(self,p,(min,max)):
        if p[0] is None:
            return p
        return p[0]+min,p[1]

class gauss_sigma(location_scale):
    """
    Gaussian (normal) lineshape class with unit height at the mean and sigma
    scale parameter. See sim_gauss_sigma for functional form and parameters.
    """
    name = "guassian"

    def sim(self,M,p):
        x = np.arange(M)
        x0, sigma = p
        return sim_gauss_sigma(x, x0, sigma)

    def guessp(self,sig):
        c,fwhm = center_fwhm(sig)
        return (c,fwhm/2.35482004503)

    def pnames(self,M):
        return ("x0","sigma")

class gauss_fwhm(location_scale):
    """
    Gaussian (normal) lineshape class with unit height at the mean and fwhm
    scale parameter. See sim_gauss_fwhm for functional form and parameters.
    """
    name = "guassian"

    def sim(self,M,p):
        x = np.arange(M)
        x0, fwhm = p
        return sim_gauss_fwhm(x, x0, fwhm)

    def guessp(self,sig):
        c,fwhm = center_fwhm(sig)
        return (c,fwhm)

    def pnames(self,M):
        return ("x0","fwhm")

class lorentz_gamma(location_scale):
    """
    Lorentzian lineshape class with unit height at the center and gamma scale
    parameter.  See sim_lorentz_gamma for functional form and parameters.
    """
    name = "lorentz"

    def sim(self,M,p):
        x = np.arange(M)
        x0, gamma = p
        return sim_lorentz_gamma(x, x0, gamma)

    def guessp(self,sig):
        c,fwhm = center_fwhm(sig)
        return (c,fwhm/2.)

    def pnames(self,M):
        return("x0","gamma")

class lorentz_fwhm(location_scale):
    """
    Lorentzian lineshape class with unit height at the center and gamma scale
    parameter.  See sim_lorentz_fwhm for functional form and parameters.
    """
    name = "lorentz"

    def sim(self,M,p):
        x = np.arange(M)
        x0, fwhm = p
        return sim_lorentz_fwhm(x, x0, fwhm)

    def guessp(self,sig):
        c,fwhm = center_fwhm(sig)
        return (c,fwhm)

    def pnames(self,M):
        return("x0","fwhm")

# Voigt (location, 2 scale-like parameters) lineshapes.

class location_2params():
    """
    Class for building a 3 parameter location, scale, other lineshape class
    """
    def nparam(self,M):
        return 3

    def add_edge(self,p,(min,max)):
        if p[0] is None:
            return p
        return p[0]-min,p[1]

    def remove_edge(self,p,(min,max)):
        if p[0] is None:
            return p
        return p[0]+min,p[1]

class voigt_fwhm(location_2params):
    """
    Voigt lineshape class with unit height at the center and full-width
    half-maximum scale parameters.  See sim_voigt_fwhm for functional form and
    parameters.
    """
    name = "voigt"

    def sim(self, M, p):
        x = np.arange(M)
        x0, fwhm_g, fwhm_l = p
        return sim_voigt_fwhm(x, x0, fwhm_g, fwhm_l)

    def guessp(self, sig):
        c, fwhm = center_fwhm(sig)
        return (c, fwhm*0.5, fwhm*0.5)

    def pnames(self, M):
        return ("x0", "fwhm_gauss", "fwhm_lorentz")

class voigt_sigmagamma(location_2params):
    """
    Voigt lineshape class with unit height at the center and sigma, gamma scale
    parameters.  See sim_voigt_sigmagamma for functional form and parameters.
    """
    name = "voigt"

    def sim(self, M, p):
        x = np.arange(M)
        x0, sigma, gamma = p
        return sim_voigt_sigmagamma(x, x0, sigma, gamma)

    def guessp(self, sig):
        c, fwhm = center_fwhm(sig)
        return (c, fwhm/2.35482004503 * 0.5  , fwhm * 0.5 * 0.5)

    def pnames(self, M):
        return ("x0", "fwhm_gauss", "fwhm_lorentz")

class pvoigt_fwhm(location_2params):
    """
    Pseudo-Voigt lineshape class with unit height at the center and full-width
    half-maximum scale parameter.  See sim_pvoigt_fwhm for functional form and
    parameters.
    """
    name = "pvoigt"

    def sim(self, M, p):
        x = np.arange(M)
        x0, fwhm, eta = p
        return sim_pvoigt_fwhm(x, x0, fwhm, eta)

    def guessp(self, sig):
        c, fwhm = center_fwhm(sig)
        return (c, fwhm, 0.5)

    def pnames(self, M):
        return ("x0", "fwhm", "eta")

# misc lineshape classes
class scale():
    """
    Scale lineshape class

    Simulates a lineshape with functional form:

    1.0, a0, a1, a2, ....

    Where a0, a1, ... are the parameters provided.

    """
    name = "scale"

    def sim(self,M,p):
        l = np.empty(M,dtype='float')
        l[0] = 1
        l[1:] = p
        return l

    def nparam(self,M):
        return int(M-1)

    def guessp(self,sig):
        return sig[1:]/sig[0]

    def pnames(self,M):
        return tuple(["a%i"%i for i in range(1,M)])

    def add_edge(self,p,(min,max)):
        return p

    def remove_edge(self,p,(min,max)):
        return p

# lineshape convience
gauss = gauss_fwhm
lorentz = lorentz_fwhm
voigt = voigt_fwhm
pvoigt = pvoigt_fwhm

# lineshape class router

def ls_str2class(l):
    """ Convert lineshape string to lineshape class """
    if l == "gauss" or l == "g":
        return gauss()
    elif l == "lorentz" or l == "l":
        return lorentz()
    elif l == "scale" or l == "s":
        return scale()
    elif l == "voigt" or l == "v":
        return voigt()
    elif l == "pvoigt" or l == "pv":
        return pvoigt()
    else:
        raise ValueError("Unknown lineshape %s",(l))

# basic lineshape analysis

def center_fwhm(signal):
    """
    Estimate the center and full-width half max of a signal.
    """

    # negate the signal if it appears to be a negative peak
    if -signal.min() > signal.max():
        signal = -signal

    # the center is the highest point in the signal
    center = signal.argmax()

    # find the points that bracket the first and last crossing of the
    # half max, then use linear extrapolation to find the location of the
    # half max on either side of the maximum.  The difference between these
    # two values is a good approximation of the full width at half max
    max = signal.max()
    hmax = max/2.

    top_args = np.nonzero(signal > hmax)[0]     # all points above half-max
    l_idx = top_args[0]     # index of left hand side above half-max
    r_idx = top_args[-1]    # index of right hand side above half-max

    # solve hmax = mx+b => x = y-b/m
    # for two points x_0 and x_1 this becomes y = (hmax-x_0)/(x_1-x_0)
    # to this value add the index of x_0 to get the location of the half-max.

    # left side
    if l_idx==0:
        left = l_idx    # this is a bad guess but the best we can do
    else:
        x_0,x_1 = signal[l_idx-1],signal[l_idx]
        left = l_idx-1+(hmax-x_0)/(x_1-x_0)

    # right side
    if r_idx == len(signal)-1:
        right = r_idx   # this is a bad guess but the best we can do
    else:
        x_0,x_1 = signal[r_idx],signal[r_idx+1]
        right = r_idx+(hmax-x_0)/(x_1-x_0)

    return center,right-left

def center_fwhm_bymoments(signal):
    """
    Estimate the center and full-width half max of a signal using moments
    """

    # calculate the zeroth, first and second moment
    x = np.arange(signal.size)
    m0 = signal.sum()
    m1 = (x*signal).sum()
    m2 = (x**2.*signal).sum()

    # mu (the center) is the first over the zeroth moment
    mu = m1/m0
    # sigma (the variance) is  sqrt( abs(m2)-mu**2)
    sigma = np.sqrt(np.abs(m2)-mu**2)

    return mu,sigma*2.3548


import math

import numpy as np

def pad(vh, rows, cols):
    """
    Pad an image to make it divisible by some block_size.
    Pad on the right and bottom edges so annotations are still usable.
    """
    r, c = vh.shape
    to_rows = math.ceil(r / rows) * rows
    to_cols = math.ceil(c / cols) * cols
    pad_rows = to_rows - r
    pad_cols = to_cols - c
    vh_pad = np.pad(vh, pad_width=((0, pad_rows), (0, pad_cols)), mode="constant", constant_values=0)
    return vh_pad, pad_rows, pad_cols

def chip_sar_img(input_img, sz):
    """
    Takes a raster from xView3 as input and outputs
    a set of chips and the coordinate grid for a
    given chip size

    Args:
        input_img (numpy.array): Input image in np.array form
        sz (int): Size of chip (will be sz x sz x # of channlls)

    Returns:
        images: set of image chips
        images_grid: grid coordinates for each chip
    """
    # The input_img is presumed to already be padded
    images = view_as_blocks(input_img, (sz, sz))
    images_grid = images.reshape(int(input_img.shape[0] / sz), int(input_img.shape[1] / sz), sz, sz)
    return images, images_grid

def view_as_blocks(arr, block_size):
    """
    Break up an image into blocks and return array.
    """
    m, n = arr.shape
    M, N = block_size
    return arr.reshape(m // M, M, n // N, N).swapaxes(1, 2).reshape(-1, M, N)


import numpy as np
from numpy import array,kron

def HeisenbergHamiltonian(N, J, h, PBC=False):
#     # Some error checking
    if (len(J) != 3):
        print("error: Vector containing the couplings has to have length 3")
    if (len(h) != 3):
        print("error: Vector containing the field strengths has to have length 3")
#     # Provide the Pauli matrices
    s0 = array([[1+0.0j,0+0.0j],[0+0.0j,1+0.0j]])
    sx = array([[0+0.0j,1+0.0j],[1+0.0j,0+0.0j]])
    sy = array([[0+0.0j,-1.0j],[0.0+1.0j,0.0+0.0j]])
    sz = array([[1+0.0j,0+0.0j],[0+0.0j,-1+0.0j]])
    H = np.zeros(shape=(2**N,2**N))
    for i in range(1,N+1):
        id_left = array(np.identity(2**(i - 1)), copy=False)
        id_right = array(np.identity(2**(N - i)), copy=False)
        H = (
            H
            + kron(kron(id_left,sx),id_right)
            + h[1]*kron(kron(id_left,sy),id_right)
            + h[2]*kron(kron(id_left,sz),id_right)
            )
#         print('H = ',H)
        if (i<N):
            id_right = array(np.identity(2**(N-i-1)), copy=False)
            H = (
                H
                + J[0]*kron(kron(kron(id_left,sx),sx),id_right)
                + J[1]*kron(kron(kron(id_left,sy),sy),id_right)
                + (J[2]/h[0])*kron(kron(kron(id_left,sz),sz),id_right)
                )
    if PBC==True:
        idx = array(np.identity(2**(N-2)), copy=False)
        H = (
            H + J[0]*kron(kron(sx,idx),sx)
                + J[1]*kron(kron(sy,idx),sy)
                + (J[2]/h[0])*kron(kron(sz,idx),sz)
            )
    return(H)

def getT(N):
    swap = array([[1., 0., 0., 0.],
       [0., 0., 1., 0.],
       [0., 1., 0., 0.],
       [0., 0., 0., 1.]])
    res = array(np.identity(2**N), copy=False)
    for i in range(1,N):
        id_left = array(np.identity(2**(i - 1)), copy=False)
        id_right = array(np.identity(2**(N - i - 1)), copy=False)
        tmp = kron(kron(id_left,swap),id_right)
        res = np.dot(tmp,res)
#         print("id_left = {}\nid_right = {}\ntmp = {}\nres = {}".format(repr(id_left),repr(id_right),repr(tmp),repr(res)))
    return(res)


from __future__ import division
from sympy import MatrixSymbol, Matrix,diff,init_printing,symbols,sqrt,pprint,simplify,exp

x = MatrixSymbol('x', 1, 2)

x = symbols('x')
y = symbols('y')
c = symbols('c')
g = sqrt(x**2 + y**2 + c**2)
gx = diff(g,x)
gy = diff(g,y)
gxx = diff(gx,x)
gyy = diff(gy,y)

print 'MQ'
print '---------------------------------------------'
pprint(g)
print '---------------------------------------------'
pprint(gx)
print '---------------------------------------------'
pprint(gy)
print '---------------------------------------------'
pprint(gxx)
print '---------------------------------------------'
pprint(gyy)
print '---------------------------------------------'
pprint(simplify(gxx+gyy))

g = exp(-(x**2 + y**2)/c**2)
gx = diff(g,x)
gy = diff(g,y)
gxx = diff(gx,x)
gyy = diff(gy,y)

print 'GAUSSIAN'
print '---------------------------------------------'
pprint(g)
print '---------------------------------------------'
pprint(gx)
print '---------------------------------------------'
pprint(gy)
print '---------------------------------------------'
pprint(gxx)
print '---------------------------------------------'
pprint(gyy)
print '---------------------------------------------'
pprint(simplify(gxx+gyy))


import numpy as np
import scipy.constants as constants

def calculate_phonon_heat_capacity(temperatures,v_dos):
    # This function calculates the phonon heat capacity from the phonon density of states.
    # INPUTS:
    # IMPORTANT: All inputs need to be in the right units! (see information below)
    # temperatures: array of shape (N,) corresponding to the temperatures for the heat capacity calculation, in K.
    # v_dos: array of shape (M,2) which contains information on the phonon density of states. The first column is
    # energy in eV and the second column is the corresponding phonon density of states in states/eV.
    #
    # OUTPUT:
    # phonon_heat_capacity: array of shape(N-1,2) which contains information on the phonon heat capacity. The first
    # column is temperature (the temperature sampling is slightly different due to the numerical differentiation).
    # The second column is heat capacity. The units depend on the units of the phonon density of states:
    # If it is in states/eV/unit cell, the heat capacity is in J/unit cell. In other words, the volume to which
    # v_dos and phonon_heat_capacity refer is the same (here: one unit cell).

    # constants
    K_B = constants.Boltzmann*constants.physical_constants['joule-electron volt relationship'][0]  # Boltzmann constant, in eV/K
    ELEMENTARY_CHARGE = constants.e # elementary charge in C

    # ensure that v_dos has only positive energy entries (zero energy causes numerical problems and the v_dos
    # should anyway be zero there.)
    v_dos = v_dos[v_dos[:,0]>0,:]

    # step 1: calculate electron energy as a function of temperature
    phonon_energy = np.empty(np.shape(temperatures))
    phonon_heat_capacity = np.empty([np.shape(temperatures)[0]-1,2])
    for i in range(0,len(temperatures)):
        if temperatures[i] == 0:
            phonon_energy[i] = 0
        else:
            bose_einstein_distribution = 1./(np.exp(v_dos[:,0]/(K_B*temperatures[i]))-1)
            thermal_occupation_number = bose_einstein_distribution*v_dos[:,1] # occupation number=distribution function*DOS
            phonon_energy[i] = np.trapz(thermal_occupation_number*v_dos[:,0],v_dos[:,0]) # energy stored in phonon system
    # convert phonon energy from eV to J:
    phonon_energy = phonon_energy*ELEMENTARY_CHARGE

    # step 2: calculate numerical derivative of phonon energy with respect to temperature to obtain heat capacity
    # temperatures:
    phonon_heat_capacity[:,0] = (temperatures[0:-1]+temperatures[1:])/2
    # heat capacity in J/(unit cell K) (assuming that the DOS is per unit cell):
    phonon_heat_capacity[:,1] = np.diff(phonon_energy)/(temperatures[1]-temperatures[0])

    return phonon_heat_capacity


import numpy as np
import matplotlib.pyplot as plt
import time
x0 = 0
xn = 1
dx = 0.1
dx = 0.01
# n = 10 #Choose when dx = 0.1
n = 100 #Choose when dx = 0.01
x = np.linspace(x0,xn,n+1)
a = np.zeros(n+1)
b = np.zeros(n+1)
c = np.zeros(n+1)
d = np.zeros(n+1)
phi = np.zeros(n+1)
#boundary conditions
phi[0] = 1.0
phi[n] = 0.0
#Calculating coefficients for the first and last node
b[1] = -0.2/(dx*dx) - 1
c[1] = 0.1/(dx*dx) + 1/(2*dx)
d[1] = phi[0]*(1/(2*dx)-0.1/(dx*dx))
a[n-1] = 0.1/(dx*dx) - 1/(2*dx)
b[n-1] = -0.2/(dx*dx) - 1
d[n-1] = phi[n]*(-1/(2*dx)-0.1/(dx*dx))
#Calculating coefficients for the rest
for i in range(2,n-1):
    a[i] = 0.1/(dx*dx) - 1/(2*dx)
    b[i] = -0.2/(dx*dx) - 1
    c[i] = 0.1/(dx*dx) + 1/(2*dx)
#Thomas algorithm
for i in range(2,n):
    a[i] = a[i]/b[i-1]
    b[i] = b[i] - a[i]*c[i-1]
    d[i] = d[i] - a[i]*d[i-1]

phi[n-1] = d[n-1] / b[n-1]
for i in range(n-2,0,-1):
    phi[i]= (d[i] - c[i]*phi[i+1])/b[i]

print(phi)
print(x)
plt.plot(x, phi)
plt.title("phi vs. x : dx = 0.01")
plt.ylabel('phi')
plt.xlabel('x')
plt.show()


"""Calculates statistics."""

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

def filterZeroVarianceRows(df):
  """
  Removes rows that have zero variance.
  :param pd.DataFrame df: numeric rows
  :return pd.DataFrame: same columns as df
  """
  ser_std = df.std(axis=1)
  indices = [i for i in ser_std.index
      if np.isclose(ser_std[i], 0.0)]
  return df.drop(indices)

def calcLogSL(df, round_decimal=4, is_nan=True):
  """
  Calculates the minus log10 of significance levels
  for large values in rows.
  :param pd.DataFrame df: Rows have same units
  :param int round_decimal: How many decimal points to round
  :param bool is_nan: force std = 0 to be np.nan
  :return pd.DataFrame: transformed
  """
  ser_std = df.std(axis=1)
  ser_mean = df.mean(axis=1)
  df1 = df.subtract(ser_mean, axis=0)
  df2 = df1.divide(ser_std, axis=0)
  # Calculate minus log10 of significance levels
  # For efficiency reasons, this is done by dictionary lookup
  df3 = df2.fillna(-4.0)
  df3 = df3.applymap(lambda v: np.round(v, 4))
  values = []
  [ [values.append(v) for v in df3[c]] for c in df3.columns]
  vals_lookup = {v: -np.log10(1 - stats.norm(0, 1).cdf(v))
      for v in pd.Series(values).unique()}
  df4 = df3.applymap(lambda v: vals_lookup[v])
  if is_nan:
    df_log = df4.applymap(lambda v: v if v > 0.01 else np.nan)
  else:
    df_log = df4
  return df_log

def decorrelate(df):
  """
  Permutes rows within columns to remove
      correlations between features.
  :return pd.DataFrame:
  """
  length = len(df)
  df_result = df.copy()
  for col in df_result.columns:
    values = df_result[col].tolist()
    df_result[col] = np.random.permutation(values)
  return df_result


import numpy as np

def calc_angle(u: np.ndarray, v: np.ndarray):
    return np.arccos(np.dot(u / np.linalg.norm(u), v / np.linalg.norm(v))) * 57.2958

def check_right_angle(angle: float, epsilon: float):
    return abs(angle - 90) < epsilon

def side_lengths_are_too_different(u: np.array, v: np.array, t: np.array, n: np.array, eps_scale: float):
    uv = np.dot(u - v, u - v)
    un = np.dot(u - n, u - n)
    vt = np.dot(v - t, v - t)
    tn = np.dot(t - n, t - n)

    shortest = min(uv, un, vt, tn)
    longest = max(uv, un, vt, tn)
    return longest > eps_scale * shortest

def check_rect(rect: np.ndarray):
    ab = rect[1] - rect[0]
    ad = rect[3] - rect[0]
    bc = rect[2] - rect[1]
    dc = rect[2] - rect[3]

    if not (check_right_angle(calc_angle(ab, ad), 20)):
        if check_right_angle(calc_angle(ab, bc), 20):
            if check_right_angle(calc_angle(bc, dc), 20):
                if check_right_angle(calc_angle(ad, dc), 20):
                    return False
    # check if it is a square grid ..
    if side_lengths_are_too_different(rect[0], rect[1], rect[2], rect[3], 1.44):
        return False

    return True

def detect_rect_corners(corners: np.array):
    rect = np.zeros((4, 2), dtype="float32")
    corners = corners.reshape(4, 2)

    corners_sum = np.sum(corners, axis=1)

    min_val_idx = np.argmin(corners_sum)

    rect[0] = corners[min_val_idx]
    corners = np.delete(corners, min_val_idx, 0)

    max_val_idx = np.argmax(corners_sum)

    if max_val_idx <= 1:
        rect[2] = corners[max_val_idx]
        corners = np.delete(corners, max_val_idx, 0)

    if corners[0][0] > corners[1][0]:
        rect[1] = corners[0]
        rect[3] = corners[1]
    else:
        rect[1] = corners[1]
        rect[3] = corners[0]

    return rect.reshape(4, 2)

def calc_dimensions(rect):
    u, v, t, n = rect
    width = max(int(np.linalg.norm(t - n)), int(np.linalg.norm(u - v)))

    height = max(int(np.linalg.norm(v - t)), int(np.linalg.norm(u - n)))

    return np.array([
        [0, 0],
        [width - 1, 0],
        [width - 1, height - 1],
        [0, height - 1]], dtype="float32"), width, height


from typing import List

import numpy as np

def random_start_weights(list_of_layer_dimensions):
    """
    creates random weights for each edge in computational graph of size 'list_of_layer_dimensions'

    :param list_of_layer_dimensions: array of dimensions of particular layer starting with input layer,
    through hidden layers, out with output layer.
    :return: list of ndarrays - list of 2n ndarrays - weights from neurons in layer a to a + 1, where a starts with 0
    (input layer) and goes through hidden layers until output layer a = L
    """
    weights = []
    for idx in range(len(list_of_layer_dimensions) - 1):
        first_layer_dim = list_of_layer_dimensions[idx]
        second_layer_dim = list_of_layer_dimensions[idx + 1]
        weights.append(np.random.rand(second_layer_dim, first_layer_dim))
    return weights

def random_start_biases(list_of_layer_dimensions):
    """
    creates random start biases for given layers of neural network

    :param list_of_layer_dimensions: array of dimensions of particular layer starting with input layer,
    through hidden layers, out with output layer.
    :return: list of ndarrays -  biases for each dim except in input layer
    """
    biases = []
    for dim in list_of_layer_dimensions[1:]:
        biases.append(np.array(np.random.rand(dim), dtype=np.float))
    return biases

def sigmoid(x):
    """
    activation function - simple and classical sigmoid
    """
    return 1 / (1 + np.exp(-x))

def dsigmoid(x):
    """
    Derivative of sigmoid function
    """
    return sigmoid(x) * (1 - sigmoid(x))

class FeedForwardNN:
    """
    Feed forward neural network with:
    - cost function c(y*, y) = 0.5 * ||y* - y||^2
    - constant minibatch size of 1
    - default learning rate of 0.01
    """

    def __init__(self,
                 layer_dimensions: List[int],
                 activation_function=sigmoid,
                 activation_derivative=dsigmoid,
                 learning_rate=0.01) -> None:
        super().__init__()
        self.layer_dimensions = layer_dimensions
        self.w = random_start_weights(layer_dimensions)
        self.b = random_start_biases(layer_dimensions)
        self.activations = []
        self.z = []
        self.activation_function = activation_function
        self.activation_derivative = activation_derivative
        self.eta = learning_rate

    def forward(self, input_vector: np.array) -> np.array:
        """
    Executes a forward step.

    Given input vector, computes activation values of all neurons and memoizes
    them, next returns activation vector of neurons in the last layer

    :param input_vector: input vector of shape(0, layer_dimensions[0])
    :return: returns activation vector of output layer
    """
        for idx, layer in enumerate(self.layer_dimensions):
            if idx is 0:
                self.activations.append(input_vector)
            else:
                previous_a = self.activations[-1]
                zeta = np.dot(self.w[idx - 1], previous_a) + self.b[idx - 1]
                self.z.append(zeta)
                a = self.activation_function(zeta)
                self.activations.append(a)
        return self.activations[-1]

    def fit(self, xs, ys):
        """
        Fits the model against the learning set
        :param xs: data
        :param ys: labels
        :return: nothing, the function changes parameters (biases and weights)
        to fit the network against train data
        """
        for x, y in zip(xs, ys):
            self._fit_single(x, y)

    def _fit_single(self, x, y):
        predicted = self.forward(x)
        gradient_weights, gradient_biases = self.backward(y, predicted)
        self.update_weights_and_biases(gradient_biases, gradient_weights)

    def update_weights_and_biases(self, grad_biases, grad_weights):
        for i in range(len(self.w)):
            self.w[i] = self.w[i] - (self.eta * grad_weights[i])
        for i in range(len(self.b)):
            self.b[i] = self.b[i] - (self.eta * grad_biases[i])

    def backward(self, real, predicted):
        """
        Executes backpropagation algorithm fitting weights and biases against predicted value
        """
        gradient_weights = [np.zeros(weight.shape) for weight in self.w]
        gradient_biases = [np.zeros(bias.shape) for bias in self.b]

        # weights and biases from layer L-1 to layer L
        partial_cost_last_a = predicted - real
        delta = self.activation_derivative(self.z[-1])
        last_layer_neuron_factor = partial_cost_last_a * delta
        last_layer_weights_gradient = np.dot(last_layer_neuron_factor.reshape((-1, 1)),
                                             self.activations[-2].reshape((1, -1)))
        gradient_weights[-1] = last_layer_weights_gradient
        gradient_biases[-1] = last_layer_neuron_factor

        # weights for other hidden layers
        for i in range(len(self.activations) - 2, 0, -1):
            z_and_old_delta = self.z[i] * delta
            delta = np.dot(self.w[i].transpose(), z_and_old_delta)
            squashed_derivative = self.activation_derivative(self.z[i - 1])
            neuron_error = squashed_derivative * delta
            gradient_weights[i - 1] = np.dot(neuron_error.reshape((-1, 1)), self.activations[i - 1].reshape((1, -1)))
            gradient_biases[i - 1] = neuron_error
        return gradient_weights, gradient_biases


import math
import numpy as np
from numba import njit
from numba import cuda

"""
Loss = sum_i(sum_j(A[i,j] * abs(i-j)/(m^2)))
"""
def loss(matrix):
    # return loss_gpu(matrix) # use GPU
    return loss_cpu(matrix) # use CPU

@njit
def loss_cpu(elements):
    """
    This file directly optimize this loss function.
    calculate the whole matrix
    @return at the scale: Loss / 2
    """
    ret = 0
    l = elements.shape[0]
    _l_1 = 1.0/(l*l)
    for i in range(l):
        for j in range(i):
            if elements[i, j] > 0:
                ret += (i-j) * _l_1 * elements[i, j]  # here because j<i, we can safely ommit abs() for speed.
    return ret

@njit
def loss_gradient_if_swap(elements, target_i, target_j):
    """
    This file directly optimize this loss function.
    only calculate i and j-th row and col
    @return at the scale: Loss * l
    """
    ret = 0  # loss gained by swapping
    l = elements.shape[0]

    for m, m_inv in [[target_i, target_j], [target_j, target_i]]:
        for n in range(l):
            if elements[m, n] > 0 or elements[m_inv, n] > 0:
                if m != n and m_inv != n:
                    ret += (abs(m-n)-abs(m_inv-n)) * (elements[m, n] - elements[m_inv, n])
    return ret

@cuda.jit
def _loss_gpu(matrix, ret):
    """ CUDA kernel function for loss_gpu() """
    x, y = cuda.grid(2)
    if x<matrix.shape[0] and y<matrix.shape[1]: # Important: Don't use early return in CUDA functions, will cause Memory Error. Use cuda-memcheck to check memory.
        if y<x: # only compute half of the matrix
            if matrix[x, y] > 0:
                loss = (x-y) * ret[1] * matrix[x, y]
                cuda.atomic.add(ret, 0, loss)

def loss_gpu(matrix):
    """ same as loss(), but run on GPU """
    ret = np.array([0.0, 1/(matrix.shape[0]*matrix.shape[0])], dtype=np.float64)
    threadsperblock = (16, 16)
    blockspergrid_x = math.ceil(matrix.shape[0] / threadsperblock[0])
    blockspergrid_y = math.ceil(matrix.shape[1] / threadsperblock[1])
    blockspergrid = (blockspergrid_x, blockspergrid_y)
    _loss_gpu[blockspergrid, threadsperblock](matrix, ret)
    return ret[0]

@njit
def swap_inplace(elements, indices, i, j):
    """ swap the matrix and indices inplace at position i and j """
    _tmp = elements[i, :].copy()
    elements[i, :] = elements[j, :]
    elements[j, :] = _tmp

    _tmp = elements[:, i].copy()
    elements[:, i] = elements[:, j]
    elements[:, j] = _tmp

    # also swap indices to keep track of the direct way from original matrix to final matrix.
    if indices is not None:
        _tmp = indices[i]
        indices[i] = indices[j]
        indices[j] = _tmp


"""ETS Prediction Model"""
__docformat__ = "numpy"

import logging
from typing import Union

import numpy as np
import pandas as pd
from statsmodels.tsa.holtwinters import ExponentialSmoothing

from openbb_terminal.decorators import log_start_end

logger = logging.getLogger(__name__)

TRENDS = ["N", "A", "Ad"]
SEASONS = ["N", "A", "M"]

@log_start_end(log=logger)
def get_exponential_smoothing_model(
    data: Union[pd.Series, np.ndarray],
    trend: str = "N",
    seasonal: str = "N",
    seasonal_periods: int = 5,
    n_predict: int = 5,
):
    """
    Perform exponential smoothing
    Parameters
    ----------
    data: Union[pd.Series, np.ndarray]
        Series of closing values
    trend: str
        Trend component.  One of [N, A, Ad]
    seasonal: str
        Seasonal component.  One of [N, A, M]
    seasonal_periods: int
        Number of seasonal periods in a year
    n_predict: int
        Number of days to forecast

    Returns
    -------
    model:
        Exponential smoothing model
    title: str
        String describing selected model
    forecast : List[float]
        List of predictions
    """
    if trend == "N":  # None
        if seasonal == "N":  # None
            title = "Trend='N',  Seasonal='N': Simple Exponential Smoothing"
            ETS = ExponentialSmoothing(
                data,
                trend=None,
                damped_trend=False,
                seasonal=None,
            )
            model = ETS.fit(
                smoothing_level=None, smoothing_trend=None, damping_trend=None
            )

        elif seasonal == "A":  # Additive
            title = "Trend='N',  Seasonal='A': Exponential Smoothing"
            ETS = ExponentialSmoothing(
                data,
                trend=None,
                damped_trend=False,
                seasonal="add",
                seasonal_periods=seasonal_periods,
            )
            model = ETS.fit(smoothing_level=None, smoothing_seasonal=None)

        elif seasonal == "M":  # Multiplicative
            title = "Trend='N',  Seasonal='M': Exponential Smoothing"
            ETS = ExponentialSmoothing(
                data,
                trend=None,
                damped_trend=False,
                seasonal="mul",
                seasonal_periods=seasonal_periods,
            )
            model = ETS.fit(smoothing_level=None, smoothing_seasonal=None)

    elif trend == "A":  # Additive
        if seasonal == "N":  # None
            title = "Trend='A',  Seasonal='N': Holt’s linear method"
            ETS = ExponentialSmoothing(
                data,
                trend="add",
                damped_trend=False,
                seasonal=None,
            )
            model = ETS.fit(
                smoothing_level=None, smoothing_trend=None, damping_trend=None
            )

        elif seasonal == "A":  # Additive
            title = "Trend='A',  Seasonal='A': Additive Holt-Winters’ method"
            ETS = ExponentialSmoothing(
                data,
                trend="add",
                damped_trend=False,
                seasonal="add",
                seasonal_periods=seasonal_periods,
            )
            model = ETS.fit(
                smoothing_level=None, smoothing_trend=None, smoothing_seasonal=None
            )

        elif seasonal == "M":  # Multiplicative
            title = "Trend='A',  Seasonal='M': Multiplicative Holt-Winters’ method"
            ETS = ExponentialSmoothing(
                data,
                trend="add",
                damped_trend=False,
                seasonal="mul",
                seasonal_periods=seasonal_periods,
            )
            model = ETS.fit(
                smoothing_level=None, smoothing_trend=None, smoothing_seasonal=None
            )

    elif trend == "Ad":  # Additive damped
        if seasonal == "N":  # None
            title = "Trend='Ad', Seasonal='N': Additive damped trend method"
            ETS = ExponentialSmoothing(
                data,
                trend="add",
                damped_trend=True,
                seasonal=None,
            )
            model = ETS.fit(
                smoothing_level=None, smoothing_trend=None, damping_trend=None
            )

        elif seasonal == "A":  # Additive
            title = "Trend='Ad', Seasonal='A': Exponential Smoothing"
            ETS = ExponentialSmoothing(
                data,
                trend="add",
                damped_trend=True,
                seasonal="add",
                seasonal_periods=seasonal_periods,
            )
            model = ETS.fit(
                smoothing_level=None,
                smoothing_trend=None,
                damping_trend=None,
                smoothing_seasonal=None,
            )

        elif seasonal == "M":  # Multiplicative
            title = "Trend='Ad', Seasonal='M': Holt-Winters’ damped method"
            ETS = ExponentialSmoothing(
                data,
                trend="add",
                damped_trend=True,
                seasonal="mul",
                seasonal_periods=seasonal_periods,
            )
            model = ETS.fit(
                smoothing_level=None,
                smoothing_trend=None,
                damping_trend=None,
                smoothing_seasonal=None,
            )

    if model.mle_retvals.success:
        forecast = [max(i, 0) for i in model.forecast(n_predict)]

    else:
        forecast = []

    return model, title, forecast


# Polynomial Regression

# Importing the libraries
# Importando as bibliotecas
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

# Importing the dataset
# Importando os dados
dataset = pd.read_csv('Position_Salaries.csv')
X = dataset.iloc[:, 1:2].values
y = dataset.iloc[:, 2].values

# Fitting Linear Regression to the Dataset (for comparisson)
# Ajustando os dados para regressão linear (para comparação)
from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X, y)

# Fitting Polynomial Regression to the Dataset
# Ajustando os dados para regressão polinomial
from sklearn.preprocessing import PolynomialFeatures
poly_reg = PolynomialFeatures(degree = 4)
X_poly = poly_reg.fit_transform(X)
lin_reg_2 = LinearRegression()
lin_reg_2.fit(X_poly, y)

# Visualising the Linear Regression results
# Visualizando os resultados da Regressão Linear
plt.scatter(X, y, color = 'red')
plt.plot(X, lin_reg.predict(X), color = 'blue')
plt.title('Truth or Bluff (Linear Regression)')
plt.xlabel('Position leve')
plt.ylabel('Salary')
plt.show()

# Visualising the Polynomial Regression results
# Visualizando os resultados da Regressão Polinomial
X_grid = np.arange(min(X), max(X), 0.1)
X_grid = X_grid.reshape((len(X_grid), 1))
plt.scatter(X, y, color = 'red')
plt.plot(X_grid, lin_reg_2.predict(poly_reg.fit_transform(X_grid)), color = 'blue')
plt.title('Truth or Bluff (Polynomial Regression)')
plt.xlabel('Position leve')
plt.ylabel('Salary')
plt.show()

# Predicting a new result with Linear Regression
# Predizendo os resultados com Regressão Linear
lin_reg.predict([[6.5]])

# Predicting a new result with Polynomial Regression
# Predizendo os resultados com Regressão polinomial
lin_reg_2.predict(poly_reg.fit_transform([[6.5]]))


import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np
import glob
import os
import sys
import datetime
import urllib.request
import sys
from sklearn import datasets, linear_model
import csv
from scipy import stats
import pylab
Calculated_GDD=[]
df = pd.DataFrame()
df2 = pd.DataFrame()
tbase = 10
tupper = 50
startYear=2012
endYear=2017
#The function takes city name and years as input and calcultes Linear Regression for spesific citiy.
def LinearRegressionplots(cityname,tbase, tupper,startYear,endYear):
    """The function takes city name and years as input and calcultes Linear Regression for spesific citiy."""
    years=[2012,2013,2014,2015,2016,2017]
    for year in years:
        for fname in glob.glob('./input/'+str(cityname) + '_' + str(year) + '.csv'):#searches for the specific file in the input folder
            print(str(cityname) + '_' + str(year))
            Data=pd.read_csv(fname,header=0)
            df=pd.DataFrame(Data)
            year = list(df['Year'])[1]
            df = df[df["Date/Time"] != str(year)+"-02-29"]
            tempmax = df['Max Temp (Â°C)']
            tempmin = df['Min Temp (Â°C)']
            length = len(pd.Series.dropna(tempmin))
            #calculates the growing degree days based on the following input
            t= GDDcalculate(list(tempmin),list(tempmax), tbase, tupper, length)
            Calculated_GDD.append(t)
            #calculates the cumulative growing degree days
            Cumulative_GDD=np.cumsum(np.array(Calculated_GDD))
        mask = ~np.isnan(Cumulative_GDD)
        Cumulative_GDD=Cumulative_GDD[mask]
        total_gdd = Cumulative_GDD[-1]
        df2 = df.append({'year': int(year), 'gdd': total_gdd}, ignore_index=True)
    x = df2.year.values; y = df2.gdd.values
    x = x.reshape(x.size,1); y = y.reshape(y.size,1)

    regr = linear_model.LinearRegression()
    regr.fit(x, y)

    text = "slope: {:0.4}\nscore: {:0.4}".format(regr.coef_[0,0],regr.score(x,y))
    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    ax.text(0.05, 0.95, text,backgroundcolor='grey',verticalalignment='top', horizontalalignment='left',transform=ax.transAxes,color='black', fontsize=15)
    ax.scatter(x, y,  color='red')
    ax.plot(x, regr.predict(x), color='blue', linewidth=3)
    ax.set_title('Annual Growing Degree Days in {} from {} to {}'.format(cityname,startYear,endYear))
    ax.set_xlabel('Year')
    ax.set_ylabel('Total GDD')
    plt.savefig('./docs/LinearReg_{}_{}_{}.png'.format(cityname,startYear,endYear))


#coding: utf-8

from numpy import *

def loadDataSet(fileName, delim='\t'):
	fr = open(fileName)
	stringArr = [line.strip().split(delim) for line in fr.readlines()]
	datArr = [map(float,line) for line in stringArr]
	return mat(datArr)

#topNfeat是可选参数，即选择N个特征。如果不设置，则默认返回全部特征
def pca(dataMat, topNfeat=9999999):
	meanVals = mean(dataMat, axis=0)
	meanRemoved = dataMat - meanVals
	covMat = cov(meanRemoved, rowvar=0)
	eigVals, eigVects = linalg.eig(mat(covMat))
	eigValInd = argsort(eigVals)
	eigValInd = eigValInd[:-(topNfeat+1):-1]
	redEigVects = eigVects[:, eigValInd]
	lowDDataMat = meanRemoved * redEigVects
	reconMat = (lowDDataMat * redEigVects.T) + meanVals
	return lowDDataMat, reconMat

def replaceNanWithMean():
	datMat = loadDataSet('secom.data', ' ')
	numFeat = shape(datMat)[1]
	for i in range(numFeat):
		meanVal = mean(datMat[nonzero(~isnan(datMat[:,i].A))[0], i])
		datMat[nonzero(isnan(datMat[:,i].A))[0],i] = meanVal
	return datMat


#! /usr/bin/env python

"""
File: centered_diff.py

Copyright (c) 2016 Taylor Patti

License: MIT

Takes the first derivative of functions numerically and demonstrates this with a set of
functions and a resulting table.
"""

from math import *
from sympy import diff, lambdify, symbols

def numdiff(f, x, h=1E-5):
    """takes the first derivative of function f"""
    return (f(x + h) - f(x - h)) / (2 * float(h))

def quadratic(x):
    return x**2 + x + 1

def test_quaddiff():
    apt = (abs(numdiff(quadratic, 2) - 5) < 1E-10)
    msg = "Derivatives do not match."
    assert apt, msg

def application():
    """makes list of the difference between the estimated derivative for h=0.01 and
    the analytical derivative"""
    application_list = []
    x = symbols('x')
    print
    print '%20s %20s' % ('Function', 'Error')
    print
    funcvar_tuples = [(lambda t: exp(t), 'exp(x)', float(0)), (lambda t : exp(-2*t**2), \
    'exp(-2*x**2)', float(0)), (lambda t: cos(t), 'cos(x)', 2*pi), (lambda t: log(t), \
    'log(x)', float(1))]
    for i in funcvar_tuples:
        prime = diff(i[1], x)
        exact = lambdify([x], prime)
        error = numdiff(i[0], i[2], 0.01) - exact(i[2])
        print '%20s %21.2E' % (i[1], error)
        print
        application_list.append(error)
    return application_list

def test_accuracycheck():
    """ensures that each item in application is bellow a certain threshold
    and thus above a certain accuracy"""
    f = application()
    apt = True
    for i in f:
        if abs(i) > 1E-3:
            apt = False
    msg = "Too large of an error."
    assert apt, msg


import numpy as np

class SimpleLinearRegression():
    def __init__(self):
        self.coefficient = None
        self.intercept = None

    def fit(self, x, y):
        '''
            Given a dataset with 1 input feature x and output feature y,
            estimates the coefficient and compute the intercept.
        '''
        self.coefficient = self._coefficient_estimate(x, y)
        self.intercept = self._compute_intercept(x, y)

    def predict(self, x):
        '''
            y = b_0 + b_1*x
        '''
        x_times_coeff = np.multiply(x, self.coefficient)
        return np.add(x_times_coeff, self.intercept)

    def r2_score(self, y_true, y_pred):
        '''
            r2 = 1 - (rss/tss)
            rss = sum_{i=0}^{n} (y_i - y_hat)^2
            tss = sum_{i=0}^{n} (y_i - y_bar)^2
        '''
        y_average = np.average(y_true)

        residual_sum_of_squares = 0
        total_sum_of_squares = 0

        for i in range(len(y_true)):
            residual_sum_of_squares += (y_true[i] - y_pred[i])**2
            total_sum_of_squares += (y_true[i] - y_average)**2

        return 1 - (residual_sum_of_squares/total_sum_of_squares)

    def _compute_intercept(self, x, y):
        '''
            intercept = y_bar - coefficient*x_bar

            WHERE:  y_bar = average(y),
                    x_bar = average(x),
                    coefficient = coefficient already estimated
        '''
        # find the average of the array x
        x_average = np.average(x)

        # multiply the coefficient and the average of the x values
        mul = self.coefficient*x_average

        return np.average(y) - mul

    def _coefficient_estimate(self, x, y):
        '''
            coefficient_{x,y} = ∑_{i=0}^{n} (x_i - x_bar) * (y_i - y_bar)
                                _________________________________________
                                ∑_{i=0}^{n} (x_i - x_bar)^2
        '''
        numerator = 0
        denominator = 0

        for i in range(len(x)):
            x_value = x[i]
            y_value = y[i]
            x_average = np.average(x)
            y_average = np.average(y)

            numerator += (x_value - x_average) * (y_value - y_average)
            denominator += (x_value - x_average)**2

        return numerator / denominator


import sys
import numpy as np
import matplotlib.pyplot as plt
#from matplotlib.patches import Circle
import math

def W(x, y):
    """Return the wind vector given a wind speed."""
    r = np.sqrt(x*x+y*y)
    v = V(r)
    if r>0:
        costheta = x/r
        sintheta = y/r
        return [-sintheta*v,costheta*v]
    else:
        return [0,0]

def V(r):
    return 2*r*r*np.exp(-r)

def example(n):
    # Grid of x, y points
    nx, ny = n, n
    x = np.linspace(-2, 2, nx)
    y = np.linspace(-2, 2, ny)

    # Wind field vector components U,V
    U, V = np.zeros((ny, nx)), np.zeros((ny, nx))
    for j in range(ny-1,-1,-1):
        for i in range(0,nx):
            vv = W(x[i],y[j])
            U[j,i]=vv[0]
            V[j,i]=vv[1]

    fig = plt.figure()
    ax1 = fig.add_subplot(1,1,1)

    # Plot the streamlines.
    ax1.streamplot(x, y, U, V, color=np.sqrt(U*U+V*V), cmap='Spectral')
    ax1.set_xlabel('$x$')
    ax1.set_ylabel('$y$')
    ax1.set_xlim(-2,2)
    ax1.set_ylim(-2,2)
    ax1.set_aspect('equal')
    plt.title('Tangential Wind Vectors')
    plt.show()

if __name__=='__main__':
    example(8)


"""
# !/usr/bin/env python
# -*- coding: utf-8 -*-
@Time        : 2022/3/26 13:25
@File        : cross-entropy.py
"""

import numpy as np

# Write a function that takes as input two lists Y, P,
# and returns the float corresponding to their cross-entropy.
def cross_entropy(Y, P):
    """
    cross_entropy
    """
    Y = np.float_(Y)
    P = np.float_(P)

    return -np.sum(Y * np.log(P) + (1 - Y) * np.log(1 - P))

udacity-program_self_driving_car_engineer_v1.0/part01-computer vision and deep learning/module03-deep learning/lesson01-introduction to neural networks/exercise04-cross entropy/cross-entropy.py


#1

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

#2

np.random.seed(42)

# Function for creating datapoints in the form of a circle
def PointsInCircum(r,n=100):
    return [(math.cos(2*math.pi/n*x)*r+np.random.normal(-30,30),math.sin(2*math.pi/n*x)*r+np.random.normal(-30,30)) for x in range(1,n+1)]

#3

# Creating data points in the form of a circle
df=pd.DataFrame(PointsInCircum(500,1000))
df=df.append(PointsInCircum(300,700))
df=df.append(PointsInCircum(100,300))

# Adding noise to the dataset
df=df.append([(np.random.randint(-600,600),np.random.randint(-600,600)) for i in range(300)])

#4

plt.figure(figsize=(10,10))
plt.scatter(df[0],df[1],s=15,color='grey')
plt.title('Dataset',fontsize=20)
plt.xlabel('Feature 1',fontsize=14)
plt.ylabel('Feature 2',fontsize=14)
plt.show()