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

# Name: Baylee Mumma, Christine Outlaw, Kristen Peet
# Email: mumma103@mail.chapman.edu
# Course: PHYS220/MATH220/CPSC220 Fall 2017
# Assignment: CLASSWORK 6

import numpy as np
import matplotlib.pyplot as plt

def derivative(a,b,n):
    """derivative(a, b, n=1000)
    Generate a matrix used for obtaining the first derivative.

    Args:
        a (float) : Lower bound of domain
        b (float) : Upper bound of domain
        n (int, optional) : Number of points in domain, defaults to 1000.

    Returns:
        D : A nxn matrix that represents the finite difference operation
    """
    dx = (b-a)/(n-1)
    D=(1/2)*(np.eye(n+1,n+1,1)-np.eye(n+1,n+1,-1))
    D[0][0] = -1
    D[-1][-1] = 1
    D[0][1] = 1
    D[-1][-2] = -1
    D = D/(dx)
    return D

def second_derivative(a,b,n):
    """second_derivative(a, b, n=1000)
    Generate a matrix used for obtaining the second derivative.

    Args:
        a (float) : Lower bound of domain
        b (float) : Upper bound of domain
        n (int, optional) : Number of points in domain, defaults to 1000.

    Returns:
        D2 : A nxn matrix that represents the finite difference operation applied to itself
    """
    dx = (b-a)/(n-1)
    D2 = np.eye(n+1,n+1,0)*-2+np.eye(n+1,n+1,2)+np.eye(n+1,n+1,-2)
    D2[0][0]=2
    D2[0][1]=-4
    D2[0][2]=2
    D2[1][0]=2
    D2[1][1]=-3
    D2[1][3]=1
    D2[-2][-1]=2
    D2[-2][-2]=-3
    D2[-2][-4]=1
    D2[-1][-1]=2
    D2[-1][-2]=-4
    D2[-1][-3]=2
    D2 = D2/((2*dx)**2)
    return D2

def gen_f_array(a,b,n):               ### The tests are failing due to the extra indent space in the line below this one
     """gen_f_array(a, b, n=1000)
    Generate a discrete approximation of y = x^2, including its
    domain and range, stored as a pair of numpy arrays.

    Args:
        a (float) : Lower bound of domain
        b (float) : Upper bound of domain
        n (int, optional) : Number of points in domain, defaults to 1000.

    Returns:
        (x, f) : Pair of numpy arrays of float64
            x  : [a, ..., b] Array of n equally spaced float64 between a and b
            f  : [f(a), ..., f(b)] Array of the function's return value at each domain point x
    """
    x = np.linspace(a,b,n+1)
    f = x**2
    return x,f

def gen_s_array(a,b,n):
    """gen_f_array(a, b, n=1000)
    Generate a discrete approximation of sin, including its
    domain and range, stored as a pair of numpy arrays.

    Args:
        a (float) : Lower bound of domain
        b (float) : Upper bound of domain
        n (int, optional) : Number of points in domain, defaults to 1000.

    Returns:
        (x, s) : Pair of numpy arrays of float64
            x  : [a, ..., b] Array of n equally spaced float64 between a and b
            s  : [s(a), ..., s(b)] Array of the function's return value at each domain point x
    """
    x = np.linspace(a,b,n+1)
    s = np.sin(x)
    return x,s

def gen_g_array(a,b,n):
    """gen_f_array(a, b, n=1000)
    Generate a discrete approximation of a gaussian bellcurve, including its
    domain and range, stored as a pair of numpy arrays.

    Args:
        a (float) : Lower bound of domain
        b (float) : Upper bound of domain
        n (int, optional) : Number of points in domain, defaults to 1000.

    Returns:
        (x, g) : Pair of numpy arrays of float64
            x  : [a, ..., b] Array of n equally spaced float64 between a and b
            g  : [g(a), ..., g(b)] Array of the function's return value at each domain point x
    """
    x = np.linspace(a,b,n+1)
    g = np.exp((-x**2)/2)/(np.sqrt(2*np.pi))
    return x,g

def plot(x,y,D,D2,title):
    """plot(x,y,D,D2,title)
    Generate a plot of a function and its first and second derivatives.

    Args:
        x (array)      : Numpy array of the domain, with evenly spaced points
        y (array)      : Numpy array of the range
        D (array)      : First derivative matrix
        D2 (array)     : Second derivative matrix
        title (string) : Title of the plot

    Returns:
        (x, y)  : Pair of numpy arrays of float64 representing the original function
        (x, d1) : Pair of numpy arrays representing the first derivative of the function
            d1  : The first derivative matrix multiplied with the range array (y)
        (x, d2) : Pair of nummpy arrays representing the second derivative of the function
            d2  : The second derivative matrix multiplied with the rage array (y)

    """
    d1 = D@y
    d2 = D2@y
    plt.plot(x,y, "gray")
    plt.plot(x,d1, "hotpink")
    plt.plot(x,d2, "darkred")
    plt.xlabel('x')
    plt.ylabel('y')
    plt.title(title, fontsize =20)
    plt.legend(['function','first derivative','second derivative'])
    plt.show()


#Using built in Single Value Decomposition function, when given a matrix, print out the decomp and plot the geometric
#representation of the decomposition to show how the matrix affects a unit circle.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from math import atan2, degrees

def SVD(matrix):
    U, d, V = np.linalg.svd(matrix, full_matrices=True)
    s = d.shape[0]
    D = np.zeros((U.shape[1], V.shape[0]))
    D[:s,:s] = np.diag(d)
    return [U,D,V]

def showDecomp(matrix):
    decomp = SVD(matrix)
    U = decomp[0]
    D = decomp[1]
    V = decomp[2]
    print("A=UDV'")
    print("The Matrix A:")
    print(U @ D @ V)
    print("The U matrix:")
    print(U)
    print("The D matrix:")
    print(D)
    print("The V' Matrix:")
    print(V)

'''
In order to use matplotlib's ellipse plotter, we must know the
counterclockwise rotation the ellipse does when transformed by the
matrix in question. I do this by finding the angle between u1 and e1
with the function rotation
'''

def rotation(x,y):
    alpha = degrees(atan2(y,x))
    return (alpha + 360) % 360

'''
geoSVD plots the unit circle with V' vectors and the transformed ellipse with
U Vector as the major axes
'''
def geoSVD(matrix):
    decomp = SVD(matrix)
    U, D, V = decomp[0], decomp[1], decomp[2]
    plt.figure(1)
    ax = plt.subplot(121)
    ax.arrow(0, 0, V[0][0], V[0][1], color = "r", head_width = .1, length_includes_head= True)
    ax.arrow(0, 0, V[1][0], V[1][1], color = "blue", head_width = .1, length_includes_head= True)
    circ = plt.Circle((0,0),1, fill=False)
    ax.add_patch(circ)
    plt.axis('scaled')
    plt.title("Unit Circle with V' vectors")
    ax2 = plt.subplot(122)
    ellipse = Ellipse((0,0),2*D[0][0], 2*D[1][1], angle = (rotation(U[0][0],U[0][1])), fill = False)
    ax2.add_patch(ellipse)
    ax2.arrow(0, 0, D[0][0]*U[0][0], D[0][0]*U[0][1], color = "r", head_width = .1, length_includes_head= True)
    if D[1][1]==0:
        plt.axis("square")
    else:
        ax2.arrow(0, 0, D[1][1]*U[1][0], D[1][1]*U[1][1], color = "blue", head_width = .1, length_includes_head= True)
        plt.axis('scaled')
    plt.title("Transformed Ellipse with U vectors")
    plt.subplots_adjust(top=1, bottom=0, left=0, right=1, wspace=0.25)
    plt.show()

#example matrices below
'''
geoSVD([[3,0],[0,-2]])

geoSVD([[2,0],[0,3]])

geoSVD([[0,2],[0,0],[0,0]])

geoSVD([[1,1],[0,0]])

geoSVD([[1,1],[1,1]])

showDecomp([[3,0],[0,-2]])

showDecomp([[2,0],[0,3]])

showDecomp([[0,2],[0,0],[0,0]])

showDecomp([[1,1],[0,0]])

showDecomp([[1,1],[1,1]])

geoSVD([[1,2],[0,2]])
'''


# -*- coding: utf-8 -*-
"""
Code adapted from lenspack (Austin Peel, Cosmostat) for jax compatibiliy.
https://github.com/austinpeel/lenspack/blob/master/lenspack/image/inversion.py
"""

import jax.numpy as np
import jax
from jax import random

def ks93(g1, g2):
    """Direct inversion of weak-lensing shear to convergence.
    This function is an implementation of the Kaiser & Squires (1993) mass
    mapping algorithm. Due to the mass sheet degeneracy, the convergence is
    recovered only up to an overall additive constant. It is chosen here to
    produce output maps of mean zero. The inversion is performed in Fourier
    space for speed.
    Parameters
    ----------
    g1, g2 : array_like
        2D input arrays corresponding to the first and second (i.e., real and
        imaginary) components of shear, binned spatially to a regular grid.
    Returns
    -------
    kE, kB : tuple of numpy arrays
        E-mode and B-mode maps of convergence.
    Raises
    ------
    AssertionError
        For input arrays of different sizes.
    See Also
    --------
    bin2d
        For binning a galaxy shear catalog.
    Examples
    --------
    >>> # (g1, g2) should in practice be measurements from a real galaxy survey
    >>> g1, g2 = 0.1 * np.random.randn(2, 32, 32) + 0.1 * np.ones((2, 32, 32))
    >>> kE, kB = ks93(g1, g2)
    >>> kE.shape
    (32, 32)
    >>> kE.mean()
    1.0842021724855044e-18
    """
    # Check consistency of input maps
    assert g1.shape == g2.shape

    # Compute Fourier space grids
    (nx, ny) = g1.shape
    k1, k2 = np.meshgrid(np.fft.fftfreq(ny), np.fft.fftfreq(nx))

    # Compute Fourier transforms of g1 and g2
    g1hat = np.fft.fft2(g1)
    g2hat = np.fft.fft2(g2)

    # Apply Fourier space inversion operator
    p1 = k1 * k1 - k2 * k2
    p2 = 2 * k1 * k2
    k2 = k1 * k1 + k2 * k2
    #k2[0, 0] = 1  # avoid division by 0
    k2 = jax.ops.index_update(k2, jax.ops.index[0, 0], 1.) # avoid division by 0
    kEhat = (p1 * g1hat + p2 * g2hat) / k2
    kBhat = -(p2 * g1hat - p1 * g2hat) / k2

    # Transform back to pixel space
    kE = np.fft.ifft2(kEhat).real
    kB = np.fft.ifft2(kBhat).real

    return kE, kB

def ks93inv(kE, kB):
    """Direct inversion of weak-lensing convergence to shear.
    This function provides the inverse of the Kaiser & Squires (1993) mass
    mapping algorithm, namely the shear is recovered from input E-mode and
    B-mode convergence maps.
    Parameters
    ----------
    kE, kB : array_like
        2D input arrays corresponding to the E-mode and B-mode (i.e., real and
        imaginary) components of convergence.
    Returns
    -------
    g1, g2 : tuple of numpy arrays
        Maps of the two components of shear.
    Raises
    ------
    AssertionError
        For input arrays of different sizes.
    See Also
    --------
    ks93
        For the forward operation (shear to convergence).
    """
    # Check consistency of input maps
    assert kE.shape == kB.shape

    # Compute Fourier space grids
    (nx, ny) = kE.shape
    k1, k2 = np.meshgrid(np.fft.fftfreq(ny), np.fft.fftfreq(nx))

    # Compute Fourier transforms of kE and kB
    kEhat = np.fft.fft2(kE)
    kBhat = np.fft.fft2(kB)

    # Apply Fourier space inversion operator
    p1 = k1 * k1 - k2 * k2
    p2 = 2 * k1 * k2
    k2 = k1 * k1 + k2 * k2
    #k2[0, 0] = 1  # avoid division by 0
    k2 = jax.ops.index_update(k2, jax.ops.index[0, 0], 1) # avoid division by 0
    g1hat = (p1 * kEhat - p2 * kBhat) / k2
    g2hat = (p2 * kEhat + p1 * kBhat) / k2

    # Transform back to pixel space
    g1 = np.fft.ifft2(g1hat).real
    g2 = np.fft.ifft2(g2hat).real

    return g1, g2

if __name__=='__main__':

    key = random.PRNGKey(0)

    # (g1, g2) should in practice be measurements from a real galaxy survey
    g1, g2 = 0.1 * random.normal(key, (2, 32, 32)) + 0.1 * np.ones((2, 32, 32))
    #g1, g2 = 0.1 * np.random.randn(2, 32, 32) + 0.1 * np.ones((2, 32, 32))
    kE, kB = ks93(g1, g2)
    print(np.mean(kE))

    # Computing shear from convergence
    gamma1, gamma2 = ks93inv(kE, kB)
    print('gamma1.shape', gamma1.shape)


#!/usr/bin/env python
"""
matrix factorization code
"""

import numpy as np

def matrix_factorization(R, P, Q, K, steps, alpha, beta):
    """
    matrix factorization
    R = rating matrix
    P = User features matrix
    Q = Item features matrix
    K = latent features
    steps = number of iterations
    alpha = learning rate
    beta = regularization parameter
    """
    Q_t = Q.T
    for step in range(steps):
        for i, elem_i in enumerate(R):
            for j, elem_j in enumerate(elem_i):
                if elem_j <= 0:
                    continue
                e_i_j = elem_j - np.dot(P[i, :], Q_t[:, j])
                for k in range(K):
                    P[i][k] = P[i][k] + alpha * \
                        (2 * e_i_j * Q_t[k][j] - beta * P[i][k])
                    Q_t[k][j] = Q_t[k][j] + alpha * \
                        (2 * e_i_j * P[i][k] - beta * Q_t[k][j])
        err = 0.
        for i, elem_i in enumerate(R):
            for j, elem_j in enumerate(elem_i):
                if elem_j <= 0:
                    continue
                err = err + (elem_j - np.dot(P[i, :], Q_t[:, j])) ** 2
                for k in range(K):
                    err = err + (beta / 2) * (P[i][k] ** 2 + Q_t[k][j] ** 2)
        if err < 1e-4:
            break

    Q = Q_t.T
    return P, Q

def test():
    """
    test script
    """
    R = np.array([
        [5, 3, 0, 1],
        [4, 0, 0, 1],
        [1, 1, 0, 5],
        [1, 0, 0, 4],
        [0, 1, 5, 4],
    ])

    nRow, nCol = len(R), len(R[0])
    K = 2
    P = np.random.rand(nRow, K)
    Q = np.random.rand(nCol, K)

    steps = 5000
    alpha = 0.0002
    beta = 0.02

    nP, nQ = matrix_factorization(R, P, Q, K, steps, alpha, beta)
    print(np.dot(nP, nQ.T))
    print(R)

    steps = 10000
    alpha = 0.0002
    beta = 0.02

    nP, nQ = matrix_factorization(R, P, Q, K, steps, alpha, beta)
    print(np.dot(nP, nQ.T))
    print(R)

if __name__ == '__main__':
    test()


from numpy import random

def distribution_generator(num_samples, distribution_type, mean=0, sd=1, interval=1, n=1, p=0.5):
    """ Generate random data within a given distribution

    :param num_samples: Int The number of samples to be returned
    :param distribution_type: String The type of distribution to be used
    :param mean: The Mean value for a normal distribution
    :param sd: The Standard Deviation for a normal distribution
    :param interval: The Interval for a poisson distribution
    :param n: The number of samples for a binomial distribution
    :param p: The probability for a binomial distribution
    :return: ndarray
    """
    if distribution_type == "normal":
        return random.normal(size=num_samples, loc=mean, scale=sd)
    elif distribution_type == "poisson":
        return random.poisson(size=num_samples, lam=interval)
    elif distribution_type == "binomial":
        return random.binomial(size=num_samples, n=n, p=p)
    else:
        raise ValueError(distribution_type + " is not a valid distribution type")


import matplotlib.pyplot as plt
import numpy as np

def F(W, L, d):
    return d**L*(1 - d)/(1 - d**W)

W = 6
d = np.linspace(0.0, 1.0, 1000, endpoint=False)

plt.figure()
for L in xrange(0, W):
    plt.plot(d, F(W, L, d))
plt.savefig('F_jk_no_labels.svg')

plt.figure()
W = 10
L = np.arange(W)
j = L - 0.4
d = 0.8
v = np.roll(F(W, L, d), 2)
plt.bar(j, v, width=0.8, color='r', label='d=0.8')
plt.hold(True)
j = L - 0.3
d = 0.3
v = np.roll(F(W, L, d), 2)
plt.bar(j, v, width=0.6, color='b', label='d=0.3')
plt.xlim(-0.5, W - 0.5)
plt.legend()
plt.title(r'$F(l,d)$ $W=10$')
plt.xlabel('Motif state')
plt.ylabel(r'$F$')
plt.savefig('F_jk_bars.svg')
plt.savefig('F_jk_bars.pdf')


from gs_orth import *
import numpy as np

def qr_decomposition_solver(A,B):
    """
    function that takes arrays A,B of A.x = B and returns list x (top to bottom)
    this function does this using QR decomposition with Gram-Schmidt orthogonalization
    followed by back substitution

    Inputs: Lists A,B (converted to arrays in the function)

    Outputs: the list x
    """

    # perform Gram-Schmidt orthogonalization
    matrix = np.array(A)
    columns,on_basis_vec = gs_orthogonalization(matrix)
    # columns store the value of columns of matrix A
    # on_basis_vec stores the value of the orthonormal basis vectors
    # these vectors are obtained using Gram-Schmidt orthogonalization

    # perform QR decomposition
    # calculating Q
    Q_t = []
    for vector in on_basis_vec:
        # adding the orthonormal basis vectors as rows
        Q_t.append(vector.tolist())
    Q_t = np.array(Q_t)
    # to get orthonormalbasis vectors as columns, taking transpose
    Q = Q_t.T

    """
    # checking is Q is orthogonalization
    check = Q_t.dot(Q) #multiplying Q_transpose and Q to check determinant
    print( np.linalg.det(check))
    # output should be 1
    """
    # calculating R
    # initializing R matrix
    n_cols = matrix.shape[1]
    R = np.zeros((n_cols,n_cols))

    # populating the R matrix
    for i in range(n_cols):
        for j in range(i,n_cols):
            R[i][j] = np.dot(columns[j],on_basis_vec[i])

    # QR decomposition done

    """
    we know that : A.x = B is reduced using QR decomposition to : R.x = Q_t.B
    """
    RHS = Q_t.dot(np.array(B))

    # using back substitution to solve for co-efficients
    b = []
    b.append(RHS[n_cols-1]/R[n_cols-1][n_cols-1])
    for i in range(n_cols-2,-1,-1):
        val = RHS[i]
        for j in range(0,n_cols-1-i):
            val = val - (R[i][n_cols-1-j])*(b[j])
        b.append(val/R[i][i])

    # since we are using back substitution, we found bn first, then b_(n-1) upto b_0
    # thus the list b contains the coefficients in the reverse order
    # therefore, reversing the list to get the indexes to match their coefficient number
    b.reverse()

    return b


## 1. Introduction to the data ##

import pandas
import matplotlib.pyplot as plt

# Read data from csv
pga = pandas.read_csv("pga.csv")

# Normalize the data
pga.distance = (pga.distance - pga.distance.mean()) / pga.distance.std()
pga.accuracy = (pga.accuracy - pga.accuracy.mean()) / pga.accuracy.std()
print(pga.head())

plt.scatter(pga.distance, pga.accuracy)
plt.xlabel('normalized distance')
plt.ylabel('normalized accuracy')
plt.show()

## 2. Linear model ##

from sklearn.linear_model import LinearRegression
import numpy as np

# We can add a dimension to an array by using np.newaxis
print("Shape of the series:", pga.distance.shape)
print("Shape with newaxis:", pga.distance[:, np.newaxis].shape)

# The X variable in LinearRegression.fit() must have 2 dimensions
linear_model = LinearRegression()
linear_model.fit(pga.distance[:,np.newaxis], pga.accuracy)
theta1 = linear_model.coef_[0]

## 3. Cost function, introduction ##

# The cost function of a single variable linear model
def cost(theta0, theta1, x, y):
    # Initialize cost
    J = 0
    # The number of observations
    m = len(x)
    # Loop through each observation
    for i in range(m):
        # Compute the hypothesis
        h = theta1 * x[i] + theta0
        # Add to cost
        J += (h - y[i])**2
    # Average and normalize cost
    J /= (2*m)
    return J

# The cost for theta0=0 and theta1=1
print(cost(0, 1, pga.distance, pga.accuracy))

theta0 = 100
theta1s = np.linspace(-3,2,100)
costs = []
for theta1 in theta1s:
    costs.append(cost(theta0, theta1, pga.distance, pga.accuracy))

plt.plot(theta1s, costs)

## 4. Cost function, continued ##

import numpy as np
from mpl_toolkits.mplot3d import Axes3D

# Example of a Surface Plot using Matplotlib
# Create x an y variables
x = np.linspace(-10,10,100)
y = np.linspace(-10,10,100)

# We must create variables to represent each possible pair of points in x and y
# ie. (-10, 10), (-10, -9.8), ... (0, 0), ... ,(10, 9.8), (10,9.8)
# x and y need to be transformed to 100x100 matrices to represent these coordinates
# np.meshgrid will build a coordinate matrices of x and y
X, Y = np.meshgrid(x,y)
print(X[:5,:5],"\n",Y[:5,:5])

# Compute a 3D parabola
Z = X**2 + Y**2

# Open a figure to place the plot on
fig = plt.figure()
# Initialize 3D plot
ax = fig.gca(projection='3d')
# Plot the surface
ax.plot_surface(X=X,Y=Y,Z=Z)

plt.show()

# Use these for your excerise
theta0s = np.linspace(-2,2,100)
theta1s = np.linspace(-2,2, 100)
COST = np.empty(shape=(100,100))

T0s,T1s = np.meshgrid(theta0s,theta1s)

for i in range(100):
    for j in range(100):
        COST[i,j] = cost(T0s[0,i], T1s[j,0], pga.distance,pga.accuracy)
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X=X,Y=Y,Z=COST)
plt.show()

## 5. Cost function, slopes ##

def partial_cost_theta1(theta0, theta1, x, y):
    # Hypothesis
    h = theta0 + theta1*x
    # Hypothesis minus observed times x
    diff = (h - y) * x
    # Average to compute partial derivative
    partial = diff.sum() / (x.shape[0])
    return partial

def partial_cost_theta0(theta0,theta1,x,y):
    h = theta0 + theta1 * x
    diff = h - y
    partial = diff.sum() / (x.shape[0])
    return partial
partial1 = partial_cost_theta1(0, 5, pga.distance, pga.accuracy)
print("partial1 =", partial1)

partial0 = partial_cost_theta0(1,1,pga.distance,pga.accuracy)
print("partial0 = ", partial0)

## 6. Gradient descent algorithm ##

# x is our feature vector -- distance
# y is our target variable -- accuracy
# alpha is the learning rate
# theta0 is the intial theta0
# theta1 is the intial theta1
def gradient_descent(x, y, alpha=0.1, theta0=0, theta1=0):
    max_epochs = 1000 # Maximum number of iterations
    counter = 0      # Intialize a counter
    c = cost(theta1, theta0, pga.distance, pga.accuracy)  ## Initial cost
    costs = [c]     # Lets store each update
    # Set a convergence threshold to find where the cost function in minimized
    # When the difference between the previous cost and current cost
    #        is less than this value we will say the parameters converged
    convergence_thres = 0.000001
    cprev = c + 10
    theta0s = [theta0]
    theta1s = [theta1]

    # When the costs converge or we hit a large number of iterations will we stop updating
    while (np.abs(cprev - c) > convergence_thres) and (counter < max_epochs):
        cprev = c
        # Alpha times the partial deriviative is our updated
        update0 = alpha * partial_cost_theta0(theta0, theta1, x, y)
        update1 = alpha * partial_cost_theta1(theta0, theta1, x, y)

        # Update theta0 and theta1 at the same time
        # We want to compute the slopes at the same set of hypothesised parameters
        #             so we update after finding the partial derivatives
        theta0 -= update0
        theta1 -= update1

        # Store thetas
        theta0s.append(theta0)
        theta1s.append(theta1)

        # Compute the new cost
        c = cost(theta0, theta1, pga.distance, pga.accuracy)

        # Store updates
        costs.append(c)
        counter += 1   # Count

    return {'theta0': theta0, 'theta1': theta1, "costs": costs}

print("Theta1 =", gradient_descent(pga.distance, pga.accuracy)['theta1'])
gd = gradient_descent(pga.distance,pga.accuracy, 0.01)
plt.scatter(np.arange(0,len(gd["costs"])),gd["costs"])
plt.show()

Machine learning Intermediate/Gradient descent-120.py


import cv2
import numpy as np
import matplotlib.pyplot as plt
"""
Main idea: Low pass filters block high-frequency parts of an image.
In other words, it has blurring effect on images.

Mathematically, we are taking the average of the center pixel and its surrounding
neighbors.
"""

def remove_noise(image, weight):
    img_copy = np.copy(image)

    # Apply low pass filter to remove image.
    # The way this works is that we remove low-intensity pixels from the image
    # to smoothen out the image
    # In the example above, we weigh all neighboring pixels the same
    # IMPORTANT: The sum of all the weights should add up to one
    low_pass_filter = 1/9 * np.array([
        [weight, weight, weight],
        [weight, weight, weight],
        [weight, weight, weight]
    ])

    return cv2.filter2D(img_copy, -1, low_pass_filter)

def gaussian_blur(image):
    """
    Might be the most commonly used low-pass filter.
    It is useful for preserving edges and
    blocking high-frequency parts of an image.

    Once again, the values are positive and normalized, meaning the weighted sum of
    values in the filter add up to one.
    """
    img_copy = np.copy(image)

    # Sums up to 16
    # Weighted sum of pixels based on distance from center
    # Gives most weight to center pixel and
    # proportionally weighs neighboring pixels based
    # on distance from center pixed
    gaussian_filter = 1/16 * np.array([
        [1, 2, 1],      # 4
        [2, 4, 2],      # 8
        [1, 2, 1]       # 4
    ])

    return cv2.filter2D(img_copy, -1, gaussian_filter)

if __name__ == "__main__":
    image = cv2.imread("../../images/cat_image.jpeg")
    image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Try fiddling around with this value
    weight = 2
    noise_removed = remove_noise(image, weight)

    # Visualize images before and after removing noise
    fig, (left_axis, right_axis) = plt.subplots(1, 2, figsize=(20, 10))

    left_axis.set_title("Original image")
    left_axis.imshow(image_gray, cmap='gray')

    right_axis.set_title("Noise removed (with low pass filter)")
    right_axis.imshow(noise_removed, cmap='gray')
    fig.show()

    # Visualize gaussian blur
    fig, (left_axis, right_axis) = plt.subplots(1, 2, figsize=(20, 10))

    left_axis.set_title("Original image")
    left_axis.imshow(image_gray, cmap='gray')

    right_axis.set_title("Gaussian blur")
    right_axis.imshow(gaussian_blur(image_gray), cmap='gray')
    fig.show()

    # Apply sobel vertical to images
    sobel_vertical = np.array([
        [-1, 0, 1],
        [-2, 0, 2],
        [-1, 0, 1]
    ])

    fig, (left_axis, right_axis) = plt.subplots(1, 2, figsize=(20, 10))

    left_axis.set_title("Original image (sobel filtered)")
    left_axis.imshow(cv2.filter2D(image_gray, -1, sobel_vertical), cmap='gray')

    right_axis.set_title("Gaussian blur (sobel filtered)")
    right_axis.imshow(cv2.filter2D(gaussian_blur(image_gray), -1, sobel_vertical), cmap='gray')
    fig.show()


import numpy as np
import scipy.stats as ss
import matplotlib.pyplot as plt
from matplotlib.patches import Patch

plt.style.use("/home/ventsi/Work/mpl-supermongo/supermongo.mplstyle")

def norm_plot(x, mu, std, **kwargs):
    """
    Easily plot a normal (Gaussian) distribution with given values.
    Keyword arguments are passed to the plt.fill_between() function.
    """
    y = ss.norm.pdf(x, mu, std)

    plt.fill_between(x, 0, y, **kwargs)
    plt.plot(x, y, linestyle="None")

x = np.linspace(-5, 5, 5000)

norm_plot(x, 0, 1, alpha=0.65)
norm_plot(x, -2, 1.5, alpha=0.65)
norm_plot(x, 2, 2.25, alpha=0.65)

plt.xlim(-5, 5)
plt.ylim(0, 0.42)

# Legend:
legend_elements = [Patch(facecolor="tab:orange", alpha=0.65, label=r"$\sigma$ = 1.50 / $\mu$ = -2"), Patch(facecolor="tab:blue", alpha=0.65, label=r"$\sigma$ = 1.00 / $\mu$ = 0"), Patch(facecolor="tab:green", alpha=0.65, label=r"$\sigma$ = 2.25 / $\mu$ = 2")]
plt.legend(handles=legend_elements)

# plt.savefig("gauss.png")
plt.show()


# Usage: python3 wizard.py n m t d
# where n: dimension of the matrix
#       m: number of test cases
#       t: number of randomized checkings
#       d: density of error of the wrong matrix

import numpy as np
import sys

# Tests if C = AB using Freivalds Algorithm
def test_equality(A, B, C, n, t):
    isEqual = True
    for _ in range(t):
        if (not isEqual):
            break
        x = np.random.binomial(1, 0.5, n)
        Cx = np.dot(C,x)
        ABx = np.dot(A, np.dot(B,x))
        if ( not (np.allclose(Cx, ABx)) ):
            isEqual = False
    return isEqual

def main (argv):
    n, m, t, d = int(argv[1]), int(argv[2]), int(argv[3]), float(argv[4])

    c_ctr = e_ctr = 0
    for i in range(m):
        A = np.random.rand(n,n)
        B = np.random.rand(n,n)
        C = np.dot(A,B)
        # C = AB

        # S: error matrix
        S = np.random.binomial(1, d, [n,n])*np.random.normal(0, 1, [n,n])
        E = C + S
        # E = AB + S, where S is an error matrix

        # S_not_zero: checks if S is not zero
        S_not_zero = np.any(S)
        C_isEqual = test_equality(A, B, C, n, t)
        E_isEqual = test_equality(A, B, E, n, t)

        c_ctr += 1 if C_isEqual else 0
        e_value = 0 if E_isEqual else 1

        # E = AB when S = 0, so we check this case
        e_ctr += e_value if S_not_zero else 1-e_value

    print ("Proportion of correct results:")
    print ("Correct matrix: ", c_ctr/m)
    print ("Wrong matrix: ", e_ctr/m)

if __name__ == '__main__':
    np.set_printoptions(precision=3)
    main(sys.argv)


import numpy as np
import matplotlib.pyplot as plt
from Bezier import Combination
from KnotVectors import PeriodicKnotVector
from BSpline import BSpline

def TMatrix(T, order):
    countT = np.size(T)
    TMat = np.ones([countT, order])

    for i in range(order - 1):
        TMat[:, i] = np.power(T, order - i - 1)

    return TMat

def BasisSum(i, j, order):
    value = 0.
    for l in range(j, order):
        value += np.power((order - (l + 1)), i) * np.power(-1., l - j) * Combination(order, l - j)
    return value

def BasisMatrix(order):
    Mat = np.zeros([order, order])

    for i in range(order):
        for j in range(order):
            ki = (1.0 / np.math.factorial(order - 1)) * Combination(order - 1, i)
            Mat[i, j] = ki * BasisSum(i, j , order)
    return Mat

# 0.0 <= T < 1.0, evaluated for each segment
def PeriodicBSplineMatrix(Points, order, T, closed=False):
    TMat = TMatrix(T, order)
    Basis = BasisMatrix(order)
    countPoints = np.size(Points, 0)
    dimension = np.size(Points, 1)

    orderSubTwo = order - 2 #k - 1 repeated/looped, subtract 2 since first vertex already there

    totalPoints = countPoints + orderSubTwo * 2

    PointsMatrix = np.zeros([totalPoints, dimension])
    PointsMatrix[orderSubTwo:orderSubTwo + countPoints, :] = Points

    if closed:
        PointsMatrix[0:orderSubTwo] = Points[-orderSubTwo:, :]
        PointsMatrix[orderSubTwo + countPoints:, :] = Points[:orderSubTwo, :]
    else:
        PointsMatrix[0:orderSubTwo] = Points[0, :]
        PointsMatrix[orderSubTwo + countPoints:, :] = Points[-1, :]

    SplineFinal = np.empty([0, dimension])

    #have to iterate over each segment of the curve
    for i in range(0, totalPoints - order + 1):
        SplineSegment = np.dot(np.dot(TMat, Basis), PointsMatrix[i:i + order, :])
        SplineFinal = np.append(SplineFinal, SplineSegment, axis=0)

    return SplineFinal

if __name__ == "__main__":
    order = 3

    Points = np.array([[0., 0.], [3., 10.], [6., 3.], [10., 5.]])
    countPoints = np.size(Points, 0)

    T = np.arange(0.0, 1.0, 0.01)

    Spline = PeriodicBSplineMatrix(Points, order, T, False)

    plt.plot(Points[:, 0], Points[:, 1])
    plt.plot(Spline[:, 0], Spline[:, 1])

    PointsBox = np.array([[2, 0], [4, 0], [4, 2], [4, 4], [2, 4], [0, 4], [0, 2], [0, 0]])

    BoxSpline = PeriodicBSplineMatrix(PointsBox, order, T, True)
    plt.plot(BoxSpline[:, 0], BoxSpline[:, 1])

    plt.show()


#!/usr/bin/python
# Dragon curve plotter
# using matplotlib.plot
#
# Actually, NSEW is not very practical
# now, direction will be measured by polar
# coordinates.
#
# all function will have this prototype
# def goDirection( coord, direction )
# @param list coord[x, y]
# @param list direction angle in radian
#
# coord = [x, y]
#

import math

# z is magnitude, ang is direction in radian
def pol2cart(z, ang):
    return z*math.cos(ang), z*math.sin(ang)

def cart2pol(x, y):
    z = math.sqrt(math.pow(x,2)+math.pow(x,2))
    return z, math.atan(y/x)

def goStraight(coord, direction):
    x,y = math.cos(direction), math.sin(direction)
    return [coord[0]+x,coord[1]+y], direction

def goRight(coord, direction):
    direction -= math.pi/2
    x,y = math.cos(direction), math.sin(direction)
    return [coord[0]+x,coord[1]+y], direction

def goLeft(coord, direction):
    direction += math.pi/2
    x,y = math.cos(direction), math.sin(direction)
    return [coord[0]+x,coord[1]+y], direction

## Pretty Plot
# usable to give -rectangular, -full, -beautiful plot
def prettyPlot(xData, yData, plotType='-k'):
    import matplotlib.pyplot as plt
    #Add 'buffer' to min-max x and y value
    buf = 5.0
    # plt.axis( [xmin, xmax, ymin, ymax] )
    plt.axis('equal')
    ax = np.array([min(xData)-buf, max(xData)+buf, min(yData)-buf, max(yData)+buf])
    plt.axis(ax)
    plt.plot(xData,yData,plotType)
    plt.show()

if __name__ == '__main__':
    import dragonfrac
    import numpy as np
    import argparse
    # We'll request input from user
    parser = argparse.ArgumentParser(description='Draw dragon fractal')
    parser.add_argument('num', metavar='N', type=int, help='Number of iteration')
    args = parser.parse_args()
    command = dragonfrac.dragoncurv(args.num)
    startPt = [1.,1.]
    startDir = math.radians(90)
    xPlot = []
    yPlot = []
    xPlot.append(startPt[0])
    yPlot.append(startPt[1])

    for x in command:
        if x=='F':
            startPt, startDir = goStraight(startPt, startDir)
        elif x=='R':
            startPt, startDir = goRight(startPt, startDir)
        elif x=='L':
            startPt, startDir = goLeft(startPt, startDir)

        xPlot.append(startPt[0])
        yPlot.append(startPt[1])

    x1 = np.array(xPlot)
    y1 = np.array(yPlot)
    prettyPlot(x1,y1)


import numpy as np
import tensorflow as tf

def primitive_multi_var():
    x1_data = [58.0, 52.0, 53.0, 53.0, 56.0]
    x2_data = [100.0, 64.0, 51.0, 93.0, 79.0]
    x3_data = [51.0, 58.0, 63.0, 74.0, 85.0]
    y_data = [187.0, 184.0, 166.0, 168.0, 169.0]

    x1 = tf.placeholder(tf.float32)
    x2 = tf.placeholder(tf.float32)
    x3 = tf.placeholder(tf.float32)
    Y = tf.placeholder(tf.float32)

    w1 = tf.Variable(tf.random_normal([1]), name='weight1')
    w2 = tf.Variable(tf.random_normal([1]), name='weight2')
    w3 = tf.Variable(tf.random_normal([1]), name='weight3')
    b = tf.Variable(tf.random_normal([1]), name='bias')
    hypothesis = x1 * w1 + x2 * w2 + x3 * w3 + b

    cost = tf.reduce_mean(tf.square(hypothesis - Y))
    optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
    train = optimizer.minimize(cost)

    sess = tf.Session()
    sess.run(tf.global_variables_initializer())

    for step in range(4001):
        cost_val, hy_val, _ = sess.run([cost, hypothesis, train],
                                       feed_dict={x1: x1_data, x2: x2_data, x3: x3_data, Y: y_data})
        if step % 100 == 0:
            print(step, "cost: ", cost_val, "prediction: ", hy_val)
            # 4000 cost:  61.5923
            # prediction:  [ 191.70774841  169.1756897   171.99211121  165.69598389  173.98240662]

def matrix_multi_var():
    x_data = [[58.0, 100.0, 51.0],
              [52.0, 64.0, 58.0],
              [53.0, 51.0, 63.0],
              [53.0, 93.0, 74.0],
              [56.0, 79.0, 85.0]]
    y_data = [[187.0], [184.0], [166.0], [168.0], [169.0]]

    X = tf.placeholder(tf.float32, shape=[None, 3])
    Y = tf.placeholder(tf.float32, shape=[None, 1])

    W = tf.Variable(tf.random_normal([3, 1]), name='weight')
    b = tf.Variable(tf.random_normal([1]), name='bias')
    hypothesis = tf.matmul(X, W) + b

    cost = tf.reduce_mean(tf.square(hypothesis - Y))
    optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
    train = optimizer.minimize(cost)

    sess = tf.Session()
    sess.run(tf.global_variables_initializer())

    for step in range(4001):
        cost_val, hy_val, _ = sess.run([cost, hypothesis, train],
                                       feed_dict={X: x_data, Y: y_data})
        if step % 100 == 0:
            print(step, "cost: ", cost_val, "prediction: ", hy_val)
            # 4000 cost:  60.7822
            # prediction:  [[ 191.85115051]
            #               [ 169.44267273]
            #               [ 172.31044006]
            #               [ 165.4127655 ]
            #               [ 173.68466187]]

# matrix_multi_var()

def multi_var_from_file():
    xy = np.loadtxt('4_multi_var_from_file.csv', delimiter=',', dtype=np.float32)
    x_data = xy[:, 0:3]
    y_data = xy[..., [-1]]

    X = tf.placeholder(tf.float32, shape=[None, 3])
    Y = tf.placeholder(tf.float32, shape=[None, 1])

    W = tf.Variable(tf.random_normal([3, 1]), name='weight')
    b = tf.Variable(tf.random_normal([1]), name='bias')
    hypothesis = tf.matmul(X, W) + b

    cost = tf.reduce_mean(tf.square(hypothesis - Y))
    optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
    train = optimizer.minimize(cost)

    sess = tf.Session()
    sess.run(tf.global_variables_initializer())

    # train
    for step in range(4001):
        cost_val, hy_val, _ = sess.run([cost, hypothesis, train],
                                       feed_dict={X: x_data, Y: y_data})
        if step % 100 == 0:
            print(step, "cost: ", cost_val, "prediction: ", hy_val)
            # 4000 cost:  60.7822
            # prediction:  [[ 191.85115051]
            #               [ 169.44267273]
            #               [ 172.31044006]
            #               [ 165.4127655 ]
            #               [ 173.68466187]]

    # test
    print("my score will be: ", sess.run(hypothesis, feed_dict={X: [[100, 100, 100]]}))
    print("Other scores will be: ", sess.run(hypothesis,
                                             feed_dict={X: [[60, 70, 80], [55, 94, 29]]}))

# multi_var_from_file()

def multi_var_from_file_batch():
    # When you use string_input_producer(), do not insert #comments in csv files.
    # It will spit inefficient data error.
    filename_queue = tf.train.string_input_producer(
        ['/Users/eunkwang/Documents/tensorflow-learning/4_multi_var_from_file.csv',
         '/Users/eunkwang/Documents/tensorflow-learning/4_multi_var_from_file_2.csv'],
        shuffle=False)

    reader = tf.TextLineReader()
    _, value = reader.read(filename_queue)

    # in case of empty columns, and also specify type of the result
    record_defaults = [[0.], [0.], [0.], [0.]]
    xy = tf.decode_csv(value, record_defaults=record_defaults)
    train_x_batch, train_y_batch = tf.train.batch([xy[0:-1], xy[-1:]], batch_size=2)

    X = tf.placeholder(tf.float32, shape=[None, 3])
    Y = tf.placeholder(tf.float32, shape=[None, 1])

    W = tf.Variable(tf.random_normal([3, 1]), name='weight')
    b = tf.Variable(tf.random_normal([1]), name='bias')
    hypothesis = tf.matmul(X, W) + b

    cost = tf.reduce_mean(tf.square(hypothesis - Y))
    optimizer = tf.train.GradientDescentOptimizer(learning_rate=1e-5)
    train = optimizer.minimize(cost)

    sess = tf.Session()
    sess.run(tf.global_variables_initializer())

    # start populating filename queue
    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(sess=sess, coord=coord)

    # train
    for step in range(4001):
        x_batch, y_batch = sess.run([train_x_batch, train_y_batch])
        cost_val, hy_val, _ = sess.run([cost, hypothesis, train],
                                       feed_dict={X: x_batch, Y: y_batch})
        if step % 100 == 0:
            print(step, "cost: ", cost_val, "prediction: ", hy_val)
            # 4000 cost:  60.7822
            # prediction:  [[ 191.85115051]
            #               [ 169.44267273]
            #               [ 172.31044006]
            #               [ 165.4127655 ]
            #               [ 173.68466187]]

    coord.request_stop()
    coord.join(threads)

    # test
    print("my score will be: ", sess.run(hypothesis, feed_dict={X: [[100, 100, 100]]}))
    print("Other scores will be: ", sess.run(hypothesis,
                                             feed_dict={X: [[60, 70, 80], [55, 94, 29]]}))

multi_var_from_file_batch()


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

Perlin noise routines from

https://github.com/pvigier/perlin-numpy

"""

import numpy as np

def generate_perlin_noise_2d(shape, res):
    def f(t):
        return 6*t**5 - 15*t**4 + 10*t**3

    delta = (res[0] / shape[0], res[1] / shape[1])
    d = (shape[0] // res[0], shape[1] // res[1])
    grid = np.mgrid[0:res[0]:delta[0],0:res[1]:delta[1]].transpose(1, 2, 0) % 1
    # Gradients
    angles = 2*np.pi*np.random.rand(res[0]+1, res[1]+1)
    gradients = np.dstack((np.cos(angles), np.sin(angles)))
    g00 = gradients[0:-1,0:-1].repeat(d[0], 0).repeat(d[1], 1)
    g10 = gradients[1:  ,0:-1].repeat(d[0], 0).repeat(d[1], 1)
    g01 = gradients[0:-1,1:  ].repeat(d[0], 0).repeat(d[1], 1)
    g11 = gradients[1:  ,1:  ].repeat(d[0], 0).repeat(d[1], 1)
    # Ramps
    n00 = np.sum(np.dstack((grid[:,:,0]  , grid[:,:,1]  )) * g00, 2)
    n10 = np.sum(np.dstack((grid[:,:,0]-1, grid[:,:,1]  )) * g10, 2)
    n01 = np.sum(np.dstack((grid[:,:,0]  , grid[:,:,1]-1)) * g01, 2)
    n11 = np.sum(np.dstack((grid[:,:,0]-1, grid[:,:,1]-1)) * g11, 2)
    # Interpolation
    t = f(grid)
    n0 = n00*(1-t[:,:,0]) + t[:,:,0]*n10
    n1 = n01*(1-t[:,:,0]) + t[:,:,0]*n11
    return np.sqrt(2)*((1-t[:,:,1])*n0 + t[:,:,1]*n1)

def generate_fractal_noise_2d(shape, res, octaves=1, persistence=0.5):
    noise = np.zeros(shape)
    frequency = 1
    amplitude = 1
    for _ in range(octaves):
        noise += amplitude * generate_perlin_noise_2d(shape, (frequency*res[0], frequency*res[1]))
        frequency *= 2
        amplitude *= persistence
    return noise

if __name__ == '__main__':
    import matplotlib.pyplot as plt

    np.random.seed(0)
    noise = generate_perlin_noise_2d((256, 256), (16, 16))
    #plt.imshow(noise, cmap='gray', interpolation='lanczos')
    plt.imshow(noise, cmap='gray')
    plt.colorbar()

    np.random.seed(0)
    noise = generate_fractal_noise_2d((256, 256), (8, 8), 5)
    plt.figure()
    plt.imshow(noise, cmap='gray', interpolation='lanczos')
    plt.colorbar()
    plt.show()


# -*- coding: utf-8 -*-
import numpy as np

def kge09(predicted, reference, sr=1.0, salpha=1.0, sbeta=1.0):
    """
    Calculate the Kling-Gupta efficiency from 2009 paper.

    Calculates the Kling-Gupta efficiency between two variables
    predicted and reference. The kge09 is calculated using the
    formula:

    KGE09 = 1 - sqrt((cc-1)**2 + (alpha-1)**2 + (beta-1)**2)

    where:
        cc = correlation coefficient between predicted and reference;
        alpha = std(predicted) / std(reference)
        beta = sum(predicted) / sum(reference)

    where s is the predicted values, o is the reference values, and
    N is the total number of values in s & o. Note that s & o must
    have the same number of values.

    Kling-Gupta efficiency can range from -infinity to 1. An efficiency of 1 (E
    = 1) corresponds to a perfect match of model to reference data.
    Essentially, the closer the model efficiency is to 1, the more accurate the
    model is.

    The efficiency coefficient is sensitive to extreme values and might yield
    sub-optimal results when the dataset contains large outliers in it.

    Kling-Gupta efficiency can be used to quantitatively describe the accuracy
    of model outputs. This method can be used to describe the predictive
    accuracy of other models as long as there is reference data to compare the
    model results to.

    Input:
    predicted : predicted values
    reference : reference values
    sr : [optional, defaults to 1.0] scaling factor for correlation
    salpha : [optional, defaults to 1.0] scaling factor for alpha
    sbeta : [optional, defaults to 1.0] scaling factor for beta

    Output:
    kge09 : Kling-Gupta Efficiency

    References:
    Gupta, Hoshin V., Harald Kling, Koray K. Yilmaz, Guillermo F. Martinez.
    Decomposition of the mean squared error and NSE performance criteria:
    Implications for improving hydrological modelling. Journal of Hydrology,
    Volume 377, Issues 1-2, 20 October 2009, Pages 80-91. DOI:
    10.1016/j.jhydrol.2009.08.003. ISSN 0022-1694
    """
    # Check that dimensions of predicted and reference fields match
    pdims = predicted.shape
    rdims = reference.shape
    if not np.array_equal(pdims, rdims):
        message = (
            "predicted and reference field dimensions do not"
            + " match.\n"
            + "shape(predicted)= "
            + str(pdims)
            + ", "
            + "shape(reference)= "
            + str(rdims)
            + "\npredicted type: "
            + str(type(predicted))
        )
        raise ValueError(message)

    for name, term in [("sr", sr), ("salpha", salpha), ("sbeta", sbeta)]:
        if term > 1 or term < 0:
            raise ValueError(
                "'{}' must be between 0 and 1, you gave {}".format(name, term)
            )

    std_ref = np.std(reference)
    if std_ref == 0:
        return -np.inf
    sum_ref = np.sum(reference)
    if sum_ref == 0:
        return -np.inf
    alpha = np.std(predicted) / std_ref
    beta = np.sum(predicted) / sum_ref
    cc = np.corrcoef(reference, predicted)[0, 1]

    # Calculate the kge09
    kge09 = 1.0 - np.sqrt(
        (sr * (cc - 1.0)) ** 2
        + (salpha * (alpha - 1.0)) ** 2
        + (sbeta * (beta - 1.0)) ** 2
    )

    return kge09


from scipy.stats import t
from numpy import power
from math import sqrt
from numpy import mean, std

def welchs_ttest(x1, x2, alpha=None):
    """
    Execute one-sided Welch's t-test.

    Return a dictionary with keys ``p``, ``mean1``, ``mean2``, ``stddev1`` and
    ``stddev2``.

    If an ``alpha`` value is supplied, result dictionary will also contain a
    key ``h0_rejected`` which is ``True`` if the p value is less than alpha
    (null hypothesis rejected), otherwise ``False``.

    Null hypothesis is that means are equal or mean of x1 is less than mean of
    x2. Null hypothesis is rejected if mean of x1 is greater than mean of x2
    (i.e., a performance regression if the supplied data are performance test
    timings, presuming x1 is data for the current changeset and x2 is data for
    the parent changeset).

    Original code by Joseph Kelly, Mozilla metrics.

    For more on Welch's t-test, see:
    http://en.wikipedia.org/wiki/Student%27s_t-test#Unequal_sample_sizes.2C_unequal_variance

    """
    n1 = len(x1)
    n2 = len(x2)

    m1 = mean(x1)
    m2 = mean(x2)

    s1 = std(x1, ddof=1)
    s2 = std(x2, ddof=1)

    prob = welchs_ttest_internal(n1, s1, m1, n2, s2, m2)

    result = {
        "p": prob,
        "stddev1": s1,
        "stddev2": s2,
        "mean1": m1,
        "mean2": m2,
        }

    if alpha is not None:
        result["h0_rejected"] = prob < alpha

    return result

def welchs_ttest_internal(n1, s1, m1, n2, s2, m2):
    """
    Execute one-sided Welch's t-test given pre-calculated means and stddevs.

    Accepts summary data (N, stddev, and mean) for two datasets and performs
    one-sided Welch's t-test, returning p-value.

    """
    v1             = power(s1, 2)
    v2             = power(s2, 2)
    vpooled        = v1/n1 + v2/n2
    spooled        = sqrt(vpooled)
    tt             = (m1-m2)/spooled
    df_numerator   = power(vpooled, 2)
    df_denominator = power(v1/n1, 2)/(n1-1) + power(v2/n2, 2)/(n2-1)
    df             = df_numerator / df_denominator

    t_distribution = t(df)
    return 1 - t_distribution.cdf(tt)


#!/usr/bin/env python
# Require python3

import os, sys
from PIL import Image
# Docs at http://pillow.readthedocs.org/index.html

import numpy as np
import math as m
import statistics as s

if len(sys.argv) < 3:
    print("Usage:")
    print("    python[3] mse_psnr.py <img1> <img2>")
    print("")
    exit(255)

img1 = Image.open(sys.argv[1])
img2 = Image.open(sys.argv[2])

if img1.size != img2.size:
    print("The size of two image is different. Aborting...")
    exit(255)

if img1.mode != img2.mode:
    print("Warning: the mode of two img is different\n",img1.mode,img2.mode)

mse = 0.0
mse_n = 0

img1_ary = np.array(img1)
img2_ary = np.array(img2)

p_max = 255

print("Calculation started")

for y in range(img1.size[0]):
    for x in range(img1.size[1]):
        for e in range(0,3):
            mse += (float(img1_ary[x,y,e]) - float(img2_ary[x,y,e])) ** 2
            mse_n += 1

mse /= mse_n
psnr = 10 * m.log((p_max**2)/mse,10)

print("MSE between these two images is %f\nPSNR between these two images is %f" % (mse,psnr))


import matplotlib.pyplot as plt
import numpy as np
X = 2 * np.random.rand(100,1)
y = 4 + 3*X+np.random.randn(100,1)

X_b = np.c_[np.ones((100,1)), X]
theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)
X_new = np.array([[0],[2]])
X_new_b = np.c_[np.ones((2,1)), X_new]
y_pred = X_new_b.dot(theta)
plt.plot(X_new, y_pred, 'r-')

plt.plot(X,y,'b.')
plt.axis([0,2,0,15])
plt.show()


"""
Q-learning: implementation of Q-learning for discrete state and actions

Q(s,a)_new <- Q(s,a)_old + alpha * ( r + gamma * max_a Q(s',a) - Q(s,a)_old  )

s     : state   (discrete)
a     : action  (discrete)
gamma : discount factor
alpha : learning rate
r     : reward

"""

import numpy as np

class Qlearning:

    def __init__(self,num_states,num_actions):
        """
            Args:
                num_states  (int): Number of actions
                num_actions (int): Number of states

        """
        self.alpha = 0.1  # learning rate
        self.gamma = 0.9  # discount factor
        self._num_states = num_states
        self._num_actions = num_actions
        self.Q = np.zeros((num_states,num_actions))

    def update(self, state, action, reward, statep, bterminal):
        """Q-learning update rule: Q(s,a)_new <- Q(s,a)_old + alpha * ( r + gamma * max_a Q(s',a) - Q(s,a)_old  )
            Args:
                state (int)     : previous state   s
                action (int)    : previous action  a
                reward (double) : current reward   r
                statep (int)    : current state    s'
                bterminal (bool): True if s is terminal state
        """
        if bterminal:
            self.Q[state, action] = reward
        else:
            self.Q[state, action] += self.alpha*(reward + self.gamma*self.Q[statep,np.argmax(self.Q[statep, :])] - self.Q[state, action])


"""
LASSO Regression: y = w0*x0 + w1*x1 + w2*x2 + ... + wD*xD
Objective: Estimate w0, w1, w2 ... wD given x1, x2 ... xD and y
where xN = input feature, x0 = 1.0
      y  = output
subject to L1 penalty
"""

# Imports
import numpy as np
import copy

# Functions
def get_data(data_frame, features, output):
    """
    Purpose: Extract features and prepare a feature matrix
             Set the first feature x0 = 1
    Input  : Original Dataframe, list of feature variables, output variable
    Output : Feature matrix array, output array
    """
    data_frame['constant'] = 1.0
    features = ['constant'] + features
    features_matrix = np.array(data_frame[features])
    if output != None:
        output_array = np.array(data_frame[output])
    else:
        output_array = []
    return(features_matrix, output_array.reshape((len(output_array))))

def normalize(features):
    """
    Purpose: Normalize feature matrix, each column of the matrix is a feature
    Input  : Unnormalized feature matrix
    Output : Normalized feature matrix, feature norms
    """
    norms = np.linalg.norm(features, axis=0)
    normalized_features = features/norms
    return (normalized_features, norms)

def predict(feature_matrix, weights):
    """
    Purpose: Compute predictions by multiplying the feature matrix with
             the estimated weights
    Input  : Feature matrix array, weight vector
    Output : Product of feature matrix array and weight vector
    """
    predictions = feature_matrix.dot(weights)
    return(predictions)

def lasso_coordinate_descent_step(i, feature_matrix, output, weights, l1_penalty):
    """
    Purpose: Compute the descent step for one feature
    Input  : Feature index, normalized feature matrix, output,
             feature weights and L1_penalty
    Output : Descent step for feature
    """
    predictions = feature_matrix.dot(weights)
    rho = (feature_matrix[:, i].T).dot(output - predictions + (weights[i] * feature_matrix[:, i]))
    if i==0:
        new_weight = rho
    elif rho < (-l1_penalty/2.0):
        new_weight = rho + (l1_penalty/2.0)
    elif rho > (l1_penalty/2.0):
        new_weight = rho - (l1_penalty/2.0)
    else:
        new_weight = 0.0
    return new_weight

def lasso_cyclical_coordinate_descent(feature_matrix, output, initial_weights, l1_penalty, tolerance):
    """
    Purpose: Perform cyclical coordinate descent
    Input  : Normalized feature matrix, output, initial weights,
             L1_penalty and tolerance for stopping the process
    Output : Final weights after the convergence of the coordinate
             descent procedure
    """
    D = feature_matrix.shape[1]
    weights = copy.copy(initial_weights)
    change = np.zeros(initial_weights.shape)
    converged = False

    while not converged:
        # Evaluate over all features
        for idx in range(D):
            # New weight for feature
            new_weight = lasso_coordinate_descent_step(idx, feature_matrix,
                                                       output, weights,
                                                       l1_penalty)
            # Compute change in weight for feature
            change[idx] = np.abs(new_weight - weights[idx])
            # assign new weight
            weights[idx] = new_weight
        # Maximum change in weight, after all changes have been computed
        max_change = max(change)
        if max_change < tolerance:
            converged = True
    return weights

def fit(feature_matrix, output, initial_weights, l1_penalty, tolerance):
    """
    Purpose: Wrapper for cyclical coordinate descent function
    Input  : Feature matrix array, initial weight vector, output vector,
             tolerance value, l1_penalty
    Output : Estimated weight vector
    """
    weights = lasso_cyclical_coordinate_descent(feature_matrix, output, initial_weights, l1_penalty, tolerance)
    return(weights)

def get_residual_sum_of_squares(feature_matrix, weights, output):
    """
    Purpose: Compute Residual Sum of Squares (RSS)
    Input  : Feature matrix, weight vector, output vector
    Output : Residual sum of squares = sum((actual output (y) - predicted output)^2)
    """
    predictions = predict(feature_matrix, weights)
    residual = np.sum((predictions - output) ** 2)
    return(residual)


import numpy as np

"""Scaling: normalize features."""

def std(data: np.ndarray):
    """Standardization: zero mean and unit variance."""
    mean_ = data.mean(axis=0)
    std_ = data.std(axis=0)
    data -= mean_
    data /= std_

def minmax(data: np.ndarray):
    """MinMax-scale: scale each dimension to [0, 1] using min-max values."""
    min_ = data.min(axis=0)
    max_ = data.max(axis=0)
    data -= min_
    data /= (max_ - min_)

def mean(data: np.ndarray):
    """Mean-scale: scale each dimension to [-1, 1] using mean and min-max."""
    min_ = data.min(axis=0)
    max_ = data.max(axis=0)
    mean_ = data.mean(axis=0)
    data -= mean_
    data /= (max_ - min_)

def unit(data: np.ndarray):
    """Unit-scale: scale to vectors with unit length."""
    norm_ = np.sqrt(np.power(data, 2).sum(axis=1).reshape((-1, 1)))
    data /= norm_


import numpy as np

def matthews_correlation_coefficient(y_true, y_pred, epsilon=1e-07):
     """Compute the Matthews correlation coefficient (MCC)
        Adapted from: https://stackoverflow.com/questions/39895742/matthews-correlation-coefficient-with-keras/40289696#40289696

    Parameters
    ----------
       y_true : array, true labels
       y_pred : array, predicted labels
       epsilon : small number to prevent divide by zero errors

    Returns
    -------
        MCC : int, the Matthews correlation coefficient (0.0 is random guessing, 1.0 is perfect correlation)
     """
    y_pred_pos = np.round(np.clip(y_pred, 0, 1))
    y_pred_neg = 1 - y_pred_pos

    y_pos = np.round(np.clip(y_true, 0, 1))
    y_neg = 1 - y_pos

    tp = np.sum(y_pos * y_pred_pos)
    tn = np.sum(y_neg * y_pred_neg)
    fp = np.sum(y_neg * y_pred_pos)
    fn = np.sum(y_pos * y_pred_neg)

    numerator = (tp * tn - fp * fn)
    denominator = np.sqrt((tp + fp) * (tp + fn) * (tn + fp) * (tn + fn))

    return numerator / (denominator + epsilon)

def false_positives(y_true, y_pred):
    """Computes the number of false positives generated by the model

    Parameters
    ----------
        y_true : array, true labels
        y_pred : array, predicted labels

    Returns
    -------
        score : int, the number of false positives
    """
    y_pred_pos = np.round(np.clip(y_pred, 0, 1))
    y_neg = 1 - np.round(np.clip(y_true, 0, 1))

    return np.sum(y_neg * y_pred_pos)


"""
This module implements various losses for the network.
You should fill in code into indicated sections.
"""
from support import sm, total_ce_loss, total_ce_loss_grad
import numpy as np

def HingeLoss(x, y):
  """
  Computes multi-class hinge loss and gradient of the loss with the respect to the input for multiclass SVM.

  Args:
    x: Input data.
    y: Labels of data.

  Returns:
    loss: Scalar hinge loss.
    dx: Gradient of the loss with the respect to the input x.

  """
  ########################################################################################
  # Compute hinge loss on input x and y and store it in loss variable. Compute gradient  #
  # of the loss with respect to the input and store it in dx variable.                   #
  ########################################################################################
  m, k = x.shape
  margin = 0.1

  cor = x[range(m), y].reshape((-1,1))
  dx = x - cor + margin

  dx = (dx > 0) *1
  dx[range(m), y] = - np.sum(dx, axis=1)
  loss = np.mean(np.sum(np.maximum(0, x - cor + margin), axis=1, keepdims=1))
  ########################################################################################
  #                              END OF YOUR CODE                                        #
  ########################################################################################

  return loss, dx/float(m)

def CrossEntropyLoss(x, y):
  """
  Computes multi-class cross entropy loss and gradient with the respect to the input x.

  Args:
    x: Input data.
    y: Labels of data.

  Returns:
    loss: Scalar multi-class cross entropy loss.
    dx: Gradient of the loss with the respect to the input x.

  """
  ########################################################################################
  # Compute cross entropy loss on input x and y and store it in loss variable. Compute   #
  # gradient of the loss with respect to the input and store it in dx.                   #
  ########################################################################################
  m, k = x.shape
  one_hot = np.zeros((m, k))
  one_hot[range(m), y] = 1
  dx =  - one_hot / x
  loss = - np.sum(np.log(x[range(m), y]))/float(m)
  ########################################################################################
  #                              END OF YOUR CODE                                        #
  ########################################################################################

  return loss, dx/float(m)

def SoftMaxLoss(x, y):
  """
  Computes the loss and gradient with the respect to the input x.

  Args:
    x: Input data (matrix).
    y: Labels of data (vector).

  Returns:
    loss: Scalar softmax loss.
    dx: Gradient of the loss with the respect to the input x.

  """
  ########################################################################################
  # Compute softmax loss on input x and y and store it in loss variable. Compute gradient#
  # of the loss with respect to the input and store it in dx variable.                   #
  ########################################################################################
  y_hat = sm(x) # [batch x classes]
  m = x.shape[0]
  loss = - np.sum(np.log(y_hat[range(m), y]))/float(m)
  dx = y_hat
  dx[range(m), y] -= 1

  # loss, dx = CrossEntropyLoss(y_hat, y)
  # loc_dx = - y_hat
  # loc_dx = loc_dx * y_hat[range(m), y].reshape((-1,1)) # fixing for incorrect predictions
  # loc_dx[range(m), y] /= y_hat[range(m), y]
  # loc_dx[range(m), y] = loc_dx[range(m), y] - loc_dx[range(m), y]**2
  # dx = dx * loc_dx
  ########################################################################################
  #                              END OF YOUR CODE                                        #
  ########################################################################################

  return loss, dx/float(m)


# TODO: Create a synthetic dataset - how would the data need to look like if we were able to fit the sine wave on them?

# You want to reverse engineer data which would fit onto your 'ideal' curve:
# Eq: y = amp * np.sin (2* np.pi / per * x + shift_h) + shift_v
# Without shift_h:  2.63 * np.sin (2 * np.pi / per * x) + 17.18

import numpy as np
import matplotlib.pyplot as plt

def sine_function(x, amp, per, shift_h, shift_v):
    return amp * np.sin(2*np.pi/per * x + shift_h) + shift_v

amp, per, shift_h, shift_v = 4.59, 11.75, 0, 17.71

repeats = int(72 / per)
x_sine = np.linspace(0, repeats * per, int(per*10))
y_sine = sine_function(x_sine, amp, per, shift_h, shift_v)

# Now do the reverse engineering for x-generational families with phases ranging between 0-24:
def SynthesizeData(phase, total_gen):
    """ Phase ranges from 0 to 24 with increments of 0.2. """

    x_list = [phase]
    y_list = []

    while len(x_list) < total_gen or len(y_list) < total_gen:
        x = x_list[-1]
        y = sine_function(x=x, amp=amp, per=per, shift_h=shift_h, shift_v=shift_v)
        x_list.append(y+x)
        y_list.append(y)
    x_list = x_list[:-1]

    return x_list, y_list

phase_range = np.linspace(0, per, int(per*10) + 1)
print (phase_range)

x_data_0 = []
y_data_0 = []
for phase in list(phase_range.tolist()):
    x_list, y_list = SynthesizeData(phase=phase, total_gen=3)
    plt.scatter(x=x_list, y=y_list, color="purple", alpha=0.2, zorder=2) # label="Fake Data Point",
    y_data_0.append(y_list)
    x_data_0.append([value - x_list[0] for value in x_list])

# Now plot the thing:
plt.plot(x_sine, y_sine, color="turquoise", label="Ideal Sine Wave", zorder=1)
plt.axhline(y=shift_v, color="grey", linestyle="dashed", zorder=0)
for i in range(1, repeats):
    plt.axvline(x=per*i, color="gold", linestyle="dashed", zorder=0)
plt.xticks(np.linspace(0, repeats * per, repeats * 2 + 1), rotation=45)
plt.xlabel("Oscillation Period [hours]")
plt.ylabel("Cell Cycle Duration [hours]")
plt.title("Ideal Sine Wave: y(x) = {} * sin(2 * pi / {} * x) + {}".format(amp, per, shift_v))
plt.savefig("/Users/kristinaulicna/Documents/Rotation_2/Ideal_Wave_3_gen_round_2.png", bbox_inches="tight")
plt.show()
plt.close()

# Now plot the non-phased data:
for x, y in zip(x_data_0, y_data_0):
    plt.scatter(x=x, y=y)

plt.xlabel("Oscillation Period [hours]")
plt.ylabel("Cell Cycle Duration [hours]")
plt.title("Relationships between generations in an ideal family\n"
          "Equation: {} * np.sin (2 * np.pi / {} * x + {}) + {}"
          .format(amp, per, shift_h, shift_v))
plt.grid(which="both")
plt.savefig("/Users/kristinaulicna/Documents/Rotation_2/Ideal_Wave_Relationships_3_gen_round_2.png", bbox_inches="tight")
plt.show()
plt.close()


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

#x: data, k: number of clusters
def basic_kmeans(x,k):
    centre_indices=np.random.choice(range(np.shape(x)[0]),k,replace=False)
    centres=x[centre_indices,:]
    previous_membership=np.zeros(np.shape(x)[0])-1
    membership_change=1
    while membership_change>0:
        membership=[]
        for i in range(0,np.shape(x)[0]):
            distances=np.sum(np.square(x[i,:]-centres),axis=1)
            membership.append(np.argmin(distances))
        membership=np.array(membership)
        membership_change=np.sum(membership!=previous_membership)
        previous_membership=membership
        print('current loss: '+str(membership_change))
        for i in range(0,k):
            if sum(membership==i)>0:
                centres[i,:]=np.average(x[membership==i],axis=0)
    return centres,membership

if __name__=='__main__':
    #generate random data for clustering, fix seed so that results are reproducible
    np.random.seed(0)
    number_of_points=int(sys.argv[1])
    dimensions=int(sys.argv[2])
    k=int(sys.argv[3])
    x=np.random.rand(number_of_points,dimensions)
    centres,membership=basic_kmeans(x,k)
    #simple visualisation
    if np.shape(x)[1]==2 and k==3:
        plt.figure(figsize=(10,10))
        for i in range(0,3):
            current_x=x[membership==i,:]
            if np.shape(current_x)[0]>0:
                plt.scatter(current_x[:,0],current_x[:,1],label='cluster '+str(i))
                plt.scatter(centres[i,0],centres[i,1],label='centre '+str(i),linewidths=6)
        plt.legend()
        plt.savefig('basic_kmeans.jpg')


import datetime as dt
import pandas as pd
import numpy as np
from pandas.plotting import table
import matplotlib.pyplot as plt

def ann_return(DF):
    "function to calculate the Annualized return from monthly prices of a fund/sript"
    df = DF.copy()
    df["mon_ret"] = df["NAV"].pct_change()
    df["cum_return"] = (1 + df["mon_ret"]).cumprod()
    n = len(df)/12
    ann_ret = (df["cum_return"][-1])**(1/n) - 1
    return ann_ret

def ann_volatility(DF):
    "function to calculate annualized volatility of a trading strategy"
    df = DF.copy()
    df["mon_ret"] = df["NAV"].pct_change()
    vol = df["mon_ret"].std() * np.sqrt(12)
    return vol

def sharpe(DF, rf):
    "function to calculate sharpe ratio ; rf is the risk free rate"
    df = DF.copy()
    sr = (ann_return(df) - rf) / ann_volatility(df)
    return sr

# Import the Lipper Hedge Fund Data
Lip = pd.read_csv(r'/Users/rachnish/Dropbox/TWSA Session #1 - Wed Nov 20/Kapil_Data.csv', index_col='Date')

# format the date columns to datetime format
Lip['Performance Start Date'] = pd.to_datetime(Lip['Performance Start Date'], errors='raise', dayfirst=True)
Lip['Performance End Date'] = pd.to_datetime(Lip['Performance End Date'], errors='raise', dayfirst=True)
Lip.index = pd.to_datetime(Lip.index, errors='raise', dayfirst=True)

# Filter Funds with a continuous track record from 1995/1/1 to 1995/12/1
Yearly_data = Lip.copy()
Yearly_data = Yearly_data[(Yearly_data['Performance Start Date'] <= '1995-01-01') & (Yearly_data['Performance End Date'] >= '1995-12-31')]
Yearly_data = Yearly_data[(Yearly_data.index >= '1995-01-01') & (Yearly_data.index <= '1995-12-31')]

# Calculate Sharpe Ratio for each Fund in the selected database
HF = list(Yearly_data['Fund Name'].unique())
HF_stats = pd.DataFrame(columns=['SharpeRatioPast', 'PercentileRankingPast'], index=HF)
for i in HF:
    HF_stats['SharpeRatioPast'].loc[i] = sharpe(Yearly_data.loc[Yearly_data['Fund Name'] == i], 0.00)

# Calculate percentile ranking for each Fund in the selected database
ranks = HF_stats.SharpeRatioPast.rank(ascending=False)
HF_stats['PercentileRankingPast'] = (ranks - ranks.min())/(ranks.max() - ranks.min())*100


import numpy as np
import scipy.io as sio
import matplotlib.pyplot as plt

def to_num(alpha):
    if ord(alpha) >= 65:
        return ord(alpha)-55
    else :
        return ord(alpha)-48

def lire_alpha_digit(path, strSlct, nb_expl = 39):
    data = sio.loadmat(path)
    snip = None
    if isinstance(strSlct, str):
        for datum in strSlct:
            ind = to_num(datum)
            temp = np.concatenate(data['dat'][ind, 0:nb_expl], axis=1).flatten(order='F').reshape(320, nb_expl, order='F')
            if snip is not None:
                snip = np.hstack((snip, temp))
            else :
                snip = temp
    return snip.T

class RBM:

    def __init__(self, nb_v, nb_h):
        self.bias_a = np.zeros((1, nb_v))
        self.bias_b = np.zeros((1, nb_h))
        self.weights = 1e-1*np.random.randn(nb_v, nb_h)

    def sigmoid(self, data):
        return 1/(1+np.exp(-1*data))

    def softmax(self, data):
        return np.exp(data)/np.sum(np.exp(data), axis=1).reshape(-1, 1)

    def entree_sortie_RBM(self, v, act='sigmoid'):

        if act=='sigmoid':
            prob_h =  self.sigmoid(self.bias_b + v@self.weights)
        else:
            prob_h =  self.softmax(self.bias_b + v@self.weights)
        h = (np.random.uniform(0, 1, size=prob_h.shape) < prob_h) * 1

        return h, prob_h

    def sortie_entree_RBM(self, h, act='sigmoid'):

        if act=='sigmoid':
            prob_v =  self.sigmoid(self.bias_a + h@self.weights.T)
        else:
            prob_v =  self.softmax(self.bias_a + h@self.weights.T)

        v = (np.random.uniform(0, 1, size=prob_v.shape) < prob_v) * 1

        return v, prob_v

    def train_RBM(self, data, batch_size=50, n_epoch=10000, lr_rate=0.01, verbose=True):

        assert n_epoch > 0
        batch_size = batch_size if batch_size <= data.shape[1] else data.shape[1]

        for i in range(n_epoch):
            batch = data[np.random.choice(np.arange(data.shape[0]), batch_size), :]
            # Contrastive divergence (type I)
            h_0, prob_h_0 = self.entree_sortie_RBM(batch)
            v_1, prob_v_1 = self.sortie_entree_RBM(h_0)
            h_1, prob_h_1 = self.entree_sortie_RBM(v_1)
            grad_a, grad_b = np.mean(batch - v_1, axis=0), np.mean(prob_h_0 - prob_h_1, axis=0)
            grad_weights = batch.T@prob_h_0 - v_1.T@prob_h_1
            self.bias_a += lr_rate*grad_a.reshape(1, -1)
            self.bias_b += lr_rate*grad_b.reshape(1, -1)
            self.weights += lr_rate/batch_size*grad_weights

            if verbose==True and i%1000==0:
                print("Iteration %d out of %d. Loss value is %.4f" %(i, n_epoch,
                    np.sum((batch - v_1)**2)/batch_size))

        return self

    def generer_image_RBM(self, data_shape, nb_images=10, rows=20, cols=16, figsize=(8,6), max_iter=10000):

        data = np.random.rand(nb_images, data_shape)

        # Gibbs sampling
        for j in range(max_iter):
            data, _ = self.entree_sortie_RBM(data)
            data, _ = self.sortie_entree_RBM(data)

        im_cols = 3
        im_rows = nb_images // im_cols + nb_images % im_cols
        position = range(1,nb_images + 1)
        fig = plt.figure(1, figsize=figsize)

        for k in range(nb_images):
            ax = fig.add_subplot(im_rows, im_cols, position[k])
            ax.imshow(data[k, :].reshape(rows, cols, order='F'), cmap='gray')

        return data

if __name__ == "__main__" :
   to_learn_chrs = "842CDF" # Characters that we want to learn
   data = lire_alpha_digit("./data/binaryalphadigs.mat", to_learn_chrs) # Getting the data
   alpha_rbm = RBM(data[0, :].shape[0], 250) # Constructing an RBM class instance
   alpha_rbm =  alpha_rbm.train_RBM(data, n_epoch=50000, verbose=True) # Training the RBM
   generated = alpha_rbm.generer_image_RBM(data[0, :].shape[0], 10, max_iter=30000)


from PIL import Image
import numpy
from math import floor
import matplotlib.pyplot as plt

def getIntensityCount(np_img):
  KCount = numpy.zeros(256)
  for row in np_img:
    for K in row:
      KCount[K]+=1
  return KCount

def getCumm_Intensity(np_count):
  Cumm = numpy.zeros(256)
  Cumm[0] = np_count[0]
  for i in range(1,256):
    Cumm[i] = Cumm[i-1]+np_count[i]
  return Cumm

def HistogramEquilize(np_img):
  w,h = np_img.shape()
  norm_Intensity =  getIntensityCount(np_img)/(w*h)
  Cumm_norm_Intensity = getCumm_Intensity(norm_Intensity)
  ## TransIntensity :- T(K)
  ScaleK = lambda t: int(floor(255*t))
  Trans_Intensity = numpy.vectorize(ScaleK)(Cumm_norm_Intensity)
  transformK = lambda t: Trans_Intensity[t]
  np_equiImg = numpy.vectorize(transformK)(np_img)
  return Cumm_norm_Intensity,np_equiImg

im = Image.open('lenna.png','r')
im_grey = im.convert('L')
np_im_grey = numpy.array(im_grey)
w,h = np_im_grey.shape
Cumm_norm_Intensity, np_equiImg = HistogramEquilize(np_im_grey)

## Show Both Images
concat_np_img = numpy.concatenate((np_im_grey,np_equiImg))
concat_img = Image.fromarray(concat_np_img)
concat_img.show()

## Plot Cummulative Frequency Histograms
Trans_NormIntensity = getIntensityCount(np_equiImg)/(w*h)
Trans_CommIntensity = getCumm_Intensity(Trans_NormIntensity)
plt.plot(Cumm_norm_Intensity)
plt.plot(Trans_CommIntensity)
plt.show()


import numpy as np
import matplotlib.pyplot as plt

def cg(A, b, x0, tolerance):
    iterates = [x0]
    r = b - A @ x0
    p = r
    x = x0
    error = np.linalg.norm(r)
    errors = [error]
    iters = 0
    while error >= tolerance and iters < 100:
        iters += 1
        alpha = (r.T @ r) / (p.T @ A @ p)
        x_new = x + alpha * p
        r_new = r - alpha * (A @ p)
        beta = (r_new.T @ r_new) / (r.T @ r)
        p_new = r_new + beta * p

        x = x_new
        r = r_new
        p = p_new

        iterates.append(x)
        error = np.linalg.norm(r)
        errors.append(error)
    return iterates, errors

def gd(A, b, x0, tolerance, alpha=1e-1):
    x = x0
    iters = 0
    error = np.linalg.norm((A@x) - b)
    iterates = [x]
    errors = [error]
    alpha_0 = alpha
    while error >= tolerance and iters < 100:
        iters += 1

        grad = A @ x - b
        x -= alpha * grad
        alpha = alpha_0 / (iters + 1)

        error = np.linalg.norm((A@x) - b)
        errors.append(error)
        iterates.append(x)
    return iterates, errors

def main():
    M = np.random.rand(10, 10)
    A = M.T @ M
    b = np.random.rand(10, 1)
    x0 = np.zeros_like(b)
    tolerance = 1e-10

    iterates, errors = cg(A, b, x0, tolerance)
    iterates_gd, errors_gd = gd(A, b, x0, tolerance)

    iters = np.arange(len(errors))
    iters_gd = np.arange(len(errors_gd))
    plt.plot(iters, errors, label='Conjugate Gradient')
    plt.plot(iters_gd, errors_gd, label='Gradient Descent')
    plt.xlabel("Iteration")
    plt.ylabel("L2 Error")
    plt.legend()

    plt.show()

if __name__ == '__main__':
    main()


"""
    Obliczyć wyznacznik macierzy A korzystając z rozwinięcia Laplace'a.
    https://pl.wikipedia.org/wiki/Rozwini%C4%99cie_Laplace%E2%80%99a
"""
import numpy as np

MESSAGE_REGARDING_DIFFERENT_DIMENSIONS = "The matrix should be a square matrix"

def validate_matrix_dimensions(A):

    # Sprawdź czy podana macierz jest macierzą kwadratową,
    # jeżeli nie jest wyrzuć wyjątek
    n_1, n_2 = A.shape

    if n_1 != n_2:
        raise ValueError(MESSAGE_REGARDING_DIFFERENT_DIMENSIONS)

def calculate_the_determinant_of_the_matrix(A):

    # Jeżeli macierz ma wymiary (1,1) oznacza to że zawiera tylko 1 element,
    # zwróć ten element
    m,n = A.shape
    if (m,n) == (1, 1):
        return A[0][0]

    suma = 0
    # Iterujemy po kolejnych kolumnach macierzy A
    for i in range(n):
        # -1 podnosimy do potęgi i, ponieważ w macierzy kwadratowej
        # oznacza ono zarówno indeks wiersza jak i kolumny
        poverty = (-1) ** i

        # Jako kolejne elementy będziemy brać kolejne elementy pierwszego wiersza
        current_element = A[0][i]

        # Nasz bieżący element będzie mnożony przez macierz pozbawioną pierwszego wiersza oraz i-tej kolumny
        temp_A = A[1:, [k for k in range(n) if k != i]]

        # Sumujemy kolejne częsci rozwinięcia Laplace’a
        suma += poverty * current_element * calculate_the_determinant_of_the_matrix(temp_A)

    return suma

def determinant_of_the_matrix(A):

    validate_matrix_dimensions(A=A)
    return calculate_the_determinant_of_the_matrix(A=A)

# Tests
A = np.array([[ 1.,  3.,  0.,  0.],
              [ -3.,  2.,  3.,  2.],
              [ 1.,  2.,  2.,  2.],
              [ 1.,  0.,  0.,  3.]])

np.testing.assert_equal(round(determinant_of_the_matrix(A), 2),
                        round(np.linalg.det(A), 2))

try:
    determinant_of_the_matrix(np.ones((2,3)))

except (BaseException, Exception) as error:
    if type(error) != ValueError or \
            str(error) != MESSAGE_REGARDING_DIFFERENT_DIMENSIONS:
        raise AssertionError(str(error))

print("All tests were successful.")


from multiprocessing import cpu_count
from multiprocessing.pool import Pool

import numpy as np
import pandas as pd

"""
Chapter 5 of Advances in Financial Machine Learning book by Marcos Lopez de Prado
"""

def get_weights_ffd(d, threshold=1e-5):
    """
    Obtain the weights for the binomial representation of time series
    :param d: coefficient
    :param threshold: threshold
    """

    w, k = [1.], 1
    while abs(w[-1]) > threshold:
        w_ = -w[-1] / k * (d - k + 1)
        w.append(w_)
        k += 1

    w = np.array(w[::-1])

    return w

def _frac_diff_ffd(data: pd.Series, d: float, threshold=1e-5):
    """
    Fractionally Differentiated Features Fixed Window
    :param data: data
    :param d: difference coefficient
    :param threshold: threshold
    """
    # 1) Compute weights for the longest series
    w = get_weights_ffd(d, threshold)
    # 2) Apply weights to values
    return data.rolling(w.size, min_periods=w.size).apply(lambda x: np.dot(x, w), raw=True).dropna()

def frac_diff_ffd(data: pd.Series, d: float, threshold=1e-5, parallel=False):
    """
    Fractionally Differentiated Features Fixed Window
    :param data: data
    :param d: difference coefficient
    :param threshold: threshold
    :param parallel: run in parallel
    """
    if isinstance(data.index, pd.MultiIndex):
        if parallel:
            with Pool(cpu_count()) as p:
                ret_list = p.starmap(_frac_diff_ffd, [(group, d, threshold) for name, group in data.groupby(level='symbol', group_keys=False, sort=False)])
                return pd.concat(ret_list)
        else:
            return data.groupby(level='symbol', group_keys=False, sort=False).apply(_frac_diff_ffd, d=d, threshold=threshold)
    else:
        return _frac_diff_ffd(data=data, d=d, threshold=threshold)

# def plot_weights(d_range, n_plots):
#     import matplotlib.pyplot as plt
#
#     w = pd.DataFrame()
#     for d in np.linspace(d_range[0], d_range[1], n_plots):
#         w_ = get_weights_ffd(d)
#         w_ = pd.DataFrame(w_, index=range(w_.shape[0])[::-1], columns=[d])
#         w = w.join(w_, how='outer')
#     ax = w.plot()
#     ax.legend(loc='upper left');
#     plt.show()
#     return
#
#
# if __name__ == '__main__':
#     plot_weights(d_range=[0, 1], n_plots=11)
#     plot_weights(d_range=[1, 2], n_plots=11)


import numpy as np

EPSILON = 1e-10

def _error(actual: np.ndarray, predicted: np.ndarray):
    """ Simple error """
    return actual - predicted

def _percentage_error(actual: np.ndarray, predicted: np.ndarray):
    """
    Percentage error

    Note: result is NOT multiplied by 100
    """
    return _error(actual, predicted) / (actual + EPSILON)

def _naive_forecasting(actual: np.ndarray, seasonality: int = 1):
    """ Naive forecasting method which just repeats previous samples """
    return actual[:-seasonality]

def _relative_error(
    actual: np.ndarray, predicted: np.ndarray, benchmark: np.ndarray = None
):
    """ Relative Error """
    if benchmark is None or isinstance(benchmark, int):
        # If no benchmark prediction provided - use naive forecasting
        if not isinstance(benchmark, int):
            seasonality = 1
        else:
            seasonality = benchmark
        return _error(actual[seasonality:], predicted[seasonality:]) / (
            _error(actual[seasonality:], _naive_forecasting(actual, seasonality))
            + EPSILON
        )

    return _error(actual, predicted) / (_error(actual, benchmark) + EPSILON)

def mse(actual: np.ndarray, predicted: np.ndarray):
    """ Mean Squared Error """
    return np.mean(np.square(_error(actual, predicted)))

def rmse(actual: np.ndarray, predicted: np.ndarray):
    """ Root Mean Squared Error """
    return np.sqrt(mse(actual, predicted))

def mae(actual: np.ndarray, predicted: np.ndarray):
    """ Mean Absolute Error """
    return np.mean(np.abs(_error(actual, predicted)))

def wape(actual: np.ndarray, predicted: np.ndarray):
    """ Weighted Absolute Percentage Error """
    return mae(actual, predicted) / (np.mean(actual) + EPSILON)

def mape(actual: np.ndarray, predicted: np.ndarray):
    """
    Mean Absolute Percentage Error

    Properties:
        + Easy to interpret
        + Scale independent
        - Biased, not symmetric
        - Undefined when actual[t] == 0

    Note: result is NOT multiplied by 100
    """
    return np.mean(np.abs(_percentage_error(actual, predicted)))

def smape(actual: np.ndarray, predicted: np.ndarray):
    """
    Symmetric Mean Absolute Percentage Error

    Note: result is NOT multiplied by 100
    """
    return 100 * np.mean(
        2.0 * np.abs(actual - predicted) / ((np.abs(actual) + np.abs(predicted)))
    )

def mase(actual: np.ndarray, predicted: np.ndarray, seasonality: int = 1):
    """
    Mean Absolute Scaled Error

    Baseline (benchmark) is computed with naive forecasting (shifted by @seasonality)
    """
    return mae(actual, predicted) / (
        mae(actual[seasonality:], _naive_forecasting(actual, seasonality))
    )

def std_ae(actual: np.ndarray, predicted: np.ndarray):
    """ Normalized Absolute Error """
    __mae = mae(actual, predicted)
    return np.sqrt(
        np.sum(np.square(_error(actual, predicted) - __mae)) / (len(actual) - 1)
    )

def std_ape(actual: np.ndarray, predicted: np.ndarray):
    """ Normalized Absolute Percentage Error """
    __mape = mape(actual, predicted)
    return np.sqrt(
        np.sum(np.square(_percentage_error(actual, predicted) - __mape))
        / (len(actual) - 1)
    )

def mre(actual: np.ndarray, predicted: np.ndarray, benchmark: np.ndarray = None):
    """ Mean Relative Error """
    # return np.mean( np.abs(_error(actual, predicted)) / (actual + EPSILON))
    return np.mean(_relative_error(actual, predicted, benchmark))

def rae(actual: np.ndarray, predicted: np.ndarray):
    """ Relative Absolute Error (aka Approximation Error) """
    return np.sum(np.abs(actual - predicted)) / (
        np.sum(np.abs(actual - np.mean(actual))) + EPSILON
    )

def mrae(actual: np.ndarray, predicted: np.ndarray, benchmark: np.ndarray = None):
    """ Mean Relative Absolute Error """
    return np.mean(np.abs(_relative_error(actual, predicted, benchmark)))

METRICS = {
    "mse": mse,
    "rmse": rmse,
    "mae": mae,
    "wape": wape,
    # "mape": mape,
    # "smape": smape,
    "mase": mase,
    # "std_ae": std_ae,
    # "std_ape": std_ape,
    # "rae": rae,
    #'mre': mre,
    #'mrae': mrae
}

import matplotlib.pyplot as plt

def evaluate(
    actual: np.ndarray,
    predicted: np.ndarray,
    metrics=("mae", "mse", "mase", "smape", "wape"),
):
    results = {}
    for name in metrics:
        try:
            res = []

            for y, o in zip(actual, predicted):
                all_zeros = name in ["mape", "wape", "std_ape", "rae"] and np.all(
                    y == 0.0
                )
                all_identical = name in ["mase", "wape", "mape"] and np.all(
                    np.abs(y - np.mean(y)) < 0.001
                )
                if not all_zeros and not all_identical:
                    res.append(METRICS[name](y, o))

                if (
                    False
                    and not all_zeros
                    and not all_identical
                    and METRICS[name](y, o) > 100000
                ):
                    plt.plot(y, label="real")
                    plt.plot(o, label="predicted")
                    plt.title("{}: {}".format(name, METRICS[name](y, o)))
                    plt.legend()
                    plt.show()

            results[name] = np.mean(res)

        except Exception as err:
            results[name] = np.nan
            print("Unable to compute metric {0}: {1}".format(name, err))

    return results

def evaluate_all(actual: np.ndarray, predicted: np.ndarray):
    return evaluate(actual, predicted, metrics=set(METRICS.keys()))


'''
- Physical constants: h, c, k, sigma, G, N_avogadro, Rstart
- Plank function
- Demonstration of how to convert differnt units, using the package *pint*.

License
-------
BSD 3-clause (see https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html)
'''

import numpy as np
from scipy import constants

# Get basic physical and thermodynamic constants

# Physical constants
h     = constants.h     #Planck's constant
c     = constants.c     #Speed of light
k     = constants.k     #Boltzman thermodynamic constant
sigma = constants.sigma #Stefan-Boltzman constant
G     = constants.G     #Gravitational constant

# Thermodynamic constants

# Following will come out in J/(deg kmol), so that dividing Rstar by molecular
# weight gives gas constant appropriate for mks units
N_avogadro = constants.Avogadro  #Avogadro's number
Rstar = 1000. * k * N_avogadro   #Universal gas constant

#----------------Radiation related functions-------------
def B(nu,T):
    '''Planck function (of frequency)
    Density of blackbody radiation.

    Parameters
    ----------
        nu : float
            Frequency [Hz]
        T : float
            Temperature [K]

    Return
    ------
        B : float
            Corresponding blackbody radiation density

    .. math::
        B(\\nu, T) = \\frac{2 k^3 T^3}{h^2 c^2} \\frac{u^3}{e^u -1}

    Example
    -------
    >>> import matplotlib.pyplot as plt
    >>>
    >>> nu = np.linspace(1e12, 1e14, 1001)
    >>> T = 300
    >>> blackbody_radiation = B(nu, T)
    >>>
    >>> plt.plot(nu, blackbody_radiation)
    >>> plt.xlabel(r'$\\nu [Hz]$')
    >>> plt.ylabel(r'$B(\\nu)$')
    >>> plt.title('Blackbody Radiation')
    >>> plt.show()

    '''

    u = h*nu/(k*T)
    u = np.atleast_1d(u)
    u[u>500] = 500           #To prevent overflow
    B = 2.*h*nu**3/c**2 / (np.exp(u)-1.)
    if len(B)==1:
        B = B[0]

    return B

if __name__=='__main__':
    # Example for working with units -----------------------
    # While the example is for "temperature", most common physical units
    # can be converted.
    import pint

    # Select a temperature
    units = pint.UnitRegistry()
    Quantity = units.Quantity

    temp_deg = 30                                # Temperature in deg Celsius
    Temperature = Quantity(temp_deg, units.degC)  # Temperature-object
    temp_K = Temperature.to(units.K).magnitude    # Temperature in deg Kelvin

    print('{0:5.1f} deg C = {1:5.1f} deg K'.format(temp_deg, temp_K))

    # Show how to use the Planck-function
    import matplotlib.pyplot as plt

    nu = np.linspace(1e12, 1e14, 1001)
    T = 300
    print('B_max at nu= {0:6.3e} Hz'.format(58.8e9*T))
    blackbody_radiation = B(nu, T)
    plt.plot(nu, blackbody_radiation)
    plt.xlabel(r'$\nu [Hz]$')
    plt.ylabel(r'$B(\nu)$')
    plt.title('Blackbody Radiation')
    plt.show()

    nu = 1.5e13
    print('The radiation density at {0:5.3e} Hz and {1} K is: {2:8.6e}'.format(nu, T, B(nu, T)))


from sympy import Symbol
from sympy import integrate
from decimal import *
"""
    Estos seran los datos de entrada de nuestro programa.
        f(x) representa la funcion que queremos integrar
        [a,b] es el intervalo donde queremos obtener el valor de la integral
        m son los intervalos que utilizaremos.
"""
x=Symbol('x')
f = 1/(1+x**2)

a=-4
b=4
m=10

"""
    A partir de aqui, comienza el codigo de nuestro programa.
    Primero de todo, calcularemos el valor de h y los nodos que utilizaremos.
"""
n=2*m

h=Decimal((b-a))/Decimal(n)

nodos=[]
for i in range(n+1):
    nodos.append(a+i*h)
    """print(nodos[i])"""

"""
    A continuacion, calcularemos el valor de la integral.
"""
suma1=0
suma2=0
for i in range(1,m+1):
    suma1=suma1+4*f.subs(x,nodos[2*i-1])
    if(i>=2):
        suma2=suma2+2*f.subs(x,nodos[2*i-2])
"""print("\n")
print(f.subs(x,nodos[0]))
print(suma1)
print(suma2)
print(f.subs(x,nodos[n]))

print("\n")
print(h)
print(h/3)
print(f.subs(x,nodos[0])+suma1+suma2+f.subs(x,nodos[n]))"""
integral=(h/3)*(f.subs(x,nodos[0])+suma1+suma2+f.subs(x,nodos[n]))

print(integral)


import numpy as np
import matplotlib.pyplot as plt

from IPython.html.widgets import  interactive, IntSlider, widget, FloatText, FloatSlider, Checkbox, ToggleButtons

sigmin = 0.01
sigmax = 0.1

sigma_0 = 0 # conductivity of the air
h_1 = 1.
h_boom = 0.
h_boom_max = 2.

zmax = 4.

z = np.linspace(0.,zmax,1000)

phi_v = lambda z: (4.*z) / (4.*z**2 + 1.)**(3./2.)
phi_h = lambda z: 2 - (4.*z) / (4.*z**2 + 1.)**(1./2.)

R_v = lambda z: 1./(4.*z**2. + 1.)**(1./2.)
R_h = lambda z: (4.*z**2 + 1.)**(1./2.) - 2.*z

sigma_av = lambda h_boom, h_1, sigma_1, sigma_2: sigma_0*(1.-R_v(h_boom)) + sigma_1*(R_v(h_boom) - R_v(h_1+h_boom)) + sigma_2*R_v(h_1+h_boom)
sigma_ah = lambda h_boom, h_1, sigma_1, sigma_2: sigma_0*(1.-R_h(h_boom)) + sigma_1*(R_h(h_boom) - R_h(h_1+h_boom)) + sigma_2*R_h(h_1+h_boom)

def plot_ResponseFct(h_boom,h_1,sigma_1,sigma_2,orientation='vertical'):

    sigvec = sigma_1*np.ones(z.shape)
    sigvec[z > h_1] = sigma_2

    if orientation is 'vertical':
        phi = phi_v(z + h_boom)
        sig_a = sigma_av(h_boom,h_1,sigma_1,sigma_2)
        phi_title = '$\phi_V$'
    elif orientation is 'horizontal':
        phi = phi_h(z + h_boom)
        sig_a = sigma_ah(h_boom,h_1,sigma_1,sigma_2)
        phi_title = '$\phi_H$'

    phisig = phi*sigvec

    fig, ax = plt.subplots(1,3,figsize=(11,6))

    fs = 13

    ax[0].plot(sigvec,z,'r',linewidth=1.5)
    ax[0].set_xlim([0.,sigmax*1.1])
    ax[0].invert_yaxis()
    ax[0].set_ylabel('z/s',fontsize = fs)
    ax[0].set_title('$\sigma$', fontsize = fs+4, position=[.5, 1.02])
    ax[0].set_xlabel('Conductivity (S/m)', fontsize=fs)
    ax[0].grid(which='both',linewidth=0.6,color=[0.5,0.5,0.5])

    ax[1].plot(phi,z,linewidth=1.5)
    ax[1].set_xlim([0.,2.])
    ax[1].invert_yaxis()
    ax[1].set_title('%s'%(phi_title), fontsize = fs+4, position=[.5, 1.02])
    ax[1].set_xlabel('Response Function', fontsize=fs)
    ax[1].grid(which='both',linewidth=0.6,color=[0.5,0.5,0.5])

    ax[2].plot(phisig,z,color='k',linewidth=1.5)
    ax[2].fill_betweenx(z,phisig,color='k',alpha=0.5)
    ax[2].invert_yaxis()
    ax[2].set_title('$\sigma \cdot$ %s'%(phi_title), fontsize = fs+4, position=[.5, 1.02])
    ax[2].set_xlabel('Weighted Conductivity (S/m)', fontsize=fs)
    ax[2].set_xlim([0.,sigmax*2.])
    ax[2].grid(which='both',linewidth=0.6,color=[0.5,0.5,0.5])

    props = dict(boxstyle='round', facecolor='grey', alpha=0.3)

    # place a text box in upper left in axes coords
    textstr = '$\sigma_a=%.3f$ S/m'%(sig_a)
    ax[2].text(sigmax*0.9, 3.75, textstr, fontsize=fs+2,
            verticalalignment='bottom', bbox=props)

    plt.tight_layout()
    plt.show()

    return None

def interactive_responseFct():
	app = interactive(plot_ResponseFct,h_boom = FloatSlider(min=h_boom, max = h_boom_max, step = 0.1, value = h_boom, continuous_update=False),
                  h_1 = FloatSlider(min=0., max=zmax,value=0.1, step = 0.1, continuous_update=False),
                  sigma_1 = FloatSlider(min=sigmin, max = sigmax,value=sigmin, step = sigmin, continuous_update=False),
                  sigma_2 = FloatSlider(min=sigmin, max = sigmax,value=sigmin, step = sigmin, continuous_update=False),
                  orientation=ToggleButtons(options=['vertical','horizontal']))
	return app

if __name__ == '__main__':
	plot_ResponseFct(1., sigmin, sigmax)


# coding=utf-8
# MSC means Multiple Spectral Clustering
import numpy as np
import scipy as sp
import scipy.linalg as linalg
import networkx as nx
import matplotlib.pyplot as plt

def getNormLaplacian(W):
    """input matrix W=(w_ij)
    "compute D=diag(d1,...dn)
    "and L=D-W
    "and Lbar=D^(-1/2)LD^(-1/2)
    "return Lbar
    """
    d = [np.sum(row) for row in W]
    D = np.diag(d)
    L = D - W
    # Dn=D^(-1/2)
    Dn = np.power(np.linalg.matrix_power(D, -1), 0.5)
    Lbar = np.dot(np.dot(Dn, L), Dn)
    return Lbar

def getKSmallestEigVec(Lbar, k):
    """input
    "matrix Lbar and k
    "return
    "k smallest eigen values and their corresponding eigen vectors
    """
    eigval, eigvec = linalg.eig(Lbar)
    dim = len(eigval)

    # 查找前k小的eigval
    dictEigval = dict(zip(eigval, range(0, dim)))
    kEig = np.sort(eigval)[0:k]
    ix = [dictEigval[k] for k in kEig]
    return eigval[ix], eigvec[:, ix]

def checkResult(Lbar, eigvec, eigval, k):
    """
    "input
    "matrix Lbar and k eig values and k eig vectors
    "print norm(Lbar*eigvec[:,i]-lamda[i]*eigvec[:,i])
    """
    check = [np.dot(Lbar, eigvec[:, i]) - eigval[i] * eigvec[:, i] for i in range(0, k)]
    length = [np.linalg.norm(e) for e in check] / np.spacing(1)
    print("Lbar*v-lamda*v are %s*%s" % (length, np.spacing(1)))

g = nx.karate_club_graph()
nodeNum = len(g.nodes())
m = nx.to_numpy_matrix(g)
Lbar = getNormLaplacian(m)
k = 2
kEigVal, kEigVec = getKSmallestEigVec(Lbar, k)
print("k eig val are %s" % kEigVal)
print("k eig vec are %s" % kEigVec)
checkResult(Lbar, kEigVec, kEigVal, k)

# 跳过k means，用最简单的符号判别的方法来求点的归属

clusterA = [i for i in range(0, nodeNum) if kEigVec[i, 1] > 0]
clusterB = [i for i in range(0, nodeNum) if kEigVec[i, 1] < 0]

# draw graph
colList = dict.fromkeys(g.nodes())
for node, score in colList.items():
    if node in clusterA:
        colList[node] = 0
    else:
        colList[node] = 0.6
plt.figure(figsize=(8, 8))
pos = nx.spring_layout(g)
nx.draw_networkx_edges(g, pos, alpha=0.4)

nx.draw_networkx_labels(g, pos, font_size=10, font_family='sans-serif')
plt.axis('off')
plt.title("karate_club spectral clustering")
plt.savefig("spectral_clustering_result.png")
plt.show()

import numpy,import scipy,import networkx


# -*- coding: utf-8 -*-
"""
stochastic chain rule

    dX = (α-X) dt + β*sqrt(X) dW, X(0) = X0

this equation is integrated using the Euler-Maruyama method, first directly
and a second time using V = sqrt(X), which yields (after applying the
stochastic chain rule):
    dV = ((4*α-β**2)/(8*V) - V/2) dt + β/2 dW
"""

import numpy as np
from numpy.random import randn
import matplotlib.pyplot as plt

np.random.seed(100)

α = 2; β = 1; X0 = 1
T = 1; N = 200; dt = T / N
t = np.arange(0, T+dt, dt)

dW = np.sqrt(dt)*randn(N)

# direct
X = np.zeros(N+1)
X[0] = X0
# chain rule
V = np.zeros(N+1)
V[0] = X0**2

for i in range(1, N+1):
    X[i] = X[i-1] + (α - X[i-1]) * dt \
            + β * np.sqrt(np.abs(X[i-1])) * dW[i-1]
    V[i] = V[i-1] + ((4*α-β**2) / (8*V[i-1]) - .5*V[i-1]) * dt \
            + .5*β*dW[i-1]

plt.plot(t, np.sqrt(X), 'b-', label='direct')
plt.plot(t, V, 'r:', label='chain rule')
plt.xlabel('t')
plt.ylabel('V(X)')
plt.legend()

print("err: %f" % np.max(np.abs(np.sqrt(X)-V)))


"""krylov methods"""

import numpy as np
import math

def cg(x, A, b):
    """conjugate gradient"""
    n = b.size

    r = b - A.dot(x)
    p = np.copy(r)

    r2 = r.dot(r)
    error = math.sqrt(r2)

    Ap = np.zeros(n)

    while error > 0:
        Ap[:] = A.dot(p)
        alpha = r2 / p.dot(Ap)

        x += alpha * p
        r -= alpha * Ap

        old_r2 = r2
        r2 = r.dot(r)

        error = math.sqrt(r2)

        yield error, r

        beta = r2 / old_r2
        p[:] = r + beta * p

def cr(x, A, b):
    """conjugate residual"""

    r = b - A.dot(x)
    p = np.copy(r)

    Ar = A.dot(r)
    Ap = np.copy(Ar)

    rAr = r.dot(Ar)
    r2 = r.dot(r)

    error = math.sqrt(r2)

    while error > 0:
        alpha = rAr / Ap.dot(Ap)

        x += alpha * p
        r -= alpha * Ap

        r2 = r.dot(r)
        error = math.sqrt(r2)

        yield error, r

        Ar[:] = A.dot(r)
        old_rAr = rAr

        rAr = r.dot(Ar)

        beta = rAr / old_rAr

        p[:] = r + beta * p
        Ap[:] = Ar + beta * Ap

# TODO pcg, pcr


# Author: Jintao Huang
# Email: hjt_study@qq.com
# Date:

from numba import njit
import random
from typing import Callable

@njit
def func(x: float) -> float:
    return x ** 2 - 1

def func_integral(x: float) -> float:
    return x ** 3 / 3 - x

@njit
def HitorMiss2(f: Callable[[float], float],
               a: float, b: float, c: float, d: float,
               n: int) -> float:
    """f: [a, b]->[c, d]"""
    k = 0  # 命中
    c, d = min(c, 0), max(d, 0)
    S = (d - c) * (b - a)
    #
    for _ in range(n):
        x = random.uniform(a, b)
        y = random.uniform(c, d)
        fx = f(x)
        #
        if 0 < y <= fx:  # (x, y)在阴影处
            k += 1
        if fx <= y < 0:
            k -= 1
    return k / n * S

a, b, c, d = -1, 3, func(0), func(3)
print("准确解: %f" % (func_integral(b) - func_integral(a)))
#
n = int(1e8)
res = HitorMiss2(func, a, b, c, d, n)
print("n: %d, 计算的积分值: %f" % (n, res))

"""Out
准确解: 5.333333
n: 100000000, 计算的积分值: 5.337512
"""


import numpy as np

def population_correlation(data_matrix, x_index, y_index):
    """
    data_matrix is a numpy multi-dimensional array (matrix)
    x_index and y_index are the index for the first and second variables respectively
    it returns the correlation between two variables in a data_matrix
    """
    transposed_data = data_matrix.transpose()
    x_population = transposed_data[x_index]
    x_mean = np.mean(x_population)
    x_std = np.std(x_population)
    y_population = transposed_data[y_index]
    y_mean = np.mean(y_population)
    y_std = np.std(y_population)

    # To calculate the expectation means to calculate the cov(x_population, y_population)
    # This can also be done using numpy. For that use: np.cov(x_population, y_population, bias=True)
    # bias=True indicates that we are calculating the population covariance
    # np.cov returns a bxb matrix, where b is the amount of vectors passed as parameter, in our case b=2
    expectation = np.mean((x_population - x_mean) * (y_population - y_mean))
    std_product = x_std * y_std

    return expectation/std_product

def sample_correlation(data_matrix, x_index, y_index):
    # Sample information
    sample_len = data_matrix[0].size
    sample_sum = data_matrix.sum(axis=0)

    # Feature information
    transposed_data = data_matrix.transpose()
    x_population = transposed_data[x_index]
    y_population = transposed_data[y_index]
    xy = np.multiply(x_population, y_population)
    x_pow = np.multiply(x_population, x_population)
    y_pow = np.multiply(y_population, y_population)

    # Sample correlation calculation
    numerator = (sample_len * xy.sum()) - (sample_sum[x_index] * sample_sum[y_index])
    x_denominator = (sample_len * x_pow.sum()) - (x_population.sum() ** 2)
    y_denominator = (sample_len * y_pow.sum()) - (y_population.sum() ** 2)
    # TODO: Fix runtimeWarning: overflow encountered in long_scalars and output value
    denominator = (x_denominator * y_denominator) ** (1/2)

    return numerator/denominator