import numpy as np
from math import sqrt
from sys import argv

def sphere(x_, y_, z_):
    """
        calculate best fitting sphere (LSM) on points
        :param returns: x0, y0, z0, R
    """
    n_ = x_.shape[0]
    a = np.c_[x_, y_, z_, np.full(n_, 1, 'float64')]
    b = -np.square(x_) - np.square(y_) - np.square(z_)
    res = np.linalg.lstsq(a, b, rcond=None)[0]
    return -0.5 * res[0], -0.5 * res[1], -0.5 * res[2], \
          sqrt((res[0]**2 + res[1]**2 + res[2]**2) / 4 - res[3])

if __name__ == "__main__":
    if len(argv) > 1:
        file_names = argv[1:]
    else:
        file_names = ['sphere1.txt']
    for file_name in file_names:
        pnts = np.genfromtxt(file_name, 'float64', delimiter=',')
        if pnts.shape[1] > 3:
            pnts = pnts[:,1:4]  # skip first column (point id)
        sph = sphere(pnts[:,0], pnts[:,1], pnts[:,2])
        print("x0: {:.3f} y0: {:.3f} z0: {:.3f} R: {:.3f}".format(sph[0], sph[1], sph[2], sph[3]))
        dr = np.sqrt(np.sum(np.square(pnts - sph[:3]), 1)) - sph[3] # difference in radius direction
        RMS = sqrt(np.sum(np.square(dr)) / pnts.shape[0])
        print("RMS: {:.3f}".format(RMS))


"""Von neumann entropy metric."""
import numpy as np

from toqito.matrix_props import is_density

def von_neumann_entropy(rho: np.ndarray) -> float:
    r"""
    Compute the von Neumann entropy of a density matrix [WikVent]_. [WatVec]_.

    Let :math:`P \in \text{Pos}(\mathcal{X})` be a positive semidefinite operator, for a complex
    Euclidean space :math:`\mathcal{X}`. Then one defines the *von Neumann entropy* as

    .. math::
        H(P) = H(\lambda(P)),

    where :math:`\lambda(P)` is the vector of eigenvalues of :math:`P` and where the function
    :math:`H(\cdot)` is the Shannon entropy function defined as

    .. math::
        H(u) = -\sum_{\substack{a \in \Sigma \\ u(a) > 0}} u(a) \text{log}(u(a)),

    where the :math:`\text{log}` function is assumed to be the base-2 logarithm, and where
    :math:`\Sigma` is an alphabet where :math:`u \in [0, \infty)^{\Sigma}` is a vector of
    nonnegative real numbers indexed by :math:`\Sigma`.

    Examples
    ==========

    Consider the following Bell state:

    .. math::
        u = \frac{1}{\sqrt{2}} \left(|00 \rangle + |11 \rangle \right) \in \mathcal{X}.

    The corresponding density matrix of :math:`u` may be calculated by:

    .. math::
        \rho = u u^* = \frac{1}{2} \begin{pmatrix}
                         1 & 0 & 0 & 1 \\
                         0 & 0 & 0 & 0 \\
                         0 & 0 & 0 & 0 \\
                         1 & 0 & 0 & 1
                       \end{pmatrix} \text{D}(\mathcal{X}).

    Calculating the von Neumann entropy of :math:`\rho` in :code:`toqito` can be done as follows.

    >>> from toqito.state_props import von_neumann_entropy
    >>> import numpy as np
    >>> test_input_mat = np.array(
    >>>     [[1 / 2, 0, 0, 1 / 2], [0, 0, 0, 0],
    >>>      [0, 0, 0, 0], [1 / 2, 0, 0, 1 / 2]]
    >>> )
    >>> von_neumann_entropy(test_input_mat)
    5.88418203051333e-15

    Consider the density operator corresponding to the maximally mixed state of dimension two

    .. math::
        \rho = \frac{1}{2}
        \begin{pmatrix}
            1 & 0 \\
            0 & 1
        \end{pmatrix}.

    As this state is maximally mixed, the von Neumann entropy of :math:`\rho` is
    equal to one. We can see this in :code:`toqito` as follows.

    >>> from toqito.state_props import von_neumann_entropy
    >>> import numpy as np
    >>> rho = 1/2 * np.identity(2)
    >>> von_neumann_entropy(rho)
    1.0

    References
    ==========
    .. [WikVent] Wikipedia: Von Neumann entropy
        https://en.wikipedia.org/wiki/Von_Neumann_entropy

    .. [WatVec] Watrous, John.
        "The theory of quantum information."
        Section: "Definitions of quantum entropic functions".
        Cambridge University Press, 2018.

    :param rho: Density operator.
    :return: The von Neumann entropy of :code:`rho`.
    """
    if not is_density(rho):
        raise ValueError("Von Neumann entropy is only defined for density " "operators.")
    eigs, _ = np.linalg.eig(rho)
    eigs = [eig for eig in eigs if eig > 0]
    return -np.sum(np.real(eigs * np.log2(eigs)))


from scipy import *

def forwardsub(L,b):
	"""
 	forwardsub(L,b)

	Solve the lower-triangular linear system with matrix L and right-hand side
	vector b.
	"""
	n = len(b)
	x = zeros(n)
	for i in range(n):
		s = L[i,:i] @ x[:i]
		x[i] = ( b[i] - s ) / L[i,i]
	return x

def backsub(U,b):
	"""
	backsub(U,b)

	Solve the upper-triangular linear system with matrix U and right-hand side
	vector b.
	"""
	n = len(b)
	x = zeros(n)
	for i in range(n-1,-1,-1):
		s = U[i,i+1:] @ x[i+1:]
		x[i] = ( b[i] - s ) / U[i,i]
	return x

def lufact(A):
	"""
	lufact(A)

	Compute the LU factorization of square matrix A, returning the factors.
	"""
	n = A.shape[0]
	L = eye(n)      # puts ones on diagonal
	U = copy(A)

	# Gaussian elimination
	for j in range(n-1):
		for i in range(j+1,n):
			L[i,j] = U[i,j] / U[j,j]   # row multiplier
			U[i,j:] = U[i,j:] - L[i,j]*U[j,j:]
	return L,triu(U)


import numpy as np
import pandas as pd
from scipy.integrate import ode, solve_ivp
import matplotlib.pyplot as plt

def sir_ode(times,init,parms):
    b, g = parms
    S,I,R = init
    # ODEs
    dS = -b*S*I
    dI = b*S*I-g*I
    dR = g*I
    return [dS,dI,dR]

parms = [0.1,0.05]
init = [0.99,0.01,0]
times = np.linspace(0,200,2001)

sir_sol = solve_ivp(fun=lambda t, y: sir_ode(t, y, parms), t_span=[min(times),max(times)], y0=init, t_eval=times)

sir_out = pd.DataFrame({"t":sir_sol["t"],"S":sir_sol["y"][0],"I":sir_sol["y"][1],"R":sir_sol["y"][2]})

# Plot
sline = plt.plot("t","S","",data=sir_out,color="red",linewidth=2)
iline = plt.plot("t","I","",data=sir_out,color="green",linewidth=2)
rline = plt.plot("t","R","",data=sir_out,color="blue",linewidth=2)
plt.xlabel("Time",fontweight="bold")
plt.ylabel("Number",fontweight="bold")
legend = plt.legend(title="Population",loc=5,bbox_to_anchor=(1.25,0.5))
frame = legend.get_frame()
frame.set_facecolor("white")
frame.set_linewidth(0)
plt.show()


from mpl_toolkits.mplot3d import Axes3D  # noqa: F401, needed for 3D axes
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from tabulate import tabulate

from efficient_calculations import expTaylor, lnTaylor

def Q2to4():
    """Code for ICT questions 2--4."""

    domain = np.linspace(-2, 2)

    fig, ax = plt.subplots()
    ax.plot(domain, np.exp(domain), 'k--', label='Exact')
    for n in range(1, 4):
        ax.plot(domain, expTaylor(n, domain), label=f'{n} Terms')

    ax.set_title('Comparison of exp and Taylor Series approximation')
    ax.set_xlim((domain.min(), domain.max()))
    ax.legend()

def Q5():
    """Code for ICT question 5."""

    domain = np.linspace(-1, 1, num=9)
    # Construct a grid, such that a pair of elements (one from each array)
    # gives the corresponding (x, y) coordinates.
    X, Y = np.meshgrid(domain, domain)
    Z = X**2 + Y**2  # Construct function values

    # Use and modify base code from
    # https://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html

    fig = plt.figure()
    ax = fig.gca(projection='3d')

    surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
                           linewidth=0, antialiased=False)

    ax.set_xlim(-1, 1)
    ax.set_ylim(-1, 1)
    ax.set_zlim(0, 2)

    # Add a color bar which maps values to colors.
    fig.colorbar(surf, shrink=0.5, aspect=5)

def Q6():
    """Code for ICT question 6."""

    x, h   = 1, np.logspace(-1, -6, 6)
    exact  = np.log(1+x+h)
    approx = lnTaylor(3, x+h)

    error = np.abs(exact - approx)
    print(tabulate({
        'ln(1+x)'    : exact,
        'Taylor'     : approx,
        'Error'      : error,
        'Error / h^2': error / h**2,
        'Error / h^3': error / h**3,
        'Error / h^4': error / h**4
    }, headers='keys'))

def fvec(xvec):
    """Vector function for Q7."""
    x, y = xvec
    return np.array([
        x**4 + y**4 - 1,
        x**2 - y**2 + 1
    ])

def jacobian(xvec):
    """Jacobian function for Q7."""
    x, y = xvec
    return np.array([
        [4*x**3, 4*y**3],
        [2*x,    -2*y  ]
    ])

def newton_solver(initial, func, grad=None, step=0.02, goal=None):
    state = initial.copy()
    value = func(state)

    if goal is None:
        goal = np.zeros_like(value)

    if grad is None:
        delta = np.eye(state.size) * step

        def grad(x):
            return (func(x+delta) - func(x)) / step

    while not np.allclose(value, goal, atol=1e-4, rtol=1e-4):
        state -= np.linalg.solve(grad(state), func(state))
        value = func(state)

    return state

def Q7to9():
    """Code for ICT questions 7 to 9."""

    initial = np.array([1, 1], dtype=float)

    x_sol, y_sol = newton_solver(initial, fvec, grad=jacobian)
    print(f'The analytical solution is at x={x_sol:.3f}, y={y_sol:.3f}')

    x_sol, y_sol = newton_solver(initial, fvec)
    print(f'The numerical solution is at  x={x_sol:.3f}, y={y_sol:.3f}')

if __name__ == '__main__':
    questions = (Q2to4, Q5, Q6, Q7to9)
    for question in questions:
        input(f'Press `Enter` to run {question.__name__} ')

        plt.close('all')        # <- Close all existing figures
        question()
        plt.show(block=False)   # <- Allow code execution to continue

    input('Press `Enter` to quit the program.')


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

# Parallel Processing Teaching Toolkit
# PyOpenCL - Example 06
# Matrix x Vector
# https://github.com/javierip/parallel-processing-teaching-toolkit

import pyopencl as cl
from pyopencl import array
import numpy as np

import time   # For measure the running times

if __name__ == "__main__":

	VECTOR_SIZE=4096 # Elements in the vector and matrix elements = VECTOR_SIZE*VECTOR_SIZE

	# Create an random vector
	vector= np.random.randint(10,size=VECTOR_SIZE).astype(np.float32)
	# Create an random matrix
	matrix= np.random.randint(10,size=(VECTOR_SIZE,VECTOR_SIZE)).astype(np.float32)
	# Create empty vectors for the result
	matrix_dot_vector_cpu = np.zeros(VECTOR_SIZE, np.float32)
	matrix_dot_vector = np.zeros(VECTOR_SIZE, np.float32)

	tic=time.time()
	#Operation using the cpu
	matrix_dot_vector_cpu=np.dot(matrix,vector)

	time_cpu=time.time()-tic

	# Create CL context
	platform = cl.get_platforms()[0]
	device = platform.get_devices()[0] #get first gpu available

	print "Running: ", platform
	print "On GPU: ", device

	ctx = cl.Context([device])
	queue = cl.CommandQueue(ctx)

	# Kernel code
	program = cl.Program(ctx, """
			__kernel void matrix_dot_vector(__global const float *matrix,
		 __global const float *vector, __global float *result)
		 {
		 	int tx = get_global_id(0);
		 	int size=4096;
		    float value=0 ;

    			for (unsigned int k = 0; k < size; ++k) {
        			value += matrix[tx * size + k] * vector[k];
   				 }
   				 result[tx]=value;
		 }
		 """).build()

	#Create GPU resources
	queue = cl.CommandQueue(ctx)

	mem_flags = cl.mem_flags
	matrix_gpu = cl.Buffer(ctx, mem_flags.READ_ONLY |
				  mem_flags.COPY_HOST_PTR, hostbuf=matrix)
	vector_gpu = cl.Buffer(ctx, mem_flags.READ_ONLY |
				  mem_flags.COPY_HOST_PTR, hostbuf=vector)

	matrix_dot_vector_gpu = cl.Buffer(ctx, mem_flags.WRITE_ONLY,
					 matrix_dot_vector.nbytes)

	tic=time.time()
	#Operation using the GPU - call the kernel on the card
	program.matrix_dot_vector(queue, matrix_dot_vector.shape, None,
							   matrix_gpu, vector_gpu, matrix_dot_vector_gpu)
	time_gpu=time.time()-tic

	#Clear GPU resources
	cl.enqueue_copy(queue, matrix_dot_vector, matrix_dot_vector_gpu)

	print "Matrix:"
	print matrix
	print
	print "Vector:"
	print vector
	print
	print "Check:"
	print matrix_dot_vector_cpu-matrix_dot_vector #if = 0 then GOOD
	print "-" * 80
	print "Matrix x Vector : Size= ", VECTOR_SIZE
	print "Time CPU:", time_cpu
	print "Time GPU:", time_gpu


#steven 02/03/2020
#function integral to calculate area of curve and x axis
import numpy as np
import matplotlib.pyplot as plt

def softmaxFuc(x):
    #x = [2.0, 2.0, 2.0, 2.0, 2.0, 2.0]
    softmax = np.exp(x)/np.sum(np.exp(x))
    print(softmax)
    print(np.sum(softmax))
    return softmax

def plot(x,y):
    plt.plot(x,y)
    plt.show()

def fun(x):
    #return x
    #return x**2
    #return np.sqrt(1-x**2)   #y=sqrt(1-x**2)  #circle equations calculate pi
    #return np.exp(x)
    #return 1/(1 + np.power(np.e,-1*x))
    return np.power(x,x)

def IntegralFuc():
    """calculate area y=x^2  form x = 0 to 1
    divide 0~1 to N shares,  erevy part considered as a rectangle.
    """
    N = 100000
    s = 0
    for i in range(N):
        x = 1/N
        y = fun(i/N)
        s += x*y

    print(s)
    #pi = s*4 #when fuc = np.sqrt(1-x**2)
    #print(pi)
    return s

def fillColor():
    x = np.linspace(0,1.5, 100)

    y1 = np.zeros(len(x))
    y2 = fun(x)
    #new_ticks = np.linspace(0,2,5)
    #print(new_ticks)
    #plt.xticks(new_ticks)

    plt.plot(x,y1,c='b',alpha=0.5)
    plt.plot(x,y2,c='b',alpha=0.5)

    plt.fill_between(x,y1,y2,where=x<=1,facecolor='green')
    #plt.grid(True)
    plt.show()

def main():
    IntegralFuc()
    fillColor()

    #x = np.linspace(-5,5, 50)
    #y = fun(x)
    #y = softmaxFuc(x)
    #plot(x,y)

if __name__ == '__main__':
    main()


import numpy as np
TOL = 1.0e-16

def exp_taylor(x, N_terms):
    partial_sums = np.zeros_like(x, dtype=np.float64)
    terms_summed = np.zeros_like(x)

    # An array of the N_terms
    N_array = np.arange(1, N_terms+1, dtype=np.float64)
    N_array = 1 / N_array

    # Calculate the terms array as outer product
    terms = np.outer(x, N_array)
    terms = np.where(terms < 0, -1*terms, terms)

    # Use a loop to accumulate the partial sums
    for i in range(terms.shape[0]):
        term = 1.0
        partial_sum = term
        for j in range(terms.shape[1]):
            term *= terms[i, j]  # jth term = x**j / (j!)
            partial_sum += term  # Partial sum incremented in-place
            terms_summed[i] = j+1
            partial_sums[i] = partial_sum
            # I do not know of any easy way to do this using "where"
            if (abs(term) < TOL * abs(partial_sum)):
                break

    # Apply a mask of original values that are negative to take reciprocal
    mask = x < 0
    partial_sums[mask] = 1 / partial_sums[mask]
    return (partial_sums, terms_summed)  # returns value & number or terms summed

def test_exp_taylor():
    N_max = 100
    R = 20
    step = 4

    header = "x".center(10) + "# terms".rjust(8) + "true".rjust(19)
    header += "approximate".rjust(19) + "error".rjust(19)
    print header
    print "="*(10+19+19+19+8)

    # Generate the numpy array of x values
    x = np.arange(-R, R+1, step)

    # Perform only one call to exp_taylor function
    (y, N_terms) = exp_taylor(x, N_max)
    exp_true = np.exp(x)

    # Display the results
    for i in range(y.shape[0]):
        relative_error = abs((y[i]-exp_true[i]) / exp_true[i])
        print "%10.5f%8d%19g%19g%19g" % (x[i], N_terms[i], exp_true[i],
                                         y[i], relative_error)

if __name__=='__main__':
    test_exp_taylor()


from sympy import Eq, Matrix, pi, sin, sqrt, Symbol
from sympy.mpmath import mnorm, mpf
from sympy.solvers import nsolve
from sympy.utilities.lambdify import lambdify
from sympy.utilities.pytest import raises

def test_nsolve():
    # onedimensional
    x = Symbol('x')
    assert nsolve(sin(x), 2) - pi.evalf() < 1e-15
    assert nsolve(Eq(2*x, 2), x, -10) == nsolve(2*x - 2, -10)
    # Testing checks on number of inputs
    raises(TypeError, lambda: nsolve(Eq(2*x,2)))
    raises(TypeError, lambda: nsolve(Eq(2*x,2),x,1,2))
    # Issue 1730
    assert nsolve(x**2/(1-x)/(1-2*x)**2-100, x, 0) # doesn't fail
    # multidimensional
    x1 = Symbol('x1')
    x2 = Symbol('x2')
    f1 = 3 * x1**2 - 2 * x2**2 - 1
    f2 = x1**2 - 2 * x1 + x2**2 + 2 * x2 - 8
    f = Matrix((f1, f2)).T
    F = lambdify((x1, x2), f.T, modules='mpmath')
    for x0 in [(-1, 1), (1, -2), (4, 4), (-4, -4)]:
        x = nsolve(f, (x1, x2), x0, tol=1.e-8)
        assert mnorm(F(*x),1) <= 1.e-10
    # The Chinese mathematician Zhu Shijie was the very first to solve this
    # nonlinear system 700 years ago (z was added to make it 3-dimensional)
    x = Symbol('x')
    y = Symbol('y')
    z = Symbol('z')
    f1 = -x + 2*y
    f2 = (x**2 + x*(y**2 - 2) - 4*y)  /  (x + 4)
    f3 = sqrt(x**2 + y**2)*z
    f = Matrix((f1, f2, f3)).T
    F = lambdify((x, y, z), f.T, modules='mpmath')
    def getroot(x0):
        root = nsolve(f, (x, y, z), x0)
        assert mnorm(F(*root),1) <= 1.e-8
        return root
    assert map(round, getroot((1, 1, 1))) == [2.0, 1.0, 0.0]
    assert nsolve([Eq(f1), Eq(f2), Eq(f3)], [x, y, z], (1, 1, 1)) # just see that it works
    a = Symbol('a')
    assert nsolve(1/(0.001 + a)**3 - 6/(0.9 - a)**3, a, 0.3).ae(
        mpf('0.31883011387318591'))


"""
Implementation of Principal component analysis (PCA)
https://en.wikipedia.org/wiki/Principal_component_analysis
"""

import numpy as np
from svd import svd

class PCA(object):
    """Principal component analysis (PCA)

    Linear dimensionality reduction using Singular Value Decomposition of the
    data to project it to a lower dimensional space.

    """
    def __init__(self, n_components=None, random_state=None, epsilon=1e-10):
        self.n_components = n_components
        self.random_state = random_state
        self.epsilon = epsilon
        self.U, self.S, self.VT = None, None, None
        self.X_mean = None
        self.explained_variance_ = None
        self.explained_variance_ratio_ = None

    def fit(self, X):
        """Fit the model to the data X.

        Parameters:
        X: original matrix for fit

        """
        if self.n_components is None:
            # set maximum number of components
            self.n_components = X.shape[1]
        # calculate mean vector
        self.X_mean = X.mean(0)
        # extract mean vector from matrix
        X_centered = X - self.X_mean
        # performe SVD
        self.U, self.S, self.VT = svd(
            X_centered, epsilon=self.epsilon, random_state=self.random_state)
        n_samples = X.shape[0]
        # calculate explained variance
        self.explained_variance_ = (self.S ** 2) / (n_samples - 1)
        self.explained_variance_ = self.explained_variance_[:self.n_components]
        # calculate explained variance ratio
        total_var = self.explained_variance_.sum()
        self.explained_variance_ratio_ = self.explained_variance_ / total_var
        self.explained_variance_ratio_ = self.explained_variance_ratio_[:self.n_components]

    def transform(self, X):
        """Apply dimensionality reduction on X.

        Parameters:
        X : matrix for projection

        Returns:

        X_new: projected matrix
        """
        X_centered = X - self.X_mean
        X_transform = np.dot(X_centered, self.VT[:self.n_components].T)
        return X_transform

    def inverse_transform(self, X):
        """Transform data back to its original space.

        Parameters:
        X : projected matrix

        Returns:
        X_original : Original matrix

        """
        X_original = np.dot(X, self.VT[:self.n_components]) + self.X_mean
        return X_original

if __name__ == "__main__":

    from sklearn.decomposition import PCA as PCA_

    data = np.array([
        [2, 5, 3],
        [1, 2, 1],
        [4, 1, 1],
        [3, 5, 2],
        [5, 3, 1],
        [4, 5, 5],
        [2, 4, 2],
        [2, 2, 5],
    ], dtype='int64')

    n_components = 2
    pca = PCA(n_components=n_components, random_state=37)
    pca.fit(data)

    pca_ = PCA_(n_components=n_components, random_state=37)
    pca_.fit(data)

    check_transform = (np.round(
        pca.transform(data) - pca_.transform(data), decimals=3) == 0).all()

    X_transform = pca.transform(data)
    check_inverse = (np.round(
        pca.inverse_transform(X_transform) - pca_.inverse_transform(X_transform),
        decimals=3) == 0).all()

    print('data:\n{}'.format(data))
    print('Data transformed:\n{}'.format(X_transform))
    print('Is transform correct: {}'.format(check_transform))
    print('Inverse transformed data:\n{}'.format(pca.inverse_transform(X_transform)))
    print('Is inverse transform correct: {}'.format(check_inverse))


import numpy as np
import numexpr as ne
from scipy.linalg.blas import dgemm, sgemm

def polynomial_kernel_matrix(P, Q, c, degree):
    """
    Calculate kernel matrix using polynomial kernel.

    k(p,q) = (p^{T}q + c)^d

    Parameters:
    -----------
    P : `numpy.ndarray`
        (nDataP, nDim) matrix of data. Each row corresponds to a data point.
    Q : `numpy.ndarray`
        (nDataQ, nDim) matrix of data. Each row corresponds to a data point.
    c : `float`
        Bias term, c >= 0.
    degree : `int`
        Degree of the polynomial kernel function.

    Returns:
    --------
    K : `numpy.ndarray`
        (nDataP,nDataQ) matrix, the polynomial kernel matrix of the P and Q data matrix.
    """
    return ne.evaluate('(c + A)**d', {
        'A' : dgemm(alpha=1.0, a=P, b=Q, trans_b=True),
        'c' : c,
        'd' : degree
    })

def gaussian_kernel_matrix(P, Q, c):
    """
    Calculate kernel matrix using gaussian kernel.

    ||p-q||^2 = ||p||^2 + ||q||^2 - 2 * p^T * q

    k(p,q) = exp(-c*||p-q||^2)
           = exp(-c*[||p||^2 + ||q||^2 - 2 * p^T * q])

    C: dgemm(alpha=1.0, a=P, b=Q, trans_b=True)  double precision
    C: sgemm(alpha=1.0, a=P, b=Q, trans_b=True)  single precision
    C: np.dot(P,Q.T)                             single precision
            P = P.astype(np.float32)
            Q = Q.astype(np.float32)

    Parameters:
    -----------
    P : `numpy.ndarray`
        (nDataP, nDim) matrix of data. Each row corresponds to a data point.
    Q : `numpy.ndarray`
        (nDataQ, nDim) matrix of data. Each row corresponds to a data point.
    c : `int`
        Width of the gaussian kernel function.

    Returns:
    --------
    K : `numpy.ndarray`
        (nDataP,nDataQ) matrix, the gaussian kernel matrix of the P and Q data matrix.
    """
    # Calculate norm
    P_norm = np.einsum('ij,ij->i',P,P)
    Q_norm = np.einsum('ij,ij->i',Q,Q)
    return ne.evaluate('exp(-gamma * (A + B - 2*C))', {
        'A' : P_norm[:,None],
        'B' : Q_norm[None,:],
        'C' : dgemm(alpha=1.0, a=P, b=Q, trans_b=True),
        'gamma' : c
    })


# --------------
# Code starts here

import numpy as np

# Code starts here

# Adjacency matrix
adj_mat = np.array([[0,0,0,0,0,0,1/3,0],
                   [1/2,0,1/2,1/3,0,0,0,0],
                   [1/2,0,0,0,0,0,0,0],
                   [0,1,0,0,0,0,0,0],
                  [0,0,1/2,1/3,0,0,1/3,0],
                   [0,0,0,1/3,1/3,0,0,1/2],
                   [0,0,0,0,1/3,0,0,1/2],
                   [0,0,0,0,1/3,1,1/3,0]])

# Compute eigenvalues and eigencevectrs
eigenvalues, eigenvectors = np.linalg.eig(adj_mat)
print('Eigen values are', eigenvalues)
print('*'*25)
#print(eigenvectors)
print('Eigen Vector are', abs(eigenvectors[:,0]))
print('*'*25)
eigen_1 = abs(eigenvectors[:,0]) / np.linalg.norm(eigenvectors[:,0],1)
print('Normalize eigen vector are', eigen_1)
print('*'*50)
page =  np.where(np.max(eigen_1) == eigen_1)[0][0] + 1
print('The most important page is', page)

# Eigen vector corresponding to 1

# most important page

# Code ends here

# --------------
# Code starts here

# Initialize stationary vector I
# Code starts here

# Initialize stationary vector I
init_I = np.array([1,0,0,0,0,0,0,0])

# Perform iterations for power method
for i in range(10):
    init_I = np.dot(adj_mat, init_I)
    init_I /= np.linalg.norm(init_I, 1)

print(init_I)
power_page = np.where(np.max(init_I) == init_I)[0][0] + 1
print(power_page)

# Code ends here

print('*'*100)
print('*'*100)
print('*'*100)
print('*'*100)
print('*'*100)

# Code ends here

# --------------
# Code starts here

# New Adjancency matrix
# New Adjancency matrix
new_adj_mat = np.array([[0,0,0,0,0,0,0,0],
                   [1/2,0,1/2,1/3,0,0,0,0],
                  [1/2,0,0,0,0,0,0,0],
                   [0,1,0,0,0,0,0,0],
                   [0,0,1/2,1/3,0,0,1/2,0],
                   [0,0,0,1/3,1/3,0,0,1/2],
                   [0,0,0,0,1/3,0,0,1/2],
                   [0,0,0,0,1/3,1,1/2,0]])

# Initialize stationary vector I
new_init_I = np.array([1,0,0,0,0,0,0,0])
#print(new_init_I)

# Perform iterations for power method
for  i in range (10):
     new_init_I = np.dot(new_adj_mat, new_init_I)
     new_init_I /= np.linalg.norm(new_init_I, 1)
print(new_init_I)

# Code ends here

# --------------
# Alpha value
alpha = 0.85

# Code starts here

# Modified adjancency matrix
G = (alpha*new_adj_mat) + (1-alpha)*(1/len(new_adj_mat))*np.ones(new_adj_mat.shape)
print(G)

# Initialize stationary vector I
final_init_I = np.array([1,0,0,0,0,0,0,0])

# Perform iterations for power method
for i in range (1000):
    final_init_I = np.dot(new_adj_mat, final_init_I)
    final_init_I /= np.linalg.norm(final_init_I, 1)
print(final_init_I)
# Code ends here


import numpy as np

def featureNormalize(X):
    """
       returns a normalized version of X where
       the mean value of each feature is 0 and the standard deviation
       is 1. This is often a good preprocessing step to do when
       working with learning algorithms.
    """
    X_norm = np.zeros(X.shape)
    mu = np.zeros((1, X.shape[1]))
    sigma = np.zeros((1, X.shape[1]))
    # X_norm, mu, sigma = [],[],[]
    # ====================== YOUR CODE HERE ======================
    # Instructions: First, for each feature dimension, compute the mean
    #               of the feature and subtract it from the dataset,
    #               storing the mean value in mu. Next, compute the
    #               standard deviation of each feature and divide
    #               each feature by it's standard deviation, storing
    #               the standard deviation in sigma.
    #
    #               Note that X is a matrix where each column is a
    #               feature and each row is an example. You need
    #               to perform the normalization separately for
    #               each feature.
    #
    # Hint: You might find the 'mean' and 'std' functions useful.
    #
    for i in range(X.shape[1]):
        mu[0, i] = np.mean(X[:, i])
        sigma[0, i] = np.std(X[:, i])
        X_norm[:, i] = X[:, i] - mu[0, i]
        X_norm[:, i] = X_norm[:, i] / sigma[0, i]
    # ============================================================

    return X_norm, mu, sigma


'''
grad_descent.py

Use gradient descent to find the minimum value of a
single variable function. This also checks for the existence
of a solution for the equation, f'(x)=0 and plots the intermediate
points traversed.
'''

from sympy import Derivative, Symbol, sympify, solve
import matplotlib.pyplot as plt

def grad_descent(x0, f1x, x):
    # check if f1x=0 has a solution
    if not solve(f1x):
        print('Cannot continue, solution for {0}=0 does not exist'.format(f1x))
        return None
    epsilon =  1e-6
    step_size = 1e-4
    x_old = x0
    x_new = x_old - step_size*f1x.subs({x:x_old}).evalf()

    # list to store the X values traversed
    X_traversed = []
    while abs(x_old - x_new) > epsilon:
        X_traversed.append(x_new)
        x_old = x_new
        x_new = x_old-step_size*f1x.subs({x:x_old}).evalf()

    return x_new, X_traversed

def frange(start, final, interval):

    numbers = []
    while start < final:
        numbers.append(start)
        start = start + interval

    return numbers

def create_plot(X_traversed, f, var):
    # First create the graph of the function itself
    x_val = frange(-1, 1, 0.01)
    f_val = [f.subs({var:x}) for x in x_val]
    plt.plot(x_val, f_val, 'bo')
    # calculate the function value at each of the intermediate
    # points traversed
    f_traversed = [f.subs({var:x}) for x in X_traversed]
    plt.plot(X_traversed, f_traversed, 'r.')
    plt.legend(['Function', 'Intermediate points'], loc='best')
    plt.show()

if __name__ == '__main__':

    f = input('Enter a function in one variable: ')
    var = input('Enter the variable to differentiate with respect to: ')
    var0 = float(input('Enter the initial value of the variable: '))
    try:
        f = sympify(f)
    except SympifyError:
        print('Invalid function entered')
    else:
        var = Symbol(var)
        d = Derivative(f, var).doit()
        var_min, X_traversed = grad_descent(var0, d, var)
        if var_min:
            print('{0}: {1}'.format(var.name, var_min))
            print('Minimum value: {0}'.format(f.subs({var:var_min})))
            create_plot(X_traversed, f, var)


import numpy as np
import matplotlib.pyplot as plt
from BSpline import BSpline, OpenUniformKnotVector
import math

def FindSide(P1, P2, P):
    val = (P[1] - P1[1]) * (P2[0] - P1[0]) - (P2[1] - P1[1]) * (P[0] - P1[0])

    return np.sign(val)

def LineDist(P1, P2, P):
    return abs((P[1] - P1[1]) * (P2[0] - P1[0]) - (P2[1] - P1[1]) * (P[0] - P1[0]))

def QuickHull(Points, n, P1, P2, side, Hull):
    index = -1
    max_dist = 0

    for i in range(0, n):
        temp = LineDist(P1, P2, Points[i, :])
        if(FindSide(P1, P2, Points[i, :]) == side and temp > max_dist):
            index = i
            max_dist = temp

    if(index == -1):
        Hull.append(P1)
        Hull.append(P2)
        return

    QuickHull(Points, n, Points[index, :], P1, -FindSide(Points[index, :], P1, P2), Hull)
    QuickHull(Points, n, Points[index, :], P2, -FindSide(Points[index, :], P2, P1), Hull)

def ConvexHull2D(Points):
    maxX = np.argmax(Points[:, 0])
    minX = np.argmin(Points[:, 0])
    countPoints = np.size(Points, 0)

    Hull = []

    QuickHull(Points, countPoints, Points[minX, :], Points[maxX, :], 1, Hull)
    QuickHull(Points, countPoints, Points[minX, :], Points[maxX, :], -1, Hull)

    Hull = np.asarray(Hull)

    Hull = np.unique(Hull, axis=0)

    #sort by angle so it plots nicely
    Center = np.average(Hull)

    ToCenter = Hull - Center
    Angles = np.arctan2(ToCenter[:, 0], ToCenter[:, 1])

    SortedAngles = np.argsort(Angles)

    Hull = np.array(Hull)[SortedAngles]

    #copy first element so it loops on itself in plot
    Hull = np.append(Hull, [Hull[0, :]], axis=0)

    return Hull

if __name__ == "__main__":
    #shows that the b spline curve fits in the convex hull of the control points
    Points = np.array([[1., 1.], [2., 4.], [2., 6.], [4., 3.], [6., 6.], [8., 6.]])
    countPoints = np.size(Points, 0)
    order = 3

    Knots = OpenUniformKnotVector(order, countPoints, True)
    T = np.arange(0, 1.0, 0.01)

    Spline = BSpline(Points, order, Knots, T)

    Hull = ConvexHull2D(Points)

    plt.plot(Points[:, 0], Points[:, 1])
    plt.plot(Hull[:, 0], Hull[:, 1], 'r--')
    plt.plot(Spline[:, 0], Spline[:, 1])
    plt.show()


## 2. The Empirical Probability ##

p_tail = 44 / 100
p_six = 28 / 200
p_odd = 102/ 200
print(p_tail)
print(p_six)
print(p_odd)

## 3. Probability as Relative Frequency ##

p_heads_1 = 1 - (162/300)
percentage_1 = p_heads_1 * 100

p_heads_2 = 1 - (2450/5000)
percentage_2 = p_heads_2 * 100

print(percentage_1)
print(percentage_2)

## 4. Repeating an Experiment ##

# INITIAL CODE
from numpy.random import seed, randint

seed(1)

def coin_toss():
    if randint(0,2) == 1:
        return 'HEAD'
    else:
        return 'TAIL'

probabilities = []
heads = 0

for n in range(1, 10001):
    # Uncomment above and complete code from here
    outcome = coin_toss()
    if outcome == 'HEAD':
        heads +=1
    current_probability = heads / n
    probabilities.append(current_probability)

print(probabilities[:10])
print(probabilities[-10:])

## 5. The True Probability Value ##

p_l = 87/ 200
p_l_and_c = 40 / 200
p_h = 63/200
p_no = 1 - (160/200)
print(p_l)
print(p_l_and_c)
print(p_h)
print(p_no)

## 6. The Theoretical Probability ##

p_5 = 1/6
p_ht = 1/4
p_tt = 1/4

## 7. Events vs. Outcomes ##

p_even = 3/6
p_odd_no_3 = 2/6
p_odd_greater_5 = 0/6

## 8. A Biased Die ##

p_blue = 10 /100
p_red = 90/100

5. Probability and Statistics/probability-fundamentals/Estimating Probabilities-377.py


from __future__ import print_function
from __future__ import division
from math import log
import numpy as np

def calcShannonEnt(dataSet):
    numEntries = len(dataSet)
    labelCounts = {}
    for featVec in dataSet:
        currentLabel = featVec[-1]
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1

    shannonEnt = 0.0
    for key in labelCounts:
        prob = float(labelCounts[key]) / numEntries
        shannonEnt -= prob * log(prob, 2)

    return shannonEnt

def calcShannonEnt_(labels):
    numEntries = len(labels)
    labelCounts = {}

    for currentLabel in labels:
        if currentLabel not in labelCounts.keys():
            labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1

    shannonEnt = 0.0
    for key in labelCounts:
        prob = float(labelCounts[key]) / numEntries
        shannonEnt -= prob * log(prob, 2)

    return shannonEnt

def createDataSet():
    dataSet = [[1, 1, 'yes'],
               [1, 1, 'yes'],
               [1, 0, 'no'],
               [0, 1, 'no'],
               [0, 1, 'no']]
    features = ['no surfacing', 'flippers']
    return dataSet, features

if __name__ == '__main__':
    data, features = createDataSet()
    print(calcShannonEnt(data))

    labels = ['yes', 'yes', 'no', 'no', 'no']
    print(calcShannonEnt_(labels))


import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import freqz

if __name__ == '__main__':
    fs = 5000
    Ts = 1/fs
    Ns = 1024

    # Generate the signal
    f1 = 500
    f2 = 2000
    t = np.arange(0, 1, Ts)
    x1 = np.sin(2 * np.pi * f1 * t)
    x2 = np.sin(2 * np.pi * f2 * t)
    x = x1 + x2

    x = x[:Ns]
    t = t[:Ns]

    # Plot the signal and the magnitude spectrum
    plt.figure(1)
    plt.subplot(211)
    plt.plot(t, x)
    plt.subplot(212)
    X = np.fft.fft(x)
    X = X[:int(len(X)/2)]
    f = np.linspace(0, fs/2, len(X))
    A = np.sqrt(np.imag(X)**2 + np.real(X)**2)
    A = A/len(A)
    plt.plot(f, A)

    #Design a LP FIR filter
    fc = 1000
    wc = fc*np.pi/fs
    n = np.arange(0, Ns)
    h = np.sin(wc*(n - (Ns-1)/2))/(np.pi*(n - (Ns-1)/2))
    # print(h[int((Ns-1)/2)])
    # print(wc/np.pi)
    plt.figure(2)
    plt.plot(n, h)

    #Filter the signal with convolution
    y1 = np.convolve(x,h,mode='same')
    plt.figure(1)
    plt.subplot(211)
    plt.plot(t, y1)
    plt.subplot(212)
    Y = np.fft.fft(y1)
    Y = Y[:int(len(Y) / 2)]
    f = np.linspace(0, fs / 2, len(Y))
    Ay = np.sqrt(np.imag(Y) ** 2 + np.real(Y) ** 2)
    Ay = Ay / len(Ay)
    plt.plot(f, Ay)

    # Design a window for the filter - Triangle
    tri_win = 1 - np.abs((2*n-Ns+1)/(Ns-1))
    h_win = np.multiply(h, tri_win)
    plt.figure(2)
    #plt.plot(n, tri_win)
    plt.plot(n, h_win)

    # Filter the signal with convolution
    y2 = np.convolve(x, h_win, mode='same')
    plt.figure(1)
    plt.subplot(211)
    plt.plot(t, y2)
    plt.subplot(212)
    Y = np.fft.fft(y2)
    Y = Y[:int(len(Y) / 2)]
    f = np.linspace(0, fs / 2, len(Y))
    Ay = np.sqrt(np.imag(Y) ** 2 + np.real(Y) ** 2)
    Ay = Ay / len(Ay)
    plt.plot(f, Ay)

    # check the filter response
    w1, h1 = freqz(h, worN=8000)
    f = np.linspace(0,fs/2,8000)
    w2, h2 = freqz(h_win, worN=8000)
    plt.figure(3)
    plt.plot(f,np.abs(h1))
    plt.plot(f, np.abs(h2))

    plt.show()


import numpy as np
import time

def to3d(point):
    return np.array([point[0], point[1], 1.0])

def determinent(p1, p2, p3):
    mat = np.vstack((to3d(p1), to3d(p2), to3d(p3)))
    print(mat)
    return np.linalg.det(mat)

def simple_determinent(p1, p2, p3):
    return p1[0] * (p2[1] - p3[1]) + p2[0] * (p3[1] - p1[1]) + p3[0] * (p1[1] - p2[1])

p1 = (1, 2)
p2 = (2, 3)
p3 = (3, 4)

t1 = time.time()
det = determinent(p1, p2, p3)
print('time taken = ', time.time() - t1)
epsilon = 1e-2

det = 0 if det < epsilon else det
print(det)

t1 = time.time()
det = simple_determinent(p1, p2, p3)
print('time taken = ', time.time() - t1)
epsilon = 1e-2

det = 0 if det < epsilon else det
print(det)


import numpy as np
from RRT.polygon_functions import *
INT_MAX = 10000

def is_inside_circle(conf, circle_obstacle):
    """
    Checks to see if the configuration is in collision with a circle obstacle.

    conf: The location of the point being tested represented as an np.ndarray
    of shape (2,).
    circle_obstacle: The circle obstacle being tested.

    return: True if the configuration is in collision with the circle and False if not.
    """

    # Store the points that represent the randomly chosen point conf
    x = conf[0]
    y = conf[1]

    # Store circle center (x,y) value
    center = circle_obstacle.position
    center_x = center[0]
    center_y = center[1]

    # Store circle radius
    r = circle_obstacle.size

    # Set bounds of y for circle at current point
    y_max = center_y + np.sqrt(np.abs(r**2 - (x-center_x)**2))
    y_min = center_y - np.sqrt(np.abs(r**2 - (x-center_x)**2))

    # Set bounds of x for circle at current point
    x_max = center_x + np.sqrt(np.abs(r**2 - (y-center_y)**2))
    x_min = center_x - np.sqrt(np.abs(r**2 - (y-center_y)**2))

    # Check bounds of circle
    # If point is within bounds of circle, then there is a collision and return True
    if ((y >= y_min) and (y <= y_max) and (x >= x_min) and (x <= x_max)):
        return True

    else:
        return False

def is_inside_polygon(p, points):
    """
    Function checks whether or not point 'p' is within the polygon outlined by
    the set of vertices 'points'.

    p: The location of the point being tested represented as an np.ndarray of shape (2,).

    points: Set of vertices that represents the polygon represented as a list of tuples.

    returns: Returns true if the point lies within the polygon and False otherwise.
    """

    n = len(points)

    # There must be at least 3 vertices
    # in polygon
    if n < 3:
        return False

    # Create a point for line segment
    # from p to infinite
    extreme = (INT_MAX, p[1])
    count = i = 0

    while True:
        next = (i + 1) % n

        # Check if the line segment from 'p' to
        # 'extreme' intersects with the line
        # segment from 'polygon[i]' to 'polygon[next]'
        if (line_intersect(points[i], points[next], p, extreme)):

            # If the point 'p' is collinear with line
            # segment 'i-next', then check if it lies#
            # on segment. If it lies, return true, otherwise false
            if orientation(points[i], p, points[next]) == 0:
                return on_segment(points[i], p, points[next])

            count += 1

        i = next

        if (i == 0):
            break

    # Return true if count is odd, false otherwise
    return (count % 2 == 1)


import numpy as np
from numpy import linalg as la
import matplotlib.pyplot as plt
import bisection as bis

'''Gradient descent for 2-dimensions minimization'''
class Gradient():

    def __init__(self, alpha = 0.01, precision = 10**-6, X = np.array([[0.] , [0.]])):
         self.Xs = [] # Candidates
         self.Xs.append(X) # Append first candidate (X0)
         self.alpha = alpha   # Learning rate
         self.precision = precision # Stop criteria

    '''Returns the gradient of f(x1, x2) evaluated at X'''
    def gradient(self, X):
        x1 = X[0][0]
        x2 = X[1][0]

        return np.array([[4*(x1 - 2)],
                         [4*(x2 - 3)]])

    '''Evaluate f at X'''
    def evaluate(self, X):
        return 2*(X[0] - 2)**2 + 2*(X[1] - 3)**2 # Function to be minimized

    '''Returns the point (x1, x2) which minimizes f'''
    def descent(self):
        d = - self.gradient(self.Xs[0])

        # Calculate new X and Update direction
        while la.norm(d) > self.precision:
            ialpha = bis.getAlpha(self.Xs[-1], d) # Iteration alpha from bisection
            X = self.Xs[-1] + ialpha*d
            self.Xs.append(X)
            d = - self.gradient(self.Xs[-1])
        return self.Xs[-1]

    def plot(self, title, xlabel, ylabel):
        x1s = []
        x2s = []

        for X in self.Xs:
            x1s.append(X[0][0])
            x2s.append(X[1][0])

        plt.plot(x1s, x2s, 'bo')
        plt.title(title)
        plt.xlabel(xlabel)
        plt.ylabel(ylabel)
        plt.show()


import numpy as np

class SignalGenerator:
	def __init__(self, period, signal_type="sine", amplitude=1, vertical_shift=0, phase_shift=0):
		assert signal_type.lower() in ["sine", "cos", "half-sine", "half-cos", "sawtooth"], "get unknown signal_type: '{}'".format(signal_type)

		self.period = period
		self.signal_type = signal_type.lower()
		self.amplitude = amplitude
		self.vertical_shift = vertical_shift
		self.phase_shift = phase_shift

	def _cal_x(self, t):
		"""
		Convert t into x which has range of [0, 1]
		"""
		x = np.mod(t + self.phase_shift, self.period)
		x = x / self.period
		return x

	def _cal_y(self, x):
		"""
		Calculate y from x according to signal type
		"""
		if self.signal_type == "sine":
			y = np.sin(2 * np.pi * x) * self.amplitude + self.vertical_shift
		elif self.signal_type == "cos":
			y = np.cos(2 * np.pi * x) * self.amplitude + self.vertical_shift
		elif self.signal_type == "half-sine":
			y = np.sin(2 * np.pi * (x / 2 - 0.25)) * self.amplitude + self.vertical_shift
		elif self.signal_type == "half-cos":
			y = np.cos(2 * np.pi * x / 2) * self.amplitude + self.vertical_shift
		else:
			y = x * self.amplitude + self.vertical_shift
		return y

	def __call__(self, start_t, stop_t):
		t = np.arange(start_t, stop_t)
		x = self._cal_x(t)
		y = self._cal_y(x)
		return y


import numpy as np
import random

from q1_softmax import softmax
from q2_sigmoid import sigmoid, sigmoid_grad
from q2_gradcheck import gradcheck_naive

def forward_backward_prop(data, labels, params, dimensions):
    """
    Forward and backward propagation for a two-layer sigmoidal network

    Compute the forward propagation and for the cross entropy cost,
    and backward propagation for the gradients for all parameters.
    """

    ### Unpack network parameters (do not modify)
    ofs = 0
    Dx, H, Dy = (dimensions[0], dimensions[1], dimensions[2])

    W1 = np.reshape(params[ofs:ofs+ Dx * H], (Dx, H))
    ofs += Dx * H
    b1 = np.reshape(params[ofs:ofs + H], (1, H))
    ofs += H
    W2 = np.reshape(params[ofs:ofs + H * Dy], (H, Dy))
    ofs += H * Dy
    b2 = np.reshape(params[ofs:ofs + Dy], (1, Dy))

    ### YOUR CODE HERE: forward propagation
    h_per_item = sigmoid(np.dot(data, W1) + b1)
    yhat_per_item = softmax(np.dot(h_per_item, W2) + b2)
    cost = -np.sum(labels * np.log(yhat_per_item))
    ### END YOUR CODE

    ### YOUR CODE HERE: backward propagation
    grad_softmax_per_item = yhat_per_item - labels
    grad_b2 = np.sum(grad_softmax_per_item, axis=0, keepdims=True)
    grad_W2 = np.dot(h_per_item.T, grad_softmax_per_item)
    grad_sigmoid_per_item = sigmoid_grad(h_per_item)
    grad_b1_per_item = np.dot(grad_softmax_per_item, W2.T) * grad_sigmoid_per_item
    grad_b1 = np.sum(grad_b1_per_item, axis=0, keepdims=True)
    grad_W1 = np.dot(data.T, grad_b1_per_item)
    ### END YOUR CODE
    assert grad_b2.shape == b2.shape
    assert grad_W2.shape == W2.shape
    assert grad_b1.shape == b1.shape
    assert grad_W1.shape == W1.shape

    ### Stack gradients (do not modify)
    grad = np.concatenate((grad_W1.flatten(), grad_b1.flatten(),
        grad_W2.flatten(), grad_b2.flatten()))

    return cost, grad

def sanity_check():
    """
    Set up fake data and parameters for the neural network, and test using
    gradcheck.
    """
    print "Running sanity check..."

    N = 20
    dimensions = [10, 5, 10]
    data = np.random.randn(N, dimensions[0])   # each row will be a datum
    labels = np.zeros((N, dimensions[2]))
    for i in xrange(N):
        labels[i,random.randint(0,dimensions[2]-1)] = 1

    params = np.random.randn((dimensions[0] + 1) * dimensions[1] + (
        dimensions[1] + 1) * dimensions[2], )

    gradcheck_naive(lambda params: forward_backward_prop(data, labels, params,
        dimensions), params)

def your_sanity_checks():
    """
    Use this space add any additional sanity checks by running:
        python q2_neural.py
    This function will not be called by the autograder, nor will
    your additional tests be graded.
    """
    print "Running your sanity checks..."
    ### YOUR CODE HERE
    raise NotImplementedError
    ### END YOUR CODE

if __name__ == "__main__":
    sanity_check()
    your_sanity_checks()


# Reference Book: Python Data Science Handbook (page:(51-58))
# Date(20 April, 2019) Time = 1:33 AM

import numpy as np

# big-O(N**2)

def selectionSort(x):
    for i in range(len(x)):
        swap = i + np.argmin(x[i:])
        (x[i], x[swap]) = (x[swap], x[i])
    return x

# big-O(N * N!)

def bogosort(x):
    while(np.any(x[:-1] > x[1:])):
        np.random.shuffle(x)
    return x

x = np.array([20, 10, 40, 30, 50])
selectionSort(x)
print(x)

y = np.array([20, 10, 40, 30, 50])
bogosort(y)
print(y)

# Fast Sorting in NumPy: np.sort and np.argsort
x = np.array([2, 1, 4, 3, 5])
print(np.sort(x))  # numpy sort
print(np.argsort(x)) # numpy arg sort

x.sort() #python builting sort
print(x[:])

#Sorting along rows or columns
rand = np.random.RandomState(42)
x = rand.randint(0,10,(4,6))
print(x)
'''
[[6 3 7 4 6 9]
 [2 6 7 4 3 7]
 [7 2 5 4 1 7]
 [5 1 4 0 9 5]]
'''
print(np.sort(x, axis=0)) #row based
'''
[[2 1 4 0 1 5]
 [5 2 5 4 3 7]
 [6 3 7 4 6 7]
 [7 6 7 4 9 9]]
'''
print(np.sort(x, axis=1)) #column based
'''
[[3 4 6 6 7 9]
 [2 3 4 6 7 7]
 [1 2 4 5 7 7]
 [0 1 4 5 5 9]]
'''
# Keep in mind that this treats each row or column as an independent array, and any
# relationships between the row or column values will be lost

#Partial Sorts: Partitioning


import numpy as np

class Activation:
    """An activation function"""

    def __init__(self, name, activation, d_activation, vectorize=True):
        self.name = name
        self.activation = np.vectorize(activation) if vectorize else activation
        self.derivative = np.vectorize(d_activation) if vectorize else d_activation

    def __call__(self, inputs, D=False) -> np.array:
        return self.activation(inputs) if (not D) else self.derivative(inputs)

# Some Common Activation Functions
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def sigmoid_derivative(x):
    return sigmoid(x) * (1 - sigmoid(x))

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

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

# Common Activations
IDENTITY = Activation('None', lambda x: x, lambda x: 1)
RELU = Activation('ReLU',
                  lambda x: x if (x > 0) else 0,
                  lambda x: 1 if (x > 0) else 0)
SIGMOID = Activation('Sigmoid', sigmoid, sigmoid_derivative)
TANH = Activation('Hyperbolic', tanh, tanh_derivative)


#------------------------Packages------------------------#

import numpy as np
import scipy.stats as si
import matplotlib.pyplot as plt
import pymc3 as pm
### I have 252 observations for HV, so 0 to 251 ###
### I have 253 observations for IV, so 0 to 252 ###

#-------------------------Option Pricing---------------------------#

    ######## Black-Scholes Model########

''' Call Option Premium C = SN(d1) - Xe^(-rt) N(d2)
     Put Option Premium P = Xe^(-rT) N(-d2) - S0 N(-d1)'''

def BS_price(strategy, sp, x, r, sd, t):
    d1 = (np.log(sp/x) + (r + (sd**2*0.5)*t)) / sd*np.sqrt(t)
    #print("D1 = ", d1)
    d2 = d1 - sd*np.sqrt(t)
    if strategy == 'c':
        price = sp * si.norm.cdf(d1,0,1) - x * np.exp(-r*t) * si.norm.cdf(d2,0,1)
        return price
    elif strategy == 'p':
        price = x * np.exp(-r*t) * si.norm.cdf(-d2,0,1) - sp * si.norm.cdf(-d1,0,1)
        return price
    else:
        print("No Such Option Strategy; Enter 'c' for Call or 'p' for Put")
        exit()

    ######## Calculating Historical Volatility (A.K.A standard deviation of the periodic daily return) #######
    #'n' Max is 252 days#

def hist_vol(ticker, n):
    file = []
    if ticker == 'GOOG':
        file = open('/Users/TristanTaylor/Documents/Master_Project/HV/GOOG_HV.csv', 'r')
    elif ticker == 'AMZN':
        file = open('/Users/TristanTaylor/Documents/Master_Project/HV/AMZN_HV.csv', 'r')
    elif ticker == 'AAPL':
        file = open('/Users/TristanTaylor/Documents/Master_Project/HV/AAPL_HV.csv', 'r')
    else:
        print("Enter 'GOOG', 'AMZN', or 'AAPL' for ticker")
        exit()
    s = []
    for lines in file:
        s = np.append(s, float(lines))
    #print(s)
    r = []
    for i in range(n):
        r.append(np.log(s[i]/s[i+1]))
        #print(r)

    a = []
    r_mean = np.mean(r)
    #print('Mean: ', r_mean)
    diff_square = [(r[j] - r_mean) ** 2 for j in range(0, len(r))]
    #print(diff_square)
    std = np.sqrt(sum(diff_square) * (1.0 / (n)))
    hist = std * np.sqrt(n+1)
    return hist, std

####GOOG on 06/24/19: adj c.price=1115.52, strike=1115.00, 10yr. Treasury=0.02016, time=88days, target=45.30, "call"

#OTM Call & Put
####GOOG on 06/27/19: adj c.price=1076.01, strike=1077.50, 10yr. Treasury=0.02016, time=29days, target=35.55, "call"
####GOOG on 06/27/19: adj c.price=1076.01, strike=1075.00, 10yr. Treasury=0.02016, time=29days, target=33.75, "put"

####AMZN on 06/27/19: adj c.price=1904.28, strike=1905.00, 10yr. Treasury=0.02016, time=29days, target=66.00, "call"
####AMZN on 06/27/19: adj c.price=1904.28, strike=1902.50, 10yr. Treasury=0.02016, time=29days, target=61.48, "put"

####AAPL on 6/27/19: adj c.price=199.74, strike=200.00, 10yr. Treasury=0.02016, time=29days, target=5.07, "call"
####AAPL on 6/27/19: adj c.price=199.74, strike=197.50, 10yr. Treasury=0.02016, time=29days, target=4.53, "put"

#25 Delta Call & Put
####GOOG on 06/27/19: adj c.price=1076.01, strike=1095.00, 10yr. Treasury=0.02016, time=29days, target=27.05, "call"
####GOOG on 06/27/19: adj c.price=1076.01, strike=1057.50, 10yr. Treasury=0.02016, time=29days, target=24.65, "put"

####AMZN on 06/27/19: adj c.price=1904.28, strike=1922.50, 10yr. Treasury=0.02016, time=29days, target=56.98, "call"
####AMZN on 06/27/19: adj c.price=1904.28, strike=1885.00, 10yr. Treasury=0.02016, time=29days, target=53.58, "put"

####AAPL on 06/27/19: adj c.price=199.74, strike=217.50, 10yr. Treasury=0.02016, time=29days, target=0.6, "call"
####AAPL on 06/27/19: adj c.price=199.74, strike=180.00, 10yr. Treasury=0.02016, time=29days, target=0.85, "put"

    ######## Calculating Vega ########

def vega(sp, x, r, sd, t):
    d1 = (np.log(sp/x) + (r + (sd**2/2)*t)) / sd*np.sqrt(t)
    return sp * np.sqrt(t) * si.norm.pdf(d1,0,1)

    ######### Calculating Implied Volatility########

def imp_vol(target, strategy, sp, x, r, sd, t):
    precision = 0.0000001

    price = BS_price(strategy, sp, x, r, sd, t)
    veg = vega(sp, x, r, sd, t)
    diff = target - price
    new_sd = sd + diff / (veg)

    if abs(diff) > precision:
        new_sd = imp_vol(target, strategy, sp, x, r, new_sd, t)
    else:
        new_sd = sd + diff/vega(sp, x, r, new_sd, t)
        #print('New SD = ', new_sd)

    return new_sd

def iv_range_formula(sp, sd, t):
    upper = sp + sp*sd*np.sqrt(t)
    lower = sp - sp*sd*np.sqrt(t)
    return upper, lower

def iv_percent(ticker, strategy, n, sd):
    file = []
    if ticker == "GOOG":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/GOOG_call_IV2.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/GOOG_put_IV2.csv', 'r')
    elif ticker == "AMZN":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AMZN_call_IV2.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AMZN_put_IV2.csv', 'r')
    elif ticker == "AAPL":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AAPL_call_IV2.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AAPL_put_IV2.csv', 'r')
    else:
        exit()
    s = []
    for lines in file:
        s = np.append(s, float(lines))
    # print(s)
    r = []
    for i in range(n):
        r.append(s[i])
        # print(r)
    b = 0
    for i in range(len(r)):
        if r[i] < sd*100:
            b += 1
        else:
            pass
    p = b/252
    return p

#----------------------Bayesian Inference-------------------------#

    ######## Plotting Implied Volatility for GOOG, AAPL, & AMZN ########

def data_iv(ticker, strategy, n):
    file = []
    if ticker == "GOOG":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/GOOG_call_IV2.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/GOOG_put_IV2.csv', 'r')
    elif ticker == "AMZN":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AMZN_call_IV2.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AMZN_put_IV2.csv', 'r')
    elif ticker == "AAPL":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AAPL_call_IV2.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AAPL_put_IV2.csv', 'r')
    else:
        exit()
    s = []
    for lines in file:
        s = np.append(s, float(lines))
    # print(s)
    r = []
    for i in range(n):
        r.append(s[i])
        # print(r)
    fig, ax = plt.subplots(figsize=(14, 8))
    ax.plot(r, label='Implied Volatility Plot')
    ax.set(xlabel='Time (Days)', ylabel='25 Trading Days IV')
    ax.legend()
    plt.show()
    r_mean = np.mean(r)
    #print('Mean: ', r_mean)
    diff_square = [(r[j] - r_mean) ** 2 for j in range(0, len(r))]
    # print(diff_square)
    var = (np.sum(diff_square) / (n))
    # std = np.sqrt(np.sum(diff_square)/(n))
    #print('Variance: ', var)
    # print(std)
    # hist = std * np.sqrt(n+1)
    return r_mean, var

def data_iv_update(ticker, strategy, n):
    file = []
    if ticker == "GOOG":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/GOOG_call_IV.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/GOOG_put_IV.csv', 'r')
    elif ticker == "AMZN":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AMZN_call_IV.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AMZN_put_IV.csv', 'r')
    elif ticker == "AAPL":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AAPL_call_IV.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AAPL_put_IV.csv', 'r')
    else:
        exit()
    s = []
    for lines in file:
        s = np.append(s, float(lines))
    # print(s)
    r = []
    for i in range(n):
        r.append(s[i])
        # print(r)
    fig, ax = plt.subplots(figsize=(14, 8))
    ax.plot(r, label='Implied Volatility Plot')
    ax.set(xlabel='Time (Days)', ylabel='25 Trading Days IV')
    ax.legend()
    plt.show()
    r_mean = np.mean(r)
    # print('Mean: ', r_mean)
    diff_square = [(r[j] - r_mean) ** 2 for j in range(0, len(r))]
    # print(diff_square)
    var = (np.sum(diff_square) / (n))
    # std = np.sqrt(np.sum(diff_square)/(n))
    # print('Variance: ', var)
    # print(std)
    # hist = std * np.sqrt(n+1)
    return r_mean, var

    ######## Methods of Moments Estimation of Gamma Parameters ########

def parameters(mean, var):
    shape = mean ** 2 / var
    #print('Shape: ', shape)
    scale = var / mean
    #print('Scale: ', scale)
    return shape, scale

def parameters_inv(mean, var):
    shape = mean ** 2 / var + 2
    scale = mean * (mean ** 2 / var + 1)
    return shape, scale

    ######## QQPlot: See if Data Follows a Distribution ########

def qqplot(ticker, strategy, n, mean, var, shape, scale, inv_shape, inv_scale):
    file = []
    if ticker == "GOOG":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/GOOG_call_IV2.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/GOOG_put_IV2.csv', 'r')
    elif ticker == "AMZN":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AMZN_call_IV2.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AMZN_put_IV2.csv', 'r')
    elif ticker == "AAPL":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AAPL_call_IV2.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AAPL_put_IV2.csv', 'r')
    else:
        exit()
    s = []
    for lines in file:
        s = np.append(s, float(lines))
    #print(s)
    r = []
    for i in range(n):
        r.append(s[i])
    #print(r)

    fig = plt.figure()
    ax_1 = fig.add_subplot(221)
    ax_2 = fig.add_subplot(222)
    ax_3 = fig.add_subplot(223)
    res_g = si.probplot(r, dist=si.gamma, sparams=(shape, scale), plot=ax_1)
    res_n = si.probplot(r, dist=si.norm, sparams=(mean, np.sqrt(var)), plot=ax_2)
    res_i = si.probplot(r, dist=si.invgamma, sparams=(inv_shape, inv_scale), plot=ax_3)
    ax_1.set_title("Probplot on Gamma Distribution")
    ax_2.set_title("Probplot on Normal Distribution")
    ax_3.set_title("Probplot on Inverse Gamma Distribution")
    plt.show()
    return r

def qqplot_update(ticker, strategy, n, mean, var, shape, scale, inv_shape, inv_scale):
    file = []
    if ticker == "GOOG":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/GOOG_call_IV.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/GOOG_put_IV.csv', 'r')
    elif ticker == "AMZN":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AMZN_call_IV.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AMZN_put_IV.csv', 'r')
    elif ticker == "AAPL":
        if strategy == 'c':
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AAPL_call_IV.csv', 'r')
        else:
            file = open('/Users/TristanTaylor/Documents/Master_Project/IV/AAPL_put_IV.csv', 'r')
    else:
        exit()
    s = []
    for lines in file:
        s = np.append(s, float(lines))
    #print(s)
    r = []
    for i in range(n):
        r.append(s[i])
    #print(r)

    fig = plt.figure()
    ax_1 = fig.add_subplot(221)
    ax_2 = fig.add_subplot(222)
    ax_3 = fig.add_subplot(223)
    res_g = si.probplot(r, dist=si.gamma, sparams=(shape, scale), plot=ax_1)
    res_n = si.probplot(r, dist=si.norm, sparams=(mean, np.sqrt(var)), plot=ax_2)
    res_i = si.probplot(r, dist=si.invgamma, sparams=(inv_shape, inv_scale), plot=ax_3)
    ax_1.set_title("Probplot on Gamma Distribution")
    ax_2.set_title("Probplot on Normal Distribution")
    ax_3.set_title("Probplot on Inverse Gamma Distribution")
    plt.show()
    return r

def bayesian_modeling(mean, var, alpha, beta, inv_a, inv_b, iv):
    with pm.Model() as model:
        prior = pm.InverseGamma('bv', inv_a, inv_b)

        likelihood = pm.Gamma('like', alpha, beta, observed=iv)

    with model:
        # step = pm.Metropolis()

        v_trace = pm.sample(10000, tune=1000)
        #print(v_trace['bv'][:])
        trace = v_trace['bv'][:]
        #print(trace1)

    pm.traceplot(v_trace)
    plt.show()

    pm.autocorrplot(v_trace)
    plt.show()

    #s = pm.summary(v_trace)
    #print(s)
    return trace

def update_bayesian_modeling(mean_upd, var_upd, alpha_upd, beta_upd, inv_a_upd, inv_b_upd, iv_upd, strategy, stock_price, strike_price, risk_free, time):
    with pm.Model() as update_model:
        prior = pm.InverseGamma('bv', inv_a_upd, inv_b_upd)

        likelihood = pm.InverseGamma('like', inv_a_upd, inv_b_upd, observed=iv_upd)

    with update_model:
        # step = pm.Metropolis()

        v_trace_update = pm.sample(10000, tune=1000)
        #print(v_trace['bv'][:])
        trace_update = v_trace_update['bv'][:]
        #print(trace)

    pm.traceplot(v_trace_update)
    plt.show()

    pm.autocorrplot(v_trace_update)
    plt.show()

    pm.plot_posterior(v_trace_update[100:], color='#87ceeb', point_estimate='mean')
    plt.show()

    s = pm.summary(v_trace_update).round(2)
    print("\n Summary")
    print(s)

    a = np.random.choice(trace_update, 10000, replace=True)
    ar = []
    for i in range(9999):
        t = a[i] / 100
        ar.append(t)
    #print("Bayesian Volatility Values", ar)

    op = []
    for i in range(9999):
        temp = BS_price(strategy, stock_price, strike_price, risk_free, ar[i], time)
        op.append(temp)
    #print("Bayesian Option Prices", op)

    plt.hist(ar, bins=50)
    plt.title("Volatility")
    plt.ylabel("Frequency")
    plt.show()

    plt.hist(op, bins=50)
    plt.title("Option Price")
    plt.ylabel("Frequency")
    plt.show()
    return trace_update

#--------------------------Main Code to Run--------------------------#
def main():
    ######## Getting Input from User ########

    ticker = input("Enter stock ticker symbol: ")

    stock_price = float(input("Enter current stock price: "))

    strike_price = float(input("Enter strike price: "))

    risk_free = float(input("Enter risk-free interest rate: "))

    time = float(input("Enter days to maturity: "))
    time = time/365

    target = float(input("Enter Target Value: "))

    strategy = input("Enter Strategy: ")

    ######## Calculate Implied Volatility & Black-Scholes Option Price w/ Historical Volatility ########

    hist = hist_vol(ticker, 252)

    vol = imp_vol(target, strategy, stock_price, strike_price, risk_free, hist[0], time)

    bs = BS_price(strategy, stock_price, strike_price, risk_free, vol, time)

    percent = iv_percent(ticker, strategy, 252, vol)

    std_dev = iv_range_formula(stock_price, vol, time)

    print("\n Annual Historical Volatility, Periodic Daily Return:")
    print(hist)

    print("\n Option Price with HV:")
    print(BS_price(strategy, stock_price, strike_price, risk_free, hist[0], time))

    print("\n Implied Volatility:")
    print(vol)
    print("\n Option Price with IV:")
    print(bs)
    print("\n IV Percentile")
    print(percent)
    print("\n Expected Price Range at Maturity")
    print(std_dev)

    ######## Calculate Parameters: mean, variance, alpha, & beta ########

    mean, var = data_iv(ticker, strategy, 252)
    mean = float(mean)
    alpha, beta = parameters(mean, var)
    print("\n Gamma Parameters")
    print(alpha, beta)
    inv_a, inv_b = parameters_inv(mean, var)
    print("\n Inverse Gamma Parameters")
    print(inv_a, inv_b)
    iv = qqplot(ticker, strategy, 252, mean, var, alpha, beta, inv_a, inv_b)

    ######## Simple Bayesian Statistics (NUTS) ########

    trace = bayesian_modeling(mean, var, alpha, beta, inv_a, inv_b, iv)

    ######## Define New Parameters: mean, variance, alpha, & beta for Update ########

    mean_update, var_update = np.mean(trace), np.var(trace)
    mean_update = float(mean)
    alpha_update, beta_update = parameters(mean_update, var_update)
    print("\n Gamma Parameters")
    print(alpha_update, beta_update)
    inv_a_update, inv_b_update = parameters_inv(mean_update, var_update)
    print("\n Inverse Gamma Parameters")
    print(inv_a_update, inv_b_update)
    iv_update = qqplot_update(ticker, strategy, 252, mean_update, var_update, alpha_update, beta_update, inv_a_update, inv_b_update)
    new_mean, new_var = data_iv_update(ticker, strategy, 252)
    new_alpha, new_beta = parameters(new_mean, new_var)
    new_inv_a, new_inv_b = parameters_inv(new_mean, new_var)
    ######## Update Posterior ########

    new_trace = update_bayesian_modeling(mean_update, var_update, new_alpha, new_beta, new_inv_a, new_inv_b, iv_update, strategy, stock_price, strike_price, risk_free, time)

    ###CALL###
    # 03/20/18-03/20/19: GOOG mean=23.939, var=33.696, shape=17.008, scale=1.408, bma=23.995
    # 03/26/18-03/26/19: AMZN mean=30.104, var=72.564, shape=12.489, scale=2.410, bma=30.132
    # 03/26/18-03/26/19: AAPL mean=23.539, var=35.819, shape=15.469, scale=1.522, bma=23.463

    ###PUT###
    # 03/20/18-03/20/19: GOOG mean=26.395, var=45.190, shape=15.417, scale=1.712, bma=26.412
    # 03/26/18-03/26/19: AMZN mean=33.377, var=97.999, shape=11.367, scale=2.936, bma=33.376
    # 03/26/18-03/26/19: AAPL mean=26.570, var=57.393, shape=12.300, scale=2.160, bma=26.623

main()


import numpy as np

def evaluate(y_true, y_pred, precision=10):
    # print('MSE:', round(MSE(y_true, y_pred), precision))
    # print('RMSE:', round(RMSE(y_true, y_pred), precision))
    # print('MAE:', round(MAE(y_true, y_pred), precision))
    # print('MAPE:', round(MAPE(y_true, y_pred), precision), '%')
    # print('PCC:', round(PCC(y_true, y_pred), precision))
    return MSE(y_true, y_pred), RMSE(y_true, y_pred), MAE(y_true, y_pred), MAPE(y_true, y_pred)

def MAPE(y_pred:np.array, y_true:np.array, epsilon=1.0):
    y_pred[y_pred < 0] = 0
    return np.mean(np.abs(y_pred - y_true) / np.clip(np.abs(y_true), epsilon, None)) * 100

def MSE(y_true, y_pred):
    y_pred[y_pred < 0] = 0
    return np.mean(np.square(y_pred - y_true))

def RMSE(y_true, y_pred):
    y_pred[y_pred < 0] = 0
    return np.sqrt(MSE(y_pred, y_true))

def MAE(y_true, y_pred):
    y_pred[y_pred < 0] = 0
    return np.mean(np.abs(y_pred - y_true))

# def MAPE(y_pred:np.array, y_true:np.array, epsilon=1e-3):       # avoid zero division
#     return np.mean(np.abs(y_pred - y_true) / np.clip((np.abs(y_pred) + np.abs(y_true)) * 0.5, epsilon, None))

# def PCC(y_pred:np.array, y_true:np.array):      # Pearson Correlation Coefficient
#     return np.corrcoef(y_pred.flatten(), y_true.flatten())[0,1]


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

#############################################################
# 1. Imports
#############################################################

import numpy as np
import matplotlib.pyplot as plt

from scipy.optimize import curve_fit

#############################################################
# 2. General Functions
#############################################################

def lsq(x, y):
    assert len(x) == len(y), 'Array dimensions do not match'
    n = float(len(x)) # Don't lose precision with int * float multiplication

    # compute covariance matrix and correlation coefficient of data
    cov  = np.cov(x, y)
    varx = cov[0][0]
    vary = cov[1][1]
    sxy  = cov[0][1]
    r    = sxy / (np.sqrt(vary) * np.sqrt(varx))

    # lambda expression for a line
    # dummy parameter array of [1, 1]
    f    = lambda x, *p: p[0]*x + p[1]
    pars = [1, 1]

    pvals, pcov = curve_fit(f, x, y, p0=pars)

    m, b = pvals
    sm   = np.sqrt(pcov[0, 0])
    sb   = np.sqrt(pcov[1, 1])
    sy   = np.sqrt(vary)

    # y = mx + b; r is correlation
    return m, b, sy, sm, sb, r

#############################################################
# 3. Data & Globals
#############################################################

current = np.array([5.372, 10.024, 14.975, 20.482, 24.878, 30.105]) * 1e-3 # mA
voltage = np.array([0.503, 1.043, 1.526, 2.034, 2.521, 3.018]) # V

# The multimeter tends to have a variable uncertainty, so these arrays is needed
dI      = np.array([0.001, 0.002, 0.002, 0.001, 0.001, 0.003]) * 1e-3
dV      = np.array([0.002, 0.001, 0.003, 0.001, 0.001, 0.002])

#############################################################
# 4. Lab-Specific Functions
#############################################################

def plot_line():

    # Least-squares linear regression for y = mx + b
    m, b, sy, sm, sb, r = lsq(current * 1e3, voltage) # We want to plot in mA

    # You will NEED to call this for each plot so that you don't have multiple plots
    # overlaid on each other
    plt.figure()

    # Range upon which we want to plot the line
    x = np.linspace(5, 31, 1000)
    plt.plot(x, m*x + b, 'c--')

    plt.errorbar(x=(current * 1e3), y=voltage, xerr=(dI * 1e3), yerr=dV, fmt='r.', ecolor='k', alpha=0.5)

    plt.xlabel('Current ($mA$)')
    plt.ylabel('Voltage ($V$)')

def get_resistance():
    m, b, sy, sm, sb, r = lsq(current, voltage)

    # Resistance is the slope m; its uncertainty sm is already computed by lsq()
    return (m, sm)


import numpy as np
import sys

np.seterr(all='warn')

def sisEcua(mat_A, mat_B):
    a_inv = np.linalg.inv(mat_A)
    C = a_inv.dot(mat_B.T)
    return C

def sisDeEcuaciones(yx, x_elev, grado, n_datos):
    dimension = grado+1
    total_suma = len(x_elev)
    sistema = (dimension, dimension)
    mat_A = np.zeros(sistema)
    mat_B = np.matrix(yx)
    # ubicacion de datos en la matriz
    # primera fila
    col = 1
    for i in range(0, dimension-1):
        mat_A[0][col] = x_elev[i]
        col += 1
    # el resto de la ubicciones
    col = 0
    inicio = 0
    fin = dimension
    mat_A[0][0] = n_datos
    for i in range(1, dimension):
        for j in range(inicio, fin):
            mat_A[i][col] = x_elev[j]
            col += 1
        inicio += 1
        fin += 1
        col = 0
    # Para visualizar las matrices del sistema de ecuaciones
    #print(mat_A, mat_B)
    return sisEcua(mat_A, mat_B)

def multiplicacion(eje_y, datos_elev, cant_de_datos):
    datos_yx=[]
    for k in range(0, cant_de_datos):
        yx = eje_y[k]*datos_elev[k]
        datos_yx.append(yx)
        #print(datos_yx)
    return datos_yx

def potencia(eje_x, cant_de_datos, i):
    x_elev_i = []
    suma_x = 0
    for j in range(0, cant_de_datos):
        potencia = eje_x[j]**i
        x_elev_i.append(potencia)
        suma_x = suma_x+potencia
    return suma_x, x_elev_i

def rPolinomial(eje_x, eje_y, grado_del_polinomio):
    cant_de_datos = len(eje_y)
    cant_de_val_elevados = int(grado_del_polinomio*2)
    eje_y = np.array(eje_y)
    # vectores auxiliares
    suma_val_elevados_x = []
    suma_yx = []
    suma_y = np.sum(eje_y)
    suma_yx.append(suma_y)
    for i in range(1, cant_de_val_elevados+1):
        sumatoria, datos_elev = potencia(eje_x, cant_de_datos, i)
        suma_val_elevados_x.append(sumatoria)
        if i <= grado_del_polinomio:
            m = np.array(datos_elev)
            datos_yx = m*eje_y  # aqui falla
            suma_datos_yx = np.sum(datos_yx)
            suma_yx.append(suma_datos_yx)
            # Para visualizar las multiplicaciones de y*xi, y*x**2, etc.
            # print(datos_yx)
            # print(m)
            #print(datos_yx)
            # print(suma_yx)
    coeficientes = sisDeEcuaciones(
        suma_yx, suma_val_elevados_x, grado_del_polinomio, cant_de_datos)
    # visualizacion de los resultados
    print('\n     COEFICIENTES DEL AJUSTE POLINOMIAL\n')
    ecuacion_final = 'y = '
    for k in range(0, grado_del_polinomio+1):
        a = float(coeficientes[k])
        a_redondeada = "{0:.7f}".format(a)
        print(f'             a{k} = {a_redondeada} ')
        if k == 0:
            ec = str(a_redondeada)
        elif k == 1:
            ec = ' + '+str(a_redondeada)+'*x'
        else:
            ec = ' + '+str(a_redondeada)+'*x^'+str(k)
        ecuacion_final = ecuacion_final+ec
    print('\n La ecuacion de ajuste es:\n')
    print(f'         {ecuacion_final}')

#datos de prueba
""" x = [280, 650, 1000, 1200, 1500, 1700]
y = [32.7, 45.4, 52.15, 53.7, 52.9, 50.3]
grado = 2
rPolinomial(x, y, grado) """

""" x = [1976, 1992, 2001, 2012]
y = [205.42, 289.21, 276.45, 301.85]
grado = 2
rPolinomial(x, y, grado) """

""" x=[273,283,293,303,313,323,333,343,353,363,373]
y=[1.00738,1.00129,0.99883,0.99802,0.99804,0.99854,0.99943,1.00067,1.00229,1.00437,1.00697]
grado=4
rPolinomial(x, y, grado) """

""" x=[2,3,4,7,8,9,5,5]
y=[9,6,5,10,9,11,2,3] """

""" x = [50, 60, 70, 80,90,100]
y = [24.94,30.11,36.05,42.84,50.57,59.3]
grado=2
rPolinomial(x, y, grado) """

src/4. Ajuste de curvas/Metodos/regresion_polinomial.py


import numpy as np

def featureNormalize(X):
    """ returns a normalized version of X where
    the mean value of each feature is 0 and the standard deviation
    is 1. This is often a good preprocessing step to do when
    working with learning algorithms.
    """

    mu = np.mean(X, axis=0)
    X_norm = X - mu

    sigma = np.std(X_norm, axis=0, ddof=1)
    X_norm /= sigma

    return X_norm, mu, sigma


import numpy as np
import matplotlib.pylab as plt
def basic_softmax(a):
    exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a

    return y

def simple_softmax(a):
    c = np.max(a)
    exp_a = np.exp(a - c)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a

    return y

x = np.array([800, 695, 690])
y1 = basic_softmax(x) # nan 출력(값을 초과함)
y2 = simple_softmax(x) # 상대적으로 작은 값, 값 간의 차이를 줄이기 위한 방법 - 각 값을 해당 array의 최대값으로 뺀 값

plt.plot(x, y1)
plt.plot(x, y2, linestyle="--")
plt.ylim(-0.1, 1.1)

print(y1)
print(y2)
print(np.sum(y1)) # 값의 합은 언제나 1이다.
print(np.sum(y2)) # 값의 합은 언제나 1이다.

plt.show()


import pandas as pd
import numpy as np
# Partitioning a dataset in training and test sets
df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data', header=None)
df_wine.columns=['Class label', 'Alcohol',
                                 'Malic acid', 'Ash',
                                 'Alcalinity of ash', 'Magnesium',
                                 'Total phenols', 'Flavanoids',
                                 'Nonflavanoid phenols',
                                 'Proanthocyanins',
                                 'Color intensity', 'Hue',
                                 'OD280/OD315 of diluted wines',
                                 'Proline']
print 'Class labels', np.unique(df_wine['Class label'])

df_wine.head()

from sklearn.cross_validation import train_test_split
X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:,0]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

# Bringing features onto the same scale
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
x = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
mms = MinMaxScaler()
stdsc = StandardScaler()
mms.fit_transform(x)
stdsc.fit_transform(x)

# There are two common approaches to bringing different features onto the same scale:
# normalization and standardization.
from sklearn.preprocessing import MinMaxScaler
mms = MinMaxScaler()
X_train_norm = mms.fit_transform(X_train)
X_test_norm = mms.transform(X_test)

from sklearn.preprocessing import StandardScaler
stdsc = StandardScaler()
X_train_std = stdsc.fit_transform(X_train)
X_test_std = stdsc.transform(X_test)

# Selecting meaningful features
'''
A reason for overfitting is that our model is too complex for the given training data
and common colutions to reduce  the generalization error are listed as follows:
. Collect more training data
. Introduce a penalty for complexity via regularization
. Choose a simpler model with fewer parameters
. Reduce the dimensionality of the data

Common ways to reduce overfitting by regularization and dimensionality reduction
via feature selection.

'''

# Sparse solutions with L1 regularization
# For regularized models in scikit-learn that support L1 regularization, we can simply
# set the penalty parameter to 'l1' to yield the sparse solution.
from sklearn.linear_model import LogisticRegression
LogisticRegression(penalty='l1')
'''
Applied to the standardized Wine data, the L1 regularized logistic regression would
yield the following sparse solution.
'''
lr = LogisticRegression(penalty='l1', C=0.1)
lr.fit(X_train_std, y_train)
print 'Training accuracy: ', lr.score(X_train_std, y_train)
print 'Test accuracy: ', lr.score(X_test_std, y_test)

'''
Both training and test accuracies(both 98 percent) do not indicate any overfitting
of our model. When we access the intercept terms via the lr.intercept_attribute,
we can see that the array returns three values:
'''
lr.intercept_

lr.coef_

'''
We noticed that the weight vectors are sparse, which means that they only have a
few non-zero entries.
'''

'''
Lastly, let's plot the regularization path, which is the weight coefficients of the different
features fro different regularization strengths:
'''
import matplotlib.pyplot as plt
fig = plt.figure()
ax = plt.subplot(111)

colors = ['blue', 'green', 'red', 'cyan',
                'magenta', 'yellow', 'black',
                'pink', 'lightgreen', 'lightblue',
                'gray', 'indigo', 'orange']

weights, params = [], []
for c in np.arange(-4, 6):
    lr = LogisticRegression(penalty='l1', C=10**c, random_state=0)
    lr.fit(X_train_std, y_train)
    weights.append(lr.coef_[1])
    params.append(10**c)

weights = np.array(weights)

for column, color in zip(range(weights.shape[1]), colors):
    plt.plot(params, weights[:, column], label=df_wine.columns[column+1], color=color)

plt.axhline(0, color='black', linestyle='--', linewidth=3)
plt.xlim([10**(-5), 10**5])
plt.ylabel('weight coefficient')
plt.xlabel('C')
plt.xscale('log')
plt.legend(loc='upper left')
ax.legend(loc='upper center', bbox_to_anchor=(1.38, 1.03), ncol=1, fancybox=True)
plt.show()
'''
The resulting plot provides us with further insights about the behavior of L1 regularization.
As we can see, all features weights will be zero if we penalizethe model with a strong
regularization parameter(C<0.1); C is the inverse of the regularization parameter lambda.
'''

# Sequential feature selection algorithms
from sklearn.base import clone
from itertools import combinations
import numpy as np
from sklearn.cross_validation import train_test_split
from sklearn.metrics import accuracy_score

class SBS():
    def __init__(self, estimator, k_features, scoring=accuracy_score, test_size=0.25, random_state=1):
        self.scoring = scoring
        self.estimator = clone(estimator) # copy
        self.k_features = k_features
        self.test_size = test_size
        self.random_state = random_state

    def fit(self, X, y):
        X_train, X_test, y_train, y_test =  \
                    train_test_split(X, y, test_size=self.test_size, random_state=self.random_state)
        dim = X_train.shape[1] #the following calculations are for the situation where dim = self.k_features
        self.indices_ = tuple(range(dim)) # (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
        self.subsets_ = [self.indices_] # [(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)]
        score = self._calc_score(X_train, y_train, X_test, y_test, self.indices_)
        self.scores_ = [score]

        while dim > self.k_features:
            scores = []
            subsets = []

            for p in combinations(self.indices_, r=dim-1):
                score = self._calc_score(X_train, y_train, X_test, y_test, p)
                scores.append(score)
                subsets.append(p)
            # for each value of dim, the index and score for larget score combination will be pushed to self.indices_,self.score_
            best = np.argmax(scores) # find the index with largest score
            self.indices_ = subsets[best] # find the combination index for the largest score
            self.subsets_.append(self.indices_) # push the index combination into self.subsets
            dim -= 1

            self.scores_.append(scores[best]) # push the largest score to self.scores_
        self.k_score_ = self.scores_[-1] # the score based on k_features

        return self

    def transform(self, X):
        return X[:, self.indices]

    def _calc_score(self, X_train, y_train, X_test, y_test, indices): # score calculation
        self.estimator.fit(X_train[:, indices], y_train)
        y_pred = self.estimator.predict(X_test[:, indices])
        score = self.scoring(y_test, y_pred)
        return score

'''
Let's see our SBS implementation in action using the KNN classification from scikit-learn
'''
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
knn = KNeighborsClassifier(n_neighbors=2)
sbs = SBS(knn, k_features=1) #number of features from 13 to 1
sbs.fit(X_train_std, y_train)

k_feat = [len(k) for k in sbs.subsets_] # we only care about how many features used during plot
plt.plot(k_feat, sbs.scores_, marker='o')
plt.ylim([0.7, 1.1])
plt.ylabel('Accuracy')
plt.xlabel('Number of features')
plt.grid()
plt.show()

'''
To satisfy our own curiosity, let's see what those five features are that yielded such a
good performance on the validation dataset:
'''
k5 = list(sbs.subsets_[8]) # index is 8 for this list [13,12,11,10,9,8,7,6,5...]
print df_wine.columns[1:][k5]

'''
Next let's evaluate the performance of the KNN classifier on the original test set
'''
knn.fit(X_train_std, y_train)
print 'Training accuracy: ', knn.score(X_train_std, y_train)
print 'Test accuracy: ', knn.score(X_test_std, y_test)

'''
Now let's use the selected 5-feature subset and see how well KNN performs
'''
knn.fit(X_train_std[:, k5], y_train)
print 'Training accuracy: ', knn.score(X_train_std[:, k5], y_train)
print 'Test accuracy: ', knn.score(X_test_std[:, k5], y_test)

# Accesing feature importance with random forests
from sklearn.ensemble import RandomForestClassifier
feat_labels = df_wine.columns[1:] # 0 index is y column
forest = RandomForestClassifier(n_estimators=10000, random_state=0, n_jobs=-1 )
forest.fit(X_train, y_train)
importances = forest.feature_importances_
indices = np.argsort(importances)[::-1] # accending sort index, then change to decending index

for f in range(X_train.shape[1]):
    print "%2d) %-*s %f" % (f + 1, 30, feat_labels[indices[f]], importances[indices[f]])

plt.title('Feature Importances')
plt.bar(range(X_train.shape[1]), importances[indices], color='lightblue', align='center')
plt.xticks(range(X_train.shape[1]), feat_labels[indices], rotation=90)
plt.xlim(-1, X_train.shape[1])
plt.tight_layout()
plt.show()

X_selected = forest.transform(X_train, threshold=0.15)
X_selected.shape

#___________________________________________________________________#

# numpy.argsort(a, axis=-1, kind='quicksort', order=None)
'''
Returns the indices that would sort an array.
Perform an indirect sort along the given axis using the algorithm specified by the kind keyword.
It returns an array of indices of the same shape as a that index data along the given axis in sorted order.
'''

X_train.shape[1]
#Out[7]: 13L
X_train.shape
#Out[8]: (124L, 13L)
indices
#Out: array([ 9, 12,  6, 11,  0, 10,  5,  3,  1,  8,  4,  7,  2], dtype=int64)
importances[indices]
#Out:
#array([ 0.18250763,  0.15857438,  0.15095391,  0.13198329,  0.10656371,
#        0.07824855,  0.06071706,  0.03203891,  0.02538503,  0.02236895,
#        0.02207032,  0.01465534,  0.01393292])

#itertools.combinations(iterable, r)
'''
Return r length subsequences of elements from the input iterable.
So, if the input iterable is sorted, the combination tuples will be produced in sorted order.
'''
#numpy.argmax(a, axis=None, out=None)[source]
'''
Returns the indices of the maximum values along an axis.
'''

self_practice/Chapter 4 Wine data set.py


from sympy import S, symbols, Integer, Rational, \
    sqrt, I, solve_poly_system, raises, Poly

x, y, z = symbols('xyz')

def test_solve_poly_system():
    assert solve_poly_system([x-1], x) == [(S.One,)]

    assert solve_poly_system([y - x, y - x - 1], x, y) == None

    assert solve_poly_system([y - x**2, y + x**2], x, y) == [(S.Zero, S.Zero)]

    assert solve_poly_system([2*x - 3, 3*y/2 - 2*x, z - 5*y], x, y, z) == \
        [(Rational(3, 2), Integer(2), Integer(10))]

    assert solve_poly_system([x*y - 2*y, 2*y**2 - x**2], x, y) == \
       [(0, 0), (2, -2**S.Half), (2, 2**S.Half)]

    assert solve_poly_system([y - x**2, y + x**2 + 1], x, y) == \
           [(I*S.Half**S.Half, -S.Half), (-I*S.Half**S.Half, -S.Half)]

    a, b = -1 - 2**S.Half, -1 + 2**S.Half

    assert solve_poly_system([x**2+y+z-1, x+y**2+z-1, x+y+z**2-1], x, y, z) == \
        [(a, a, a), (0, 0, 1), (0, 1, 0), (b, b, b), (1, 0, 0)]

    solution = [(1, -1), (1, 1)]

    assert solve_poly_system([Poly(x**2 - y**2), Poly(x - 1)]) == solution
    assert solve_poly_system([x**2 - y**2, x - 1], x, y) == solution
    assert solve_poly_system([x**2 - y**2, x - 1]) == solution

    raises(ValueError, "solve_poly_system([x**3-y**3], x, y)")


import numpy as np
from pycsminwel import csminwel

# Test function
def rosenbrock(x):
    """
    Rosenbrock Function
    :param x: vector of legth 2
    :return: float
    """
    return (1 - x[0]) ** 2 + 105 * (x[1] - x[0] ** 2) ** 4

def drosenbrock(x):
    """
    Gradient of the Rosenbrock Function
    :param x: vector of legth 2
    :return: gradient vector
    """
    dr = np.zeros(2)
    dr[0] = 2 * (x[0] - 1) - 8 * 105 * x[0] * (x[1] - x[0] ** 2) ** 3
    dr[1] = 4 * 105 * (x[1] - x[0] ** 2) ** 3
    return dr

print(' ===== Optimization with NUMERCIAL derivatives =====')
x0 = np.array([10, -9])
h0 = np.eye(2) * 0.5
fh, xh, _, _, itct, _, _ = csminwel(rosenbrock, x0, h0)
print(f'Convergence in {itct} steps')
print(f'Minimal value is {round(fh, 4)}')
print('Optimal point is', xh)
print('\n')

print(' ===== Optimization with ANALYTICAL derivatives =====')
x0 = np.array([10, -9])
h0 = np.eye(2) * 0.5
fh, xh, _, _, itct, _, _ = csminwel(rosenbrock, x0, h0, drosenbrock)
print(f'Convergence in {itct} steps')
print(f'Minimal value is {round(fh, 4)}')
print('Optimal point is', xh)
print('\n')


"""
Normalization is used to standardize the intensity values in an image by adjusting the range of
gray level values so that they extend in a desired range of values and improve the contrast of the
image. The main goal of normalization is to reduce the variance of the gray level value along the
ridges to facilitate subsequent processing steps
"""
from math import sqrt
import numpy as np

def normalize_pixel(x, v0, v, m, m0):
    """
    From Handbook of Fingerprint Recognition pg 133
    Normalize job used by Hong, Wan and Jain(1998)
    similar to https://pdfs.semanticscholar.org/6e86/1d0b58bdf7e2e2bb0ecbf274cee6974fe13f.pdf equation 21
    :param x: pixel value
    :param v0: desired variance
    :param v: global image variance
    :param m: global image mean
    :param m0: desired mean
    :return: normilized pixel
    """
    dev_coeff = sqrt((v0 * ((x - m)**2)) / v)
    return m0 + dev_coeff if x > m else m0 - dev_coeff

def normalize(im, m0, v0):
    m = np.mean(im)
    v = np.std(im) ** 2
    (y, x) = im.shape
    normilize_image = im.copy()
    for i in range(x):
        for j in range(y):
            normilize_image[j, i] = normalize_pixel(im[j, i], v0, v, m, m0)

    return normilize_image


import numpy as np

a = input("Enter the choice of array(input a or b or c): ")
if a=='a':
  x=np.array([10,15,20,22.5,30],float)
  y=np.array([227.04,362.78,517.35,602.97,901.67],float)
elif a=='b':
  x=np.array([-1,0,1,2],float)
  y=np.array([3,-4,5,6],float)
elif a=='c':
  x=np.array([1,2,2.5,3,4,4.5,5],float)
  y=np.array([-1.5,-1,0.5,0.25,1,4.5,5],float)
else:
  print("Array Doesn't exist!")

n=len(x)
nn=80

xd=(x[n-1]-x[0])/nn

listx=[]  # creating an empty list for x values.

for j in range(nn+1):
    xn=x[0]+j*xd
    listx.append(xn)
print(listx)
p = float(input("Enter the value of the data point p= "))

f=0

for i in range(n):
     y1=1  ## important  Do not put y1 before defining the range for i,
     # otherwise while evaluating the multiplication,
     #  y1 will continue with the next iteration for i after finishing with one i
     for j in range(n):
        if i!=j:
          y1=y1*(p-x[j])/(x[i]-x[j])

     f+=y[i]*y1

# print(y1)
print("Value of the polynomial is = ", f)


import numpy as np
from figaro.exceptions import FIGAROException

def MC_integral(p, q, n_draws = 1e4, error = True):
    """
    Monte Carlo integration using FIGARO reconstructions.
        ∫p(x)q(x)dx ~ ∑p(x_i)/N with x_i ~ q(x)

    p(x) must have a pdf() method and q(x) must have a rvs() method.
    Lists of p and q are also accepted.

    Arguments:
        :list or class instance p: the probability density to evaluate. Must have a pdf() method.
        :list or class instance q: the probability density to sample from. Must have a rvs() method.
        :int n_draws:              number of MC draws
        :bool error:               whether to return the uncertainty on the integral value or not.

    Return:
        :double: integral value
        :double: uncertainty (if error = True)
    """
    # Check that both p and q are iterables or callables:
    if not ((hasattr(p, 'pdf') or np.iterable(p)) and (hasattr(q, 'rvs') or np.iterable(q))):
        raise FIGAROException("p and q must be list of callables or having pdf/rvs methods")
    # Number of p draws and methods check
    if np.iterable(p):
        if not np.alltrue([hasattr(pi, 'pdf') for pi in p]):
            raise FIGAROException("p must have pdf method")
        n_p = len(p)
        np.random.shuffle(p)
        iter_p = True
    else:
        if not hasattr(p, 'pdf'):
            raise FIGAROException("p must have pdf method")
        iter_p = False
    # Number of q draws and methods check
    if np.iterable(q):
        if not np.alltrue([hasattr(qi, 'rvs') for qi in q]):
            raise FIGAROException("q must have rvs method")
        n_q = len(q)
        np.random.shuffle(q)
        iter_q = True
    else:
        if not hasattr(q, 'rvs'):
            raise FIGAROException("q must have rvs method")
        iter_q = False

    n_draws = int(n_draws)

    # Integrals
    if iter_p and iter_q:
        shortest = np.min([n_p, n_q])
        probabilities = np.array([qi.pdf(pi.rvs(n_draws)) for pi, qi in zip(p[:shortest], q[:shortest])])
    elif iter_p and not iter_q:
        probabilities = np.array([q.pdf(pi.rvs(n_draws)) for pi in p])
    elif iter_q and not iter_p:
        samples = p.rvs(n_draws)
        probabilities = np.array([qi.pdf(samples) for qi in q])
    else:
        probabilities = np.atleast_2d(q.pdf(p.rvs(n_draws)))

    means = probabilities.mean(axis = 1)
    I = means.mean()
    if not error:
        return I
    mc_error = (probabilities.var(axis = 1)/n_draws).mean()
    figaro_error = means.var()/len(means)
    return I, np.sqrt(mc_error + figaro_error)


import numpy as np
import matplotlib.pyplot as plt
def V(x):
	return 0.5*x*x

def numerov(E,plot=0,normalize=0,returnfi=0):
	#lim=5*np.sqrt(2*E)
	xmin = -8.0
	xmax = 8.0
	ndivide = 1000

	s=(xmax-xmin)/(ndivide-1)

	G = np.zeros(ndivide,dtype=np.dtype('f16'))
	f = np.zeros(ndivide,dtype=np.dtype('f16'))
	x = np.linspace(xmin, xmax, num=ndivide,dtype=np.dtype('f16'))

	nn = 0 #number of nodes

	#assign initial values of phi
	f[0] = 0
	f[1] = 0.0001

	G[0] = 2*V(x[0]) - 2*E
	G[1] = 2*V(x[1]) - 2*E

	for i in range(2, ndivide):
		G[i] = 2*V(x[i]) - 2*E
		f[i] = (-f[i-2] + 2*f[i-1] + 5.0*G[i-1]*f[i-1]*s*s/6.0 + G[i-2]*f[i-2]*s*s/12.0)/(1-G[i]*s*s/12.0)
		if (f[i]*f[i-1]) < 0.0:
			nn+=1

	#print('E = %.10f Phimax = %.5f nn = %d'%(E,f[i],nn))
	if normalize:
		I=np.trapz(x=x,y=f**2)
		f=f/np.sqrt(I)
	if plot:
		plt.plot(x,f,label='%.10f'%E)
		#plt.savefig('%.10f.png'%E)
		#plt.clf()
	if returnfi:
		return nn,f[i]
	else:
		return nn

#uniform sampling, found limits of nn changes
Es=np.linspace(0,7,num=200,dtype=np.dtype('f16'))
NNs=[numerov(i) for i in Es]
#print(NNs)

Pairs=[]
for i in range(1,len(NNs)):
	if NNs[i]!=NNs[i-1]:
		Pairs.append((Es[i-1],Es[i],NNs[i-1],NNs[i]))

epsilon=0.0001
print('With accuracy of %.10f'%epsilon)
for a,b,nn0,nn1 in Pairs:
	#print(a,b,nn0,nn1)
	x0=a
	x1=b
	_,fxnew=numerov(x0,normalize=1,returnfi=1)
	while(abs(fxnew) > epsilon):
		xnew=0.5*(x0+x1)
		nn_new,fxnew=numerov(xnew,normalize=1,returnfi=1)
		print(xnew,nn_new,fxnew)
		if (nn_new == nn0):
			x0 = xnew
		elif (nn_new == nn1):
			x1 = xnew
	print('Found eigenenergy at %.10f, nu = %d'%(x0,nn0))
	numerov(x0,plot=1,normalize=1)

plt.legend()
plt.xlabel(r'$x_r$')
plt.title('First several wavefunctions')
plt.savefig('sum.png')


import numpy as np
import random

random.seed(21)
np.random.seed(21)

ages = [random.randint(10,89) for i in range(10,89)]
#the above code is the short form of the below one
# ages =[]
# for x in range(90):
# 	ages.append( random.randint(10,89) )

net_worths =[ m * 8.78  + abs(np.random.normal(scale = 20.)) for m in ages ]
print(net_worths)
#This is the expansion of the above code
# net_worths =[]
# for m in ages:
# 	net_worths.append(8.78*m + abs(np.random.normal(scale=20.)))

#for the linear regression to work we need to convert the array into
# rows = total no. of element
# column = 1
#for that we need to use the reshape function in numpy
#but for that we need to change the list into a numpy array
#np.reshape(numpy_array_name, ( no.of_rows, no.of_columns ) )

ages       = np.reshape( np.array(ages), (len(ages), 2))
net_worths = np.reshape( np.array(net_worths), (len(net_worths), 1))

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

ages_train,ages_test,net_worths_train,net_worths_test = train_test_split(ages,net_worths)

reg = LinearRegression()

reg.fit(ages_train, net_worths_train)

slope = reg.coef_
intercept = reg.intercept_

print("The actuall slope : 8.78")
print("The calculated slope : ", slope)
print("The intercept : ", intercept)

testing_score = round(reg.score(ages_test, net_worths_test),4)
training_score = round(reg.score(ages_train, net_worths_train),4)

print("The scores of the ")
print("Testing data score % :", testing_score*100)
print("Training  data Score % : ", training_score*100)

import matplotlib.pyplot as plt

plt.scatter(ages, net_worths, color='orange',label ='Actuall_data')
plt.plot(ages_test,reg.predict(ages_test),color ='green',label ="Regression_data")
plt.xlabel('Ages')
plt.ylabel('Net Worth')
plt.legend()
plt.show()


"""Variance ratio test"""

# Authors: Thierry Moudiki
#
# License: BSD 3

import numpy as np
from scipy.stats import f

# inspired from R's var.test
def var_test(x, y, ratio=1, alternative="less", level=95):

    level = level / 100

    assert alternative in (
        "twosided",
        "less",
        "greater",
    ), "must have `alternative` in ('twosided', 'less', 'greater')"

    dfx = len(x) - 1
    dfy = len(y) - 1

    assert dfx >= 1, "not enough observations for `x`"

    assert dfy >= 1, "not enough observations for `y`"

    varx = np.var(x)
    vary = np.var(y)

    estimate = varx / vary
    statistic = estimate / ratio
    parameter = [dfx, dfy]

    pval = f.cdf(statistic, dfx, dfy)

    if alternative == "twosided":
        pval = 2 * min(pval, 1 - pval)
        beta = (1 - level) / 2
        cint = [
            estimate / f.ppf(1 - beta, dfx, dfy),
            estimate / f.ppf(beta, dfx, dfy),
        ]

    if alternative == "greater":
        pval = 1 - pval
        cint = [estimate / f.ppf(level, dfx, dfy), np.infty]

    if alternative == "less":
        cint = [0, estimate / f.ppf(1 - level, dfx, dfy)]

    return {
        "statistic": statistic,
        "parameter": parameter,
        "p_value": pval,
        "conf_int": cint,
        "estimate": estimate,
        "null_value": ratio,
        "alternative": alternative,
    }


from sympy import Symbol, Matrix, Eq, MatAdd, MatMul, preview, S, zeros

def get_symbols_dict(s: str) -> dict:
    return {i: Symbol(i) for i in s.split(' ')}

def create_endos_v(endos: dict) -> Matrix:
    """
    Вектор ЭНДОГЕННЫХ переменных
    """
    return Matrix([[i] for i in endos.values()])

def create_predeters_v(pseudos: list, predeters: dict) -> Matrix:
    """
    Вектор ПРЕДОПРЕДЕЛЕННЫХ (и мнимых) переменных
    """
    return Matrix([[i] for i in [*pseudos, *predeters.values()]])

def calc_M(A: Matrix, B: Matrix) -> Matrix:  # noqa
    """
    M = -A ** (-1) * B
    """
    return -A.inv() * B

def get_reduced_form(X: Matrix, Y: Matrix, A: Matrix, M: Matrix, U: Matrix) -> Eq:  # noqa
    if zeros(*U.shape) == U:
        res = MatMul(M, X)
    else:
        res = MatAdd(MatMul(M, X), MatMul(A.inv(), U))
    return Eq(Y, res, evaluate=False)

def save_components(path: str, **kwargs):
    for k, v in kwargs.items():
        eq = Eq(S(k), v, evaluate=False)
        preview(eq, output='png', viewer='file', filename=f'{path}/{k}.png', euler=False)

def save_reduced_matrix(reduced_form, path: str, dvioptions=None):
    preview(
        reduced_form,
        output='png',
        viewer='file',
        filename=f'{path}/0_reduced_form_matrix.png',
        euler=False,
        dvioptions=dvioptions
    )

def save_reduced_system(reduced_form, path: str, dvioptions=None):
    preview(
        reduced_form,
        output='png',
        viewer='file',
        filename=f'{path}/0_reduced_form_system.png',
        euler=False,
        dvioptions=dvioptions
    )