'''created 9/25/16 by Charles Franzen

Notes
-----
This module implements:

* three matrix multiplication algorithms:
    -naive iterative
    -naive recursive
    -Strassen recursive

* two QR decompositions:
    -Givens rotations
    -Householder reflections

* two Hessenberg algorithms:
    -upper Hessenberg reduction
    -QR decomp of upper Hessenberg matrices

* the QR algorithm for real eigenvalues, both with and without Hessenberg
  reduction.

This was created as part of a final project for DSCI6001 at GalvanizeU.
'''

import numpy as np
import numpy.linalg as LA
import time

# matrix multiplication

def naive_mat_mul(A, B):
    '''
    Naive iterative method of matrix multiplication

    Inputs- A, B (np.array): two matrices of the same dimensions 2^n x 2^n

    Output- (np.array): a matrix of dimensions 2^n x 2^n
    '''
    # get matrix dimensions
    n = A.shape[0]
    # initialize result matrix to all zeros
    C = np.zeros((n, n), dtype=np.complex_)
    # iterate through rows and columns to build up dot products
    for i in range(n):
        for l in range(n):
            for k in range(n):
                C[i, l] += A[i, k] * B[k, l]
    return C

def recursive_mat_mul(A, B):
    '''
    Naive recursive method of matrix multiplication

    Inputs- A, B (np.array): two matrices of the same dimensions 2^n x 2^n

    Output- (np.array): a matrix of dimensions 2^n x 2^n
    '''
    # get matrix dimensions
    n = A.shape[0]
    # base case: 1x1 matrices
    if n == 1:
        return A * B
    # recursive case
    else:
        # get dimensions of sub-matrices
        i = int(n / 2)
        # initialize result matrix
        C = np.zeros((n, n), dtype=np.complex_)

        # calculate each submatrix as an addition of two matrix products
        # note that this requires 8 matrix multiplications
        C[:i, :i] = recursive_mat_mul(A[:i, :i], B[:i, :i])\
            + recursive_mat_mul(A[:i, i:], B[i:, :i])

        C[:i, i:] = recursive_mat_mul(A[:i, :i], B[:i, i:])\
            + recursive_mat_mul(A[:i, i:], B[i:, i:])

        C[i:, :i] = recursive_mat_mul(A[i:, :i], B[:i, :i])\
            + recursive_mat_mul(A[i:, i:], B[i:, :i])

        C[i:, i:] = recursive_mat_mul(A[i:, :i], B[:i, i:])\
            + recursive_mat_mul(A[i:, i:], B[i:, i:])

        return C

def strassen_mat_mul(A, B):
    '''
    Strassen's recursive method of matrix multiplication

    Inputs- A, B (np.array): two matrices of the same dimensions 2^n x 2^n

    Output- (np.array): a matrix of dimensions 2^n x 2^n
    '''
    # get matrix dimensions
    n = A.shape[0]
    # base case: 1x1 matrices
    if n == 1:
        return A * B
    # recursive case
    else:
        # get dimensions of sub-matrices
        i = int(n / 2)
        # initialize result matrix
        C = np.zeros((n, n), dtype=np.complex_)

        # calculate intermediate matrices.
        # note that this requires only 7 matrix multiplications
        M1 = strassen_mat_mul(A[:i, :i] + A[i:, i:], B[:i, :i] + B[i:, i:])
        M2 = strassen_mat_mul(A[i:, :i] + A[i:, i:], B[:i, :i])
        M3 = strassen_mat_mul(A[:i, :i], B[:i, i:] - B[i:, i:])
        M4 = strassen_mat_mul(A[i:, i:], B[i:, :i] - B[:i, :i])
        M5 = strassen_mat_mul(A[:i, :i] + A[:i, i:], B[i:, i:])
        M6 = strassen_mat_mul(A[i:, :i] - A[:i, :i], B[:i, :i] + B[:i, i:])
        M7 = strassen_mat_mul(A[:i, i:] - A[i:, i:], B[i:, :i] + B[i:, i:])

        # calculate sub-matrices by addition of the intermediate matrices
        C[:i, :i] = M1 + M4 - M5 + M7
        C[:i, i:] = M3 + M5
        C[i:, :i] = M2 + M4
        C[i:, i:] = M1 - M2 + M3 + M6

        return C

def mat_time(n, func, number=1000, repeats=3):
    '''
    Records running times for matrix multiplications

    Inputs- n (int): size of test matrices. must be a power of 2
            func (function): matrix multiplication function to be used
            num_trials (int): number of trials for the experiment
            repeats (int): number of experiments

    Output- list: times for each trial
    '''
    # create random n x n matrices
    A = np.random.randint(0, n**2, (n, n))
    B = np.random.randint(0, n**2, (n, n))

    def _timer(A, B):
        t1 = time.time()
        func(A, B)
        t2 = time.time()
        return t2 - t1
    # run all trials
    trials = [np.mean([_timer(A, B) for _ in range(number)])
              for _ in range(repeats)]
    return trials

# QR decomp and the QR algorithm

def _givens(a, b):
    '''
    Subroutine to calculate a rotation matrix g: [gamma, -sigma]
                                                 [sigma, gamma]
    such that g*[a] = [r]
                [b]   [0]

    This is a linear transformation that zeros the lower left element of
    a matrix M

    Inputs- a, b (float): values from the matrix to be decomposed

    Outputs- gamma, sigma (float): scalars used to construct a givens rotation
                                   matrix
    '''
    if np.abs(b) >= np.abs(a):
        tau = a / b
        sigma = 1 / np.sqrt(1 + tau**2)
        gamma = sigma * tau
    else:
        tau = b / a
        gamma = 1 / np.sqrt(1 + tau**2)
        sigma = gamma * tau
    return gamma, sigma

def givens_QR(A):
    '''
    Uses givens rotations to perform QR decomposition of A

    Input- A (np.array): the matrix to be decomposed

    Outputs- Q, R (np.array): an orthonormal matrix Q and an upper triangular
                              matrix R such that Q*R=A
    '''
    # get dimensions of a
    n, m = A.shape
    # initialize Q
    Q = np.identity(n)
    # initialize R
    R = np.copy(A)
    # for n columns
    for j in range(n):
        # for rows j-m
        for i in range(m - 1, j, -1):
            # calculate rotation matrix
            c, s = _givens(R[i - 1, j], R[i, j])
            # broadcast to an nxn matrix G
            G = np.identity(n)
            G[i - 1, i - 1] = c
            G[i, i] = c
            G[i, i - 1] = s
            G[i - 1, i] = -s
            # these matrices zero the lower diagonal elements of R
            # update R
            R = np.dot(G.T, R.copy())
            # update Q
            Q = np.dot(Q.copy(), G)
    return Q, R

def _givens_mat(c, s, n, i):
    '''
    Subroutine to return a givens rotation matrix

    Inputs- c, s (int): parameters for the givens matrix
            n (int): n_rows of the matrix
            i (int): index of the diagonal submatrix into which c and s should
                     be broadcast

    Output- G (np.array): givens rotation matrix
    '''
    # initialize matrix
    G = np.identity(n,)
    # assign values to the ith 2x2 diagonal submatrix
    G[i, i] = c
    G[i + 1, i + 1] = c
    G[i + 1, i] = s
    G[i, i + 1] = -s
    return G

def house_QR(A):
    '''
    Uses householder reflections to perform QR decomposition of A

    Input- A (np.array): the matrix to be decomposed

    Outputs- Q, R (np.array): an orthonormal matrix Q and an upper triangular
                              matrix R such that Q*R=A
    '''
    # get dimension of A
    n = len(A)
    # initialize Q
    Q = np.identity(n)
    # initialize R
    R = A.copy()
    # for n-1 columns
    for i in range(n - 1):
        # initialize householder tranformation
        H = np.identity(n)
        # embed reflection matrix
        H[i:, i:] = _house_mat(R[i:, i])
        # update R and Q
        Q = np.dot(Q, H)
        R = np.dot(H, R)
    return Q, R

def _house_mat(x):
    '''
    subroutine to calculate a householder reflection to zero all but the first
    entry of a column of a matrix

    Input- x (vector): vector to be reflected

    Output- H (matrix): householder transformation matrix. usually embedded into
                        an identity matrix
    '''
    # calculate normal to the hyperplane of reflection
    v = x / (x[0] + np.copysign(np.linalg.norm(x), x[0]))
    v[0] = 1
    # initialize H
    H = np.identity(x.shape[0])
    # calculate tranformation matrix
    H -= (2 / np.dot(v, v)) * np.outer(v, v)
    return H

def hessenberg(A, return_Q=True):
    '''
    Uses householder reflections to transform a matrix A into upper hessberg form

    Input- A (np.array): square matrix to be transformed

    Outputs- Q, H (np.array): orthonormal matrix Q and upper hessberg matrix H
                              such that Q*H=A
    '''
    # get dimension of A
    n = len(A)
    # initialize H
    R = A.copy()
    # initialize Q
    if return_Q:
        Q = np.identity(n)
    # perform n-2 householder reflections
    for i in range(n - 2):
        H = np.identity(n)
        # perform the reflection to zero all but the first 2 entries of the
        # column
        H[i + 1:, i + 1:] = _house_mat(R[i + 1:, i])
        R = H.dot(R).dot(H.T)
        if return_Q:
            Q = np.dot(Q, H)
    if return_Q:
        return Q, R
    else:
        return R

def hessenberg_QR(H):
    '''
    Uses givens rotations to perform QR decomposition on an upper hessberg matrix

    Input- H (np.array): square matrix in upper hessberg form

    Outputs- R (np.array): upper triangular matrix of the QR decomposition
             Gs (list): list of givens rotation matrices used to produce R
    '''
    # initialize R
    R = H.copy()
    # get dimension of H
    n = len(H)
    # initialize Gs
    Gs = []
    # perform n-1 givens rotations on the lower subdiagonal
    for i in range(n - 1):
        # get givens params
        c, s = _givens(R[i, i], R[i + 1, i])
        # get givens transformation matrix
        G = _givens_mat(c, s, n, i)
        # update R
        R = np.dot(G.T, R.copy())
        # update Gs
        Gs.append(G)
    return R, Gs

def eig(A, iterations=100):
    '''
    Uses givens rotations to perform the QR algorithm for finding real eigenvalues

    Inputs- A (np.array): matrix for which to find eigenvalues
            iterations (int): desired number of iterations

    Output- np.array: sorted array of real eigenvalues
    '''
    for _ in range(iterations):
        # calculate QR decomp
        Q, R = givens_QR(A)
        # compose new A
        A = R.dot(Q)
    # eigenvalues converge on the diagonal of A
    return np.sort(np.diag(A))

def hessenberg_eig(A, iterations=100):
    '''
    Converts a matrix into upper hessberg form, then uses givens rotations to
    perform the QR algorithm for finding real eigenvalues

    Inputs- A (np.array): matrix for which to find eigenvalues
            iterations (int): desired number of iterations

    Output- np.array: sorted array of real eigenvalues
    '''
    # convert A to upper hessberg form
    H = hessenberg(A, return_Q=False)
    for _ in range(iterations):
        # QR decompostion of H
        H, G = hessenberg_QR(H)
        # since Q is the product of all the transformations in G, R*Q can be
        # calculated as the product of R and all the transformations in G
        # this is guaranteed to return another upper hessberg matrix, for which
        # the QR decomposition can be computed again using the fast hessberg_QR
        # method
        for g in G:
            H = np.dot(H, g)
    # eigenvalues converge on the diagonal of H
    return np.sort(np.diag(H))

def eig_time(n, func, number=1000, repeats=3, A=None):
    '''
    Records running times for eigenvalue algorithms

    Inputs- n (int): size of test matrix
            func (function): eigenvalue function to be used
            num_trials (int): number of trials for the experiment
            repeats (int): number of experiments

    Output- list: times for each trial
    '''
    if A is None:
        # create random n x n matrix
        A = np.random.randint(0, n, (n, n))
        A = A.dot(A.T)

    def _timer():
        t1 = time.time()
        func(A)
        t2 = time.time()
        return t2 - t1
    # run all trials
    trials = [np.mean([_timer() for _ in range(number)])
              for _ in range(repeats)]
    return trials


# -*- coding: utf-8 -*-
"""
这是一个pip打包的例子

@author: lowinli

@email: lowinli@outlook.com
"""

import numpy as np

def softmax(x):
    """对向量进行softmax处理

    这只是对自动api文档的一个例子

    Args:
        x (int): 输入向量

    Returns:
        np.array: softmax结果

    Examples:
        >>> array = softmax(np.array([1, 1]))
        >>> array
        np.array([0.5, 0.5])

    References:
        softmax维基百科  https://en.wikipedia.org/wiki/Softmax_function
    """
    return np.exp(x) / np.sum(np.exp(x), axis=0)


import numpy as np

MAX_ITERS = 100
DOUBLE_PRECISION_THRESHOLD = 1e-15

def euler(y_n, t_n, f, h):
    return y_n + h*f(t_n, y_n)

def trapezoidal_rule(y_n, t_n, f, h, y_nn=None):
    if y_nn is None: # we should solve nonlinear system then
        raise Exception('Not implemented')

    t_nn = t_n + h
    return y_n + h/2. * (f(t_n, y_n) + f(t_nn, y_nn))

def heun(y_n, t_n, f, h):
    # euler is predictor, trapezoidal is corrector
    y_pred = euler(y_n, t_n, f, h)
    return trapezoidal_rule(y_n, t_n, f, h, y_pred)

def rk4(y_n, t_n, f, h):
    k_1 = h*f(t_n, y_n)
    k_2 = h*f(t_n + h/2., y_n + k_1/2.)
    k_3 = h*f(t_n + h/2., y_n + k_2/2.)
    k_4 = h*f(t_n + h, y_n + k_3)
    return y_n + 1/6. * (k_1 + 2*k_2 + 2*k_3 + k_4)

def ab4(y_4n, t_n, f, h):
    # Adams-Bashforth 4-step scheme
    # y_n == y_4n[3], y_{n-1} == y_4n[2], ..., y_{n-3} == y_4n[0]
    return y_4n[3] + h/24. * (55*f(t_n, y_4n[3]) - 59*f(t_n - h, y_4n[2]) + 37*f(t_n - 2*h, y_4n[1]) - 9*f(t_n - 3*h, y_4n[0]))

def am4(y_3n, t_n, f, h, y_nn=None):
    # Adams-Moulton 3-step scheme
    # y_n == y_3n[2], y_{n-1} == y_3n[1], y_{n-2} == y_3n[0]
    if y_nn is None:
        raise Exception('Not implemented')

    return y_3n[2] + h/24. * (9*f(t_n + h, y_nn) + 19*f(t_n, y_3n[2]) - 5*f(t_n - h, y_3n[1]) + f(t_n - 2*h, y_3n[0]))

def am_predictor_corrector(y_4n, t_n, f, h):
    # Apply predictor
    y_nn = ab4(y_4n, t_n, f, h)

    # Use inner iteration for implicit method (corrector) to converge
    for k in range(MAX_ITERS):
        y_nn_prev = y_nn
        y_nn = am4(y_4n[1:], t_n, f, h, y_nn=y_nn_prev)
        if np.abs(y_nn_prev - y_nn) < DOUBLE_PRECISION_THRESHOLD:

            print('Iteration converged at k = {} with error = {}'.format(k, np.abs(y_nn_prev - y_nn)))
            return y_nn

    return y_nn


"""
Euclidean algorithm (gcd).
"""
from sage.all import *

def euclidean_algorithm(f, g):
    """
    Euclidean Algorithm.

    Returns one gcd of two elements f, g belonging to an euclidean domain.

    Parameters
    ----------
    f : the first element.
    g : the second element.

    Returns
    -------
    A gcd of f and g.
    """

    if f.parent() is not g.parent():
        raise ValueError("Arguments should belong to the same ring")

    domain = f.parent()

    if not domain.is_euclidean_domain():
        raise ValueError("Arguments should belong to an euclidean domain")

    a, b = f, g

    while b != domain.zero():
        _, rem = a.quo_rem(b)
        a, b = b, rem

    return a

def main():
    """ Execute the examples. """
    print euclidean_algorithm(ZZ(126), ZZ(35))  # Expected 7
    print euclidean_algorithm(ZZ(112242), ZZ(989712))  # Expected 6
    print euclidean_algorithm(ZZ(33461), ZZ(236322))  # Expected 1

    R = PolynomialRing(QQ, 'x')
    print euclidean_algorithm(R('x^2 - 1'), R('x + 1'))  # Expected x + 1
    print euclidean_algorithm(R('x + 1'), R('x + 2'))  # Expected 1 (or -1)

if __name__ == '__main__':
    main()


# Sebastian Raschka 2014-2020
# mlxtend Machine Learning Library Extensions
#
# Functions for different linear algebra operations.
# Author: Sebastian Raschka <sebastianraschka.com>
#
# License: BSD 3 clause

import numpy as np

def vectorspace_orthonormalization(ary,  # method='gram-schmidt',
                                   eps=1e-13):
    """Transforms a set of column vectors to a orthonormal basis.

    Given a set of orthogonal vectors, this functions converts such
    column vectors, arranged in a matrix, into orthonormal basis
    vectors.

    Parameters
    ----------
    ary : array-like, shape=[num_vectors, num_vectors]
        An orthogonal set of vectors (arranged as columns in a matrix)

    eps : float (default: 1e-13)
        A small tolerance value to determine whether
        the vector norm is zero or not.

    Returns
    ----------
    arr : array-like, shape=[num_vectors, num_vectors]
        An orthonormal set of vectors (arranged as columns)

    """

    # Gram-Schmidt Process
    #  1) col i for i = 0: keep & normalize:
    #  2) col i for i > 1:
    #   2a) project column i+1 onto i
    #   2b) subtract column i from projection vector
    #   2c) Normalize if linearly independent,
    #       and set to zero otherwise

    arr = ary.astype(np.float).copy()

    for i in range(arr.shape[1]):
        for j in range(i):
            # 2a) & 2b)
            arr[:, i] -= np.dot(arr[:, i], arr[:, j]) * arr[:, j]
        # 2c
        tmp = np.linalg.norm(arr[:, i])
        is_linearly_indepedent = tmp > eps
        if is_linearly_indepedent:
            arr[:, i] /= tmp
        else:
            arr[:, i] = np.zeros(arr[:, i].shape)

    # elif method == 'qr-factorization':
    #    Q, R = np.linalg.qr(ary)
    #    arr = Q

    # QR factorization is not used here because of non-useful
    # results in cases of linear dependence

    # else:
    #     raise ValueError("Method must be 'gram-schmidt'"
    #                      "or 'qr-factorization'")

    return arr

def vectorspace_dimensionality(ary):
    """Computes the hyper-volume spanned by a vector set

    Parameters
    ----------
    ary : array-like, shape=[num_vectors, num_vectors]
        An orthogonal set of vectors (arranged as columns in a matrix)

    Returns
    ----------
    dimensions : int
        An integer indicating the "dimensionality" hyper-volume spanned by
        the vector set

    """
    # Note that since the vectors of
    # an orthonormal vectoset have unit length or are zero,
    # the sum of the individual
    # norms equals the dimensionality of that vector space
    return int(np.sum(np.linalg.norm(
        vectorspace_orthonormalization(ary), axis=0)))


''' x = gaussPivot(a,b,tol=1.0e-9).
Resuelve [a]{x} = {b} por eliminacion de Gauss
con pivoteo parcial escalado
'''
# A  = np.array([[3.,-13., 9., 3.],[-6., 4., 1., -18.],[6., -2., 2., 4.],[12., -8., 6, 10.]])
# B  = np.array([-19., -34., 16., 26.])

# AA = np.array([[0.143, 0.357, 2.01],[-1.31, 0.911, 1.99],[11.2, -4.30, -0.605]])
# BB = np.array([-5.17, -5.46, 4.42])
import numpy as np
import sys

def gaussPivot(A,B,tol=1.0e-12):
    n = len(B)
    a = np.copy(A)
    b = np.copy(B)

    # Vector de escala
    s = np.zeros(n)
    for i in range(n):
        s[i] = max(abs(a[i,:]))

    # Vector de permutaciones
    vp = np.array(range(n))

    for k in range(0,n-1): # Ciclo sobre las columnas

        # Intercambio de renglones si es necesario
        p = np.argmax(abs(a[k:n,k])/s[k:n]) + k
        if abs(a[p,k]) < tol:
           err('La matriz es singular')
        if p != k:
           swapRensAGP(a,k,p)  #Matriz de coeficientes
           swapRensAGP(b,k,p)  #Vector independiente
           swapRensAGP(s,k,p)  #Vector de escala
           swapRensAGP(vp,k,p) #Vector de permutaciones
           print 'Intercambio:',k,p
        # Eliminacion
        for i in range(k+1,n):
            if a[i,k] != 0.0:
               lam = a[i,k]/a[k,k]
               a[i,k:n] = a [i,k:n] - lam*a[k,k:n]
               b[i] = b[i] - lam*b[k]

    if abs(a[n-1,n-1]) < tol:
         err('La matriz es singular')

      # Sustitucion regresiva
    for k in range(n-1,-1,-1):
        b[k] = (b[k] - np.dot(a[k,k+1:n],b[k+1:n]))/a[k,k]
    return b,vp

def swapRensAGP(v,i,j):
    if len(v.shape) == 1:
       v[i],v[j] = v[j],v[i]
    else:
      temp = v[i].copy()
      v[i] = v[j]
      v[j] = temp

def err(string):
    print string
    raw_input('Oprime return para salir')
    sys.exit()


"""
Author: Jacob Dachenhaus, jdachenh@purdue.edu
Assignment: 10.4 - Sin Cos
Date: 12/06/2021

Description:
    Program that calculates and plots the y=sin(x) and y=cos(x)
    functions from x=[0, pi/2].

Contributors:
    None

My contributor(s) helped me:
    [x] understand the assignment expectations without
        telling me how they will approach it.
    [x] understand different ways to think about a solution
        without helping me plan my solution.
    [x] think through the meaning of a specific error or
        bug present in my code without looking at my code.
    Note that if you helped somebody else with their code, you
    have to list that person as a contributor.

Academic Integrity Statement:
    I have not used source code obtained from any unauthorized
    source, either modified or unmodified; nor have I provided
    another student access to my code.  The project I am
    submitting is my own original work.
"""

import matplotlib.pyplot as plt
import numpy as np

def main():
    # Calculate the x and y values at each step
    step = 0.001
    x = np.arange(0, 2 * np.pi + step, step) # [start, stop)
    y1 = np.sin(x)
    y2 = np.cos(x)

    ##
    #  Make the plot
    ##
    fig, ax = plt.subplots()

    ax.plot(x, y1, color='r')
    ax.plot(x, y2, color='b')

    ##
    #  Customize the plot
    ##

    # Format the axes
    for spine in ('top', 'right'):
        ax.spines[spine].set_visible(False)
    for spine in ('bottom', 'left'):
        ax.spines[spine].set_position('zero')

    # Set ticks and labels
    ax.set_xticks([np.pi / 2, np.pi, 3 * np.pi / 2, 2 * np.pi])
    ax.set_xticklabels(['$\\pi/2$', '$\\pi$', '$3\\pi/2$', '$2\\pi$'])

    ax.set_yticks([-1, 1])

    ##
    #  Display the plot
    ##
    plt.show()

if __name__ == '__main__':
    main()


from function import f
from function import g
import numpy as np
import math

def fixedPoint (xi,tol,max_iter):
    res = {}
    f_xi = f(xi)
    g_xi = g(xi)
    return_list = []
    return_list.append({
            'iter':0,
            'xi': xi,
            'g(xi)':g_xi,
            'f(xi)': f_xi,
            'error':'NA'
            })
    count = 1
    error = tol + 1
    while error > tol and count <= max_iter:
        xn = g_xi
        g_xi = g(xn)
        f_xi = f(xn)
        error = abs(xn-xi)
        xi = xn
        row = {
            'iter' : count,
            'xi': xi,
            'g(xi)':g_xi,
            'f(xi)': f_xi,
            'error': error
            }
        return_list.append(row)
        if(f_xi == 0):
            res["iters"] = return_list
            res["status"] = 'Root found! ;)'
            res["error"] = False
            return res
        elif(error < tol):
            res["iters"] = return_list
            res["status"] = 'Err lower than tolerance! :)'
            res["error"] = False
            return res
        elif(count >= max_iter):
            res["iters"] = return_list
            res["status"] = 'Overpassed max iteration! :('
            res["error"] = True
            return res
        count = count + 1

    return {"iters" : return_list}


'''
02 - Hierarchies of stocks

In chapter 1, you used k-means clustering to  cluster  companies  according  to  their
stock price movements. Now, you'll perform  hierarchical  clustering of the  companies.
You are given a NumPy array of price movements  movements, where the  rows  correspond
to companies, and a list of the company names companies. SciPy hierarchical  clustering
doesn't fit into a sklearn pipeline, so you'll need to use the normalize() function from
sklearn.preprocessing instead of Normalizer.

linkage and dendrogram have already been imported from scipy.cluster.hierarchy, and PyPlot
has been imported as plt.

Instructions:

- Import normalize from sklearn.preprocessing.

- Rescale the price movements for each stock by using the normalize() function on movements.

- Apply the linkage() function to normalized_movements, using 'complete' linkage, to calculate
  the hierarchical clustering. Assign the result to mergings.

- Plot a dendrogram of the hierarchical clustering, using the list companies of company names as
  the labels. In addition, specify the leaf_rotation=90, and leaf_font_size=6 keyword arguments as
  you did in the previous exercise.
'''
# Import normalize
from sklearn.preprocessing import normalize

# Normalize the movements: normalized_movements
normalized_movements = normalize(movements)

# Calculate the linkage: mergings
mergings = linkage(normalized_movements, method='complete')

# Plot the dendrogram
dendrogram(mergings,
          labels=companies,
          leaf_rotation=90,
          leaf_font_size=6)
plt.show()

27_Unsupervised Learning in Python/02_visualization-with-hierarchical-clustering-and-t-sne/02_hierarchies-of-stocks.py


# -*- coding: utf-8 -*-
# @version : Python3.6
# @Time    : 2017/4/30 15:54
# @Author  : Jianyang-Hu
# @contact : jianyang1993@163.com
# @File    : sincinterp_0430.py
# @Software: PyCharm

import numpy as np
from scipy import interpolate
import matplotlib.pyplot as plt
#一维插值

#创建数据点并添加噪音
x = np.linspace(-18, 18, 36)
noise = 0.1 * np.random.random(len(x))
signal = np.sinc(x) + noise

#创建一个线性插值函数，并应用于有5倍数据点个数的输入数组
interpreted = interpolate.interp1d(x, signal)
x2 = np.linspace(-18, 18, 180)
y = interpreted(x2)

#使用三次插值
cubic = interpolate.interp1d(x, signal, kind="cubic")
y2 = cubic(x2)

plt.plot(x, signal, 'o', label="data")
plt.plot(x2, y, '-', label="linear")
plt.plot(x2, y2, '-', lw=2, label="cubic")

plt.legend()
plt.show()


import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA

def create_corr_data(corr = 0.8, data_min = 10, data_max = 80):

    # Set the Random Seed
    np.random.seed(seed = 0)

    # Set the x and y range for the data
    data_x_range = np.array([data_min, data_max])
    data_y_range = np.array([data_min, data_max])

    # Set the average of the x and y postions of the data points
    means = [data_x_range.mean(), data_y_range.mean()]

    # Set the standard deviation of the x and y positions of the data points
    stds = [data_x_range.std() / 3, data_y_range.std() / 3]

    # Construct the Covariance matrix
    covs = [[stds[0]**2, stds[0]*stds[1]*corr],
            [stds[0]*stds[1]*corr, stds[1]**2]]

    # Return the correlated data with 1000 data points
    return np.random.multivariate_normal(means, covs, 1000)

def plot_data(X, corr=None):

    # Make a Scatter plot of the data
    plt.scatter(X[:,0], X[:,1],color = 'white', alpha = 0.5, linewidth = 0)
    ax = plt.gca()
    ax.set_facecolor('lightslategray')
    plt.grid()
    plt.xlabel('$X$', fontsize = 20)
    plt.ylabel('$Y$', fontsize = 20)

    # Put legend on plot if correlation is provided
    if corr:
        props = dict(boxstyle = 'round', facecolor = 'wheat', alpha = 0.5)
        textstr = 'Corr(X,Y) = %.2f'%(corr)
        plt.text(0.05, 0.91, textstr, fontsize = 20, horizontalalignment = 'left',
                verticalalignment = 'top', bbox = props, transform = ax.transAxes)

    plt.show()

def mean_normalize_data(X):

    # Average of the values in each column of X
    ave_cols = X.mean(axis = 0)

    # Standard Deviation of the values in each column of X
    std_cols = X.std(axis = 0)

    # Return the mean normalized X
    return (X - ave_cols) / std_cols

def rotate_data(X, angle = 45.0):

    # Convert the angle from degrees to radians
    theta = (angle / 180.0) * np.pi

    #Create the 2D rotation matrix
    rotMatrix = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta),  np.cos(theta)]])

    # Return the rotated X
    return np.matmul(X, rotMatrix)

def get_pca_comp(X, n_cpm = 2):

    # Perform PCA for the given number of components
    pca = PCA(n_components = n_cpm)
    pca.fit(X)

    # Return the principal components
    return pca.components_

def get_proj_pts(X, pca_components):

    # Rotate X to get the min and max values
    X_rot = rotate_data(X)

    # Create and empty array to hold our projected points
    proj_pts = np.array([])

    for i in range(2):

        # Get the indices of the min and max data points
        min_idx = X_rot[:,i].argmin()
        max_idx = X_rot[:,i].argmax()

        # Select the x and y coordinates of the points to be projected
        q1 = np.array([X[min_idx,0], X[min_idx,1]])
        q2 = np.array([X[max_idx,0], X[max_idx,1]])

        # Set a point equal to the origin
        p0 = np.array([0,0])

        # Set a point that is in the direction of the ith eigenvector
        p1 = pca_components[i]

        # Create the A matrices
        a1 = np.array([[-q1[0]*(p1[0]-p0[0]) - q1[1]*(p1[1]-p0[1])], [-p0[1]*(p1[0]-p0[0]) + p0[0]*(p1[1]-p0[1])]])
        a2 = np.array([[-q2[0]*(p1[0]-p0[0]) - q2[1]*(p1[1]-p0[1])], [-p0[1]*(p1[0]-p0[0]) + p0[0]*(p1[1]-p0[1])]])

        # Create the B matrix
        b = np.array([[p1[0] - p0[0], p1[1] - p0[1]], [p0[1] - p1[1], p1[0] - p0[0]]])

        # Solve the linear equations Bx = A
        proj_pt1 = - np.linalg.solve(b, a1)
        proj_pt2 = - np.linalg.solve(b, a2)

        # Append the values of the projected points
        proj_pts = np.append(proj_pts, proj_pt1)
        proj_pts = np.append(proj_pts, proj_pt2)

    return proj_pts

def plot_data_with_pca_comp(corr = 0.8, data_min = 10, data_max = 80):

    # Create correlated data
    X = create_corr_data(corr, data_min, data_max)

    # Mean normalize X
    X_norm = mean_normalize_data(X)

    # Get the principal components
    pca_components = get_pca_comp(X_norm)

    # Get the projected points onto the principal components
    proj_pts = get_proj_pts(X_norm, pca_components)

    # Set the first and second components
    first_pc = pca_components[0]
    second_pc = pca_components[1]

    # Plot the correlated data
    plt.scatter(X_norm[:,0], X_norm[:,1], color = 'white', alpha = 0.5, linewidth = 0)
    ax = plt.gca()
    ax.set_facecolor('lightslategray')
    plt.grid()

    # Plot the first principal component (eigenvector) as a line
    x_vals = np.linspace(proj_pts[1], proj_pts[3], 10)
    y_vals = (first_pc[1] / first_pc[0]) * x_vals
    plt.plot(x_vals, y_vals, color = 'm', linewidth = 2, label = '$1^{st}$ PC')

    # Plot the second principal component (eigenvector) as a line
    x_vals = np.linspace(-proj_pts[5], -proj_pts[7], 10)
    y_vals = (second_pc[1] / second_pc[0]) * x_vals
    plt.plot(x_vals, y_vals, color = 'c', linewidth = 2, label = '$2^{nd}$ PC')
    plt.legend()

#     # Plot projected points
#     plt.scatter(proj_pts[0],proj_pts[1], color='r')
#     plt.scatter(proj_pts[2],proj_pts[3], color='c')
#     plt.scatter(proj_pts[4],proj_pts[5], color='r')
#     plt.scatter(proj_pts[6],proj_pts[7], color='c')

    # Plot legend
    props = dict(boxstyle = 'round', facecolor = 'wheat', alpha = 0.5)
    textstr = 'Corr(X,Y) = %.2f'%(corr)
    plt.text(0.05, 0.91, textstr, fontsize = 20, horizontalalignment = 'left',
            verticalalignment = 'top', bbox = props, transform = ax.transAxes)

    # Set the axis to equal or square
    plt.axis('equal')
#     plt.axis('square')

    plt.show()


import numpy as np
import pandas as pd
import scipy.sparse as sps
import matplotlib.pyplot as plt

from mlhub.pkg import mlask, mlcat
from IPython.display import display
from collections import Counter

from relm.mechanisms import LaplaceMechanism

mlcat("Differentially Private Release Mechanism", """\
This demo is based on the Jupyter Notebook from the RelM
package on github.

RelM can be readily utilised for the differentially private
release of data. In our demo database the records indicate the age
group of each patient who received a COVID-19 test on 9 March 2020.
Each patient is classified as belonging to one of eight age groups:
0-9, 10-19, 20-29, 30-39, 40-49, 50-59, 60-69, and 70+.  One common
way to summarise this kind of data is with a histogram.  That is, to
report the number of patients that were classified as belonging to
each age group.

For this demonstration we will create a histogram for the actual data
and then a histogram for differentially private data.

The data is first loaded from a csv file. It simply consists of two
columns, the first is the date and the scond is the age group.""")

# Read the raw data.

data = pd.read_csv("pcr_testing_age_group_2020-03-09.csv")

mlask(True, True)

# Compute the exact query responses.

exact_counts = data["age_group"].value_counts().sort_index()
values = exact_counts.values

mlcat("Data Sample", """\
Here's a random sample of some of the records:
""")

print(data.sample(10))

mlask(True, True)

mlcat("Laplace Mechanism", """\
The Laplace mechanism can be used to produce a differentially private
histogram that summarises the data without compromising the privacy of
the patients whose data comprise the database. To do so, Laplace noise
is added to the count for each age group and the noisy counts are
released instead of the exact counts.

The noise that is added results in perturbed values that are real
numbers rather than integers, and so if the results we are expecting
are integers, the results can be rounded without loss of privacy. We
do that here for our peturbed values.""")

# Create a differentially private release mechanism

epsilon = 0.1
mechanism = LaplaceMechanism(epsilon=epsilon, sensitivity=1.0)
perturbed_counts = mechanism.release(values=values.astype(np.float))
perturbed_counts = perturbed_counts.astype(np.int64)

mlask(True, True)

mlcat("Choosing Epsilon", f"""\
The magnitude of the differences between the exact counts
and perturbed counts depends only on the value of the privacy parameter,
epsilon. Smaller values of epsilon yield larger perturbations. Larger
perturbations yeild lower utility.

To understand this compare the actual and peturbed values below. If
the value of epsilon is not too small, then we expect that the two
histograms will look similar.

For our purposes we have chosen epsilon as {epsilon} resulting in the
following peturbation.
""")

# Extract the set of possible age groups.

age_groups = np.sort(data["age_group"].unique())

# Reformat the age group names for nicer display.

age_ranges = np.array([a.lstrip("AgeGroup_") for a in age_groups])

# Create a dataframe with both exact and perturbed counts.

column_names = ["Age Group", "Exact Counts", "Perturbed Counts"]
column_values = [age_ranges, values, perturbed_counts]
table = {k: v for (k, v) in zip(column_names, column_values)}
df = pd.DataFrame(table)

# Display as a table.

print(df)

mlask(True, True)

mlcat("Visualising the Perturbations", """\
The two histograms show that the peturbed values remain consistent
with the true values, whilst ensuring privacy.
""")

# Plot the two histograms as bar graphs.

df.plot(x="Age Group", title="Test Counts by Age Group", kind="bar", rot=0)
plt.show()

exit()

mlcat("Geometric Mechanism", """\

TODO

In this example, all of the exact counts are integers. That is because
they are the result of so-called counting queries. The perturbed counts
produced by the Laplace mechanism are real-valued. In some applications,
e.g. when some downstream processing assumes it will receive
integer-valued data, we may need the perturbed counts to be integers.
One way to achieve this is by simply rounding the outputs of the Laplace
mechanism to the nearest integer. Because this differentially private
release mechanisms are not affected by this kind of post-processing,
doing so will not affect any privacy guarantees.

Alternatively, we could use the geometric mechanism to compute the
permuted counts. The geometric mechanism is simply a discrete version of
the Laplace mechanism and it produces integer valued perturbations.
""")
mlask()

mlcat("", """Basic Usage
""")
mlask()

mlcat("", """
# Create a differentially private release mechanism
from relm.mechanisms import GeometricMechanism
mechanism = GeometricMechanism(epsilon=0.1, sensitivity=1.0)
perturbed_counts = mechanism.release(values=values)
""")
mlask()
# Create a differentially private release mechanism
from relm.mechanisms import GeometricMechanism
mechanism = GeometricMechanism(epsilon=0.1, sensitivity=1.0)
perturbed_counts = mechanism.release(values=values)
mlcat("", """Visualising the Results
As with the Laplace mechanism, we can plot the exact histogram alongside
the differentially private histogram to get an idea if we have used too
small a value for epsilon.
""")
mlask()

mlcat("", """
# Create a dataframe with both exact and perturbed counts
column_values = [age_ranges, values, perturbed_counts]
table = {k: v for (k, v) in zip(column_names, column_values)}
df = pd.DataFrame(table)

# Display the two histograms as a table
display(df.style.set_caption("Test Counts by Age Group"))

# Plot the two histograms as bar graphs
df.plot(x="Age Group", title="Test Counts by Age Group", kind="bar", rot=0)
plt.show()
""")
mlask()
# Create a dataframe with both exact and perturbed counts
column_values = [age_ranges, values, perturbed_counts]
table = {k: v for (k, v) in zip(column_names, column_values)}
df = pd.DataFrame(table)

# Display the two histograms as a table
display(df.style.set_caption("Test Counts by Age Group"))

# Plot the two histograms as bar graphs
df.plot(x="Age Group", title="Test Counts by Age Group", kind="bar", rot=0)
plt.show()
mlcat("", """Exponential Mechanism
""")
mlask()

mlcat("", """Basic Usage
The ExponentialMechanism does not lend itself to vectorised queries as
easily as the LaplaceMechanism or GeometricMechanism. So, to produce a
histogram query that is comparable to those discussed above we wrap the
query releases in a loop and compute them one at a time.
""")
mlask()

mlcat("", """
# Create a differentially private release mechanism
from relm.mechanisms import ExponentialMechanism

output_range = np.arange(2**10)
utility_function = lambda x: -abs(output_range - x)

perturbed_counts = np.empty(len(values), dtype=np.int)
for i, value in enumerate(values.astype(np.float)):
    mechanism = ExponentialMechanism(epsilon=0.1,
                                     utility_function=utility_function,
                                     sensitivity=1.0,
                                     output_range=output_range)

    perturbed_counts[i] = mechanism.release(values=value)
""")
mlask()
# Create a differentially private release mechanism
from relm.mechanisms import ExponentialMechanism

output_range = np.arange(2**10)
utility_function = lambda x: -abs(output_range - x)

perturbed_counts = np.empty(len(values), dtype=np.int)
for i, value in enumerate(values.astype(np.float)):
    mechanism = ExponentialMechanism(epsilon=0.1,
                                     utility_function=utility_function,
                                     sensitivity=1.0,
                                     output_range=output_range)

    perturbed_counts[i] = mechanism.release(values=value)
mlcat("", """Visualising the Results
""")
mlask()

mlcat("", """
# Create a dataframe with both exact and perturbed counts
column_values = [age_ranges, values, perturbed_counts]
table = {k: v for (k, v) in zip(column_names, column_values)}
df = pd.DataFrame(table)

# Display the two histograms as a table
display(df.style.set_caption("Test Counts by Age Group"))

# Plot the two histograms as bar graphs
df.plot(x="Age Group", title="Test Counts by Age Group", kind="bar", rot=0)
plt.show()
""")
mlask()
# Create a dataframe with both exact and perturbed counts
column_values = [age_ranges, values, perturbed_counts]
table = {k: v for (k, v) in zip(column_names, column_values)}
df = pd.DataFrame(table)

# Display the two histograms as a table
display(df.style.set_caption("Test Counts by Age Group"))

# Plot the two histograms as bar graphs
df.plot(x="Age Group", title="Test Counts by Age Group", kind="bar", rot=0)
plt.show()
mlcat("", """Sparse Mechanisms
We currently have four mechanisms that take advantage of sparsity to
answer more queries about the data for a given privacy budget. All of
these mechanisms compare noisy query responses to a noisy threshold
value. If a noisy response does not exceed the noisy threshold, then the
mechanism reports only that the value did not exceed the threshold.
Otherwise, the mechanism reports that the value exceeded the threshold.
Furthermore, in the latter case some mechanisms release more information
about the underlying exact count. This extra information is computed
using some other differentially private mechanism and therefore imposes
some additional privacy costs.
""")
mlask()

mlcat("", """Data Wrangling
All three of our mechanims share an input format. We require a sequence
of exact query responses and a threshold value to which these responses
will be compared.
""")
mlask()

mlcat("", """
# Read the raw data
fp = '20200811_QLD_dummy_dataset_individual_v2.xlsx'
data = pd.read_excel(fp)

# Limit our attention to the onset date column
data.drop(list(data.columns[1:]), axis=1, inplace=True)

# Remove data with no onset date listed
mask = data['ONSET_DATE'].notna()
data = data[mask]

# Compute the exact query responses
queries = [(pd.Timestamp('2020-01-01')  + i*pd.Timedelta('1d'),) for i in range(366)]
exact_counts = dict.fromkeys(queries, 0)
exact_counts.update(data.value_counts())

dates, values = zip(*sorted(exact_counts.items()))
values = np.array(values, dtype=np.float64)
""")
mlask()
# Read the raw data
fp = '20200811_QLD_dummy_dataset_individual_v2.xlsx'
data = pd.read_excel(fp)

# Limit our attention to the onset date column
data.drop(list(data.columns[1:]), axis=1, inplace=True)

# Remove data with no onset date listed
mask = data['ONSET_DATE'].notna()
data = data[mask]

# Compute the exact query responses
queries = [(pd.Timestamp('2020-01-01')  + i*pd.Timedelta('1d'),) for i in range(366)]
exact_counts = dict.fromkeys(queries, 0)
exact_counts.update(data.value_counts())

dates, values = zip(*sorted(exact_counts.items()))
values = np.array(values, dtype=np.float64)
mlcat("", """Above Threshold
The simplest of the sparse release mechanisms simply reports the index
of the first query response that exceeds the specified threshold.
""")
mlask()

mlcat("", """Basic Usage
""")
mlask()

mlcat("", """
from relm.mechanisms import AboveThreshold
mechanism = AboveThreshold(epsilon=1.0, sensitivity=1.0, threshold=100)
index = mechanism.release(values)
""")
mlask()
from relm.mechanisms import AboveThreshold
mechanism = AboveThreshold(epsilon=1.0, sensitivity=1.0, threshold=100)
index = mechanism.release(values)
mlcat("", """Empirical Distribution
Because AboveThreshold returns a single index, we can run many
experiments and plot a histogram of the results of those experiments to
get an empirical estimate of the distribution of the mechanism’s output.
""")
mlask()

mlcat("", """
TRIALS = 2**10
threshold = 100
results = np.zeros(TRIALS)
for i in range(TRIALS):
    mechanism = AboveThreshold(epsilon=1.0, sensitivity=1.0, threshold=threshold)
    index = mechanism.release(values)
    results[i] = index
""")
mlask()
TRIALS = 2**10
threshold = 100
results = np.zeros(TRIALS)
for i in range(TRIALS):
    mechanism = AboveThreshold(epsilon=1.0, sensitivity=1.0, threshold=threshold)
    index = mechanism.release(values)
    results[i] = index
mlcat("", """Visualising the Results
""")
mlask()

mlcat("", """
print("The index of the first exact count that exceeds the threshold is: %i\n" % np.argmax(values >= threshold))

histogram = dict.fromkeys(np.arange(min(results), max(results)), 0)
histogram.update(Counter(results))

plt.xlabel("Index")
plt.ylabel("Count")
plt.title("Distribution of AboveThreshold outputs")
plt.plot(list(histogram.keys()), list(histogram.values()))
plt.axvline(x=np.argmax(values >= threshold), color='orange')
""")
mlask()
print("The index of the first exact count that exceeds the threshold is: %i\n" % np.argmax(values >= threshold))

histogram = dict.fromkeys(np.arange(min(results), max(results)), 0)
histogram.update(Counter(results))

plt.xlabel("Index")
plt.ylabel("Count")
plt.title("Distribution of AboveThreshold outputs")
plt.plot(list(histogram.keys()), list(histogram.values()))
plt.axvline(x=np.argmax(values >= threshold), color='orange')
mlcat("", """Sparse Indicator
The SparseIndicator is a straightforward extension of the AboveThreshold
mechanism. Here, we find the indices of several values that exceeds the
specified threshold. The number of indices that this mechanism will
return is controlled by the cutoff parameter.
""")
mlask()

mlcat("", """Basic Usage
""")
mlask()

mlcat("", """
from relm.mechanisms import SparseIndicator
mechanism = SparseIndicator(epsilon=1.0, sensitivity=1.0, threshold=100, cutoff=3)
indices = mechanism.release(values)
""")
mlask()
from relm.mechanisms import SparseIndicator
mechanism = SparseIndicator(epsilon=1.0, sensitivity=1.0, threshold=100, cutoff=3)
indices = mechanism.release(values)
mlcat("", """Visualising the Results
""")
mlask()

mlcat("", """
TRIALS = 16
cutoff = 4
threshold = 100
indices = np.empty((TRIALS, cutoff), dtype=np.int)
for i in range(TRIALS):
    mechanism = SparseIndicator(epsilon=1.0, sensitivity=1.0, threshold=threshold, cutoff=cutoff)
    indices[i] = mechanism.release(values)

df = pd.DataFrame(indices,
                  columns=["Hit %i" % (j+1) for j in range(cutoff)],
                  index=["Trial %i" % i for i in range(TRIALS)])
display(df)
""")
mlask()
TRIALS = 16
cutoff = 4
threshold = 100
indices = np.empty((TRIALS, cutoff), dtype=np.int)
for i in range(TRIALS):
    mechanism = SparseIndicator(epsilon=1.0, sensitivity=1.0, threshold=threshold, cutoff=cutoff)
    indices[i] = mechanism.release(values)

df = pd.DataFrame(indices,
                  columns=["Hit %i" % (j+1) for j in range(cutoff)],
                  index=["Trial %i" % i for i in range(TRIALS)])
display(df)
mlcat("", """Sparse Numeric
The SparseNumeric mechanism returns perturbed values alongside the
indices of the values that exceeded the threshold.
""")
mlask()

mlcat("", """Basic Usage
""")
mlask()

mlcat("", """
from relm.mechanisms import SparseNumeric
mechanism = SparseNumeric(epsilon=1.0, sensitivity=1.0, threshold=100, cutoff=3)
indices, perturbed_values = mechanism.release(values)
""")
mlask()
from relm.mechanisms import SparseNumeric
mechanism = SparseNumeric(epsilon=1.0, sensitivity=1.0, threshold=100, cutoff=3)
indices, perturbed_values = mechanism.release(values)
mlcat("", """Visualising the Results
Notice that in these experiemnts we have set epsilon=4.0. This is a
larger value than we use in the other sparse mechanisms. Because the
SparseNumeric mechanism releases more information about the underlying
exact query responses than does SparseIndices, for example, it consumes
the available privacy budget more quickly. To achieve comparable utility
with respect the the indices returned by the two mechanisms, we
therefore need to a larger value for epsilon.
""")
mlask()

mlcat("", """
TRIALS = 2**4
cutoff = 3
threshold = 100
indices = np.empty(shape=(TRIALS, cutoff), dtype=np.int)
perturbed_values = np.empty(shape=(TRIALS, cutoff), dtype=np.float)
for i in range(TRIALS):
    mechanism = SparseNumeric(epsilon=4.0, sensitivity=1.0, threshold=threshold, cutoff=cutoff)
    indices[i], perturbed_values[i] = mechanism.release(values)

hit_names = ["Hit %i" % (j+1) for j in range(cutoff)]
value_names = ["Value %i" % (j+1) for j in range(cutoff)]
column_pairs = zip(hit_names, value_names)
column_names = [val for pair in column_pairs for val in pair]
value_pairs = zip(indices.transpose(), perturbed_values.transpose())
column_values = [val for pair in value_pairs for val in pair]
table = {k: v for (k, v) in zip(column_names, column_values)}
df = pd.DataFrame(table, index=["Trial %i" % i for i in range(TRIALS)])
display(df)
""")
mlask()
TRIALS = 2**4
cutoff = 3
threshold = 100
indices = np.empty(shape=(TRIALS, cutoff), dtype=np.int)
perturbed_values = np.empty(shape=(TRIALS, cutoff), dtype=np.float)
for i in range(TRIALS):
    mechanism = SparseNumeric(epsilon=4.0, sensitivity=1.0, threshold=threshold, cutoff=cutoff)
    indices[i], perturbed_values[i] = mechanism.release(values)

hit_names = ["Hit %i" % (j+1) for j in range(cutoff)]
value_names = ["Value %i" % (j+1) for j in range(cutoff)]
column_pairs = zip(hit_names, value_names)
column_names = [val for pair in column_pairs for val in pair]
value_pairs = zip(indices.transpose(), perturbed_values.transpose())
column_values = [val for pair in value_pairs for val in pair]
table = {k: v for (k, v) in zip(column_names, column_values)}
df = pd.DataFrame(table, index=["Trial %i" % i for i in range(TRIALS)])
display(df)
mlcat("", """Report Noisy Max
""")
mlask()

mlcat("", """Basic Usage
""")
mlask()

mlcat("", """
from relm.mechanisms import ReportNoisyMax
mechanism = ReportNoisyMax(epsilon=1.0)
index, perturbed_value = mechanism.release(values)
""")
mlask()
from relm.mechanisms import ReportNoisyMax
mechanism = ReportNoisyMax(epsilon=1.0)
index, perturbed_value = mechanism.release(values)
mlcat("", """Empirical Distribution
Because ReportNoisyMax returns a single index and a single value, we can
run many experiments and plot a histogram of the results of those
experiments to get an empirical estimate of the distribution of the
mechanism’s output.
""")
mlask()

mlcat("", """
TRIALS = 2**10
indices = np.zeros(TRIALS)
perturbed_values = np.zeros(TRIALS)
for i in range(TRIALS):
    mechanism = ReportNoisyMax(epsilon=0.1)
    indices[i], perturbed_values[i] = mechanism.release(values)
""")
mlask()
TRIALS = 2**10
indices = np.zeros(TRIALS)
perturbed_values = np.zeros(TRIALS)
for i in range(TRIALS):
    mechanism = ReportNoisyMax(epsilon=0.1)
    indices[i], perturbed_values[i] = mechanism.release(values)
mlcat("", """Visualising the Results
The ReportNoisyMax mechanism resturns two values, an index and a
perturbed query response. We analyze the distribution of each output
individually.
""")
mlask()

mlcat("", """Indices
""")
mlask()

mlcat("", """
print("The index of the greatest exact count is: %i\n" % np.argmax(values))

histogram = dict.fromkeys(np.arange(min(indices), max(indices)), 0)
histogram.update(Counter(indices))

plt.xlabel("Index")
plt.ylabel("Count")
plt.title("Distribution of ReportNoisyMax output indices")
plt.plot(list(histogram.keys()), list(histogram.values()))
plt.axvline(x=np.argmax(values), color='orange')
""")
mlask()
print("The index of the greatest exact count is: %i\n" % np.argmax(values))

histogram = dict.fromkeys(np.arange(min(indices), max(indices)), 0)
histogram.update(Counter(indices))

plt.xlabel("Index")
plt.ylabel("Count")
plt.title("Distribution of ReportNoisyMax output indices")
plt.plot(list(histogram.keys()), list(histogram.values()))
plt.axvline(x=np.argmax(values), color='orange')
mlcat("", """Perturbed Values
""")
mlask()

mlcat("", """
print("The greatest exact count is: %i\n" % np.max(values))

#histogram = dict.fromkeys(np.arange(min(results), max(results)), 0)
#histogram.update(Counter(results))

plt.hist(perturbed_values, bins=128)

plt.xlabel("Perturbed Value")
plt.ylabel("Count")
plt.title("Distribution of ReportNoisyMax output values")
plt.axvline(x=np.max(values), color='orange')
""")
mlask()
print("The greatest exact count is: %i\n" % np.max(values))

#histogram = dict.fromkeys(np.arange(min(results), max(results)), 0)
#histogram.update(Counter(results))

plt.hist(perturbed_values, bins=128)

plt.xlabel("Perturbed Value")
plt.ylabel("Count")
plt.title("Distribution of ReportNoisyMax output values")
plt.axvline(x=np.max(values), color='orange')
mlcat("", """Correlated Noise Mechanisms
""")
mlask()

mlcat("", """Data Wrangling
""")
mlask()

mlcat("", """
# Generate some synthetic data
data = pd.DataFrame()
test_results = np.random.choice(["Negative", "Positive", "N/A"], size=100000, p=[0.55,0.35,0.1])
data["Test Result"] = test_results

# Compute a histogram representation of the data
from relm.histogram import Histogram
hist = Histogram(data)
real_database = hist.get_db()
db_size = real_database.size
db_l1_norm = real_database.sum()

# Specify the queries to be answered
queries = [[{"Test Result": "Negative"}, {"Test Result": "Positive"}],
           [{"Test Result": "Positive"}, {"Test Result": "N/A"}],
           [{"Test Result": "Negative"}, {"Test Result": "N/A"}]]
num_queries = len(queries)
queries = sps.vstack([hist.get_query_vector(q) for q in queries])

# Compute the exact query responses
values = (queries @ real_database)/real_database.sum()
""")
mlask()
# Generate some synthetic data
data = pd.DataFrame()
test_results = np.random.choice(["Negative", "Positive", "N/A"], size=100000, p=[0.55,0.35,0.1])
data["Test Result"] = test_results

# Compute a histogram representation of the data
from relm.histogram import Histogram
hist = Histogram(data)
real_database = hist.get_db()
db_size = real_database.size
db_l1_norm = real_database.sum()

# Specify the queries to be answered
queries = [[{"Test Result": "Negative"}, {"Test Result": "Positive"}],
           [{"Test Result": "Positive"}, {"Test Result": "N/A"}],
           [{"Test Result": "Negative"}, {"Test Result": "N/A"}]]
num_queries = len(queries)
queries = sps.vstack([hist.get_query_vector(q) for q in queries])

# Compute the exact query responses
values = (queries @ real_database)/real_database.sum()
mlcat("", """SmallDB Mechanism
""")
mlask()

mlcat("", """Basic Usage
""")
mlask()

mlcat("", """
from relm.mechanisms import SmallDB
mechanism = SmallDB(epsilon=0.01, alpha=0.1)
synthetic_database = mechanism.release(values, queries, db_size, db_l1_norm)
""")
mlask()
from relm.mechanisms import SmallDB
mechanism = SmallDB(epsilon=0.01, alpha=0.1)
synthetic_database = mechanism.release(values, queries, db_size, db_l1_norm)
mlcat("", """Visualising the Results
""")
mlask()

mlcat("", """
TRIALS = 2**4
synthetic_responses = np.empty((TRIALS, queries.shape[0]))
for i in range(TRIALS):
    mechanism = SmallDB(epsilon=0.01, alpha=0.1)
    synthetic_database = mechanism.release(values, queries, db_size, db_l1_norm)
    synthetic_responses[i] = (queries @ synthetic_database) / synthetic_database.sum()

df = pd.DataFrame(data=np.row_stack((values, synthetic_responses)),
                  columns=["Query %i" % i for i in range(queries.shape[0])],
                  index=["Exact Responses"] + ["TRIAL %i" % i for i in range(TRIALS)])

display(df)
""")
mlask()
TRIALS = 2**4
synthetic_responses = np.empty((TRIALS, queries.shape[0]))
for i in range(TRIALS):
    mechanism = SmallDB(epsilon=0.01, alpha=0.1)
    synthetic_database = mechanism.release(values, queries, db_size, db_l1_norm)
    synthetic_responses[i] = (queries @ synthetic_database) / synthetic_database.sum()

df = pd.DataFrame(data=np.row_stack((values, synthetic_responses)),
                  columns=["Query %i" % i for i in range(queries.shape[0])],
                  index=["Exact Responses"] + ["TRIAL %i" % i for i in range(TRIALS)])

display(df)
mlcat("", """Online Multiplicative Weights Mechanism
""")
mlask()

mlcat("", """
from scipy.special import comb

# Generate some synthetic data
data = pd.DataFrame()
db_size = 8
probs = np.random.random(db_size)
probs /= probs.sum()
print(probs)
test_results = np.random.choice(np.arange(db_size), size=2**22, p=probs)
data["Test Result"] = test_results

# Compute a histogram representation of the data
from relm.histogram import Histogram
hist = Histogram(data)
real_database = hist.get_db()
db_size = real_database.size
db_l1_norm = real_database.sum()

# Specify the queries to be answered
num_ones = 5
q_size = comb(db_size, num_ones, exact=True)
queries = [{"Test Result": k for k in np.random.choice(np.arange(db_size), size=num_ones, replace=False)} for i in range(1024)]
num_queries = len(queries)
queries = sps.vstack([hist.get_query_vector(q) for q in queries])

# Compute the exact query responses
values = (queries @ real_database)/real_database.sum()
""")
mlask()
from scipy.special import comb

# Generate some synthetic data
data = pd.DataFrame()
db_size = 8
probs = np.random.random(db_size)
probs /= probs.sum()
print(probs)
test_results = np.random.choice(np.arange(db_size), size=2**22, p=probs)
data["Test Result"] = test_results

# Compute a histogram representation of the data
from relm.histogram import Histogram
hist = Histogram(data)
real_database = hist.get_db()
db_size = real_database.size
db_l1_norm = real_database.sum()

# Specify the queries to be answered
num_ones = 5
q_size = comb(db_size, num_ones, exact=True)
queries = [{"Test Result": k for k in np.random.choice(np.arange(db_size), size=num_ones, replace=False)} for i in range(1024)]
num_queries = len(queries)
queries = sps.vstack([hist.get_query_vector(q) for q in queries])

# Compute the exact query responses
values = (queries @ real_database)/real_database.sum()
mlcat("", """Basic Usage
""")
mlask()

mlcat("", """
from relm.mechanisms import PrivateMultiplicativeWeights
mechanism = PrivateMultiplicativeWeights(epsilon=1.0, alpha=0.15, beta=0.01, q_size=q_size, db_size=db_size, db_l1_norm=db_l1_norm)
dp_responses = mechanism.release(values, queries)
""")
mlask()
from relm.mechanisms import PrivateMultiplicativeWeights
mechanism = PrivateMultiplicativeWeights(epsilon=1.0, alpha=0.15, beta=0.01, q_size=q_size, db_size=db_size, db_l1_norm=db_l1_norm)
dp_responses = mechanism.release(values, queries)
mlcat("", """
print(values)
print(dp_responses)
""")
mlask()
print(values)
print(dp_responses)
mlcat("", """
print(mechanism.db_l1_norm)
print(mechanism.cutoff)
print(mechanism.q_size)
print(mechanism.beta)
print(mechanism.est_data)
print(mechanism.threshold)
""")
mlask()
print(mechanism.db_l1_norm)
print(mechanism.cutoff)
print(mechanism.q_size)
print(mechanism.beta)
print(mechanism.est_data)
print(mechanism.threshold)
mlcat("", """
print(mechanism.alpha)
temp = 36*np.log(mechanism.db_size)
temp *= np.log(mechanism.q_size) + np.log(32*mechanism.db_size/(mechanism.alpha**2 * mechanism.beta))
temp /= mechanism.epsilon * mechanism.db_l1_norm * mechanism.alpha**2
print(temp)
""")
mlask()
print(mechanism.alpha)
temp = 36*np.log(mechanism.db_size)
temp *= np.log(mechanism.q_size) + np.log(32*mechanism.db_size/(mechanism.alpha**2 * mechanism.beta))
temp /= mechanism.epsilon * mechanism.db_l1_norm * mechanism.alpha**2
print(temp)
mlcat("", """
np.max(np.abs(values - dp_responses))
""")
mlask()
np.max(np.abs(values - dp_responses))
mlcat("", """

""")
mlask()

mlcat("", """

""")
mlask()

mlcat("", """

""")
mlask()


from nose.tools import assert_raises
from nose.tools import assert_equal
import sympy
from nose.tools import assert_almost_equal
import numpy as np
from functools import reduce
from sympy import GramSchmidt as GramSchmidt_sy
from sympy import Matrix

def proj(x, u):
    u = unit_vec(u)
    return np.dot(x, u) * u

def unit_vec(x):
    return x / np.linalg.norm(x)

def _orthogonalize(*vecs, **kwargs):
    normalize = kwargs.get('normalize', False)
    rankcheck = kwargs.get('rankcheck', False)

    def project(a, b):
        return b * (a.dot(b, hermitian=True) / b.dot(b, hermitian=True))

    def perp_to_subspace(vec, basis):
        """projects vec onto the subspace given
        by the orthogonal basis ``basis``"""

        components = [project(vec, b) for b in basis]

        if len(basis) == 0:
            return vec

        return vec - reduce(lambda a, b: a + b, components)

    ret = []
    vecs = list(vecs)  # make sure we start with a non-zero vector

    while len(vecs) > 0 and vecs[0].is_zero_matrix:
        if rankcheck is False:
            del vecs[0]
        else:
            raise ValueError("GramSchmidt: vector set not linearly independent")

    for vec in vecs:
        perp = perp_to_subspace(vec, ret)

        if not perp.is_zero_matrix:
            ret.append(Matrix(perp))
        elif rankcheck is True:
            raise ValueError("GramSchmidt: vector set not linearly independent")

    if normalize:
        ret = [vec / vec.norm() for vec in ret]

    return ret

def orthogonalize(*vecs, **kwargs):
    return _orthogonalize(*vecs, **kwargs)

def GramSchmidt(vlist, orthonormal=False):
    return orthogonalize(
        *vlist, normalize=orthonormal, rankcheck=False
    )

def np_gramSchmidt(vectors):
    vectors = np.atleast_2d(vectors)

    if len(vectors) == 0:
        return []

    if len(vectors) == 1:
        return unit_vec(vectors)

    u = vectors[-1]

    basis = np_gramSchmidt(vectors[0:-1])

    w = np.atleast_2d(u - np.sum(proj(u, v) for v in basis))
    basis = np.append(basis, unit_vec(w), axis=0)

    return basis

def my_GramSchmidt(vectors):
    vectors = np.array(vectors)
    vectors = np.transpose(vectors)
    vectors = vectors.tolist()
    vectors = np_gramSchmidt(vectors)
    dim = np.linalg.matrix_rank(vectors)

    if dim == vectors.shape[0]:
        return vectors
    else:
        vectors = np.transpose(vectors)
        for i in vectors:
            for pos, j in enumerate(i):
                if pos >= dim:
                    i[pos] = 0

        return vectors

def gram_schmidt_np(V):
    # YOUR CODE HERE
    if type(V) is not np.ndarray:
        raise ValueError
    else:
        if V.shape[0] != V.shape[1]:
            raise ValueError

    return my_GramSchmidt(V)

def gram_schmidt_sp(V):
    V = V.tolist()
    nv = np.array(V, dtype=int)
    nv = np.transpose(nv)
    result = np_gramSchmidt(nv)
    V = result.tolist()
    V = sympy.Matrix(V)
    return V

# Check that it works for a specific matrix V of linearly independent vectors.
V = np.array([[1, 2], [3, 4]])
W = np.array([[0.31622777, 0.9486833], [0.9486833, -0.31622777]])
W1 = gram_schmidt_np(V)
difference = np.linalg.norm(W1 - W)
assert_almost_equal(difference, 0, delta=1e-8)

# Check that it works for a case when vectors are linearly dependent
V = np.array([[1, 2], [2, 4]])
W = gram_schmidt_np(V)

W1 = np.array([[0.4472136, 0.], [0.89442719, 0.]])
difference = np.linalg.norm(W1 - W)
assert_almost_equal(difference, 0, delta=1e-8)

assert_raises(ValueError, gram_schmidt_np, 1)
assert_raises(ValueError, gram_schmidt_np, np.array([[1, 2], [3, 4], [5, 6]]))

V = sympy.Matrix([[1, 2], [3, 4]])
W = sympy.Matrix([[sympy.sqrt(10) / 10, 3 * sympy.sqrt(10) / 10], [3 * sympy.sqrt(10) / 10, -sympy.sqrt(10) / 10]])
# W1 = gram_schmidt_sp(V)
V = [Matrix([1, 3]), Matrix([2, 4])]
# W1 = GramSchmidt_sy(V, orthonormal=True)
W1 = GramSchmidt(V, orthonormal=True)
ma_list = []
for i in W1:
    tmp_list = []
    for j in i:
        tmp_list.append(j)
    tmp = tmp_list
    ma_list.append(tmp)

W1 = Matrix(ma_list)
# W1.row_join()
assert_equal(W - W1, sympy.zeros(2, 2))

V = sympy.Matrix([[1, 2], [2, 4]])
V = [Matrix([1, 2]), Matrix([2, 4])]
W = sympy.Matrix([[sympy.sqrt(5) / 5, 0], [2 * sympy.sqrt(5) / 5, 0]])
W1 = GramSchmidt(V, orthonormal=True)

ma_list = []
for i in W1:
    tmp_list = []
    for j in i:
        tmp_list.append(j)
    tmp = tmp_list
    ma_list.append(tmp)

W1 = Matrix(ma_list).H
W1 = W1.row_join(Matrix([[0], [0]]))
assert_equal(W - W1, sympy.zeros(2, 2))

assert_raises(ValueError, gram_schmidt_sp, 1)
assert_raises(ValueError, gram_schmidt_sp, sympy.Matrix([[1, 2], [3, 4], [5, 6]]))


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

# # Descriptive Statistics: The Central Tendency Using Pandas

# In[1]:

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

# In[2]:

height_weight_data = pd.read_csv('datasets/500_Person_Gender_Height_Weight_Index.csv')

height_weight_data.head(5)

# In[3]:

height_weight_data.drop('Index', inplace=True, axis=1)

# In[4]:

height_weight_data.shape

# In[5]:

height_weight_data.isnull().sum()

# In[6]:

min_height = height_weight_data['Height'].min()

min_height

# In[7]:

max_height = height_weight_data['Height'].max()

max_height

# In[8]:

min_weight = height_weight_data['Weight'].min()

min_weight

# In[9]:

max_weight = height_weight_data['Weight'].max()

max_weight

# In[10]:

range_of_height = max_height - min_height

range_of_height

# In[11]:

range_of_weight = max_weight - min_weight

range_of_weight

# In[12]:

weight = height_weight_data['Weight']

weight.head()

# In[13]:

sorted_weight = weight.sort_values().reset_index(drop=True)

sorted_weight.head()

# In[14]:

def mean(data):
    num_elements = len(data)
    print('Number of elements: ', num_elements)

    weight_sum = data.sum()
    print('Sum: ', weight_sum)

    return weight_sum / num_elements

# In[15]:

def median(data):
    num_elements = len(data)

    if(num_elements % 2 == 0):
        return  (data[(num_elements / 2) - 1] + data[(num_elements / 2)]) / 2

    else:
        return (data[((num_elements + 1) / 2) - 1])

# In[16]:

mean(height_weight_data['Weight'])

# In[17]:

weight_mean = height_weight_data['Weight'].mean()

weight_mean

# In[18]:

median(height_weight_data['Weight'])

# In[19]:

median(sorted_weight)

# In[20]:

weight_median = height_weight_data['Weight'].median()

weight_median

# In[21]:

plt.figure(figsize=(12, 8))

height_weight_data['Weight'].hist(bins=30)

plt.axvline(weight_mean, color='r', label='mean')

plt.legend()

# In[22]:

plt.figure(figsize=(12, 8))

height_weight_data['Weight'].hist(bins=30)

plt.axvline(weight_median, color='g', label='median')

plt.legend()

# In[23]:

plt.figure(figsize=(12, 8))

plt.bar(height_weight_data['Height'], height_weight_data['Weight'])

plt.axhline(weight_mean, color='r', label='mean')
plt.axhline(weight_median, color='b', label='median')

plt.show()

# In[24]:

height_weight_data

# In[25]:

listOfSeries = [pd.Series(['Male', 205, 460], index=height_weight_data.columns ),
                pd.Series(['Female', 202, 390], index=height_weight_data.columns ),
                pd.Series(['Female', 199, 410], index=height_weight_data.columns ),
                pd.Series(['Male', 202, 390], index=height_weight_data.columns ),
                pd.Series(['Female', 199, 410], index=height_weight_data.columns ),
                pd.Series(['Male', 200, 490], index=height_weight_data.columns )]

# In[26]:

height_weight_updated = height_weight_data.append(listOfSeries , ignore_index=True)

height_weight_updated.tail()

# In[27]:

updated_weight_mean = height_weight_updated['Weight'].mean()

updated_weight_mean

# In[28]:

weight_mean

# In[29]:

updated_weight_median = height_weight_updated['Weight'].median()

updated_weight_median

# In[30]:

weight_median

# In[31]:

plt.figure(figsize=(12, 8))

plt.bar(height_weight_updated['Height'], height_weight_updated['Weight'])

plt.axhline(updated_weight_mean, color='r', label='mean')
plt.axhline(updated_weight_median, color='b', label='median')

plt.show()

# In[32]:

plt.figure(figsize=(12, 8))

height_weight_data['Weight'].hist(bins=20)

plt.axvline(updated_weight_mean, color='r', label='mean')
plt.axvline(updated_weight_median, color='g', label='median')

plt.legend()

# In[33]:

plt.figure(figsize=(12, 8))

height_weight_updated['Weight'].hist(bins=100)

plt.axvline(updated_weight_mean, color='r', label='mean')
plt.axvline(updated_weight_median, color='g', label='median')

plt.legend()

# In[34]:

height_counts = {}

for p in height_weight_data['Height']:
    if p not in height_counts:
        height_counts[p] = 1
    else:
        height_counts[p] += 1

# In[35]:

height_counts

# In[36]:

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

x_range = range(len(height_counts))

plt.bar(x_range, list(height_counts.values()), align='center')
plt.xticks(x_range, list(height_counts.keys()))

plt.xlabel('Height')
plt.ylabel('Count')

plt.show()

# In[37]:

count = 0
size = 0

for s, c in height_counts.items():
    if count < c:
        count = c
        size = s

print('Size: ', size, '\nFrequency: ', count)

# In[38]:

height_weight_data['Height'].mode()

# In[39]:

height_weight_data['Weight'].mode()

# In[40]:

height_mean = height_weight_data['Height'].mean()

height_median = height_weight_data['Height'].median()

height_mode = height_weight_data['Height'].mode().values[0]

# In[41]:

plt.figure(figsize=(12, 8))

height_weight_data['Height'].hist()

plt.axvline(height_mean, color='r', label='mean')
plt.axvline(height_median, color='g', label='median')
plt.axvline(height_mode, color='y', label='mode')

plt.legend()

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:


"""
dot

The dot tool returns the dot product of two arrays.

import numpy

A = numpy.array([ 1, 2 ])
B = numpy.array([ 3, 4 ])

print numpy.dot(A, B)       #Output : 11

cross

The cross tool returns the cross product of two arrays.

import numpy

A = numpy.array([ 1, 2 ])
B = numpy.array([ 3, 4 ])

print numpy.cross(A, B)     #Output : -2

Task

You are given two arrays
and . Both have dimensions of X

.
Your task is to compute their matrix product.

Input Format

The first line contains the integer
.
The next lines contains space separated integers of array .
The following lines contains space separated integers of array

.

Output Format

Print the matrix multiplication of
and

.

Sample Input

2
1 2
3 4
1 2
3 4

Sample Output

[[ 7 10]
 [15 22]]
"""

import numpy

a=int(input())

arr1=numpy.array([list(map(int,input().split())) for _ in range(a)])

arr2=numpy.array([list(map(int,input().split())) for _ in range(a)])

print(numpy.dot(arr1,arr2))


import numpy as np

def mean(data, weights=None, trimmed=None):
    """ Calculates the average of a set of data

    Arguments:
        data {array-like} -- [data to be summarized (float or int)]

    Keyword Arguments:
        weights {array-like} -- [If provided, weights will be used to calculate the weighted average] (default: {None})
        trimmed {int} -- [If provided, mean will be calculated without the highest and lowest `x` values where `x` is parameter passed] (default: {None})
    """

    if data is None:
        raise ValueError("Parameter `data` must be provided")

    if len(data) == 0:
        return None

    if trimmed:
        data = sorted(data)[trimmed:len(data)-trimmed]

        if weights:
            weights = sorted(weights)[trimmed:len(weights)-trimmed]

    num = np.sum(data)
    denom = len(data)

    if weights:
        if len(weights) != len(data):
            raise ValueError('Parameters `data` and `weights` must have the same number of elements')

        num = np.sum(np.array(data) * np.array(weights))
        denom = np.sum(weights)

    return num / denom


import numpy as np
import labfuns

def mlParams(X, labels, W=None):
    """
    NOTE: you do not need to handle the W argument for this part!
    in:      X - N x d matrix of N data points
        labels - N vector of class labels
    out:    mu - C x d matrix of class means (mu[i] - class i mean)
         sigma - C x d x d matrix of class covariances (sigma[i] - class i sigma)
    """
    assert(X.shape[0]==labels.shape[0])
    Npts, Ndims = np.shape(X)
    classes = np.unique(labels)
    Nclasses = np.size(classes)

    if W is None:
        W = np.ones((Npts,1))/float(Npts)

    mu = np.zeros((Nclasses,Ndims))
    sigma = np.zeros((Nclasses,Ndims,Ndims))

    # ==================================================================
    # calucalte the mu and sigma maximum likehood estimator
    # ==================================================================
    for cidx, c in enumerate(classes):  # c means class
        idxs = np.where(labels == c)   # the indices of this class
        mu[cidx, :] = np.mean(X[idxs], axis=0)  # avg over the axis 0, keep axis 1

        # We make the sigma matrix as diagonal matrix, which is a naive assumption
        # dvi: deviation (x - mu)
        dvi = X[idxs] - mu[cidx, :]
        diag = np.full(Ndims, np.mean(dvi**2, axis=0))
        sigma[cidx, :] = np.diag(diag)

    return mu, sigma

# ======================================================================
if __name__ == '__main__':
    # ## Test the Maximum Likelihood estimates
    #
    # Call `genBlobs` and `plotGaussian` to verify your estimates.
    X, labels = labfuns.genBlobs(centers=5)
    mu, sigma = mlParams(X,labels)
    # here we use 68-95-99.7 rule
    # the default of plotGaussian plotting 2 sigma, which is 95% Confident interval
    labfuns.plotGaussian(X, labels, mu, sigma)


# -*- coding: utf-8 -*-
# @version : Python3.6
# @Time    : 2017/4/21 15:56
# @Author  : Jianyang-Hu
# @contact : jianyang1993@163.com
# @File    : stock_csv_0421.py
# @Software: PyCharm
import numpy
from numpy import *
from datetime import datetime

#usecols=(4,5)计数从0开始
c,v = loadtxt("stocks.csv",delimiter=",",usecols=(4,5),unpack=True)
#加权平均价格
vwap = average(c,weights=v)
print("VWAP=",vwap)

#算术平均值
print("mean=",mean(c))

#范围
print("the price span is:",ptp(c))

#价格的中位数
print("the median=",median(c))

#排序并且检查中位数
sorted_close = msort(c)
print("sorted:",sorted_close)

#中位数位置
N = len(c)
# mid = sorted()
print(N)

#求股票收益率
returns = diff(c) / c[:-1]
print("Standard deviation = ", std(returns))

#哪个交易日收益为正
posretindices = where(returns > 0)
print("indices with positive returns",posretindices)

#波动率
logreturns = diff(log(c))
annual_volatility = std(logreturns) / mean(logreturns)
annual_volatility = annual_volatility / sqrt(1./252.)
print("Annual volatility",annual_volatility)
print("Monthly volatility",annual_volatility * sqrt(1./12.))

#处理日期
# def datastr2num(s):
#     return datetime.datetime.strptime\
#             (s,"%d-%m-%Y").date().weekday()
# datas,c2 = loadtxt("stocks.csv",delimiter=",",usecols=(0,4),converters={1:datastr2num},unpack=True)
# print(datas)
#
# averages = zeros(5)
#
# for i in range(5):
#     indices = where(datas == i)
#     prices = take(c2,indices)
#     avg = mean(prices)
#     print("Day",i,"prices",prices,"averag",avg)
#     average[i] = avg

# top = max(averages)
# print("Top day of the week",argmax(averages))
#
# bottom = min(averages)
# print("Bottom day of the day",argmin(averages))


import numpy as np
from scipy import stats

def create_data(N = 10):
    a = np.random.randn(N) + 2 #mean = 2, var = 1
    b = np.random.randn(N)  #mean = 0, var = 1

    return a, b

def variance(a,b):
    var_a = a.var(ddof = 1) #Numpy uses the population (N) and not sample (N-1), thus pass ddof = 1
    var_b = b.var(ddof = 1)

    return var_a, var_b

def pooledstd(var_a, var_b):
    """
    Calculates the pooled standard deviation (Sp)
    """
    sp = np.sqrt((var_a + var_b) / 2)

    return sp

def t_stat(a, b, sp, N = 10):
    """
    Calculates the t-statistic and the degrees of freedom (df)
    """
    t = (a.mean() - b.mean())/(sp * np.sqrt(2/N))

    df = 2*N - 2

    return t, df

def p_value():
    N = 10
    a, b = create_data(N = N)
    var_a, var_b = variance(a, b)
    sp = pooledstd(var_a, var_b)
    t, df = t_stat(a, b, sp, N = N)
    p = 1 - stats.t.cdf(t, df)
    p = p*2 #Since it is a 2-tailed test
    print('t-stat: ', t,'P: ', p)
    t2, p2 = stats.ttest_ind(a, b)
    print('t-stat scipy: ', t2,'P scipy: ', p2)

if __name__ == "__main__":
    p_value()


"""
Created on Mon Nov 16 09:57:55 2020

@author: Larisa

Laborator: 6
"""

import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
import sympy.utilities.lambdify as lam

"""
Exercițiul 1:
Fie f(x, y) = x^2 / 4 + y^2 si domeniul (x, y) aparține [-6, 6] X [-4, 4].
"""

# a) Să se construiască această suprafață (z = f(x, y)) pe domeniul dat.
(a, b) = (-6, 6)
(c, d) = (-4, 4)
(Nx, Ny) = (20, 20) #nr de puncte în care să fie împărțit intervalul

x_grafic = np.linspace(a, b, Nx)
y_grafic = np.linspace(c, d, Ny)

[X, Y] = np.meshgrid(x_grafic, y_grafic)
# print(X)
# print(Y)

plt.figure(1)
plt.plot(X, Y, 'o', markerfacecolor = 'red', markersize = 10)
plt.grid(True)
plt.title('Fig 1: Rețeaua de puncte care acoperă domeniul (a, b) X (c, d)')
plt.show()

f = lambda x, y: (x * x) / 4 + y * y
Z = f(X, Y)
# print(Z)

fig = plt.figure(2)
axes = plt.axes(projection = '3d')
surf = axes.plot_surface(X, Y, Z, cmap = plt.cm.jet)
fig.colorbar(surf)

# b) Să se afiseze în plan curbele de nivel Z = 2, 4, 8
fig = plt.figure(3)
axes = plt.axes(projection = '3d')
plt.contour(X, Y, Z, levels = [2, 4, 8])
plt.show()

# c) Afisare linia de nivel care trece prin punctul de coordonate (-2, 1)
x0 = -2
y0 = 1
plt.figure(4)
plt.plot(x0, y0, 'o', markerfacecolor = 'red', markersize = 10)
plt.contour(X, Y, Z, levels = [f(x0, y0)])
plt.show()

# d) Să se afle simbolic gradientul funcției
x, y = sym.symbols('x y')
f_expr = f(x, y)
df1 = [sym.diff(f_expr, x), sym.diff(f_expr, y)]
df2 = sym.lambdify((x, y), [df1[0], df1[1]])

# e) Calculați direcția funcției în raport cu care aceasta creste/descreste cel mai rapid
# Direcția pe care funcția creste cel mai rapid
v_max = df2(x0, y0)
v_max = v_max / np.sqrt(v_max[0] ** 2 + v_max[1] ** 2)
print(f'df calculat pentru ({x0}, {y0}): {v_max}')
plt.plot([x0, x0 + v_max[0]], [y0, y0 + v_max[1]], linewidth = 4)
plt.axis('equal')  # Pentru ca axele sa fie egale
# plt.show()

# Direcția pe care funcția descreste cel mai rapid
v_min = -v_max
print(f'df calculat pentru ({x0}, {y0}): {v_min}')
plt.plot([x0, x0 + v_min[0]], [y0, y0 + v_min[1]], linewidth = 4)
plt.axis('equal')  # Pentru ca axele sa fie egale
# plt.show()

# f) Construiți curba pe suprafața dată, care are reprezentarea parametrică
s = np.linspace(-7, 7, 30)  # parametrul din reprezentarea parametrică a curbei
x_curba = x0 + s * v_max[0]
y_curba = y0 + s * v_max[1]
z_curba = f(x_curba, y_curba)
axes = plt.axes(projection = '3d')
axes.plot3D(x_curba, y_curba, z_curba, linewidth = 3)
plt.show()

# g) Să se afle punctul de minim local de la ex1, folosind gradient descent
A = np.array([[1/2, 0], [0, 2]])
b = np.array([[0], [0]])
x_old = np.array([[x0], [y0]])
eps = 10 ** (-3)
k = 0
xk = []
xk.append([x_old[0], x_old[1]])

while True:
    v = df2(x_old[0], x_old[1])  # directia gradientului
    if np.sqrt(v[0] ** 2 + v[1] ** 2) < eps:
        break

    s = (np.transpose(v) @ (A @ x_old - b)) / (np.transpose(v) @ (A @ v))
    x_new = x_old - s * v
    xk.append([x_new[0], x_new[1]])
    k += 1
    x_old = x_new

print(x_old)  # soluția aproximativă
x_array = np.asarray(xk)

plt.figure(6)
for i in range(np.shape(x_array)[0]):
    plt.plot(x_array[i][0][0], x_array[i][1][0], '-o', linewidth = 3,
             markerfacecolor = 'red', markersize = 10)
    plt.contour(X, Y, Z, levels=[f(x_array[i][0][0], x_array[i][1][0])])
    print(f(x_array[i][0][0], x_array[i][1][0]))
plt.axis('equal')
plt.show()

Calcul Numeric (CN)/Laborator/Laborator 6/lab6.py


# -*- coding: utf-8 -*-
"""
Created on Mon Mar 11 10:33:01 2019

@author: Miguel Angel Velez
"""

import numpy as np
import scipy.stats as ss

#------------------------------------------------------------------------------------------------#
#---------------------------------- Probability Distributions -----------------------------------#
#------------------------------------------------------------------------------------------------#

def binom_pmf(n, pi, x):
    """
    """
    px = ss.binom(n, pi).pmf(x)
    return px

def binom_cdf(n, pi, x):
    """
    """
    px = ss.binom(n, pi).cdf(x)
    return px

def hypergeom_pmf(N, r, n, x):
    """
    """
    px = ss.hypergeom(N, r, n).pmf(x)
    return px

def hypergeom_cdf(N, r, n, x):
    """
    """
    px = ss.hypergeom(N, r, n).cdf(x)
    return px

def poisson_pmf(mu, x):
    """
    """
    px = ss.poisson(mu).pmf(x)
    return px

def poisson_cdf(mu, x):
    """
    """
    px = ss.poisson(mu).cdf(x)
    return px

def expon_cdf(mu, x): #mu = mu
    """
    Función para calcular la función de probabilidad acumulada de la distribución exponencial continua
    """
    px = 1 - np.exp(-mu * x)
    return px

def uniform_cdf(a, b, x):
    """
    """
    width = b - a
    px = ss.uniform(a, width).cdf(x)
    return px

def norm_cdf(mu, sigma, x):
    """
    """
    px = ss.norm(mu, sigma).cdf(x)
    return px

def sample_norm_cdf(mu, sigma, n, x):
    """
    """
    error = sigma / (n**0.5)
    px = ss.norm(mu, error).cdf(x)
    return px

def sample_prop_cdf(n, pi, p):
    """
    """
    error = ((pi * (1 - pi)) / n)**0.5
    px = ss.norm(pi, error).cdf(p)
    return px

#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#


# Exercise 5.14
# Author: Noah Waterfield Price

import numpy as np

def L_k(x, k, xp, yp):
    ans = 1
    # if x > xp[-1]:
    #   raise ValueError('x out of range of function domain')
    for i in range(len(xp)):
        if i != k:
            ans *= (x - xp[i]) / (xp[k] - xp[i])
    return ans

def p_L(x, xp, yp):
    ans = 0
    # if x > xp[-1]:
    #   raise ValueError('x out of range of function domain')
    for k in range(len(yp)):
        ans += yp[k] * L_k(x, k, xp, yp)
    return ans

def verify(xp, yp):
    status = 'Verified!'
    for k in range(len(xp)):
        if abs(p_L(xp[k], xp, yp) - yp[k]) > 1e-15:
            status = 'Error!'
            break
    print status

def verbose_verify(xp, yp):
    verify(xp, yp)
    print '%10s %10s %10s %10s' % ('x', 'Exact', 'Approx', 'Difference')
    for k in range(len(xp)):
        x = xp[k]
        exact = yp[k]
        approx = p_L(xp[k], xp, yp)
        diff = abs(p_L(xp[k], xp, yp) - yp[k])
        print '%10f %10f %10f %10f' % (x, exact, approx, diff)

xlist = np.linspace(0, np.pi, 5)
ylist = np.sin(xlist)

if __name__ == '__main__':
    verify(xlist, ylist)
    verbose_verify(xlist, ylist)

"""
Sample run:
python Lagrange_poly1.py
Verified!
         x      Exact     Approx Difference
  0.000000   0.000000   0.000000   0.000000
  0.785398   0.707107   0.707107   0.000000
  1.570796   1.000000   1.000000   0.000000
  2.356194   0.707107   0.707107   0.000000
  3.141593   0.000000   0.000000   0.000000
"""


# moment statistics python  'IMPORTANT'
# https://www.google.com/search?q=moment+statistics+python&sxsrf=ALeKk03IR29YXksd2BrmuqG_1yKbLknFXQ%3A1621251343715&ei=D1WiYJT0Ko2ImAWc-6uwBg&oq=moment+statistics+python&gs_lcp=Cgdnd3Mtd2l6EAMyBggAEBYQHjoHCAAQRxCwAzoHCAAQsAMQQzoCCABQxDhYv0JgjERoAXACeACAAZ8CiAGsC5IBBTAuNi4ymAEAoAEBqgEHZ3dzLXdpesgBCsABAQ&sclient=gws-wiz&ved=0ahUKEwjUt7vzz9DwAhUNBKYKHZz9CmYQ4dUDCA4&uact=5
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.moment.html
# https://math.stackexchange.com/questions/190531/what-is-the-use-of-moments-in-statistics

'''
What do moments represent?
Moments [of a statistical distribution]

1. The mean, which indicates the central tendency of a distribution.

2. The second moment is the variance, which indicates the width or deviation.

3. The third moment is the skewness, which indicates any asymmetric 'leaning'
to either left or right.
'''
from scipy import stats
import numpy as np

arr = np.random.randint(1, 10, 10)
arr = list(arr)
print(arr)
print(stats.moment(arr, moment=1))  # ???
print(stats.moment(arr, moment=2))

# print(stats.moment(arr, moment=3))
# print(stats.skew(arr))


from math import sqrt

import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate
from scipy.optimize import root
from scipy.interpolate import BarycentricInterpolator

from solutions import cheb

# Solving the river crossing problem with end states
# z(-1) = 0, z(1) = z1
z1 = 5.

# Function that describes the current of the river
def r(x):
	return -.7*(x-1.)*(x+1.)

# a = (1-r)^{1/2}
def a(x):
	return (1.-r(x)**2.)**(-1./2)

# Family of possible trajectories across the river satisfying the
# given end-states. Also their derivatives.
def y(x,eps):
	return z1/2.*(x-(-1.)) + eps *(x-1.)*(x+1)*x

def yp(x,eps):
	return z1/2. + eps*(2.*x*x + (x-1.)*(x+1))

def current_plot():
	x0 = np.linspace(-1,1,8)
	r0_ = r(x0)
	x1 = np.linspace(-1,1,100)
	r_, y_ = r(x1), z1/2.*(x1-(-1.)) #y(x1,-.7)
	plt.quiver( x0, np.zeros(x0.shape), np.zeros(x0.shape),  r0_, pivot='tail', color='b', scale_units='xy',scale=1.)
	plt.axis([-1.1,1.1,0. -.05,z1 +.05])

	# # Plots the function r to ensure that the
	# # length of the arrows above are correct.
	# plt.plot(x1,r_,'-k')

	# # Plots a trajectory y_
	y2 = np.linspace(0-.05,z1+.05,200)
	plt.plot(-np.ones(y2.shape),y2,'-k',linewidth=2.5)
	plt.plot(np.ones(y2.shape),y2,'-k',linewidth=2.5)
	plt.plot(x1,y_,'-g',linewidth=2.)
	plt.plot(-1,0,'*g',markersize=10.)
	plt.plot(1,z1,'*g',markersize=10.)
	# plt.savefig('rivercurrent.pdf')
	# plt.show()
	plt.clf()

def time_functional():
	# The integrand of the functional that gives the time required to cross
	# the river on a given trajectory.
	def L(x,eps):
		a_, yp_ = a(x), yp(x,eps)
		return a_*(1 + a_**2.*yp_**2.)**(1./2) - a_**2.*r(x)*yp_

	list = range(-50,60)
	eps = np.array([item/100. for item in list])
	out = 10.*np.ones(eps.shape)
	for j in range(len(list)):
		out[j] = integrate.quad(lambda x:L(x,eps[j]),-1,1)[0]
	min_time = np.min(out)
	index = np.argmin(out)
	eps = eps[index]
	return eps, min_time

def trajectory():
	N = 200
	D, x = cheb(N)
	eps = 0.

	def L_yp(x,yp_):
		a_ = a(x)
		return a_**3.*yp_*(1 + a_**2.*yp_**2.)**(-1./2) - a_**2.*r(x)

	def g(z):
		out = D.dot(L_yp( x,D.dot(z) ))
		out[0], out[-1] = z[0] - z1, z[-1] - 0
		return out

	# Use the straight line trajectory as an initial guess.
	# Another option would be to use the shortest-time trajectory found
	# in heuristic_tractory() as an initial guess.
	eps, time = time_functional()
	sol = root(g,y(x,eps))
	# sol =  root(g,z1/2.*(x-(-1.)))
	# print sol.success
	z = sol.x
	poly = BarycentricInterpolator(x,D.dot(z))
	num_func = lambda inpt: poly.__call__(inpt)

	def L(x):
		a_, yp_ = a(x), num_func(x)
		return a_*(1 + a_**2.*yp_**2.)**(1./2) - a_**2.*r(x)*yp_

	print "The shortest time is approximately "
	print integrate.quad(L,-1,1,epsabs=1e-10,epsrel=1e-10)[0]

	# x0 = np.linspace(-1,1,200)
	# y0 = y(x0,eps)
	# plt.plot(x0,y0,'-g',linewidth=2.,label='Initial guess')
	# plt.plot(x,z,'-b',linewidth=2.,label="Numerical solution")
	# ax = np.linspace(0-.05,z1+.05,200)
	# plt.plot(-np.ones(ax.shape),ax,'-k',linewidth=2.5)
	# plt.plot(np.ones(ax.shape),ax,'-k',linewidth=2.5)
	# plt.plot(-1,0,'*b',markersize=10.)
	# plt.plot(1,z1,'*b',markersize=10.)
	# plt.xlabel('$x$',fontsize=18)
	# plt.ylabel('$y$',fontsize=18)
	# plt.legend(loc='best')
	# plt.axis([-1.1,1.1,0. -.05,z1 +.05])
	# # plt.savefig("minimum_time_rivercrossing.pdf")
	# plt.show()
	# plt.clf()
	return x, z, N

def angle():
	x,z, N = trajectory()
	num = int(N/20)
	D, _ = cheb(N)
	yp = D.dot(z)
	r_ = r(x)

	theta1 = np.arctan(yp) # This is incorrect
	theta2 = (1-r_**2.)**(-1)*(-r_*yp + np.sqrt( (r_*yp)**2. + (1-r_**2)*(1. + yp**2.)))
	theta2 = np.arccos(1./theta2)
	# plt.plot(x,theta1,'-g',linewidth=2.)
	plt.plot(x,theta2,'-b',linewidth=2.)
	plt.xlabel('$x$',fontsize=18)
	plt.ylabel(r'$\theta$',fontsize=18)
	plt.yticks([0, np.pi/6, np.pi/3.,np.pi/2.],
	           ['$0$', r'$\frac{\pi}{6}$', r'$\frac{\pi}{3}$', r'$\frac{\pi}{2}$'])
	# plt.savefig('trajectory_angle.pdf')
	plt.show()
	plt.clf()

	theta = theta1
	# Checking that the angle is correct.
	print 0., np.min(theta), np.max(theta), np.pi/2.
	xdist, ydist = np.cos(theta), np.sin(theta)
	plt.quiver( x[::num], z[::num], xdist[::num],  ydist[::num],
				pivot='tail', color='b', scale_units='xy',scale=3., angles='xy')
	# plt.plot(x,z,'-k',linewidth=2.)
	plt.axis([-1.1,1.1,0. -.5,z1 +1.])
	plt.show()

def newfunc():
	# The integrand of the functional that gives the time required to cross
	# the river on a given trajectory.
	def yp(x):
		return 2.5

	def L(x,yp):
		a_, yp_ = a(x), yp(x)
		return a_*(1 + a_**2.*yp_**2.)**(1./2) - a_**2.*r(x)*yp_

	print integrate.quad(lambda x:L(x,yp),-1,1)[0]
	return

if __name__=="__main__":
	# current_plot()
	print time_functional()
	trajectory()
	angle()
	# newfunc()


import numpy as np
import matplotlib.pylab as plt
from sklearn.datasets import load_iris

iris = load_iris()
x2 = np.array([4.9, 3.0, 1.4, 0.2])
print("Exercise 2.1.1:")
print("x2: {}".format(x2))
print("x2_shape: {}".format(x2.shape))
print("reshape x2 as (1,-1): \n{}".format(x2.reshape((1,-1))))
print("reshape x2 as (-1,1): \n{}".format(x2.reshape((-1,1))))

print("---------- ========================== ---------")

from sklearn.datasets import load_digits

digits = load_digits()
samples = [0, 10, 20, 30, 1, 11, 21, 31] # Indices of samples
d = [] # Store the samples of digits
for i in range(8):
    d.append(digits.images[samples[i]])

plt.figure(figsize=(8,2))
for i in range(8):
    plt.subplot(1, 8, i+1) # subplot(rows, columns, index, **kwarg)
    plt.imshow(d[i], interpolation='nearest', cmap=plt.cm.bone_r)
    plt.grid(False); plt.xticks([]); plt.yticks([])
    plt.title('image {}'.format(i+1))
plt.suptitle('Images of zero and one')
plt.tight_layout()
# plt.show()

v = []
for i in range(8):
    v.append(d[i].reshape(64,1)) # Unfolding each data and contain to 'v'

plt.figure(figsize=(8,3))
for i in range(8):
    plt.subplot(1, 8, i+1) # subplot(rows, columns, index, **kwarg)
    plt.imshow(v[i], aspect=0.4,
               interpolation='nearest', cmap=plt.cm.bone_r)
    plt.grid(False); plt.xticks([]); plt.yticks([])
    plt.title('Vector {}'.format(i+1))
plt.suptitle('Images of vectorized zero and one', y=1.05)
plt.tight_layout()
# plt.show()

print("Exercise 2.1.2")
X = np.array([[5.1, 3.5, 1.4, 0.2],
              [4.9, 3.0, 1.4, 0.2]])
print("X: \n{}".format(X))

print("---------- ============= TENSOR ============= ---------")
from scipy import misc

img_rgb = misc.face()
print(img_rgb.shape)

plt.subplot(221)
plt.imshow(img_rgb, cmap = plt.cm.gray)
plt.axis('off')
plt.title('RGB image')

plt.subplot(222)
plt.imshow(img_rgb[:,:,0], cmap=plt.cm.gray)
plt.axis('off')
plt.title('Red channel')

plt.subplot(223)
plt.imshow(img_rgb[:,:,1], cmap=plt.cm.gray)
plt.axis('off')
plt.title('Green channel')

plt.subplot(224)
plt.imshow(img_rgb[:,:,2], cmap=plt.cm.gray)
plt.axis('off')
plt.title('Blue channel')

# plt.show()

print("Exercise 2.1.3")
X = np.asarray(load_iris())
print("X_transpose: \n{}".format(X.T))
print("(X.T).T == X: {}".format(X.T.T == X))

print("Exercise 2.1.4")

zero_vector = np.zeros((5,1))
one_vector = np.ones((5,1))
square_matrix = np.array([[1, 2, 3],
                          [4, 5, 6],
                          [7, 8, 9]])
identity_matrix = np.identity(5)
symmetric_matrix = np.array([[1, 2, 3],
                             [2, 4, 5],
                             [3, 5, 6]])

print(zero_vector)
print(one_vector)
print(square_matrix)
print(identity_matrix)
print(symmetric_matrix)


import numpy as np
np.random.seed(0)

def compute_reciprocals(values):
    output = np.empty(len(values))
    for i in range(len(values)):
        output[i] = 1.0 / values[i]
    return output

values = np.random.randint(1,10,size=5)
print(compute_reciprocals(values))
big_array = np.random.randint(1,100,size=1000000)
# %timeit compute_reciproals(big_array)

#introducing Ufunctions
###vectorized operation part of numpy###
#%timeit (1/big_array)

#vectorized operations are implemented via the set of ufuncs in numpy

print(np.arange(5) / np.arange(1,6))
#not limited to only 1d arrays
x = np.arange(9).reshape((3,3))
print( 2 ** x)

###exploring Numpy's UFuncs###

#array Arithmetic
x = np.arange(4)
print("x =", x)
print("x + 5=", x+5)
print("x - 5=", x-5)
print("x * 2=", x*2)
print("x / 2=", x/2)
print("x // 2=", x//2) #floor division

print("-x=", -x)
print("x ** 2=", x ** 2)
print("x % 2=", x%2)

#these are rappers for np. functions such as np.add
print("np.add(x, 2)=",np.add(x, 2))

#absolute value
x = np.array([-2,-1,0,1,2])
print(x)
print("abs x",abs(x))
#coresponding NumPy ufunc is np.absolute/ np.abs
print("np abs x", np.abs(x))

#can also handle complex data, returning the magnitude
x = np.array([3-4j, 4-3j, 2+0j, 0 +1j])
print(np.abs(x))

##Trigonometric functions

theta = np.linspace(0, np.pi, 3)

print("theta      =", theta)
print("sin(theta) =", np.sin(theta))
print("cos(theta) =", np.cos(theta))
print("tan(theta) =", np.tan(theta))

theta = [-1, 0, 1]
print("arcsin(theta) =", np.arcsin(theta))
print("arccos(theta) =", np.arccos(theta))
print("arctan(theta) =", np.arctan(theta))

##exponets and logs

x = [1,2,3]
print("x    =",x)
print("e^x  =", np.exp(x))
print("2^x  =", np.exp2(x))
print("3^x  =", np.power(3,x))

x = [1,2,4,10]

print("x=", x)
print("lnx=" ,np.log(x))
print("log2(x)=", np.log2(x))
print("log10(x)=", np.log10(x))

#special cases for percision

x=[0,0.001,0.01, 0.1]
print(x)
print("exp(x)-1", np.expm1(x))
print("log(1+x)", np.log1p(x))

##specialized ufuncs
from scipy import special
#gama functions (generalized factorials) and related
x= [1,5,10]
print("gamma(x)", special.gamma(x))
print("ln|gamma(x)", special.gammaln(x))
print("beta(x,2)", special.beta(x,2))

#error function (intergral of Gaussian)
#it's complement and its inverse
x= np.array([0,0.3,0.7,1.0])
print("erf(x)", special.erf(x))
print("erfc(x)", special.erfc(x))
print("erfinv(x)", special.erfinv(x))

##advance ufunc features
#specifying output
print("advance features")

x= np.arange(5)
y = np.empty(5)
np.multiply(x, 10, out=y)
print(y)

y = np.zeros(10)
np.power(2,x,out=y[::2])
print(y)
# for large arrays this is a significant savings vs y[::2] = 2 ** x

print("Aggregates")
x= np.arange(1,6)
print(np.add.reduce(x))
print(np.multiply.reduce(x))
print(np.add.accumulate(x))
print(np.multiply.accumulate(x))

print("outer products")
x = np.arange(1,6)
print(np.multiply.outer(x,x))


'''
Programa DNL para analisis de campos en dos dimensiones.
author:@julianamette3@gmail.com

El objetivo de este programa es tener herramientas que permitan un analisis rapido
para sistemas de escuaciones de dos dimensiones.

'''
import numpy as np
import matplotlib.pyplot as plt
from numpy import linalg as LA

#Aca se define la funcion de tu campo de dos cordenadas!
def f(x,y):
    return y**3-4*x, y**3-y-3*x

### este es un ejemplo copado para mas adelante
def funcion_linda(x,y,a,b):
    return y , a + b*x + x**2 -x*y
####

#Esta funcion, dada una matriz te devuelve los autovalores y autovectores de la misma
#Sirve para ver la parte lineal y la usamos mas delante para otras funcioens
def aval_avec(matrix):
    '''
    input: matriz de la parte lineal
    output: w vector de los autovalres y v vector que tiene los autovectores en columnas
    '''
    w,v = LA.eig(matrix)
    print('Los autovalores son ', w )
    print('Los autovectores son ', v[:,0], ' y ', v[:,1])
    return w,v

#La siguiente funcion es la que uno mas va a usar y es para graficar un campo y sus mulclinas
def nulclinas_y_campo(fn,xmin,xmax,ymin,ymax,nro_puntos, plot = 'si',m_lin = 'none',ax = 'none'):

    '''
    input:
    fn: funcion que quieras graficar
    xmin: minimo en el eje x que se quiere realizar el grafico
    xmax: maximo de x
    ymin: minimo de y
    ymax: maximo de y
    nro_puntos:  es la resolucion en la que queres que se grafiquen las cosas, recomendada: 1000
    plot: default: si, si pones plot = 'no' no va a graficar y podes usar lo que te devuelve para
          lo que quieras.
    m_lin: default : 'none',  si se introduce la matriz de la parte lineal te va a graficar
            los autovectores y decir sus autovalores, esta bueno a veces. Si no podes nada
            no los va a graficar.
    ax :  default: 'none' Es el par de ejes sobre el que queres que grafique, a menos que
    quieras usar la funcion para meterla adentro de otra es mejor no poner ningun input.

    RECORDAR: si la funcion ya tiene un default no es necesario poner de input esos parametros
    NOTA: esta funcion tiene un parametro magico en la parte de ax.streamplot que es el de density
    ahora esta seteado en 1.5, si queres mas resolucion de las lineas de corriente, subilo,
    1.7 o 1.9 es algo ya bien denso, el tema es que va a ser re caro hacer la animacion rapudo
    asi que no es tan trivial.
    '''
    x = np.linspace(xmin,xmax,nro_puntos)
    y = np.linspace(ymin,ymax,nro_puntos)
    X, Y = np.meshgrid(x,y)
    (u,v) = fn(X,Y)
    if ax == 'none':
        fig, ax = plt.subplots()
    ax.streamplot(X, Y, u, v,density=1.5,color = 'teal')
    cs_u = ax.contour(X,Y,u,[0],colors=['navy'])
    cs_v = ax.contour(X,Y,v,[0])
    ax.grid()
    try:
        ax.clabel(cs_u ,fmt = 'Nulclina x', colors=['navy'])
        ax.clabel(cs_v ,fmt = 'Nulclina y')
    except:
        pass
    if m_lin != 'none':
        w,v = aval_avec(m_lin)
        ax.plot((0,v[:,0][0]),(0,v[:,0][1]),'.-' , label = 'Avec con aval %f' %w[0])
        ax.plot((0,v[:,1][0]),(0,v[:,1][1]),'.-',  label = 'Avec con aval %f' %w[1])
        ax.legend()
    if plot == 'si':
        plt.show()

##La proxima seccion es para analizar como cambia el campo en funcion de los parametros
#y las diferentes bifurcaciones que tiene
#IMPORTANTE: Esta escrita para f(x,y,a,b) por lo que si es ese tu caso con muy pocos cambios
#lo vas a poder hacer pero la logica es la misma para mas variables asi que es muy analogo

#Supongo que tengo un campo que depende de dos parametros a y b, propongo una parametrizacion
#para ir moviendo estos. La siguiente es un circulo de radio 1.
def param(theta):
    return np.cos(theta) , np.sin(theta) #la primera coordenada es a y la segunda b

#Como la parametrizacion depende de theta pongo los valores entre los que me voy a mover
theta = np.linspace(0,2*np.pi,100)

#Ahora igualo los valores a la parametrizacion para ya tenerlos guardados
val = param(theta)

#La siguiente funcion es la animacion para ir variando los parametros
def animacion(fn,array,xmin,xmax,ymin,ymax):
    '''
    fn: funcion que quieras ver fn(x,y,a,b)
    array:  es el array de los valores que voy a ir variando.
    xmin, xmax, ymin, ymax son todos los bordes otra vez
    '''
    fig, ax = plt.subplots()
    for i in range(len(theta)):
        def g(x,y):
            return fn(x,y, array[0][i], array[1][i])
        nulclinas_y_campo(g,xmin,xmax,xmin,xmax,1000,plot = 'no', ax = ax)
        ax.set_title('a = %.2f , b = %.2f' %(array[0][i],array[1][i]))
        plt.pause(0.1)
        ax.clear()

animacion(funcion_linda,val,-5,5,-5,5)
#nulclinas_y_campo(f,0,20,0,20,1000)


import numpy as np
import pickle as pk
import matplotlib.pyplot as pl
from scipy.optimize import curve_fit as cf

size = [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]

# Obtain standard deviation
f_file = open('T2f_sdheight.pickle', 'rb')
sd = pk.load(f_file)
f_file.close()

pl.figure()
pl.loglog(size, sd, 'bo', label = r"Standard deviation of the height $\sigma_h$")
pl.xlabel(r"System size $L$")
pl.ylabel(r"Standard deviation $\sigma_h$")
pl.grid()
pl.ylim(0.1, 10)

# Optimise a scaling funvtion for it
def scaling(L, a0, w0, a1, w1):
    return a0*(L**w0)*(1 - a1*L**-w1)

para, var = cf(scaling, np.log(size)/np.log(10), np.log(sd)/np.log(10), maxfev = 4000)

xpts = np.logspace(0.2, 3.1, 5000)
ypts = 10**(para[0]*(np.log(xpts)/np.log(10))**para[1]*(1 - para[2]*(np.log(xpts)/np.log(10))**(-para[3])))

pl.loglog(xpts, ypts, 'r-', label = r"Scaling function $a_0 L^{\omega_0} (1 - a_1 L^{-\omega_1})$ fit with"
          + "\n" + r"$a_0 = %.3f \pm %.3f$" %(para[0], np.sqrt(np.diag(var)[0])) + "\n" + r"$\omega_0 = %.3f \pm %.3f$" %(0.2388, np.sqrt(np.diag(var)[1]))
          + "\n" + r"$a_1 = %.3f \pm %.3f$" %(para[2], np.sqrt(np.diag(var)[2])) + "\n" + r"$\omega_1 = %.3f \pm %.3f$" %(para[3], np.sqrt(np.diag(var)[3])))
pl.legend()

# Divide by a0*L**w0 to obtain trend for large L - expect SD to tend towards a0*L**w0
yptsdiv = ypts / 10**(para[0]*(np.log(xpts)/np.log(10))**para[1])
sddiv = sd / 10**(para[0]*(np.log(size)/np.log(10))**para[1])

pl.figure()
pl.loglog(size, sddiv, 'bo', label = r"Scaled standard deviation $\sigma_h / a_0 L^{\omega_0}$")
pl.xlabel(r"System size $L$")
pl.ylabel(r"Scaled standard deviation $\sigma_h / a_0 L^{\omega_0}$")
pl.grid()
pl.loglog(xpts, yptsdiv, 'r-', label = r"Scaling function $(1 - a_1 L^{-\omega_1})$ fit")
pl.legend()
pl.ylim(0.1, 10)

# Save para and var for use in Task 2g
f_file1 = open('T2f_para.pickle', 'wb')
pk.dump(para, f_file1)
f_file1.close()