#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
GeeksforGeeks-numpy_in_python-set_1-introduction-2_array_creation.py
￣
GeeksforGeeks
https://www.geeksforgeeks.org/

NumPy in Python | Set 1 (Introduction)
(Contributed by Nikhil Kumar.)
https://www.geeksforgeeks.org/numpy-in-python-set-1-introduction/

To read more about the related topics,
  NumPy Reference
  https://docs.scipy.org/doc/numpy-1.10.1/reference/index.html

￣
2019-07-04 (Thu)
"""
# Numpy in Python > Introduction > 2.Array Creation

# This example covers:
#   1. Arrays in Numpy
#     creation (from a list)
#     type
#     ndim
#     shape
#     size
#     dtype
#
#   2. Array creation
#     from a list
#     from a tuple
#     zeros
#     *ones
#     full
#     *empty  No example presented by the tutorial. So I added examples by myself
#     random
#     arange
#     linspace
#     reshape
#     flatten
#
#   3. Array Indexing
#     Slicing
#     Integer array indexing
#     Boolean array indexing
#
#   4. basic operations
#     Operations on single array
#     Unary operators
#     Universal functions (ufunc)
#
#   5. Sorting array
#     np.sort( arr ), sort the array (row-wise)
#     axis=1, row-wise sorting
#     axis=0, column-wise sorting
#     kind='mergesort', selecting the sorting method with
#     axis=None, flatten and sort the all elements
#     sort a structured array
#     order='name' defined by dtypes
#     order=['grad_year','cgpa'] defined by dtypes
# Read more about:
#   numpy.empty
#   https://docs.scipy.org/doc/numpy/reference/generated/numpy.empty.html
#
#    Recommended Posts:
#    Python | Numpy numpy.ndarray.__ne__()
#    Python | Numpy numpy.ndarray.__and__()
#    Python | Numpy numpy.ndarray.__neg__()
#    Python | Numpy numpy.ndarray.__isub__()
#    Python | Numpy numpy.ndarray.__pos__()
#    Python | Numpy numpy.ndarray.__iadd__()
#    Python | Numpy numpy.ndarray.__xor__()
#    Python | Numpy numpy.ndarray.__eq__()
#    Python | Numpy numpy.ndarray.__ge__()
#    Python | Numpy numpy.ndarray.__imul__()
#    Python | Numpy numpy.ndarray.__lshift__()
#    Python | Numpy numpy.ndarray.__rshift__()
#    Python | Numpy numpy.ndarray.__pow__()
#    Python | Numpy numpy.ndarray.__divmod__()
#    Python | Numpy numpy.ndarray.__invert__()

import numpy as np

line="-" * 30

#====================================================================
print("1. Arrays in Numpy")
print( line )

arr = np.array( [[1,2,3],[4,2,5]] )
print("type=", type(arr))
#type= <class 'numpy.ndarray'>
print("number of dimensions=", arr.ndim)
#number of dimensions= 2
print("Shape=", arr.shape)
#Shape= (2, 3)
print("Size=", arr.size)
#Size= 12
print("Data type=", arr.dtype)
#Data type= int64

#====================================================================
print("2. Array creation")
print( line )

a = np.array( [[1,2,4],[5,8,7]], dtype='float' )
print("Array created from list with type float\n",a)
# [[1. 2. 4.]
# [5. 8. 7.]]

b = np.array( (1,3,2) )
print("Array created from tuple\n",b)
# [1 3 2]

c = np.zeros( (3,4) )
print("3x4 array initialized with all zeros\n", c)
# [[0. 0. 0. 0.]
# [0. 0. 0. 0.]
# [0. 0. 0. 0.]]

d = np.full( (3,3),6,dtype='complex')
print("3x3 array initialized with all 6s\n", d)
# [[6.+0.j 6.+0.j 6.+0.j]
# [6.+0.j 6.+0.j 6.+0.j]
# [6.+0.j 6.+0.j 6.+0.j]]

# These empty examples are not in the tutorial.
# So I added them by myself.
# https://docs.scipy.org/doc/numpy/reference/generated/numpy.empty.html
d_empty = np.empty( (2,2) )
print("2x2 array initialized with empty\n", d_empty)
# [[1.9044942e-316 0.0000000e+000]
# [0.0000000e+000 0.0000000e+000]]

# [] works, too
d_empty_square = np.empty( [2,2] )
print("2x2 array initialized with empty\n", d_empty_square)
# [[1.9044942e-316 0.0000000e+000]
# [0.0000000e+000 0.0000000e+000]]

d_empty_int = np.empty( (2,2), dtype='int')
print("2x2 array initialized with empty\n", d_empty_int)
# [[38547392        0]
# [       0        0]]

d_empty_complex = np.empty( (2,2), dtype='complex')
print("2x2 array initialized with empty\n", d_empty_complex)
# [[0.0e+000+1.06718180e-321j 0.0e+000+2.03676547e-316j]
# [1.4e-322+6.91236450e-310j 4.9e-324+0.00000000e+000j]]

e = np.random.random( (2,2) )
print("2x2 array initialized with random numbers\n", e)
# [[0.33910781 0.9765249 ]
# [0.4583446  0.91109638]]

f = np.arange(0,30,5)
print("A sequential array: 0 to 30 with steps of 5\n", f)
# [ 0  5 10 15 20 25]
# Note 30 is missing.

g = np.linspace(0,5,10)
print("A sequential array: 0 to 5 with 10 values in-between\n", g)
#[0.         0.55555556 1.11111111 1.66666667 2.22222222 2.77777778
# 3.33333333 3.88888889 4.44444444 5.        ]

arr = np.array( [[1,2,3,4],[5,2,4,2],[1,2,0,1]] )
print("Original array: 3x4 array has 12 elements in total\n", arr)
# [[1 2 3 4]
# [5 2 4 2]
# [1 2 0 1]]

newarr = arr.reshape(2,2,3)
print("Reshaped array: 2x2x3 array has 12 elements, too\n", newarr)
# [[[1 2 3]
#  [4 5 2]]
#
# [[4 2 1]
#  [2 0 1]]]

arr = np.array( [[1,2,3],[4,5,6]] )
flarr = arr.flatten()
print("Original array\n",arr)
# [[1 2 3]
# [4 5 6]]
print("Flattened array\n",flarr)
# [1 2 3 4 5 6]

#====================================================================
print("3. Array Indexing")
print( line )

arr = np.array( [[-1,2,0,4],[4,-0.5,6,0],[2.6,0,7,8],[3,-7,4,2.0]] )
print(arr)
#[[-1.   2.   0.   4. ]
# [ 4.  -0.5  6.   0. ]
# [ 2.6  0.   7.   8. ]
# [ 3.  -7.   4.   2. ]]

# Slicing array
temp = arr[:2, ::2]
print("first two rows & alternate columns (0,2)\n",temp)
#[[-1.  0.]
# [ 4.  6.]]

# Integer array indexing
temp = arr[[0,1,2,3],[3,2,1,0]]
print("arr[0,3],arr[1,2], arr[2,1], arr[3,0]")
print( temp )
#[4. 6. 0. 3.]

# Boolean array indexing
idx = arr > 0  # Indices for the element bigger than 0
print( idx )
#[[False  True False  True]
# [ True False  True False]
# [ True False  True  True]
# [ True False  True  True]]

# temp is a sequence selected from arr.
temp = arr[idx]
print( temp )
# [2.  4.  4.  6.  2.6 7.  8.  3.  4.  2. ]

#====================================================================
print("4. Basic Operations")
print( line )
# Plethora of built-in arithmetic functions are provided in Numpy.

print("Operations on single array")
a = np.array( [1,2,5,3] )

# The arithmetic operation is added to every element.
print( a+1 )  # 1 is added to every element.
#[2 3 6 4]
print( a-3 )  # 3 is subtracted to every element.
#[-2 -1  2  0]
print( a*10 )
#[10 20 50 30]

# Power of a
print( a**2 )
#[ 1  4 25  9]

# Modify the existing array
a *=2
# Each element is doubled.
print( a )
#[ 2  4 10  6]

# Transpose of the array a
print( a.T )
#[ 2  4 10  6]
# Output is the same because of the rank is 1.(?)
# Let's check with rank=2 case.

b = np.array( [[1,2,3], [3,4,5], [9,6,0]] )
print(b)
#[[1 2 3]
# [3 4 5]
# [9 6 0]]

print(b.T)
#[[1 3 9]
# [2 4 6]
# [3 5 0]]

print("Unary operators")
# Many unary operations are provided as a method of ndarray class.
# This includes sum, min, max, etc.
# These functions can also be applied row-wise or column-wise
#   by setting an axis parameter.

arr = np.array( [[1,5,6], [4,7,2], [3,1,9]] )
print( arr )
#[[1 5 6]
# [4 7 2]
# [3 1 9]]

# Max for the matrix
print( arr.max() )
# 9

# Row-wise Max            # GREP
print( arr.max(axis=1) )  # GREP: This is not intuitive to me.
# [6 7 9]                 # GREP

# Column-wise Max         # GREP
print( arr.max(axis=0) )  # GREP: This is not intuitive to me.
# [4 7 9]                 # GREP

print( arr.sum() )
# 38

# Column-wise sum
print( arr.sum(axis=0) )
#[ 8 13 17]

# Row-wise sum
print( arr.sum(axis=1) )
# [12 13 13]

# For each row, cumulative sum
print( arr.cumsum( axis=1) )
#[[ 1  6 12]
# [ 4 11 13]
# [ 3  4 13]]

print("Binary operators")
# These operations are applied elementwise.

a = np.array( [[1,2], [3,4]] )
print(a)
#[[1 2]
# [3 4]]

b = np.array( [[4,3], [2,1]] )
print(b)
#[[4 3]
# [2 1]]

# Elementwise sum
print(a+b)
#[[5 5]
# [5 5]]

# Elementwise multiplication
print( a*b )
#[[4 6]
# [6 4]]

# Matrix multiplication
print( a.dot(b) )
#[[ 8  5]
# [20 13]]

print("Universal functions (ufunc)")
# Mathematical functions such as sin, cos, & exp operate elementwise on an array.

a = np.array( [0,np.pi/2, np.pi] )
print( a )
# [0.         1.57079633 3.14159265]

print( np.sin(a) )
#[0.0000000e+00 1.0000000e+00 1.2246468e-16]

# I don't like this about Numpy.
# sin(pi) must be 0, not a very small number like this.
print( np.sin( np.pi ) )
# 1.2246467991473532e-16

# cos(np.pi/2) must be 0, not a very small number like this.
# What's the difference between cos( np.pi/2 - epsilon ) & cos( np.pi/2 )?
print( np.cos( np.pi/2 ) )
#6.123233995736766e-17

print( np.cos(a) )
#[ 1.000000e+00  6.123234e-17 -1.000000e+00]

print( np.exp(a) )
#[ 1.          4.81047738 23.14069263]

print( np.sqrt(a) )
#[0.         1.25331414 1.77245385]

print("4. Sorting array")
# np.sort method makes the sorting task easy for us.

a = np.array( [[1,4,2], [3,4,6], [0,-1,5]] )
print(a)
#[[ 1  4  2]
# [ 3  4  6]
# [ 0 -1  5]]

print( np.sort(a) )
#[[ 1  2  4]
# [ 3  4  6]
# [-1  0  5]]
# This is a row-wise sorting, right?

# Row-wise sorting.
# axis=1 is not necessary as a matter of fact.
# I used this option just to classify.
print( np.sort(a,axis=1) )
#[[ 1  2  4]
# [ 3  4  6]
# [-1  0  5]]

# Column-wise sorting
print( np.sort(a,axis=0) )
#[[ 0 -1  2]
# [ 1  4  5]
# [ 3  4  6]]

# Column-wise sorting AND mergesort is chosen!
print( np.sort(a,axis=0, kind='mergesort') )
#[[ 0 -1  2]
# [ 1  4  5]
# [ 3  4  6]]
# Of course, the sorted result is identical.

print( np.sort(a,axis=None) )
#[-1  0  1  2  3  4  4  5  6]
# The 2d array is flattened and then sorted!

# Structured array
dtypes = [('name','S10'),('grad_year',int),('cgpa',float)]

# Values to be put into an array
values = [('Hrithik',2009,8.5),('Ajay',2008,8.7),('Pankaj',2008,7.9),('Aakash',2009,9.0)]

# Create an array that takes in values and dtypes
arr = np.array(values, dtype=dtypes)
print(arr)
#[(b'Hrithik', 2009, 8.5) (b'Ajay', 2008, 8.7) (b'Pankaj', 2008, 7.9)
# (b'Aakash', 2009, 9. )]
# Q: What does b mean?

print( np.sort( arr,order='name') )
#[(b'Aakash', 2009, 9. ) (b'Ajay', 2008, 8.7) (b'Hrithik', 2009, 8.5)
# (b'Pankaj', 2008, 7.9)]

print( np.sort(arr, order=['grad_year','cgpa']))
#[(b'Pankaj', 2008, 7.9) (b'Ajay', 2008, 8.7) (b'Hrithik', 2009, 8.5)
# (b'Aakash', 2009, 9. )]


import matplotlib.pyplot as plt
import numpy as np
import plotly.io as pio

from IMLearn.learners import UnivariateGaussian, MultivariateGaussian

pio.templates.default = "simple_white"

def test_univariate_gaussian():
    # Question 1 - Draw samples and print fitted model

    mu = 10
    var = 1
    samples = 1000
    samplesArray = np.random.normal(mu, var, samples)
    uvg = UnivariateGaussian()
    uvg.fit(samplesArray)
    print(uvg.mu_, uvg.var_)
    # Question 2 - Empirically showing sample mean is consistent

    absDist = np.zeros(100, )
    numbOfSummedVal = np.arange(10, 1001, 10)
    sum = 0
    for i in range(0, 1000, 1):
        sum += samplesArray[i]
        if i % 10 == 0 and i != 0:
            arrayLoc = int(i / 10)
            absDist[arrayLoc] = abs((sum / i) - mu)

    plt.scatter(numbOfSummedVal, absDist)
    plt.xlabel("samples size")
    plt.ylabel("distance between the estimated- and true value")
    plt.title("distance between the estimated- and true value as function "
              "of sample size")
    plt.show()
    # Question 3 - Plotting Empirical PDF of fitted model

    pdf = uvg.pdf(samplesArray)
    plt.scatter(samplesArray, pdf)
    plt.xlabel("samples value")
    plt.ylabel("samples pdf")
    plt.title("distribution of pds as function of value")
    plt.show()

def test_multivariate_gaussian():
    #Question 4 - Draw samples and print fitted model

    mu = np.array([0, 0, 4, 0])
    var = np.array([[1, 0.2, 0, 0.5], [0.2, 2, 0, 0], [0, 0, 1, 0], [0.5, 0, 0, 1]])
    ndarr = np.random.multivariate_normal(mu, var, 1000)
    mvg = MultivariateGaussian().fit(ndarr)
    print(mvg.mu_)
    print(mvg.cov_)
    #Question 5 - Likelihood evaluation

    numOfSamples = 200
    f1 = np.linspace(-10, 10, numOfSamples)
    f3 = np.linspace(-10, 10, numOfSamples)
    counta = 0
    countb = 0
    heatMat = np.zeros((numOfSamples, numOfSamples))
    curr_mu = np.array([0, 0, 0, 0])

    for i in f1:
        for j in f3:
            curr_mu[0] = i
            curr_mu[2] = j
            heat = mvg.log_likelihood(curr_mu, var, ndarr)
            heatMat[counta][countb] = heat
            countb += 1
        countb = 0
        counta += 1

    fig, ax = plt.subplots()
    min, max = np.min(heatMat), np.max(heatMat)
    c = ax.pcolormesh(f1, f3, heatMat, cmap='RdBu', vmin=min, vmax=max)
    ax.set_title('log likelihood heapMap')
    ax.axis([f1.min(), f1.max(), f3.min(), f3.max()])
    fig.colorbar(c, ax=ax)
#     #Question 6 - Maximum likelihood

    val = np.unravel_index(heatMat.argmax(), heatMat.shape)
    print(np.linspace(-10, 10, numOfSamples)[val[1]],
          np.linspace(-10, 10, numOfSamples)[val[0]])
    plt.show()

if __name__ == '__main__':
    np.random.seed(0)
    test_univariate_gaussian()
    test_multivariate_gaussian()


"""
    Simple Implementation of K-nearest neighbor algorithm.
"""

import numpy as np
import matplotlib.pyplot as plt

def edist(x, y):
    """ Compute the Euclidean distance between two samples x, y \in R^d."""
    try:
        dist = np.sqrt(np.sum((x-y)**2))
    except ValueError:
        print 'Dimensionality of samples must match!'
    else:
        return dist

def manhattan_dist(x, y):
    """ Compute the Manhattan distance between two samples x, y \in R^d."""
    try:
        dist = np.sum(np.abs(x-y))
    except ValueError:
        print 'Dimensionality of samples must match!'
    else:
        return dist

def knn(query, data, k=5, metric=edist):
    """
        Find [k] nearest neighbors of [query] from data.
        Data [data] is given as an np.array of size n x d,
        where d is the dimensionality of sample, n is the number of samples.
        [metric]: distance function. Default to Euclidean distance.
    """
    n, d = data.shape
    if k > n: k = n

    # compute distances from query to all data samples.
    dist_array = np.asarray([edist(query, x) for x in data])

    # return indices of k nearest neighbors of query.
    return np.argsort(dist_array)[:k]

def knn_classifier(query, data, labels, k=5, metric=edist):
    """
        KNN-based classifier.
        [labels]: array of sample labels.
        Return sample labels and k-neighbors indices.
    """
    k_indices = knn(query, data, k, metric)
    counts = np.bincount(labels[k_indices])

    return np.argmax(counts), k_indices

def test_knn():
    # Generate 2d uniform data samples
    data = np.random.rand(200, 2)

    # Query sample
    query = np.random.rand(1, 2)[0]

    k_indices = knn(query, data, metric=manhattan_dist)

    # Plotting the data samples and query.
    plt.plot(data[:,0], data[:,1], 'ob', query[0],query[1], 'or')

    # Show k neighbors
    plt.plot(data[k_indices,0], data[k_indices,1], 'o',
            markerfacecolor='None', markersize=15, markeredgewidth=1)

    plt.show()

def test_classifier():
    # Generate 2d uniform data samples
    data = np.random.rand(200, 2)
    labels = np.array(np.random.rand(200) > 0.5, dtype=int)

    # Query
    query = np.random.rand(1, 2)[0]

    # Classifying...
    qlabel, k_indices = knn_classifier(query, data, labels)
    print 'Classified label of query: %d' % (qlabel)

    # Visualization. Note that: label = 1(0) -> c = red(blue)
    plt.scatter(data[:,0], data[:,1], c=labels, alpha=0.8)
    plt.scatter(query[0], query[1], c='g', s=40)
    plt.plot(data[k_indices,0], data[k_indices,1], 'o', markerfacecolor='None', markersize=15, markeredgewidth=1)
    plt.show()

if __name__ == '__main__':
    #test_knn()
    test_classifier()


import matplotlib.pyplot as plt
import numpy as np

def plot_line():
    """ Plots piecewise line """

    fig, ax = plt.subplots()
    ax.plot([1, 2, 3], [3, 2, 6])
    return fig

def plot_sine():
    """ Plots sine function """

    fig, ax = plt.subplots()
    x = np.linspace(0, 2 * np.pi, 100)
    y = np.sin(x)
    ax.plot(x, y)
    return fig

def image_plot():
    """ plt.imshow demonstration

    Source:

        https://matplotlib.org/3.1.0/gallery/images_contours_and_fields/image_demo.html

    """

    delta = 0.025
    x = y = np.arange(-3.0, 3.0, delta)
    X, Y = np.meshgrid(x, y)
    Z1 = np.exp(-X**2 - Y**2)
    Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
    Z = (Z1 - Z2) * 2
    fig, ax = plt.subplots()
    im = ax.imshow(Z, interpolation='bilinear', cmap='RdYlGn',
                origin='lower', extent=[-3, 3, -3, 3],
                vmax=abs(Z).max(), vmin=-abs(Z).max()
            )
    return fig

def plot_with_args(x, y):
    """ Pass arguments to plot function """

    fig, ax = plt.subplots()
    plt.plot(x, y)
    return fig

def countour_plot(custom_title):
    """ Contour plot demo

    Source:

        https://matplotlib.org/3.1.1/gallery/images_contours_and_fields/contour_demo.html

    """

    delta = 0.025
    x = np.arange(-3.0, 3.0, delta)
    y = np.arange(-2.0, 2.0, delta)
    X, Y = np.meshgrid(x, y)
    Z1 = np.exp(-X**2 - Y**2)
    Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
    Z = (Z1 - Z2) * 2
    fig, ax = plt.subplots()
    CS = ax.contour(X, Y, Z)
    ax.clabel(CS, inline=1, fontsize=10)
    ax.set_title(custom_title)
    return fig


'''
Miscellaneous math functions.
'''

from __future__ import absolute_import, division, print_function, unicode_literals

import numpy as np

def matrix_sqrt(X=None, symmetric=False, inverse=False, eigs=None):
    '''Returns the matrix square root of X.

    Arguments:

        `X` (square class::`numpy.ndarrray`)

        `symmetric` (bool, default False):

            If True, `X` is assumed to be symmetric, which speeds up
            calculation of the square root.

        `inverse` (bool, default False):

            If True, computes the matrix square root of inv(X).

        `eigs` (2-tuple):

            `eigs` must be a 2-tuple whose first element is an array of
            eigenvalues and whose second element is an ndarray of eigenvectors
            (individual eigenvectors are in columns). If this argument is
            provided, computation of the matrix square root is much faster. If
            this argument is provided, the `X` argument is ignored (in this
            case, it can be set to None).

    Returns a class::`numpy.ndarray` `S`, such that S.dot(S) = X
    '''
    if eigs is not None:
        (vals, V) = eigs
    else:
        (vals, V) = np.linalg.eig(X)
    k = len(vals)
    if inverse is False:
        SRV = np.diag(np.sqrt(vals))
    else:
        SRV = np.diag(1. / np.sqrt(vals))
    if symmetric:
        return V.dot(SRV).dot(V.T)
    else:
        return V.dot(SRV).dot(np.linalg.inv(V))

def get_histogram_cdf_points(data, cdf_vals, ignore=None, mask=None):
    '''Returns input values corresponding to the data's CDF values.

    Arguments:

        `data` (ndarray):

            The data for which to determine the CDF values

        `cdf_vals` (sequence of floats):

            A sequence defining the CDF values for which the values of `data`
            should be returned. Each value should be in the range [0, 1]. For
            example, to get the values of `data` corresponding to the 1% lower
            tail and 5% upper tail, this argument would be (0.01, 0.95).

        `ignore` (numeric, default `None`):

            A scalar value that should be ignored when computing histogram
            points (e.g., a value that indicates bad data). If this valus is
            not specified, all data are used.

    Return value:

        A list specifying the values in `data` that correspond to the
        associated CDF values in `cdf_vals`.
    '''
    data = data.ravel()
    if mask is not None:
        data = data[mask.ravel() != 0]
        if len(data) == 0:
            raise Exception('All pixels are masked.')
    if ignore is not None and ignore in data:
        data = data[np.where(data != ignore)]
        if len(data) == 0:
            raise Exception('No data to display after masking and ignoring.')
    isort = np.argsort(data)
    N = len(data)
    return [data[isort[int(x * (N - 1))]] for x in cdf_vals]


import sympy as sp

def christoffel(ds, g_mn, abc = [], ABC = []):

    # ds contiene el orden de las variables en el intervalo
    # g_mn es la métrica, en forma de 2D tupla

    # calcula \Gamma_{ab}^c.

    # ABC contiene múltiples tuplas abc. Se usa para calcular varios símbolos
    # en una sola llamada.

    #Constantes que podrían aparecer en la métrica
    G, M, R, C1, C2, C3 = sp.symbols('G M R C1 C2 C3')

    orden = [] #el orden en el que aparecen las variables de la meteica

    for i, e in enumerate(ds):
        #Las variables de la métrica
        if e != '':
            exec("var"+str(i)+"=sp.symbols('"+e+"')")
            exec("orden.append(var"+str(i)+")")

    ordenSt = [str(k) for k in orden]
    d = len(ordenSt)

    #la métrica con los íncices a b abajo
    gabD = sp.zeros(d, d)
    for i, row in enumerate(g_mn):
        for j, elem in enumerate(row):
            if i >= d or j >= d: continue
            if elem != '': gabD[i,j] = elem
            else: gabD[i,j] = 0

    #y con los índices arriba,
    gabU = gabD.inv()

    gabD = gabD.tolist()
    gabU = gabU.tolist()

    if ABC == [] and abc != []:
        #Vamos a calcular solo el símbolo \Gamma_{ab}^c
        a = abc[0]
        b = abc[1]
        c = abc[2]

        ai = ordenSt.index(a)
        bi = ordenSt.index(b)
        ci = ordenSt.index(c)

        chrst = 0

        for di in range(len(gabD)):
            chrst += 1./2*gabU[ci][di]*(sp.diff(gabD[bi][di], ordenSt[ai]) + sp.diff(gabD[di][ai], ordenSt[bi]) - sp.diff(gabD[ai][bi], ordenSt[di]))

        return(chrst)

    elif ABC != [] and abc == []:
        #vamos a calcular varios símbolos de una sola vez
        CHRIST = []

        for elem in ABC:
            a = elem[0]
            b = elem[1]
            c = elem[2]

            ai = ordenSt.index(a)
            bi = ordenSt.index(b)
            ci = ordenSt.index(c)
            chrst = 0
            for di in range(len(gabD)):
                chrst += 1./2*gabU[ci][di]*(sp.diff(gabD[bi][di], ordenSt[ai]) + sp.diff(gabD[di][ai], ordenSt[bi]) - sp.diff(gabD[ai][bi], ordenSt[di]))
            CHRIST.append(chrst)

        return CHRIST
    else: print("wrong call! either abc or ABC must be empty")

'''
abc = ["r", "t", "t"]
ds = ['t', 'r', 'th', 'fi']
g_mn = [['-(1-2*G*M/r)', '', '', ''], ['', '1/(1-2*G*M/r)', '', ''], ['', '', 'r**2', ''], ['', '', '', 'r**2*sin(th)**2']]
print(christoffel(ds, g_mn, abc))
'''


import math
import numpy as np
import matplotlib.pylab as plt

def func(x):
    """
    Исследуемая функция.
    :param x:
    :return:
    """
    y = math.asin((x - 1) ** 2)
    return y

def show_func():
    """
    Построение графика функции.
    :return:
    """
    x = np.linspace(0, 2, 4001)
    y = np.zeros(len(x))
    for i in range(len(x)):
        y[i] = func(x[i])
    plt.plot(x, y)
    plt.grid()
    plt.show()

def dif1(x):
    """
    Первая производная (разностная).
    :param x:
    :return:
    """
    h = 1e-7
    y = (func(x + h) - func(x - h)) / (2 * h)
    return y

def dif2(x):
    """
    Вторая производная (разностная).
    :param x:
    :return:
    """
    h = 1e-7
    y = (func(x + h) - 2 * func(x) + func(x - h)) / (h ** 2)
    return y

def Newton(x):
    """
    Метод Ньютона (с разностными производными).
    :param x:
    :return:
    """
    eps = 1e-14
    x_error = []
    x2 = x
    for i in range(100):
        x1 = x2
        x2 = x1 - (dif1(x1) / dif2(x1))
        x_error.append([x2, x1, abs(x2 - x1)])
        if abs(x2 - x1) < eps:
            break
    if dif2(x2) > 0:
        print('Точка минимума: x = ', end='')
    elif dif2(x2) < 0:
        print('Точка максимума: x = ', end='')
    print(x2)
    R_theor = x_error[-2][2]
    print('Теоретическая ошибка: R_theor =', R_theor)
    return x2, x_error

def find_min():
    """
    Поиск точки минимума.
    :return:
    """
    x, x_error = Newton(0.5)
    x_0 = 1
    R_real = abs(x_0 - x)
    print('Реальная ошибка: R_real =', R_real)
    print('\nСписок ошибок:')
    for i in x_error:
        print(f'|{i[0]} - {i[1]}| = {i[2]}')

def dif1_a(x):
    """
    Первая производная (аналитическая).
    :param x:
    :return:
    """
    y = (2 * x - 2) / math.sqrt(1 - (x - 1) ** 4)
    return y

def dif2_a(x):
    """
    Вторая производная (аналитическая).
    :param x:
    :return:
    """
    y = (2 * (1 + (2 * (x - 1) ** 4) / (1 - (x - 1) ** 4))) / math.sqrt(1 - (x - 1) * 4)
    return y

def Newton_a(x):
    """
    Метод Ньютона (с аналитическими производными).
    :param x:
    :return:
    """
    eps = 1e-14
    x_error = []
    x2 = x
    for i in range(100):
        x1 = x2
        x2 = x1 - (dif1_a(x1) / dif2_a(x1))
        x_error.append([x2, x1, abs(x2 - x1)])
        if abs(x2 - x1) < eps:
            break
    if dif2_a(x2) > 0:
        print('Точка минимума: x = ', end='')
    elif dif2_a(x2) < 0:
        print('Точка максимума: x = ', end='')
    print(x2)
    R_theor = x_error[-2][2]
    print('Теоретическая ошибка: R_theor =', R_theor)
    return x2, x_error

def find_min_a():
    """
    Поиск точки минимума.
    :return:
    """
    x, x_error = Newton(0.5)
    x_0 = 1
    R_real = abs(x_0 - x)
    print('Реальная ошибка: R_real =', R_real)

    print('\nСписок ошибок:')
    for i in x_error: print(f'|{i[0]} - {i[1]}| = {i[2]}')

if __name__ == '__main__':
    find_min_a()


import numpy as np
import pandas as pd
from pandas_datareader import DataReader
from pandas_datareader._utils import RemoteDataError
import scipy.stats as st

def ewma_vol(returns, lamb=0.94):

    returns = np.array(returns)

    size = np.array(range(len(returns)))[::-1]
    mean = np.mean(returns)

    vol = np.sqrt(np.sum((returns-mean) ** 2 * (1-lamb) * (lamb ** size)))
    return vol

def ewma_corr(a, b, lamb=0.94):
    a = np.array(a)
    b = np.array(b)

    size = np.array(range(len(a)))[::-1]
    corr = np.sum((1-lamb) * (lamb ** size) * (a - np.mean(a)) * (b - np.mean(b)))

    vol1 = ewma_vol(a, lamb)
    vol2 = ewma_vol(b, lamb)

    corr = corr / (vol1 * vol2)

    return corr

def Value_at_risk(tickers, date, weights=None, EWMA_model=True, confidence=0.99, samples=252, lamb=0.94):

    """
    Calculates the daily Value at Risk of a
    given stock or portfolio (list of stocks)

    The model assumes a parametric T-distribution for the returns.

    The returns are modeled as logarithm.

    -------------------------------------------------------
    tickers:
        List of stock names, ex: [GOOG, AAPL] or [GOOG] for just one stock
        Important: You must pass the exact name used in https://finance.yahoo.com/
    date:
        The date of the VaR.
        Note: The VaR always refers to the maximum loss of the next day of the date.
    weights:
        The weight of each stock in the portfolio composition.
        If None, assumes a equally weighed portfolio.
    EWMA_model:
        To calculate the VaR using the EWMA model of volatility and correlation
        EWMA means Exponentially Weighted Moving Average
    confidence:
        The level of confidence of the VaR.
    samples:
        How many past return days to use to calculate the VaR
    lamb:
        It's the lambda parameter for EWMA model.
        More on: https://www.investopedia.com/articles/07/ewma.asp
    """

    # Deals with possible errors

    if not isinstance(tickers, list):
        raise Exception("You must pass the argument tickers as a list.")

    tickers = [t.upper() for t in tickers]

    if weights is None:
        q = len(tickers)
        weights = np.array([1/q for _ in range(q)]) # Equal weights
    else:
        if len(weights) != len(tickers):
            raise Exception('weights and tickers must have the same size')
        weights = np.array(weights)

    # Start processing

    volatility = np.array([])

    start = pd.to_datetime(date, dayfirst=True)
    adjust_date = ((30 + samples)/252) * 365 # Some extra days to compensate holidays
    start = start - pd.to_timedelta(adjust_date, unit='d')
    date = pd.to_datetime(date, dayfirst=True)

    all_data = pd.DataFrame()

    for pos, ticker in enumerate(tickers):

        try:
            data = DataReader(ticker, 'yahoo', start, date)
        except Exception as e:
            print(f"Couldn't find {ticker} in Yahoo Finance. Error code: {e}")

        size = data.shape[0]
        data = data.iloc[size-(samples+1):]

        data[f'Log Returns {ticker}'] = np.log(data['Adj Close'] / data['Adj Close'].shift(1))
        data = data[f'Log Returns {ticker}'].to_frame()
        data.dropna(inplace=True)

        if EWMA_model:
            vol = ewma_vol(data[f'Log Returns {ticker}'], lamb=lamb)
        else:
            vol = data[f'Log Returns {ticker}'].std(ddof=1)

        volatility = np.append(volatility, vol)

        if pos == 0:
            all_data = all_data.append(data)
        else:
            all_data = pd.merge(all_data, data, left_index=True, right_index=True)

    if EWMA_model:
        corr = all_data.corr(ewma_corr)
    else:
        corr = all_data.corr()

    factor = st.t.ppf(q=confidence, df=samples)
    weights_vol = weights * volatility

    var = np.sqrt(np.dot(np.dot(weights_vol.T, corr), weights_vol)) * factor

    return var

# Ticker name must be exactly the same in https://finance.yahoo.com/
var = Value_at_risk(['GOOG', 'PETR4.SA', 'ITUB4.SA', 'VALE3.SA'], '12/02/2021', weights=[0.3, 0.1, 0.4, 0.2],
                    EWMA_model=True, confidence=0.99, samples=252, lamb=0.94)

print(f'Value at risk = {round(var*100,3)}%')


import numpy as np
import matplotlib.pyplot as plt

def pi():
    x = np.random.rand(1)
    y = np.random.rand(1)

    hyp = x**2 + y**2

    return(hyp)

k = 0
n = 1000

for i in range(n):
    x = np.random.rand(1)
    y = np.random.rand(1)
    hyp = x**2 + y**2

    if hyp < 1:
        k+=1
        plt.figure(1)
        plt.scatter(x,y,color='r')
    else:
        plt.figure(1)
        plt.scatter(x,y,color='b')

plt.show()

approx = k/n
print(approx)


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

import RNG
import math
import numpy as np
from scipy.stats import norm
from scipy import stats

ZRNG = RNG.InitializeRNSeed()
n = 10000
T = 1.0
m = 32
vol = 0.3
r = 0.05
X0 = 50.0
K = 55.0
Interval = T/m
alpha = 0.05

T2 = (m+1)*Interval/2.0
Sigma2 = (2*m+1)*vol*vol/(3.0*m)
delta = (vol*vol - Sigma2)/2.0
d = (math.log(X0/K)+(r-delta+Sigma2/2)*T2)/(math.sqrt(Sigma2*T2))
muvc = math.exp(-delta*T2)*X0*norm.cdf(d) - math.exp(-r*T2)*K*norm.cdf(d-math.sqrt(Sigma2*T2))

vList = [] # List to keep the option values
vcList = [] # List to keep vc values

for i in range(n):
    Sum = 0.0
    Product = 1.0
    X = X0
    for j in range(m):
        Z = RNG.Normal(0,1,1)
        X = X * math.exp((r - vol**2/2) * Interval + vol * math.sqrt(Interval) * Z)
        Sum = Sum + X
        Product = Product * X
    v = math.exp(-r * T) * max(Sum/m - K, 0)
    vc = math.exp(-r * T) * max(Product**(1.0/m) - K, 0)
    vList.append(v)
    vcList.append(vc)

vList = np.array(vList)
vcList = np.array(vcList)
vbar = vList.mean()
vcbar = vcList.mean()

print "v Mean", vList.mean()
print "v Std", vList.std()
print "vc Mean", vcList.mean()
print "vc Std", vcList.std()

beta1 =  sum(np.multiply(vList-vbar,vcList-vcbar))/sum((vcList-vcbar)**2)
beta0 = vbar - beta1*(vcbar-muvc)
part1 = sum((vList - beta0 - beta1*(vcList-muvc))**2)/(n-2.0)
part2 = 1.0/n + (vcbar-muvc)**2/sum((vcList-vcbar)**2)
SIGMA = part1 * part2

error = stats.t.ppf(1-alpha/2,n-2) * math.sqrt(SIGMA)
CI = "(" + str(beta0 - error) + ", " + str(beta0 + error) + ")"
print "m =", m, ", CI:", CI


import numpy as np

data_path = "data/problem_06.txt"
# data_path = "data/problem_06_test.txt"

# 🐟🐠🐡
data = np.genfromtxt(data_path, dtype=np.uint64, delimiter=",")

def simulate_fish(starting_ages, days):
    age_bins = np.zeros(9, dtype=np.uint64) # 🐠⏰

    for age, count in zip(*np.unique(starting_ages, return_counts=True)):
        age_bins[age] = count

    for _day in range(days):
        # time to make babby 🐟🥚
        new_fish = age_bins[0]

        # time to get old
        age_bins[0:8] = age_bins[1:9]
        age_bins[6] += new_fish
        age_bins[8] = new_fish

    return age_bins[:9]

# part 1
print(f"Part 1 solution: {simulate_fish(data, 80).sum()}")

# part 2
print(f"Part 2 solution: {simulate_fish(data, 256).sum()}")


import numpy as np

a = np.array([3,1,9,1,5,3,7,8,9,5])     # One Dimentional array
b = np.array([[1,7,3,4],[9,3,6,1],[9,2,8,1]])   # Two Dimentional array
print("a :" ,a)
print("b :", b)

print("\nAccessing a certain item.")
print("1D : ")
print(a[2])     # Starts with 0
print(a[-1])    # Prints last element
print("2D : ")
print(b[1][2])

print("\nFinding the dimension :")
print(a.ndim,"Dimensional array")
print(b.ndim,"Dimensional array")

print("\nShape (Rows, Column)")
print(b.shape)

print("\nSize(Number of elements)")
print(b.size)

print("\nDatatype :")
print(a.dtype)

print("\nUpdating an array :")
print("1D : ")
print(a)
a[1] = 6
print(a)
print("2D :")
print(b)
b[1][2] = 8
print(b)

print("\nPrinting only fixed values(Read comments) : ")
print("1D : ")
print("a :" ,a)
print(a[:3])
print(a[3:])
print(a[3:8])
print(a[::2])   # Skips a value (prints all the second terms)
print(a[::3])   # Prints only the third value
print(a[2::3])  # Starts from the second step and prints only the third term from then
print(a[8::-2]) # Prints from the reverse direction

print("2D : ")
print("b :\n", b)
print(b[:2,:1])
print(b[:2,:2])
print(b[0,:])   # Prints only the first row
print(b[:,0])   # Prints only the first column

print("\nData Conversions : ")
c = np.array([[1,7,6,4],[2,8.4,7,11],[2,6,4.3,12]],dtype = int)
print("Int : \n",c)
c = np.array([[1,7,6,4],[2,8.4,7,11],[2,6,4.3,12]],dtype = float)
print("Float : \n",c)

print("\nConverting a 1D array into a 2D array : ")
c = np.arange(1,10).reshape(3,3)    # 3 rows and 3 columns
print(c)

print("\nConcatenating Arrays : ")
a = np.arange(0,10,2)
b = np.arange(0,10,3)
c = np.concatenate([a,b])
print(c)
c = c.reshape(3,3)
print("After converting to a 2d array : \n",c)

print("\nComparing elements of two arrays : ")
a = np.array([6,7,3,9])
b = np.array([5,7,9,9])
print(a==b)
print(a>b)

print("\nComparing complete arrays : ")
a = np.array([5,6,7,8])
b = np.array([1,2,3,4])
c = np.array([1,2,3,4])
print(np.array_equal(a,b))
print(np.array_equal(b,c))

print("\nTo add elements at the end of the array : ")
print("a :", a)
print(np.append(a,[100,200,300]))

print("\nGengerating random numbers : ")
big_data = np.random.random_integers(1,100,size=1000)   # Generating 1000 random numbers from 1-100
print(big_data)

input("Press Enter key to exit ")


"""
This modules shows the numerically solution of a differential equation with
Scipy. The problem framed is the Newton's law of cooling:

    dT/dt = -k*T

where k is a positive constant that determines the rate of cooling. The
solution has the general form:

    T(t) = T0 * exp(-k*t)
"""
import numpy as np
import matplotlib.pyplot as plt

from scipy import integrate

# True solution
def true_solution(t):
    return 50*np.exp(-0.2*t)

# Define the general form of the differential equation (y -> T)
def f(t, y):
    return -0.2*y

# Time range
t_range = (0, 10)

# Initial temperature
T0 = np.array([50])

scipy_sol = integrate.solve_ivp(f, t_range, T0, max_step=0.1)

t_vals = scipy_sol.t
T_vals = scipy_sol.y[0, :]

fig, (ax1, ax2) = plt.subplots(1, 2, tight_layout=True)

ax1.plot(t_vals, T_vals)
ax1.set_xlabel("$t$", usetex=True)
ax1.set_ylabel("$T$", usetex=True)
ax1.set_title("Solution of the cooling equation")

err = np.abs(T_vals - true_solution(t_vals))
ax2.semilogy(t_vals, err)
ax2.set_xlabel("$t$", usetex=True)
ax2.set_ylabel("Error", usetex=True)
ax2.set_title("Error in approximation (RK4)")

plt.show()


import numpy as np

def __fact(window):
    """Computes the amplitude conpensation factor to apply to a FFT for the given window.
    Just equivalent to 1/RMS(window).

    Args:
       window ( iterable object):  The windows to analyse.

    Returns:
        float: The compensation factor.
    """
    return 1./np.sqrt(np.mean(np.square(window)))

def fft(waveform, sampling_frequency=1., window=None, remove_mean=True):
    """Compute the FFT of the given signal wf and return result in a fashion way.

    Args:
        wf ( iterable object):  The time domain signal on which you want to compute FFT.
        fs (Optional[float]): Sampling frequency of wf, used for frequency vector normalization.
        window ( Optional[iterable object]):  The window to apply.
        removeMean (Optional[bool]):  Set to True if you want to remove mean on signal befor
            computing FFT.

    Returns:
        dict: The FFT result simplified and stored in a dict. The FFT result is trucated from F=0 to
            F=Fs/2 and amplitude is normalized to its real value and in case of windowing, the
            window correction factor is applied.
            keys ( strings ):
                f ( numpy array of float ): Frequency vector normalized to given "fs" frequency
                mod ( numpy array of float ): Amplitude vector divided by len(wf) and corrected if a
                    window is applied.
                phi ( numpy array of float ): Phase vector.
    """
    scale_factor = 1./len(waveform)
    if remove_mean:
        waveform = waveform - np.mean(waveform)
    if not window is None:
        waveform = waveform*window
        scale_factor = scale_factor *__fact(window)
    spectrum = np.fft.fft(waveform) *scale_factor
    frequency = np.fft.fftfreq(len(spectrum), 1/sampling_frequency)
    frequency[int(len(frequency)/2)] = abs(frequency[int(len(frequency)/2)])
    return {"f":frequency[0:int(len(frequency)/2)+1],
            "mod":abs(spectrum[0:int(len(spectrum)/2)+1]),
            "phi":np.angle(spectrum[0:int(len(spectrum)/2)+1], False)}


# -*- coding: utf-8 -*-
"""
Euler discovered the remarkable quadratic formula:

n^2 + n + 41

It turns out that the formula will produce 40 primes for the consecutive values n = 0 to 39. However, when n = 40, 402 + 40 + 41 = 40(40 + 1) + 41 is divisible by 41, and certainly when n = 41, 41^2 + 41 + 41 is clearly divisible by 41.

The incredible formula  n^2 − 79n + 1601 was discovered, which produces 80 primes for the consecutive values n = 0 to 79. The product of the coefficients, −79 and 1601, is −126479.

Considering quadratics of the form:

n^2 + an + b, where |a| < 1000 and |b| < 1000

where |n| is the modulus/absolute value of n
e.g. |11| = 11 and |−4| = 4
Find the product of the coefficients, a and b, for the quadratic expression that produces the maximum number of primes for consecutive values of n, starting with n = 0.
"""
import numpy as np
from itertools import count
def primes_up_to(n):
    if n < 2:
        return np.zeros(n+1, dtype=bool)

    A = np.ones(n+1, dtype=bool)
    A[0] = A[1] = False
    for i in xrange(2, int(np.sqrt(n))+1):
        if A[i]:
            for j in xrange(i**2, n+1, i):
                A[j] = False
    return np.where(A)[0]

def isprime(n):
    """Returns True if n is prime."""
    if n < 2:
        return False
    if n == 2 or n == 3:
        return True
    if n % 2 == 0 or n % 3 == 0:
        return False
    i = 5
    w = 2
    while i * i <= n:
        if n % i == 0:
            return False
        i += w
        w = 6 - w
    return True

def prime_length(a, b):
    f = lambda n: n*n + a*n + b
    nprimes = 0
    for n in count():
        if isprime(f(n)):
            nprimes += 1
        else:
            break
    return nprimes

p = primes_up_to(1000)
prime_set = set(p)

best_a, best_b, best_length = 0, 0, 0
for b in p:
    a_set = p - b - 1
    for a in a_set:
        nprimes = prime_length(a, b)
        if nprimes > best_length:
            best_a, best_b, best_length = a, b, nprimes
print best_a, best_b, best_length
print best_a * best_b


import numpy as np

# Idea:
# 1) Draw a horizontal line to the right of each point and extend it to infinity

# 2) Count the number of times the line intersects with polygon edges.

# 3) A point is inside the polygon if either count of intersections is odd or
#    point lies on an edge of polygon.  If none of the conditions is true, then
#    point lies outside.

# Given three colinear points p, q, r, the function checks if
# point q lies on line segment 'pr'
def onSegment(p, q, r):
    if (q[0] <= max(p[0], r[0]) and q[0] >= min(p[0], r[0]) and q[1] <= max(p[1], r[1]) and q[1] >= min(p[1], r[1])):
        return True
    return False

# To find orientation of ordered triplet (p, q, r).
# The function returns following values
# 0 --> p, q and r are colinear
# 1 --> Clockwise
# 2 --> Counterclockwise
def orientation(p, q, r):
    val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1])

  	# colinear
    if (val == 0):
    	return 0

   	# clock or counterclock wise
    if (val > 0):
    	return 1
    else:
    	return 2

def is_intersect(p1, q1, p2, q2):
	# Find the four orientations needed for general and special cases
    o1 = orientation(p1, q1, p2)
    o2 = orientation(p1, q1, q2)
    o3 = orientation(p2, q2, p1)
    o4 = orientation(p2, q2, q1)

    # General case
    if (o1 != o2 and o3 != o4):
        return True

    # Special Cases
    # p1, q1 and p2 are colinear and p2 lies on segment p1q1
    if (o1 == 0 and onSegment(p1, p2, q1)):
    	return True

    # p1, q1 and p2 are colinear and q2 lies on segment p1q1
    if (o2 == 0 and onSegment(p1, q2, q1)):
    	return True

    # p2, q2 and p1 are colinear and p1 lies on segment p2q2
    if (o3 == 0 and onSegment(p2, p1, q2)):
    	return True

    # p2, q2 and q1 are colinear and q1 lies on segment p2q2
    if (o4 == 0 and onSegment(p2, q1, q2)):
    	return True

    return False # Doesn't fall in any of the above cases

def is_point_in_polygon(polygon, point):
	# Create a point for line segment from p to infinite
	extreme = [point[0], 1e9]

	# Count intersections of the above line with sides of polygon
	count = 0
	i = 0

	while True:
		j = (i+1) % len(polygon)

		# Check if the line segment from 'p' to 'extreme' intersects
        # with the line segment from 'polygon[i]' to 'polygon[j]'
		if is_intersect(polygon[i], polygon[j], point, extreme):
			# If the point 'p' is colinear with line segment 'i-j',
			# then check if it lies on segment. If it lies, return true,
			# otherwise false
			if orientation(polygon[i], point, polygon[j])==0:
				return onSegment(polygon[i], point, polygon[j])
			count = count + 1

		i = j
		if i==0:
			break

	return count % 2 == 1

# use this function to check if a bounding box is inside the polygon
def is_bounding_box_intersect(bounding_box, polygon):
	for i in range(len(bounding_box)):
		if is_point_in_polygon(polygon, bounding_box[i]):
			return True
	return False

def check_bbox_intersect_polygon(polygon, bbox):
	"""

	Args:
	polygon: List of points (x,y)
	bbox: A tuple (xmin, ymin, xmax, ymax)

	Returns:
	True if the bbox intersect the polygon
	"""
	x1, y1, x2, y2 = bbox
	bb = [(x1, y1), (x2, y1), (x2, y2), (x1, y2)]
	return is_bounding_box_intersect(bb, polygon)

def cosin_similarity(a2d, b2d, debug=False):
	a = np.array((a2d[1][0] - a2d[0][0], a2d[1][1] - a2d[0][1])).astype(float)
	b = np.array((b2d[1][0] - b2d[0][0], b2d[1][1] - b2d[0][1])).astype(float)
	tmp1 = np.dot(a, b)
	tmp2 = (np.linalg.norm(a)*np.linalg.norm(b*1.0))
	if debug:
		print(a, b, tmp1, tmp2)
	return tmp1/tmp2


# -*- coding: utf-8 -*-
"""
partial influence demonstrates the partial impact of base and exponents

Copyright (c) 2016 - RocketRedNeck.com RocketRedNeck.net

RocketRedNeck and MIT Licenses

RocketRedNeck hereby grants license for others to copy and modify this source code for
whatever purpose other's deem worthy as long as RocketRedNeck is given credit where
where credit is due and you leave RocketRedNeck out of it for all other nefarious purposes.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

import matplotlib.pyplot as plot
import numpy as np

def dfdb(B, E):
    """
    B is the base
    E is the exponent
    f = B^E
    partial df/dB = E * B**(E-1)
    """
    out = E * (B**(E-1))
    return out

def dfde(B, E):
    """
    B is the base
    E is the exponent
    f = B^E
    partial df/dE = B**(E) * ln(B)
    """
    out = (B**E) * np.log(B)
    return out

plot.figure(1)
plot.cla()
plot.grid()

x = 5
Bs = np.arange(-x,+x,0.5)     # Start, Stop, Step
Es = np.arange(-x,+x,0.5)

# For each E held constant
for E in Es:
    plot.plot(Bs,dfdb(Bs,E))

plot.figure(2)
plot.cla()
plot.grid()

# For each B help constant
for B in Bs:
    plot.plot(Es,dfde(B,Es))

plot.show()


from __future__ import division
from scipy.stats import triang
from scipy.stats import norm
from scipy.stats import uniform
from sklearn import preprocessing

from cea.utilities import latin_hypercube
import pandas as pd
import numpy as np
import numpy.ma as ma

__author__ = "Jimeno A. Fonseca"
__copyright__ = "Copyright 2017, Architecture and Building Systems - ETH Zurich"
__credits__ = ["Jimeno A. Fonseca"]
__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "Daren Thomas"
__email__ = "cea@arch.ethz.ch"
__status__ = "Production"

def latin_sampler(locator, num_samples, variables, region):
    """
    This script creates a matrix of m x n samples using the latin hypercube sampler.
    for this, it uses the database of probability distribtutions stored in locator.get_uncertainty_db()
    it returns clean and normalized samples.

    :param locator: pointer to locator of files of CEA
    :param num_samples: number of samples to do
    :param variables: list of variables to sample
    :return:
        1. design: a matrix m x n with the samples where each feature is normalized from [0,1]
        2. design_norm: a matrix m x n with the samples where each feature is normalized from [0,1]
        3. pdf_list: a dataframe with properties of the probability density functions used in the exercise.

    """

    # get probability density function PDF of variables of interest
    variable_groups = ('ENVELOPE', 'INDOOR_COMFORT', 'INTERNAL_LOADS','SYSTEMS')
    database = pd.concat([pd.read_excel(locator.get_uncertainty_db(region), group, axis=1)
                          for group in variable_groups])
    pdf_list = database[database['name'].isin(variables)].set_index('name')

    # get number of variables
    num_vars = pdf_list.shape[0]  # alternatively use len(variables)

    # get design of experiments
    samples = latin_hypercube.lhs(num_vars, samples=num_samples, criterion='maximin')
    for i, variable in enumerate(variables):

        distribution = pdf_list.loc[variable, 'distribution']
        #sampling into lhs
        min = pdf_list.loc[variable, 'min']
        max = pdf_list.loc[variable, 'max']
        mu = pdf_list.loc[variable, 'mu']
        stdv = pdf_list.loc[variable, 'stdv']
        if distribution == 'triangular':
            loc = min
            scale = max - min
            c = (mu - min) / (max - min)
            samples[:, i] = triang(loc=loc, c=c, scale=scale).ppf(samples[:, i])
        elif distribution == 'normal':
            samples[:, i] = norm(loc=mu, scale=stdv).ppf(samples[:, i])
        elif distribution == 'boolean': # converts a uniform (0-1) into True/False
            samples[:, i] = ma.make_mask(np.rint(uniform(loc=min, scale=max).ppf(samples[:, i])))
        else:  # assume it is uniform
            samples[:, i] = uniform(loc=min, scale=max).ppf(samples[:, i])

    min_max_scaler = preprocessing.MinMaxScaler(copy=True, feature_range=(0, 1))
    samples_norm = min_max_scaler.fit_transform(samples)

    return samples, samples_norm, pdf_list


import numpy as np
from scipy.spatial.distance import pdist, squareform
from scipy import exp
from scipy.linalg import eigh

def rbf_kernel_pca(X, gamma, n_components):
    """
    RBF kernel PCA implementation.

    Parameters
    ------------
    X: {NumPy ndarray}, shape = [n_samples, n_features]

    gamma: float
      Tuning parameter of the RBF kernel

    n_components: int
      Number of principal components to return

    Returns
    ------------
     X_pc: {NumPy ndarray}, shape = [n_samples, k_features]
       Projected dataset

    """
    # Calculate pairwise squared Euclidean distances
    # in the MxN dimensional dataset.
    sq_dists = pdist(X, 'sqeuclidean')

    # Convert pairwise distances into a square matrix.
    mat_sq_dists = squareform(sq_dists)

    # Compute the symmetric kernel matrix.
    K = exp(-gamma * mat_sq_dists)

    # Center the kernel matrix.
    N = K.shape[0]
    one_n = np.ones((N, N)) / N
    K = K - one_n.dot(K) - K.dot(one_n) + one_n.dot(K).dot(one_n)

    # Obtaining eigenpairs from the centered kernel matrix
    # numpy.eigh returns them in sorted order
    eigvals, eigvecs = eigh(K)
    print(np.sqrt(eigvals[-1]))
    print(np.sqrt(eigvals[-2]))

    # Collect the top k eigenvectors (projected samples)
    #X_pc = np.column_stack((eigvecs[:, -i]
    #                        for i in range(1, n_components + 1)))

    # scikit-learnの結果と比べてみても, たぶんこれが正しい気がする
    # ただ結局各成分にスケール因子が入るだけなので、
    # 学習という意味ではどちらでも良いのかもしれない
    X_pc = np.column_stack((np.sqrt(eigvals[-i]) * eigvecs[:, -i]
                            for i in range(1, n_components + 1)))

    # PCA固有ベクトルvをデータサンプルに直すには X v とする必要がある
    # ここで正規化された特異ベクトルの間の関係を使う。
    #   X v_i = sigma_i a_i      (sigma_i = sqrt(lambda_i))
    # よって sqrt(lambda_i) a_i で主成分方向に基底変換したデータサンプルになる。

    return X_pc

##
# 本文の後で出てくるバージョン
# 計算は一緒で返すものが違うだけ
# 固有値と固有ベクトルを返す
#
def rbf_kernel_pca2(X, gamma, n_components):
    """
    RBF kernel PCA implementation.

    Parameters
    ------------
    X: {NumPy ndarray}, shape = [n_samples, n_features]

    gamma: float
      Tuning parameter of the RBF kernel

    n_components: int
      Number of principal components to return

    Returns
    ------------
     X_pc: {NumPy ndarray}, shape = [n_samples, k_features]
       Projected dataset

     lambdas: list
       Eigenvalues

    """
    # Calculate pairwise squared Euclidean distances
    # in the MxN dimensional dataset.
    sq_dists = pdist(X, 'sqeuclidean')

    # Convert pairwise distances into a square matrix.
    mat_sq_dists = squareform(sq_dists)

    # Compute the symmetric kernel matrix.
    K = exp(-gamma * mat_sq_dists)

    # Center the kernel matrix.
    N = K.shape[0]
    one_n = np.ones((N, N)) / N
    K = K - one_n.dot(K) - K.dot(one_n) + one_n.dot(K).dot(one_n)

    # Obtaining eigenpairs from the centered kernel matrix
    # numpy.eigh returns them in sorted order
    eigvals, eigvecs = eigh(K)

    # Collect the top k eigenvectors (projected samples)
    alphas = np.column_stack((eigvecs[:, -i]
                              for i in range(1, n_components + 1)))

    # Collect the corresponding eigenvalues
    lambdas = [eigvals[-i] for i in range(1, n_components + 1)]

    return alphas, lambdas

import numpy as np
from scipy.spatial.distance import pdist, squareform
from scipy import exp
from scipy.linalg import eigh

##
# カーネルを線形にしてみた
# test_kpca.py で使う
#
def linear_kernel_pca(X, n_components):
    """
    RBF kernel PCA implementation.

    Parameters
    ------------
    X: {NumPy ndarray}, shape = [n_samples, n_features]

    gamma: float
      Tuning parameter of the RBF kernel

    n_components: int
      Number of principal components to return

    Returns
    ------------
     X_pc: {NumPy ndarray}, shape = [n_samples, k_features]
       Projected dataset

    """
    # 線形カーネル関数は内積(x_i, x_j)とする
    N = X.shape[0]
    K = np.ones((N, N))
    for i in range(N):
        for j in range(N):
            K[i, j] = np.dot(X[i, :], X[j, :])
    print(K.shape)

    # Center the kernel matrix.
    N = K.shape[0]
    one_n = np.ones((N, N)) / N
    K = K - one_n.dot(K) - K.dot(one_n) + one_n.dot(K).dot(one_n)

    # Obtaining eigenpairs from the centered kernel matrix
    # numpy.eigh returns them in sorted order
    eigvals, eigvecs = eigh(K)
    print(np.sqrt(eigvals[-1]))
    print(np.sqrt(eigvals[-2]))

    # Collect the top k eigenvectors (projected samples)
    #X_pc = np.column_stack((eigvecs[:, -i]
    #                        for i in range(1, n_components + 1)))

    # scikit-learnの結果と比べてみても, たぶんこれが正しい気がする
    # ただ結局各成分にスケール因子が入るだけなので、
    # 学習という意味ではどちらでも良いのかもしれない
    X_pc = np.column_stack((np.sqrt(eigvals[-i]) * eigvecs[:, -i]
                            for i in range(1, n_components + 1)))

    # PCA固有ベクトルvをデータサンプルに直すには X v とする必要がある
    # ここで正規化された特異ベクトルの間の関係を使う。
    #   X v_i = sigma_i a_i      (sigma_i = sqrt(lambda_i))
    # よって sqrt(lambda_i) a_i で主成分方向に基底変換したデータサンプルになる。

    return X_pc


'''
Dada a função f(x)=A.sen(x)/x

onde A = 10. Calcule \int_0^\pi f(x) dx

    1. Use o método de tentativa e erro
    2. Use o método de amostragem média
'''
import numpy as np
import matplotlib.pyplot as plt
import random as rand

def montecarlotnterr(fx, sup, inf, esq, dir, n):
    xs = list(rand.uniform(esq, dir) for i in range(n))
    ys = list(rand.uniform(inf, sup) for i in range(n))
    ni = 0
    for x, y in zip(xs, ys):
        if y <= fx(x):
            ni += 1
    return (ni/n)*((dir-esq)*(sup-inf))

def montecarlomed(fx, esq, dir, n):
    xs = np.array(list(rand.uniform(esq, dir) for i in range(n)))
    ym = sum(fx(xs))/n
    return (dir - esq) * ym

a = 10
n = 1000
fx = lambda x: a * np.sin(x)/x

# Atividade
print('Integração por Monte Carlo')
print(f'N = {n}')
print(f'Tentativa e Erro = {montecarlotnterr(fx, 10, 0, 0, np.pi, n)}')
print(f'Amostragem Média = {montecarlomed(fx, 0, np.pi, n)}')

ns = np.arange(1, n)
itent = []
imed = []
for i in ns:
    itent.append(montecarlotnterr(fx, 10, 0, 0, np.pi, i))
    imed.append(montecarlomed(fx, 0, np.pi, i))

plt.plot(ns, itent, label='Tentativa e Erro')
plt.plot(ns, imed, label='Amostragem Média')
plt.xlabel('N')
plt.ylabel('Integral')
plt.legend()
plt.grid()
plt.savefig("funcaomontecarlo.png")


# -*- coding: utf-8 -*-
"""Computing Running Statistics from STDIN.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/18XZ5vEJ_la98Wz5pkQWXrlLUScJ0RGFu

Hello,

Thank you for completing the assessments.

The next step is to complete the coding challenge for Robert, our lead Instructor, to review.

Coding Challenge

Write a program that reads a list of numbers and for each number outputs an estimate of the running mean, running standard deviation, and running median.  The input should be read from standard in, with one number per line.  For each line of input, the program should print to standard out the estimated running mean, running standard deviation, and running median.  That is, given the input

1

2

3

137.036

the program should output values close to

1,0,1

1.5,0.5,1.5

2,0.816,2

35.759,58.477,2.5

Some notes:

Using either the biased or unbiased estimate of the standard deviation is fine, but you should report a number even for the first step.
There are several ways to define the median for an even number of samples; you may use any of these definitions.
Output numbers at a reasonable precision.

You will probably have to strike a balance between the accuracy of the results and  resources your program requires.  Choose a sensible tradeoff.  Better yet, allow this to be configurable.

Ideally, this program should be able to handle arbitrarily long lists of inputs.  It would be nice for it to output results as soon as possible, instead of needing to wait for all of standard in to be read.  You do not have to worry about malicious input (there won’t be 10 GB on a single line), but gracefully handling malformed input lines is a plus.

Upload your solution to the public DVCS host of your choice, and send us a link to the repository.  You may use any programming language or packages you like, but if you use anything outside of Python 3, Pandas, or Numpy, please include instructions to help us run your code.

Thank you,
"""

from collections import deque
import math
import numpy as np

class RunningStatistics:

    def __init__(self, max_med_samples=10000, sd_type='unbiased'):
        self.n = 0
        self.old_mean = 0
        self.new_mean = 0
        self.old_std = 0
        self.new_std = 0
        self.med_q = deque(maxlen=max_med_samples)
        self.sd_type = sd_type

    def clear(self):
        self.n = 0
        self.med_q.clear()

    def push(self, x):
        self.n += 1

        # For mean and standard deviation
        if self.n == 1:
            self.old_mean = self.new_mean = x
            self.old_std = 0
        else:
            self.new_mean = self.old_mean + (x - self.old_mean) / self.n
            self.new_std = self.old_std + (x - self.old_mean) * (x - self.new_mean)

            self.old_mean = self.new_mean
            self.old_std = self.new_std

        # For median
        self.med_q.append(x)

    def mean(self):
        return self.new_mean if self.n else 0.0

    def standard_deviation(self):
        if self.sd_type=='unbiased':
          return math.sqrt(self.new_std / (self.n - 1)) if self.n > 1 else 0.0
        else:
          return math.sqrt(self.new_std / (self.n)) if self.n > 1 else 0.0

    def median(self):
        return np.median(self.med_q)

rs = RunningStatistics(1000,'biased')
display_dec_places = 4

while True:

  # Prompt and get user input (one value at a time)
  input_val = input("Enter a numeric value (or type q to exit): ")

  # Break on specified input value
  if input_val=='q':
    break

  # Check input value for proper type, ignore if not
  try:
    input_num = float(input_val)
  except:
    continue

  # Check input value for NaN or +/-Inf, ignore if so
  if math.isnan(input_num) or math.isinf(input_num):
    continue

  # Do the computations
  rs.push(input_num)

  # Return the result
  print(np.round(rs.mean(), display_dec_places),
         np.round(rs.standard_deviation(), display_dec_places),
         np.round(rs.median(), display_dec_places))


import numpy as np
import pytest

from utils import rotate_all

sq = 1/np.sqrt(2)
testdata0 = [
    (np.array([[0., 1.], [1., 0.], [0., -1.]], dtype=float), np.pi,
     np.array([[0., -1.], [-1., 0.], [0., 1.]], dtype=float)),
    (np.array([[0., 1.], [1., 0.], [0., -1.]], dtype=float), -np.pi,
     np.array([[0., -1.], [-1., 0.], [0., 1.]], dtype=float)),
    (np.array([[0., 1.], [1., 0.], [0., -1.]], dtype=float), np.pi/2,
     np.array([[-1., 0.], [0., 1.], [1., 0.]], dtype=float)),
    (np.array([[0., 1.], [1., 0.], [0., -1.]], dtype=float), -np.pi/2,
     np.array([[1., 0.], [0., -1.], [-1., 0.]], dtype=float)),
    (np.array([[0., 1.], [1., 0.], [0., -1.]], dtype=float), np.pi/4,
     np.array([[-sq, sq], [sq, sq], [sq, -sq]], dtype=float)),
    (np.array([[0., 1.], [1., 0.], [0., -1.]], dtype=float), -np.pi/4,
     np.array([[sq, sq], [sq, -sq], [-sq, -sq]], dtype=float))
    ]

@pytest.mark.parametrize("vectors,angle,expected", testdata0)
def test_rotate_all(vectors, angle, expected):
    new_vectors = rotate_all(vectors, angle)

    assert np.allclose(new_vectors, expected)


"""
==========================
Discrete Fourier Transform
==========================

This example shows how to approximate a time series using only
some of its Fourier coefficients using
:class:`pyts.approximation.DiscreteFourierTransform`.
"""

import numpy as np
import matplotlib.pyplot as plt
from pyts.approximation import DiscreteFourierTransform

# Parameters
n_samples, n_timestamps = 100, 48

# Toy dataset
rng = np.random.RandomState(41)
X = rng.randn(n_samples, n_timestamps)

# DFT transformation
n_coefs = 30
dft = DiscreteFourierTransform(n_coefs=n_coefs, norm_mean=False,
                               norm_std=False)
X_dft = dft.fit_transform(X)

# Compute the inverse transformation
if n_coefs % 2 == 0:
    real_idx = np.arange(1, n_coefs, 2)
    imag_idx = np.arange(2, n_coefs, 2)
    X_dft_new = np.c_[
        X_dft[:, :1],
        X_dft[:, real_idx] + 1j * np.c_[X_dft[:, imag_idx],
                                        np.zeros((n_samples, ))]
    ]
else:
    real_idx = np.arange(1, n_coefs, 2)
    imag_idx = np.arange(2, n_coefs + 1, 2)
    X_dft_new = np.c_[
        X_dft[:, :1],
        X_dft[:, real_idx] + 1j * X_dft[:, imag_idx]
    ]
X_irfft = np.fft.irfft(X_dft_new, n_timestamps)

# Show the results for the first time series
plt.figure(figsize=(12, 8))
plt.plot(X[0], 'o--', label='Original')
plt.plot(X_irfft[0], 'o--', label='DFT - {0} coefs'.format(n_coefs))
plt.legend(loc='best', fontsize=14)
plt.show()


import numpy as np

def spiral_data(points, classes):
    # https://cs231n.github.io/neural-networks-case-study/
    X = np.zeros((points*classes, 2))
    y = np.zeros(points*classes, dtype='uint8')
    for class_number in range(classes):
        ix = range(points*class_number, points*(class_number+1))
        r = np.linspace(0.0, 1, points)  # radius
        t = np.linspace(class_number*4, (class_number+1)*4,
                        points) + np.random.randn(points)*0.2
        X[ix] = np.c_[r*np.sin(t*2.5), r*np.cos(t*2.5)]
        y[ix] = class_number
    return X, y

'''
import matplotlib.pyplot as plt
x, y = spiral_data(1000, 3)
plt.scatter(x[:, 0], x[:, 1], c=y)
plt.show()
'''


# This little code fragment implements a fourth order compact finite difference scheme with edge formulae
# RMC May 2019 U. Alcala, in Alcala de Henares

from numpy import linalg as LA
import numpy as np # Already done earlier in the notebook
from scipy import sparse
import scipy as sp # Already done earlier in the notebook

n = 673
if n<= 3:
    raise Exception('Sorry, friend, but this code needs 4 or more pieces of data')

x = np.array([np.cos(np.pi*(n-1-i)/(n-1)) for i in range(n)])
h = np.diff(x)

y = np.zeros(x.shape)

# Build tridiagonal matrix (floating point type, by contagion)
# subs == vector of subdiagonal entries
# diags == vector on diagonal entries
# supers == vector of superdiagonal entries
# Matrix as in the paper Compact Finite Differences and Cubic Splines
diags = np.array([4.0 for i in range(n)])
diags[0] = h[1]*(h[1]+h[2])/(h[0]+h[1])/(h[0]+h[1]+h[2])
diags[-1] = h[-2]*(h[-3]+h[-2])/(h[-2]+h[-1])/(h[-3]+h[-2]+h[-1])

subs = np.array([4.0*h[i+1]**2/(h[i]+h[i+1])**2 for i in range(n-2)]+[1])

supers = np.array([1]+[4.0*h[i]**2/(h[i]+h[i+1])**2 for i in range(n-2)])

# This factors the tridiagonal matrix.  We need only adjust the
# lower vector and the diagonal vector (the matrix is positive definite)
ell = np.zeros(subs.shape)
de  = np.zeros(diags.shape)
de[0] = diags[0]
for i in range(1,n):
    ell[i-1] = subs[i-1]/de[i-1]
    de[i]    = diags[i] - ell[i-1]*supers[i-1]

# Some made-up function to differentiate (to test)
fndata = np.zeros(diags.shape)
def fn(x):
    return 1.0/(1+x*x) # np.cos(x)
def dfn(x):
    return -2*x/(1+x*x)**2 #-1*np.sin(x)

for i in range(n):
    fndata[i] = fn(x[i])

# We will carry out the B.b operation manually; this will save storing the vectors
b = np.zeros(fndata.shape)

# Hand-translated from the Matlab (quite surprising that it worked, really)
a0 = (4*h[0]**2+6*h[0]*h[1]+3*h[0]*h[2]+2*h[1]**2+2*h[1]*h[2])*h[1]*(h[2]+h[1])/(h[0]+h[1])**2/(h[0]+h[1]+h[2])**2/h[0]
a1 = 1/h[0]*((-2*h[1]+h[0])*h[2]+2*h[1]*(-h[1]+h[0]))/h[1]/(h[1]+h[2])
a2 = -h[0]**2*(h[2]+h[1])/(h[1]+h[0])**2/(h[1])/h[2]
a3 = h[0]**2*h[1]/(h[2]+h[1]+h[0])**2/(h[2]+h[1])/h[2]
b[0] = -(a0*fndata[0] + a1*fndata[1] + a2*fndata[2] + a3*fndata[3])
for i in range(1,n-1):
    a0 = 4*h[i]**2*2*(2*h[i-1]+h[i])/h[i-1]/(h[i-1]+h[i])**3
    a1 = -8*(-h[i-1]+h[i])/h[i-1]/h[i]
    a2 = -8*h[i-1]**2*(h[i-1]+2*h[i])/(h[i-1]+h[i])**3/h[i]
    b[i] = -(a0*fndata[i-1] + a1*fndata[i] + a2*fndata[i+1])

a0 = -h[-2]*h[-1]**2/(h[-3]+h[-2]+h[-1])**2/(h[-3]+h[-2])/h[-3]
a1 = h[-1]**2/(h[-2]+h[-1])**2/h[-2]/h[-3]*(h[-2]+h[-3])
a2 = 1/h[-1]*((2*h[-2]-h[-1])*h[-3]+2*h[-2]*(h[-2]-h[-1]))/h[-2]/(h[-3]+h[-2])
a3 = -(4*h[-1]**2+(6*h[-2]+3*h[-3])*h[-1]+2*h[-2]*(h[-3]+h[-2]))/h[-1]/(h[-2]+h[-1])**2/(h[-3]+h[-2]+h[-1])**2*(h[-2])*(h[-2]+h[-3])

b[-1] = -(a0*fndata[-4] + a1*fndata[-3] + a2*fndata[-2] + a3*fndata[-1])

# This solves the tridiagonal system, given the factoring above.
# I should really peel those out into TRIDECOMP and TRISOLVE,
# implementing the so-called Thomas algorithm in a reasonably
# maintainable and re-usable way. Well, this is at this point
# just an exercise, and who will ever see this code except me?
#
# Oh, wait.  That never happens.  This code is going to escape into the wild,
# isn't it.
#
# Oops. nvm
#
y = np.zeros(b.shape)
y[0] = b[0]
for i in range(1,n):
    y[i] = b[i] - ell[i-1]*y[i-1]

sol = np.zeros(x.shape)
sol[-1] = y[-1]/de[-1]

for i in range(n-2,-1,-1): # start, stop, step (goofy language)
    sol[i] = (y[i]-supers[i]*sol[i+1])/de[i]

dy = np.zeros(x.shape)
for i in range(n):
    dy[i] = dfn(x[i])

print(LA.norm(sol-dy,2)*(n/2)**4) # This is the scaled error of derivatives at all the nodes

import numpy,from numpy,import scipy,from scipy


from IMLearn.learners import UnivariateGaussian, MultivariateGaussian
import numpy as np
import plotly.graph_objects as go
import plotly.io as pio

pio.templates.default = "plotly"

def test_univariate_gaussian():
    # Question 1 - Draw samples and print fitted model
    mu = 10
    var = 1

    samples = np.random.normal(mu, var, 1000)
    uni_gaussian = UnivariateGaussian()
    uni_gaussian.fit(samples)
    print("\nEstimated Expectation and Variance:")
    print((uni_gaussian.mu_, uni_gaussian.var_))

    # Question 2 - Empirically showing sample mean is consistent
    distance = np.empty(100)
    nums = np.arange(10, 1010, 10)

    for i, num in enumerate(nums):
        uni_gaussian.fit(samples[:num])
        distance[i] = abs(mu - uni_gaussian.mu_)

    plot1 = go.Figure(data=[go.Scatter(x=nums, y=distance, mode='markers')])
    plot1.update_layout(title_text='Distance of Empirical Mean from Actual Mean for Different Sample Sizes') \
        .update_yaxes(title_text='Distance of Empirical Mean from Actual Mean') \
        .update_xaxes(title_text='Sample Size')
    plot1.show()

    # Question 3 - Plotting Empirical PDF of fitted model
    pdfs = uni_gaussian.pdf(samples)

    plot2 = go.Figure(data=[go.Scatter(x=samples, y=pdfs, mode='markers')])
    plot2.update_layout(title_text='PDF Values of Random Samples') \
        .update_yaxes(title_text='PDF Value') \
        .update_xaxes(title_text='Sample Value')
    plot2.show()

def test_multivariate_gaussian():
    # Question 4 - Draw samples and print fitted model
    mu = np.array([0, 0, 4, 0])
    cov = np.array([[1, 0.2, 0, 0.5],
                    [0.2, 2, 0, 0],
                    [0, 0, 1, 0],
                    [0.5, 0, 0, 1]])

    samples = np.random.multivariate_normal(mu, cov, 1000)
    multi_gaussian = MultivariateGaussian()
    multi_gaussian.fit(samples)
    print("\nEstimated Expectation:")
    print(multi_gaussian.mu_)
    print("\nEstimated Covariance:")
    print(multi_gaussian.cov_)

    # Question 5 - Likelihood evaluation
    values = np.linspace(-10, 10, 200)

    log_likelihood = np.empty((200, 200))

    max_likelihood, max_pair = None, None
    for i, f1 in enumerate(values):
        for j, f3 in enumerate(values):
            new_mu = np.array([f1, 0, f3, 0])
            log_likelihood[i][j] = multi_gaussian.log_likelihood(new_mu, cov, samples)

            if max_likelihood is None or log_likelihood[i][j] > max_likelihood:
                max_likelihood = log_likelihood[i][j]
                max_pair = (f1, f3)

    fig = go.Figure(data=go.Heatmap(x=values, y=values, z=log_likelihood)) \
        .update_layout(title_text="Likelihood of a Given Sample for Different Expectations") \
        .update_yaxes(title_text="f1 value") \
        .update_xaxes(title_text="f3 value")

    fig.show()

    # Question 6 - Maximum likelihood
    print("\nMax log-likelihood: ", round(max_likelihood, 3))
    print("Max pair:", (round(max_pair[0], 3), round(max_pair[1], 3)))

if __name__ == '__main__':
    np.random.seed(0)
    test_univariate_gaussian()
    test_multivariate_gaussian()


import sympy as sp
from final_exam.numerical_diff import *

x = sp.Symbol('x')
f = sp.E**(-x)
x0 = 1

print(cd(f, x, x0))
print(bd(f, x, x0))
print(fd(f, x, x0))
print()
print(cd2(f, x, x0))
print(bd2(f, x, x0))
print(fd2(f, x, x0))


import numpy as np

def softmax(x):
    """Compute softmax values for each sets of scores in x."""
    # TODO: Compute and return softmax(x)
    result = np.exp(x)/np.sum(np.exp(x), axis=0)
    return result

logits = [3.0, 1.0, 0.2]
print(softmax(logits))


#!/usr/bin/env python -W ignore
import numpy as np

# матриця Леслі
L = np.array([
	[  0,   6, 15],
	[0.5,   0,  0],
	[  0, 0.5,  0]
])

# початковий розподіл популяції
x0 = np.array([1, 1, 1])

# розподіл через t = 5 кроків обчислюємо як L^t * x0
t = 5
xt = np.dot(np.linalg.matrix_power(L, t), x0)
print(f'x({t}) = {xt}')  # x(5) = [239.625   55.125   16.6875]

# знаходимо власні значення і власні вектори
_lambda, x = np.linalg.eig(L)
# знаходимо найбільше додатне власне значення
lambda_L = np.max(_lambda)

print(f'lambda_L = {np.float_(lambda_L)}')  # lambda_L = 2.173738392044369

# знаходимо власний вектор що йому відповідає
x_L = x[:, _lambda == lambda_L].T[0]
# нормуємо цей вектор в || ||_1 нормі
x_L /= np.linalg.norm(x_L, 1)

print(f'x_L = {np.abs(np.float_(x_L))}')  # x_L = [0.77946759 0.17929195 0.04124046]

# знаходимо min t: ||x(t)||_1 > 75
t = 0
while np.sum(x0) <= 75:
	x0 = np.dot(L, x0)
	t += 1

print(f't = {t}, X({t}) = {np.sum(x0)}')  # t = 3, X(3) = 77.25


from __future__ import division             # forces floating point division
import numpy as np                          # Numerical Python
import matplotlib.pyplot as plt             # Python plotting
from PIL import Image                       # Python Imaging Library
from numpy.fft import fft2, fftshift, ifft2 # Python DFT
import math

img = Image.open("Waldo_temp.jpg")
data = img.getdata()

r,g,b = img.split()
print(r, g, b)

r_np = np.array(r)
g_np = np.array(g)
b_np = np.array(b)

g_b_surpessed = r_np-(0.5*g_np+b_np)

img_one = Image.fromarray(g_b_surpessed )
plt.imshow(img_one)
plt.show()

I = img_one.convert('L')                     # 'L' for gray scale mode
A3 = np.asarray(I, dtype = np.float64)  # Image class instance, I1, to float32 Numpy array, a

H,W = np.shape(A3)
hW = int(np.fix(0.5*W))
hH = int(np.fix(0.5*H))

F3 = fft2(A3)/(W*H)
F3 = fftshift(F3)

xx,yy = np.meshgrid(np.linspace(-W/2,W/2,W), np.linspace(-H/2,H/2,H))
sf=0.2031
sigma = 1/sf;  #width of Gaussian (1/e half-width)
Gaussian = np.exp(-(xx**2+yy**2)/sigma**2);

gratingSin = np.sin(2*np.pi*sf*yy)
GaborSin = gratingSin*Gaussian;
F3_sin = fft2(GaborSin)/(W*H)
F3_sin = fftshift(F3_sin)
Filter_sin = F3*F3_sin
filtImgSin = ifft2(Filter_sin)*W*H
filtImgSin = fftshift(filtImgSin)

gratingCos = np.cos(2*np.pi*sf*yy)
GaborCos = gratingCos*Gaussian;
F3_cos = fft2(GaborCos)/(W*H)
F3_cos = fftshift(F3_cos)
Filter_cos = F3*F3_cos
filtImgCos = ifft2(Filter_cos)*W*H
filtImgCos = fftshift(filtImgCos)

filtImg = np.sqrt(filtImgSin**2+filtImgCos**2)
# filtImg = filtImgSin

attenuateImg = filtImg/np.max(filtImg)
attenuateImg = np.abs((attenuateImg+.25)/1.2)

center_coord = np.where(attenuateImg == np.amax(attenuateImg))
box_radius = 25
for x_coord in range(center_coord[0][0]-box_radius, center_coord[0][0]+box_radius):
	for y_coord in range(center_coord[0][0]-box_radius, center_coord[1][0]+box_radius):
		attenuateImg[x_coord, y_coord] = 0.9

attenuateImg_transposed = np.asarray([attenuateImg]*3).transpose(1, 2, 0)
# attenuateImg = np.abs(filtImg)
new_img = np.asarray(np.asarray(img, dtype = np.float64)*attenuateImg_transposed, dtype="uint8");

plt.imshow(np.abs(new_img))
plt.show()


import math
import csv
import numpy as np
import matplotlib.pyplot as plt
from sklearn import naive_bayes
color = ['black', 'white', 'saddlebrown', 'red', 'peru', 'darkorange', 'gold', 'khaki', 'yellow', 'lawngreen', 'darkgreen', 'cyan', 'deepskyblue', 'steelblue', 'royalblue', 'navy', 'indigo', 'darkviolet', 'purple', 'magenta', 'crimson']

def read_data(filename):
    data_set = []
    with open(filename, 'r') as f:
        lines = csv.reader(f)
        keys = []
        for line in lines:
            if line and not line[0].strip().startswith('#'):
                dict = {}
                for idx, val in enumerate(line):
                    if val.strip().replace('.', '').isdecimal():
                        val = float(val)
                    dict[keys[idx].replace('#', '')] = val
                data_set.append(dict)
            else:
                keys = [val.replace('"', '') for val in line]
    return data_set

def get_corr(x, y):
    m_x, m_y = [], []
    for val in x:
        m_x.append(sum(val)/len(val))
    for val in y:
        m_y.append(sum(val)/len(val))
    return np.corrcoef(np.vstack((np.array(m_x), np.array(m_y))))

def get_transpose(deg, xs):
    M = np.empty((0, len(xs)))
    for i in range(deg+1):
        M = np.vstack((xs**i, M))
    return M.T

if __name__ == '__main__':
    tfr = read_data("TFR.csv")
    rep = read_data("avgREP.csv")

    # correlation tfr-rep
    tfr_val, rep_val = [], []
    for i in range(len(rep)):
        tfr_val.append(list(tfr[i].values())[7:])
        rep_val.append(list(rep[i].values())[1:])
    tfr_val, rep_val = np.array(tfr_val).T, np.array(rep_val).T

    corr_tfr_rep = get_corr(tfr_val, rep_val)

    plt.figure()
    plt.title(f'Correlation between Total Fertility Rate and Real Estate Price ({corr_tfr_rep[0][1]:.3f})')
    plt.xlim([np.min(tfr_val)-0.3, np.max(tfr_val)+0.3])
    plt.xlabel('Total Fertility Rate (One per childbearing woman)')
    plt.ylim([np.min(rep_val)-20, np.max(rep_val)+20])
    plt.ylabel('Real Estate Price (2017.4Q=100))')
    plt.grid()
    for i in range(len(tfr_val)):
        plt.scatter(tfr_val[i], rep_val[i], marker='.', c=color[i], edgeColor="black", s=200, label=str(2006+i))
    plt.legend()
    plt.show()

    # correlation tfr-div
    tfr_val= []
    for i in range(len(tfr)):
        tfr_val.append(list(tfr[i].values())[1:])
    tfr_val = np.array(tfr_val).T

    div = read_data('divorce.csv')
    div_val = []
    for i in range(len(div)):
        div_val.append(list(div[i].values())[1:])
    div_val = np.array(div_val).T

    corr_tfr_div = get_corr(tfr_val, div_val)

    plt.figure()
    plt.title(f'Correlation between Total Fertility Rate and Divorce Rate ({corr_tfr_div[0][1]:.3f})')
    plt.xlim([np.min(tfr_val)-0.3, np.max(tfr_val)+0.3])
    plt.xlabel('Total Fertility Rate (One per childbearing woman)')
    plt.ylim([np.min(div_val)-0.5, np.max(div_val)+0.5])
    plt.ylabel('Crude Divorce Rate')
    plt.grid()
    for i in range(len(tfr_val)):
        plt.scatter(tfr_val[i], div_val[i], marker='.', c=color[-i], edgeColor="black", s=200, label=str(2000+i))
    plt.legend()
    plt.show()

    # Predict tfr to 2035
    xsp = np.linspace(-2, 45, 200)
    year = np.array([i for i in range(21)])
    tfr_val = np.array(list(tfr[0].values())[1:])

    exp_fit = np.polyfit(year, np.log(tfr_val), 1)
    exp_y = np.exp(exp_fit[1])*np.exp(exp_fit[0]*xsp)

    coeff = np.matmul(np.linalg.pinv(get_transpose(2, year)), tfr_val)
    poly_y = np.matmul(get_transpose(2, xsp), coeff)
    y2 = []
    for i, v in enumerate(exp_y):
        y2.append(math.sqrt((v**2 + poly_y[i]**2)/2))

    coeff = np.matmul(np.linalg.pinv(get_transpose(3, year)), tfr_val)
    poly_y = np.matmul(get_transpose(3, xsp), coeff)
    y3 = []
    for i, v in enumerate(exp_y):
        y3.append(math.sqrt((v**2 + poly_y[i]**2)/2))

    plt.figure()
    plt.title('Prediction of Total Fertility Rate using Curve Fitting')
    plt.xlim([-2, 35])
    plt.xlabel('year (0: 2000)')
    plt.ylim([np.min(tfr_val)-0.3, np.max(tfr_val)+0.3])
    plt.ylabel('Total Fertility Rate (One per childbearing woman)')
    for i in range(len(tfr_val)):
        plt.scatter(i, tfr_val[i], marker='o', c='red')
    plt.plot(xsp, exp_y, 'r-', label='exp')
    plt.plot(xsp, y2, 'b-', label='2*exp')
    plt.plot(xsp, y3, 'g-', label='3*exp')
    plt.legend()
    plt.show()


import numpy as np
from math import log
#calculate the shanno entropy
def calc_shanno_ent(data_set):
    num_entries = len(data_set)
    label_count ={}
    for feature_vec in data_set:
        current_label = data_set[-1]
        if current_label not in label_count.keys():
            label_count[current_label] =0
        label_count[current_label] = label_count[current_label]+1
    shanno_ent = 0
    for key in label_count.keys():
        prob = float(label_count[key] / num_entries)
        shanno_ent -=prob* log(prob,2)
    return shanno_ent
# split the dataset
def split_dataset(dataset, axis, value):
    ret_dataset = []
    for feature in dataset:
        if feature[axis] == value:
            reduced_dataset = feature[:axis]
            reduced_dataset.extend(feature[axis+1:])
            ret_dataset.append(reduced_dataset)
    return ret_dataset
def choose_feature_to_split(dataset):
    num_features = len(dataset)-1
    base_ent = calc_shanno_ent(dataset)
    info_gain = 0
    best_info_gain = 0.0
    best_feature = -1
    for i in range(num_features):
        feature_list = [example[i] for example in dataset]
        #very good job
        unique_value = set(feature_list)

        new_ent = 0.0
        for value in unique_value:
            split_data = split_dataset(dataset,i,value)
            prob = len(split_data)/len(dataset)
            new_ent += prob*calc_shanno_ent(split_data)
        info_gain = base_ent - new_ent
        if info_gain > best_info_gain:
            best_info_gain = info_gain
            best_feature = i
    return best_feature
def majorityCnt(class_list):
    class_count = {}
    for vote in class_list:
        if vote not in class_count.keys():
            class_count[vote] = 0
        class_count[vote] +=1
    sorted_class_count = sorted(class_count.items(), key= lambda x: x[1], reverse=True)
    # Debug and see why the index is [0][0]
    return sorted_class_count[0][0]

def createTree(dataset, labels):
    class_list = [example[-1] for example in dataset]
    if class_list.count(class_list[0]) == len(class_list):
        return class_list[0]
    # debug
    if len(dataset[0] == 1):
        majorityCnt(class_list)
    best_feature = choose_feature_to_split(dataset)
    best_feature_label = labels[best_feature]
    tree = {best_feature_label:{}}
    del(labels[best_feature])
    feature_values = [example[best_feature] for example in dataset]
    unique_feature = set(feature_values)
    for value in unique_feature:
        # prevent changing the original list by reference
        sub_labels = labels[:]
        tree[best_feature_label][value] = createTree(split_dataset(dataset, best_feature,value), sub_labels)

    return tree

def classify(input_tree, feature_labels, test_vec):
    first_str = input_tree.keys()[0]
    second_dict = input_tree[first_str]
    feature_index = feature_labels.index(first_str)
    for key in second_dict.keys():
        if test_vec[feature_index] == key:
            if type(second_dict[key]) == 'dict':
                class_label = classify(second_dict[key], feature_labels, test_vec)
            else:
                class_label =  second_dict[key]
    return class_label


import numpy as np
from collections import defaultdict
import space
import scipy.linalg
import scipy.sparse
import scipy.sparse.linalg
from bc import Boundary

def ddx(f, dx):
    return (f[1:-1,2:] - f[1:-1,:-2])/2.0/dx

def ddy(f, dy):
    return (f[2:,1:-1] - f[:-2,1:-1])/2.0/dy

def laplacian(f, dx, dy):
    return (f[1:-1,2:] - 2.0*f[1:-1,1:-1] + f[1:-1,:-2])/dx/dx + \
           (f[2:,1:-1] -2.0*f[1:-1,1:-1] + f[:-2,1:-1])/dy/dy

def div(u,v,dx,dy):
    return ddx(u,dx) + ddy(v,dy)

def momentum(u, v, dx, dy, nu):
    # u rhs: - d(uu)/dx - d(vu)/dy + ν d2(u)
    # v rhs: - d(uv)/dx - d(vv)/dy + ν d2(v)

    return (
        - ddx(u*u,dx) - ddy(v*u,dy) + nu*laplacian(u,dx,dy),
        - ddx(u*v,dx) - ddy(v*v,dy) + nu*laplacian(v,dx,dy)
    )

def momentum_staggered(u, v, dx, dy, nu):
    # do x-momentum - u is of size (nx + 2) x (ny + 2) - only need to do the interior points
    # u is horizontonal component of velocity, dimension 1
    # LL = u[1,2] , UR = u[n,n]

    ue = 0.5*(u[1:-1, 2:-1] + u[1:-1, 3:  ])
    uw = 0.5*(u[1:-1, 1:-2] + u[1:-1, 2:-1])
    un = 0.5*(u[1:-1, 2:-1] + u[2:,   2:-1])
    us = 0.5*(u[:-2,  2:-1] + u[1:-1, 2:-1])
    vn = 0.5*(v[2:,   1:-2] + v[2:,   2:-1])
    vs = 0.5*(v[1:-1, 1:-2] + v[1:-1, 2:-1])

    convection = - (ue**2 - uw**2)/dx - (un*vn - us*vs)/dy
    diffusion = nu * laplacian(u,dx,dy)[:,1:]#[1:-1,2:-1]

    mx = convection + diffusion

    # do y-momentum - only need to do interior points
    # v is vertical component of velocity, staggered negative on dimension 0
    # v LL = v[2,1], UR = v[n,n]

    ve = 0.5*(v[2:-1, 1:-1] + v[2:-1, 2:  ])
    vw = 0.5*(v[2:-1, :-2 ] + v[2:-1, 1:-1])
    vn = 0.5*(v[2:-1, 1:-1] + v[3:,   1:-1])
    vs = 0.5*(v[1:-2, 1:-1] + v[2:-1, 1:-1])
    ue = 0.5*(u[1:-2, 2:  ] + u[2:-1, 2:  ])
    uw = 0.5*(u[1:-2, 1:-1] + u[2:-1, 1:-1])

    convection = - (ue*ve - uw*vw)/dx - (vn**2 - vs**2)/dy
    diffusion = nu * laplacian(v,dx,dy)[1:,:]#[2:-1,1:-1]

    my = convection + diffusion

    return mx, my

def pressure_poisson(u, v, dx, dy, dt, tol, max_its, b=None, p=None, bcs=None):
    bcs = bcs if bcs else []

    if b is None:
        b = np.zeros_like(u)

    if p is None:
        p = np.zeros_like(u)

    b[1:-1,1:-1] = div(u,v,dx,dy)/dt

    pn = p.copy()
    it = 0
    err = float("inf")

    while it < max_its and err > tol:
        for bc in bcs:
            bc.apply(p)

        np.copyto(pn, p)

        p[1:-1, 1:-1] = (((pn[1:-1, 2:] + pn[1:-1, 0:-2]) * dy**2 +
                          (pn[2:, 1:-1] + pn[0:-2, 1:-1]) * dx**2) /
                          (2 * (dx**2 + dy**2)) -
                          dx**2 * dy**2 / (2 * (dx**2 + dy**2)) *
                          b[1:-1,1:-1])

        err = np.linalg.norm(p - pn, 2)
        it += 1

    return p, err

def sparse_pressure_matrix(nx, ny, dx, dy, bc_left, bc_right, bc_bottom, bc_top):

    Ap = np.zeros([ny,nx])
    Ae = 1.0/dx/dx*np.ones([ny,nx])
    As = 1.0/dy/dy*np.ones([ny,nx])
    An = 1.0/dy/dy*np.ones([ny,nx])
    Aw = 1.0/dx/dx*np.ones([ny,nx])

    # a little optimistic that this generalizes to non-dirichlet bcs
    bc_left.apply(Aw)
    bc_right.apply(Ae)
    bc_bottom.apply(As)
    bc_top.apply(An)

    Ap = -(Aw + Ae + An + As)

    n = nx*ny
    d0 = Ap.reshape(n)
    de = Ae.reshape(n)[:-1]
    dw = Aw.reshape(n)[1:]
    ds = As.reshape(n)[nx:]
    dn = An.reshape(n)[:-nx]
    A1 = scipy.sparse.diags([d0, de, dw, dn, ds], [0, 1, -1, nx, -nx], format='csr')

    return A1

def pressure_poisson_sparse(A1, u, v, dx, dy, dt, nx, ny):
    # do pressure - prhs = 1/dt * div(uhat)
    # we will only need to fill the interior points. This size is for convenient indexing
    divut = np.zeros([ny+2,nx+2])
    #divut[1:-1,1:-1] = ddx(ut,dx) + ddy(vt,dy)#div(ut,vt,dx,dy)
    divut[1:-1,1:-1] = (u[1:-1,2:] - u[1:-1,1:-1])/dx + (v[2:,1:-1] - v[1:-1,1:-1])/dy

    prhs = 1.0/dt * divut

    ###### Use the sparse linear solver
    #     pt = scipy.sparse.linalg.spsolve(A1,prhs[1:-1,1:-1].ravel()) #theta=sc.linalg.solve_triangular(A,d)
    pt,info = scipy.sparse.linalg.bicg(A1,prhs[1:-1,1:-1].ravel(),tol=1e-10) #theta=sc.linalg.solve_triangular(A,d)
    return pt.reshape([ny,nx])

class Fluid:
    def __init__(self, space):
        self.space = space
        self.bcs = defaultdict(list)

    def add_boundary_condition(self, name, bc, **kwargs):
        bctype = bc.pop('type')
        self.bcs[name].append(bctype(space=self.space,**bc,**kwargs))

    def add_boundary_conditions(self, name, bcs, **kwargs):
        for bc in bcs:
            self.add_boundary_condition(name,bc,**kwargs)

    def get_boundary_conditions(self, name):
        return self.bcs[name]

    def get_boundary_condition(self, name, dim, b):
        for bc in self.bcs[name]:
            if bc.dim == dim and bc.b == b:
                return bc
        return None

    def solve(self, dt, cb=None, **kwargs):
        raise NotImplementedError

class NavierStokesProjectionMethod(Fluid):
    def __init__(self, N, extent, rho, nu, f=None):
        super().__init__(space=space.RegularGrid(N, extent))

        self.rho = rho # density
        self.nu = nu # viscosity
        self.f = np.zeros(2) if f is None else f

        self.u = np.zeros(self.space.N)
        self.v = np.zeros(self.space.N)
        self.p = np.zeros(self.space.N)

        self._x = [ np.zeros_like(self.p) for _ in range(3) ]

    def solve(self, dt, cb=None, its=100, p_tol=1e-3, p_max_its=50):
        cb = cb if cb is not None else lambda a,b,c,d: None

        u,v,p,uh,vh,b = self.u, self.v, self.p, self._x[0], self._x[1], self._x[2]

        dx,dy = self.space.delta

        p_bcs = self.get_boundary_conditions('p')
        u_bcs = self.get_boundary_conditions('u')
        v_bcs = self.get_boundary_conditions('v')

        for i in range(its):

            for bc in u_bcs:
                bc.apply(u)

            for bc in v_bcs:
                bc.apply(v)

            # do the x-momentum RHS
            uRHS, vRHS = momentum(u,v,dx,dy,self.nu)

            uh[1:-1,1:-1] = u[1:-1,1:-1] + dt*uRHS
            vh[1:-1,1:-1] = v[1:-1,1:-1] + dt*vRHS

            p,err = pressure_poisson(uh, vh, dx, dy, dt, b=b, p=p,
                                     tol=p_tol, max_its=p_max_its,
                                     bcs=p_bcs)

            # finally compute the true velocities
            # u_{n+1} = uh - dt*dpdx
            u[1:-1,1:-1] = uh[1:-1,1:-1] - dt*ddx(p,dx)
            v[1:-1,1:-1] = vh[1:-1,1:-1] - dt*ddy(p,dy)

            cb(i, u, v, p)

        np.copyto(self.u, u)
        np.copyto(self.v, v)

class NavierStokesFVM(Fluid):
    def __init__(self, N, extent, nu, beta):
        super().__init__(space=space.StaggeredGrid(N, extent))

        self.nu = nu
        self.beta = beta

        # initialize velocities - we stagger everything in the negative direction. A scalar cell owns its minus face, only.
        # Then, for example, the u velocity field has a ghost cell at x0 - dx and the plus ghost cell at lx
        self.u = np.zeros(self.space.N+2) # include ghost cells

        # # same thing for the y-velocity component
        self.v = np.zeros(self.space.N+2) # include ghost cells

        self.ut = np.zeros_like(self.u)
        self.vt = np.zeros_like(self.v)

        # initialize the pressure
        self.p = np.zeros(self.space.N+2) # include ghost cells

    def solve(self, dt, cb=None, its=100):
        ny,nx = self.space.N
        dy,dx = self.space.delta

        u,v,ut,vt,p = self.u, self.v, self.ut, self.vt, self.p

        u_bcs = self.get_boundary_conditions('u')
        v_bcs = self.get_boundary_conditions('v')
        p_bcs = [
            self.get_boundary_condition('p',dim=1,b=Boundary.MIN), # left
            self.get_boundary_condition('p',dim=1,b=Boundary.MAX), # right
            self.get_boundary_condition('p',dim=0,b=Boundary.MIN), # bottom
            self.get_boundary_condition('p',dim=0,b=Boundary.MAX), # top
        ]
        A1 = sparse_pressure_matrix(nx, ny, dx, dy, *p_bcs)

        nsteps = 1000
        for n in range(0,nsteps):
            for bc in u_bcs:
                bc.apply(u)

            for bc in v_bcs:
                bc.apply(v)

            mx, my = momentum_staggered(u, v, dx, dy, self.nu)

            ut[1:-1,2:-1] = u[1:-1,2:-1] + dt * mx
            vt[2:-1,1:-1] = v[2:-1,1:-1] + dt * my

            p[:,:] = 0
            p[1:-1,1:-1] = pressure_poisson_sparse(A1, ut, vt, dx, dy, dt, nx, ny)

            # time advance
            u[1:-1,2:-1] = ut[1:-1,2:-1] - dt * (p[1:-1,2:-1] - p[1:-1,1:-2])/dx
            v[2:-1,1:-1] = vt[2:-1,1:-1] - dt * (p[2:-1,1:-1] - p[1:-2,1:-1])/dy

class LatticeBoltzmann(Fluid):
    def __init__(self, N, extent, rho0, tau):
        super().__init__(space=space.LatticeGrid(N, extent))

        self.rho0 = 100    # average density
        self.tau = 0.6    # collision timescale

        self.F = np.zeros(np.append(self.space.N, [self.space.NL]))
        self.rho = np.zeros(self.space.N)
        self.ux = np.zeros(self.space.N)
        self.uy = np.zeros(self.space.N)

        self.object_mask = self.space.grid_coords[0] < 0

    @property
    def vorticity(self):
        v = ( (np.roll(self.ux, -1, axis=0) - np.roll(self.ux, 1, axis=0)) -
              (np.roll(self.uy, -1, axis=1) - np.roll(self.uy, 1, axis=1)) )
        v[self.object_mask] = np.nan
        return v

    def solve(self, dt, its, cb=None):
        Ny, Nx = self.space.N
        idxs, cxs, cys, weights = self.space.idxs, self.space.cxs, self.space.cys, self.space.weights

        self.rho = np.sum(self.F,2)
        for i in idxs:
            self.F[:,:,i] *= self.rho0 / self.rho

        # Simulation Main Loop
        for it in range(its):
            # Drift
            for i, cx, cy in zip(idxs, cxs, cys):
                self.F[:,:,i] = np.roll(self.F[:,:,i], cx, axis=1)
                self.F[:,:,i] = np.roll(self.F[:,:,i], cy, axis=0)

            # Set reflective boundaries
            bndryF = self.F[self.object_mask,:]
            bndryF = bndryF[:,[0,5,6,7,8,1,2,3,4]]

            # Calculate fluid variables
            self.rho = np.sum(self.F,2)
            self.ux  = np.sum(self.F*cxs,2) / self.rho
            self.uy  = np.sum(self.F*cys,2) / self.rho

            # Apply Collision
            Feq = np.zeros(self.F.shape)
            for i, cx, cy, w in zip(idxs, cxs, cys, weights):
                Feq[:,:,i] = self.rho * w * ( 1 + 3*(cx*self.ux+cy*self.uy) +
                                              9*(cx*self.ux+cy*self.uy)**2/2 -
                                              3*(self.ux**2+self.uy**2)/2 )

            self.F += -(1.0/self.tau) * (self.F - Feq)

            # Apply boundary
            self.F[self.object_mask,:] = bndryF
            self.ux[self.object_mask] = 0
            self.uy[self.object_mask] = 0

            if it % 10 == 0:
                if cb:
                    cb(it, self)


import numpy as np
import scipy.linalg

def matrix_transform():
    """
        目的是通过矩阵乘法实现变换 ------ 旋转，翻转
        **直接**进行切片操作的此处就不介绍了
    """
    # A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    A = np.arange(1, 10).reshape(3, 3)
    print('----- 原始矩阵 -----\n', A)

    B = np.eye(3)[[2, 1, 0]]
    # C = np.transpose(A)
    C = A.T

    print('----- 上下翻转 ----')
    A1 = B.dot(A)       # 左乘
    print(A1)
    print('----- 左右翻转 ----')
    A2 = A.dot(B)       # 右乘
    print(A2)

    print('----- 旋转180° ----')
    print(np.dot(A1, B))    # rotate180 = filpud + filplr
    print(np.dot(B, A2))    # rotate180 = filplr + filpud

    print('----- 旋转90°(以顺时针为正) ----')
    print(np.dot(C, B))     # rotate90 = transpose + filpud
    print('----- 旋转-90°(以顺时针为正) ----')
    print(np.dot(B, C))     # rotate-90 = transpose + filplr

def matrix_decomposition_lu():
    """
        https://baike.baidu.com/item/lu%E5%88%86%E8%A7%A3/764245?fr=aladdin
        scipy采用'列主元三角分解': A=PLU
        手动计算(高斯消元法): A=LU
    """
    A = np.matrix('2,3; 5,4')
    b = np.matrix('4,3').T

    print('----- LU分解 (返PLU参数)-----')
    p, l, u = scipy.linalg.lu(A)
    print(p)
    print(l)
    print(u)

    print('----- Ax=b (A=PLU) 求解x -----')
    y = np.linalg.solve(np.dot(p, l), b)
    x = np.linalg.solve(u, y)
    print(x)

    print('----- 直接解方程 -----')
    x = np.linalg.solve(A, b)
    print(x)

    """
    # 这个L相当于是上述的PL，形式很怪，此处不采用
    print('----- LU分解 (返LU参数)-----')
    l, u = scipy.linalg.lu(A, permute_l=True)
    print(l)
    print(u)
    """

if __name__ == "__main__":
    # matrix_transform()
    matrix_decomposition_lu()


# -*- encoding: utf-8 -*-
'''
@Time    :   2018-3-26
@Author  :   EvilRecluse
@Contact :   https://github.com/RecluseXU
@Desc    :   图像梯度
'''

# here put the import lib
import cv2 as cv
import numpy as np

def lapalian_demo(image):  # 拉普拉斯算子
    # 方法1,API
    #     dst = cv.Laplacian(image,cv.CV_32F)
    #     lpls = cv.convertScaleAbs(dst)
    # 方法2,自定义
    kernel = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])
    dst = cv.filter2D(image, cv.CV_32F, kernel=kernel)
    lpls = cv.convertScaleAbs(dst)

    cv.imshow('lapalian_demo', lpls)

def sobel_demo(image):  # sobel算子
    grad_x = cv.Sobel(image, cv.CV_32F, 1, 0)
    grad_y = cv.Sobel(image, cv.CV_32F, 0, 1)
    # cv.CV_32F 这个参数其实还有很多
    gradx = cv.convertScaleAbs(grad_x)  # 绝对值
    grady = cv.convertScaleAbs(grad_y)
    cv.imshow('gradient-x', gradx)
    cv.imshow('gradient-y', grady)

    gradxy = cv.addWeighted(gradx, 0.5, grady, 0.5, 0)
    cv.imshow('gradient', gradxy)

src = cv.imread(
    'example/0_Basic_usage_of_the_library/openCV/picture/angle2.jpg')
cv.imshow('src', src)

lapalian_demo(src)
sobel_demo(src)

cv.waitKey(0)
cv.destroyAllWindows()


#%% data
import numpy as np
from sklearn import preprocessing

data = np.array([[ 3, -1.5,  2, -5.4],
                 [ 0,  4,  -0.3, 2.1],
                 [ 1,  3.3, -1.9, -4.3]])

#%% mean removal
data_standardized = preprocessing.scale(data)
print("\nMean =", data_standardized.mean(axis=0))
print("Std deviation =", data_standardized.std(axis=0))

#%% min max scaling
data_scaler = preprocessing.MinMaxScaler(feature_range=(0, 1))
data_scaled = data_scaler.fit_transform(data)
print("\nMin max scaled data:\n", data_scaled)

#%% normalization
data_normalized = preprocessing.normalize(data, norm='l1')
print("L1 normalized data:\n", data_normalized)
print('L1 norm of every sample for a L1 normed matrics:')
for i in range(len(data_normalized)):
    print(np.linalg.norm(data_normalized[i], ord=1))
print('L2 norm of every sample for a L1 normed matrics:')
for i in range(len(data_normalized)):
    print(np.linalg.norm(data_normalized[i], ord=2))

data_norm_l2 = preprocessing.normalize(data, norm='l2')
print("L2 normalized data:\n", data_norm_l2)
print('L1 norm of every sample for a L2 normed matrics:')
for i in range(len(data_norm_l2)):
    print(np.linalg.norm(data_norm_l2[i], ord=1))
print('L2 norm of every sample for a L2 normed matrics:')
for i in range(len(data_norm_l2)):
    print(np.linalg.norm(data_norm_l2[i], ord=2))

#%% binarization
data_binarized = preprocessing.Binarizer(threshold=1.4).transform(data)
print("\nBinarized data:\n", data_binarized)

#%% one hot encoding
encoder = preprocessing.OneHotEncoder()
encoder.fit([[0, 2, 1, 12], [1, 3, 5, 3], [2, 3, 2, 12], [1, 2, 4, 3]])
encoded_vector = encoder.transform([[2, 3, 5, 3]]).toarray()
print("\nEncoded vector:\n", encoded_vector)

##


from scipy import array, ndarray
from scipy.interpolate import CubicSpline
from sympy import sympify, SympifyError
from gaussian_quadrature import gaussian_quadrature
from utils import print_error

def get_limits():
    try:
        a, b = map(float, input('Insert the limits with the format "a, b": ').split(','))
    except ValueError:
        print_error('Error: Incorrect format, the limits should be a numbers and the separator should be a comma ",".')
    return a, b

def get_tabular_form_input():
    try:
        n = int(input('Insert the number of points of the function to integrate: '))
    except ValueError:
        print_error('Error: The number of points should be a integer.')
    print('Insert the points with the format "x, y":')
    x_points, y_points = [], []
    for _ in range(n):
        try:
            x, y = map(float, input().split(','))
        except ValueError:
            print_error('Error: Incorrect format, the points should be a numbers and the separator should be a comma ",".')
        x_points.append(x)
        y_points.append(y)
    return x_points, y_points

def get_tabular_form():
    x_points, y_points = get_tabular_form_input()
    function = CubicSpline(x_points, y_points)
    return function

def get_analytical_form():
    try:
        function = sympify(input('Insert the analytical form of the function: '))
    except SympifyError:
        print_error('Error: It is not a recognizable function')
    return lambda arg: array([function.evalf(subs={'x': i}) for i in arg]) if isinstance(arg, (tuple, list, ndarray)) else function.evalf(subs={'x': arg})

if __name__ == "__main__":
    try:
        option = int(input('Insert 1 if the function to be integrated is in the form of a table or 2 if it is in analytical form: '))
        if option != 1 and option != 2:
            print_error('Error: The number of option should be 1 or 2.')
    except ValueError:
        print_error('Error: The number of option should be a integer.')
    function = get_tabular_form() if option == 1 else get_analytical_form()
    a, b = get_limits()
    print(gaussian_quadrature(function, a, b))


import numpy as np
import math

def findZeros(values, axis=None, start=0, end=-1):
  """Find zeros in a one dimensional numpy array

  The algorithm checks for zero crossings and then performs a linear
  interpolation to determine an approximate value for the zero crossing.

  Parameters
  ----------
  values: numpy array
    The array containeng the function values
  axis: numpy array, optional
    An array containing the x-axis values. These will be used to determine
    the zero crossings. Requires axis.size = values.size.
    If not supplied, the indices of the values array will be used to calculate
    the zero crossings
  start: int, optional
    A starting index to look for zero crossings. Negative values indicate offsets
    from the end of the array. (default = 0)
  end: int, optional
    An end index to look for zero crossings. Negative values indicate offsets
    from the end of the array. (default = -1)
  """
  def getX(index):
    if (axis is None):
      return index
    lo = math.floor(index)
    alpha = index - lo
    if (alpha == 0.0):
      return axis[lo]
    else:
      return (1-alpha)*axis[lo] + alpha*axis[lo+1]

  n = values.size
  if (end<0):
    end = n + end
  if (start<0):
    start = n + start

  lastval = values[start]
  result = []

  for i in range(start+1, end+1):
    nextval = values[i]
    if (nextval==0.0):
      result.append(getX(i))
    elif (lastval*nextval < 0.0):
      result.append(getX( i - nextval/(nextval-lastval) ))
    lastval = nextval

  return np.array(result)