import numpy as np
import glob
import spams
import pandas as pd
from numpy.linalg import pinv as moore_penrose_inv
from numpy.linalg import svd, eig
from tqdm import tqdm
import seaborn as sns
def SVD_impute(df):
    """Perform SVD imputing.

    Parameters
    ----------
    matrix: array_like
            Array with rows as genes and columns as tissues/samples
            with nans for missing values

    Returns
    -------
    filled_matrix: array_like
                   Imputed matrix with entries filled by relying on eigengenes
    """

    null_idx = pd.isnull(df).any(1).nonzero()[0]

    full_matrix = df.values
    non_null_matrix  = df.dropna().values
    U, S, V_T = np.linalg.svd(non_null_matrix)
    V =  V_T.T

    for index in null_idx:
        x = full_matrix[index,:]

        # index of entries where the row is nan
        row_na_idx = np.where(np.isnan(x))

        # index of entries where the row is not nan
        row_not_na_idx = np.where(~np.isnan(x))

        # entries from row which are not nan
        x_star_not_na = x[row_not_na_idx]

         # entries from row which are not nan
        x_star_na = x[row_na_idx]

        # Eigen genes corresponding to index
        # of locations (columns) in row x which are nan
        V_star_na = np.delete(V, row_not_na_idx, 0)

        # Delete rows from V, corresponding to index
        # of locations (columns) in row x which are nan
        # We will use these to project the row with complete
        V_star_not_na = np.delete(V, row_na_idx, 0)

        gram = np.dot(V_star_not_na.T, V_star_not_na)
        coeff = np.dot(np.linalg.pinv(gram), V_star_not_na.T)

        beta = np.dot(coeff, x_star_not_na)

        # xhat = V_J \beta
        x_missing = np.dot(V_star_na, beta)

        # Fill in the missing entries
        full_matrix[index, row_na_idx] = x_missing
    return full_matrix

def plot_SVD_utils(U, S, VT):
    V = VT.T
    fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(30, 20))
    ax = axes[0, 0]
    sns.heatmap(V, square=True, cmap='RdBu', ax=ax, cbar=False)

    ax = axes[0, 1]
    sns.barplot(x=np.arange(1, len(S)+1), y=S**2/np.sum(S**2), ax=ax, color=sns.color_palette('Set2')[1])

    ax = axes[0, 2]
    ax.plot(V[:, 0], marker='o')

    ax = axes[1, 0]
    ax.plot(V[:, 1], marker='o')

    ax = axes[1, 1]
    ax.plot(V[:, 2], marker='o')

    ax = axes[1, 2]
    ax.plot(V[:, 3], marker='o')

def einsum_row_norm(a):
    return np.sqrt(np.einsum('ij,ij->i', a, a))

def einsum_col_norm(a):
    return np.sqrt(np.einsum('ij,ij->j', a, a))

def ho_SVD(list_of_X):
    """ Perform higher order SVD

    list_of_X: list
               [X_1, X_2, X_3, ..., X_n] size (n x m)

    """
    # Step 1
    # A_i = X_i^T X_i
    # A_inv = moore_penrose_inv(A_i)
    A = []
    N = len(list_of_X)
    A_inv = []
    for X in list_of_X:
        A_i = np.dot(X.T, X)
        A.append(A_i)
        A_inv.append(np.linalg.inv((A_i)))
    # Step 2
    # W = 1/N(N-1) * sum_{i=1}^jn sum_{j>i}^N A_i moore_penrose_inv(A_j) + A_j moore_penrose_inv(A_i)
    W = 0

    for i in range(N):
        for j in range(i+1, N):
            W = W + (np.dot(A[i], A_inv[j]) + np.dot(A[j], A_inv[i]))
    W =  W/(N*(N-1))

    # Step 3
    # Eigen decomposition of W?
    # WV = V\Lambda
    # V= (v_1, v_2, ..., v_n)
    # ||v||_k =1, but V is not necesarrily orthonormal
    # But we don't

    eigen_values, V = eig(W)

    idx = eigen_values.argsort()[::-1]
    eigen_values = eigen_values[idx]
    V = V[:,idx]

    # Step 4
    # solve for  VB_i = X_i^T
     #Calculate the Bi matrices

    B = []
    U = []
    sigmas = []
    for X in list_of_X:
        #B_i = spams.omp( np.asfortranarray(X.T), V, lambda1=0, numThreads = 24)]
        # VB.T = X.T
        B_i = np.dot(np.linalg.inv(V), X.T).T
        B.append(B_i)
        sigma_i  = np.linalg.norm(B_i, axis=0) #einsum_col_norm(B)
        U_i = B_i/sigma_i
        sigmas.append(sigma_i)
        U.append(U_i)
    return U, sigmas, V, eigen_values


# This Program is distributed under the terms of the MIT license.
# Author: Rui Sun
# Date: 2021-12-12
# Copyright: Rui Sun from SAA, SJTU
# Description: Task 1 - Lagrange-Polynomial
# Environment: Python 3.9.5 64-bit
#              Numpy 1.20.3
#              Matplotlib 3.4.2

import numpy as np
import matplotlib.pyplot as plt

# Lagrange-Polynomial
def L(n, x, f):
    x_ = np.linspace(-1, 1, n + 1)
    y_ = f(x_)
    l_ = np.zeros(x_.size)
    res = 0.0
    for i in range(n + 1):
        deno, nume = 1.0, 1.0
        for j in range(n + 1):
            if i != j:
                deno *= (x_[i] - x_[j])
                nume *= (x - x_[j])
        l_[i] = nume / deno
        res += l_[i] * y_[i]
    return res

def LLL(n, x, f):
    res = np.zeros(200)
    for i in range(200):
        res[i] = L(n, x[i], f)
    return res

def redefinedL(n, x, f):
    x_ = np.zeros(n + 1)
    for i in range(n + 1):
        x_[i] = np.cos((2 * i + 1) * np.pi / (2 * (n + 1)))
    y_ = f(x_)
    l_ = np.zeros(x_.size)
    res = 0.0
    for i in range(n + 1):
        deno, nume = 1.0, 1.0
        for j in range(n + 1):
            if i != j:
                deno *= (x_[i] - x_[j])
                nume *= (x - x_[j])
        l_[i] = nume / deno
        res += l_[i] * y_[i]
    return res

def redefinedLLL(n, x, f):
    res = np.zeros(200)
    for i in range(200):
        res[i] = redefinedL(n, x[i], f)
    return res

def f(x):
    return 1.0 / (1.0 + 25.0 * x**2)

def g(x):
    return np.exp(x)

# main
n = np.array([5, 10, 20])
x = np.array([-0.95, -0.47, 0.1, 0.37, 0.93])

# function f(x) = 1 / (1 + 25x^2)
for i in n:
    print(f'n = {i}:')
    for j in x:
        print(f'f({j})-p_n({j}) = {f(j) - L(i, j, f)}')
    plt.title(r'Lagrange-Polynomial of $f(x)=\dfrac{1}{25+x^2}$')
    plt.grid('on')
    xx = np.linspace(-1, 1, 200)
    yy = f(xx)
    zz = LLL(i, xx, f)
    plt.plot(xx, yy, 'r-', label='$f(x)=\dfrac{1}{25+x^2}$')
    plt.plot(xx, zz, 'g:', label=f'$p{i}(x)$')
    plt.legend()
    plt.show()

# function g(x) = e^x
for i in n:
    print(f'n = {i}:')
    for j in x:
        print(f'g({j})-p_n({j}) = {g(j) - L(i, j, g)}')
    plt.title(r'Lagrange-Polynomial of $g(x)=e^x$')
    plt.grid('on')
    xx = np.linspace(-1, 1, 200)
    yy = g(xx)
    zz = LLL(i, xx, g)
    plt.plot(xx, yy, 'r-', label='$g(x)=e^x$')
    plt.plot(xx, zz, 'g:', label=f'$p{i}(x)$')
    plt.legend()
    plt.show()

# Redefined Lagrange-Polynomial
# function f(x) = 1 / (1 + 25x^2)
for i in n:
    print(f'n = {i}:')
    for j in x:
        print(f'f({j})-p_n({j}) = {f(j) - redefinedL(i, j, f)}')
    plt.title(r'Lagrange-Polynomial of $f(x)=\dfrac{1}{25+x^2}$')
    plt.grid('on')
    xx = np.linspace(-1, 1, 200)
    yy = f(xx)
    zz = redefinedLLL(i, xx, f)
    plt.plot(xx, yy, 'r-', label='$f(x)=\dfrac{1}{25+x^2}$')
    plt.plot(xx, zz, 'g:', label=f'$p{i}(x)$')
    plt.legend()
    plt.show()


# -*- coding: utf-8 -*-
"""
Created on Wed Apr 18 07:30:49 2018

@author: adrian
"""

# Regla de Simpson 1/3

import math
from scipy.optimize import fsolve
from numpy import sign
from numpy import exp

# Función f(x)
def f(x):
    return 4+math.cos(x+1)

# Función g(x)
def g(x):
    return (math.exp(x))*(math.sin(x))

# Función para aproximación de la integral
def simpson( limInf, limSup, nParticiones, funcion ):

    # Cálculo del valor de h
    h = ( limSup - limInf )/nParticiones

    # List for storing value of x and f(x)
    x = list()
    fx = list()

    # Calcular valores de x y f(x)
    i = 0
    while i<= nParticiones:
        x.append(limInf + i * h)
        fx.append(funcion(x[i]))
        i += 1

    # Cálculo del resultado
    res = 0
    i = 0
    while i<= nParticiones:
        if i == 0 or i == nParticiones:
            res+= fx[i]
        elif i % 2 != 0:
            res+= 4 * fx[i]
        else:
            res+= 2 * fx[i]
        i+= 1
    res = res * (h / 3)
    return res

def busquedaIncremental(f,a,b,intervalo,error):

    x1 = a
    x2 = a + intervalo
    f1 = f(a)
    f2 = f(x2)

    while (sign(f1) == sign(f2) and abs(x2-x1)>=error):
        if (x2 >= b):
            return None
        else:
            x1 = x2
            x2 = x1 + intervalo
            f1 = f2
            f2 = f(x2)

    return (x1 + x2)/2.0

def resta(x): return f(x) - g(x)

def encontrarRaices():
    intervalo = 0.0001
    error = 0.000001
    maximo = 5
    contador = -5

    raices = []

    while (contador < maximo):

        a = contador
        b = contador + intervalo
        resultado = busquedaIncremental(resta,a,b,intervalo,error)

        if (resultado != None):
            raices.append(resultado)
        contador += intervalo

    print("\nPuntos de intersección de las dos curvas: \n",raices,"\n")
    return raices

def main():

    raices = encontrarRaices()

    limInferior = raices[0]
    limSuperior = raices[1]

    puntoMedio = (limSuperior + limInferior)/2

    if(f(puntoMedio) > g(puntoMedio)):
        fMayor = f
        fMenor = g
    else:
        fMayor = g
        fMenor = f

    nParticiones = 10

    simpsonMayor = simpson(limInferior, limSuperior, nParticiones, fMayor)
    simpsonMenor = simpson(limInferior, limSuperior, nParticiones, fMenor)

    resultado = simpsonMayor - simpsonMenor
    print('Área encerrada por las curvas entre x =',limInferior,' y x =',limSuperior,' es ',resultado,' unidades cuadradas (u^2)')

if __name__ == "__main__":
    main()


import numpy as np

def _check_inverse(coeffs):
    det = np.linalg.det(coeffs)
    #import ipdb; ipdb.set_trace()
    if np.isclose(det, 0.0):
        raise ZeroDivisionError

def _matrix_sanity(coeffs):
    assert(coeffs.ndim == 2)#, 'Input matrix must be 2 dimensional')
    assert(coeffs.shape[0]+1 == coeffs.shape[1])

def _load_coefficients(coefficients_file):
    coeffs = np.genfromtxt(coefficients_file, dtype=str)
    _matrix_sanity(coeffs)
    coeffs = np.matrix([[eval(x) for x in row] for row in coeffs])
    return coeffs

def _check_matrices(coeffs, consts):
    assert(coeffs.shape[0] == coeffs.shape[1])
    assert(coeffs.shape[0] == consts.shape[0])
    assert(consts.shape[1] == 1)

def _list_to_matrix(coefficients):
    for l in coefficients:
        assert(len(l) == len(coefficients[0]))
    coeffs = np.matrix(coefficients)
    _matrix_sanity(coeffs)
    return coeffs

def handle_input(coefficients):
    if isinstance(coefficients, str):
        return _load_coefficients(coefficients)
    elif isinstance(coefficients, list):
        return _list_to_matrix(coefficients)
    elif isinstance(coefficients, np.matrix):
        _matrix_sanity(coefficients)
        return coefficients
    elif isinstance(coefficients, np.ndarray):
        _matrix_sanity(coefficients)
        return np.matrix(coefficients)
    else:
        raise(TypeError, 'Unsupported input type.')

def solve_linear_system(coefficients):
    coeffs = handle_input(coefficients)
    A = coeffs[:, :-1]
    B = coeffs[:, -1].reshape((-1, 1))
    _check_matrices(A, B)
    try:
        _check_inverse(A)
        return A.I * B
    except ZeroDivisionError:
        print('Determinant of coefficients matrix is 0. No unique solution.')
        return None


import numpy as np
from scipy.fftpack import fft,ifft
import matplotlib.pyplot as plt
import seaborn

#采样点选择1400个，因为设置的信号频率分量最高为600赫兹，根据采样定理知采样频率要大于信号频率2倍，所以这里设置采样频率为1400赫兹（即一秒内有1400个采样点，一样意思的）
x=np.linspace(0,1,1400)

#设置需要采样的信号，频率分量有180，390和600
y=7*np.sin(2*np.pi*180*x) + 2.8*np.sin(2*np.pi*390*x)+5.1*np.sin(2*np.pi*600*x)

yy=fft(y)                     #快速傅里叶变换
yreal = yy.real               # 获取实数部分
yimag = yy.imag               # 获取虚数部分

yf=abs(fft(y))                # 取绝对值
yf1=abs(fft(y))/len(x)           #归一化处理
yf2 = yf1[range(int(len(x)/2))]  #由于对称性，只取一半区间

xf = np.arange(len(y))        # 频率
xf1 = xf
xf2 = xf[range(int(len(x)/2))]  #取一半区间

plt.subplot(221)
plt.plot(x[0:50],y[0:50])
plt.title('Original wave')

plt.subplot(222)
plt.plot(xf,yf,'r')
plt.title('FFT of Mixed wave(two sides frequency range)',fontsize=7,color='#7A378B')  #注意这里的颜色可以查询颜色代码表

plt.subplot(223)
plt.plot(xf1,yf1,'g')
plt.title('FFT of Mixed wave(normalization)',fontsize=9,color='r')

plt.subplot(224)
plt.plot(xf2,yf2,'b')
plt.title('FFT of Mixed wave)',fontsize=10,color='#F08080')

plt.show()


#Program to perform auto correlation

import numpy as np
import scipy as sy
from matplotlib import pyplot as plt

#input response
#x = [1,0,0,2]
x = eval(input('Enter the input sequence x[n]='))
N1 = len(x)
h=np.zeros(N1)
N2 = len(x)
N = N1+N2-1
y = np.zeros(N)
for i in range (N1):
    h[N1-1-i]=x[i]

#Correlation using Linear convolution built-in function in NumPy
y1 = np.convolve(x,h)
#Correlation using Correlation built-in function in NumPY
y2 = np.correlate(x,x,'full')
print('Auto correlation using NumPy Linear convolution built-in function -correlation result y=\n',y1)
print('Auto correlation using NumPy correlation built-in function - correlation result  y=\n',y2)

m = N-N1
n = N-N2
#Padding zeros to x and h to make their length to N
x =np.pad(x,(0,m),'constant')
h =np.pad(h,(0,n),'constant')

#correlation using formula
for n in range (N):
    for k in range (N):
        if n >= k:
             y[n] = y[n]+x[n-k]*h[k]

print('correlation using formula - correlation result y =\n',y)

#RESULT
##Auto correlation using NumPy Linear convolution built-in function -correlation result y=
## [2. 0. 0. 5. 0. 0. 2.]
##Auto correlation using NumPy correlation built-in function - correlation result  y=
## [2 0 0 5 0 0 2]
##correlation using formula - correlation result y =
## [2. 0. 0. 5. 0. 0. 2.]


# -*- coding: utf-8 -*-
"""C2S1 - Matrix (Images) in Python.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/165vXorZLFCgEdntLefWhA7VWu_sw4sNh

# Chapter 2 - Session 1
# Matrix (Images) in Python

## Objectives
#### learn how to use python library call NumPy which is dedicated to matrix handling and related function (all images are form of matrixes)

## Content
#### 1) Installation and Importing NumPy Library
#### 2) Creating Matrixes using NumPy
#### 3) Indexing Matrixes
#### 4) Math Operations with Matrixes
#### 5) Get Statistics of Matrixes

<hr>

# 1) Installation and Importing NumPy Library

First we have to install NumPy to the Python using pip3 command as below

    pip3 install numpy

if you use Anaconda, NumPy library is already installed by default

then we can import and access various functions from NumPy library to our python work space
"""

'''import numpy library to python workspace as np'''

import numpy as np

"""# 2) Creating Matrixes using NumPy

Actually, we can represent vector or matrix as lists in python. as below

    [1,2,3,4] - vecor
    [[1,2,3,4],[5,6,7,8]] - matrix

but in order to do operation on matrixes, we have to use "for" loops which is not efficient and hectic. to address this, NumPy provide alternative way, which is easy to manage and efficient

"""

'''lists and numpy matrixes'''

my_list = [[1,2,3,4],[5,6,7,8]]
my_matrix = np.array([[1,2,3,4],[5,6,7,8]])

print(type(my_list))
print(type(my_matrix))

print('\n---------------------\n')

'''getting shape of matrixes'''
my_matrix = np.array([[1,2,3,4],[5,6,7,8]])
print(my_matrix.shape)

print('\n---------------------\n')

'''creating numpy arrays and matrixes'''

row_vector = np.array([1,2,3,4])
col_vector = np.array([1,2,3,4]).T #transpose
my_matrix = np.array([[1,2,3,4],[5,6,7,8]])

print(row_vector)
print(col_vector)
print(my_matrix)

print('\n---------------------\n')

'''we can use built in function in python to creat special matrixes, easily'''

zeros_mat = np.zeros((4,4))
ones_mat = np.zeros((4,4))
random_mat = np.random.rand(4,4)

print(zeros_mat)
print(ones_mat)
print(random_mat)

"""### Python Data Types

NumPy library has their own data types which are broader than python default data types

    int8 - Byte (-128 to 127)
    nt16 - Integer (-32768 to 32767)
    int32 - Integer (-2147483648 to 2147483647)
    uint8 - Unsigned integer (0 to 255)
    uint16 - Unsigned integer (0 to 65535)
    uint32 - Unsigned integer (0 to 4294967295)
    float16 - Half precision float: sign bit, 5 bits exponent, 10 bits mantissa
    float32 - Single precision float: sign bit, 8 bits exponent, 23 bits mantissa
    float64 - Double precision float: sign bit, 11 bits exponent, 52 bits mantissa

So we can define our own data type for matrix when we are creating it or we can converty between data types
"""

'''get data type of matrix'''

my_matrix = np.array([[1,2,3,4],[5,6,7,8]])
print(my_matrix.dtype)

print('\n---------------------\n')

'''convert data type from float to int'''

my_matrix = np.array([1.5, 2.5, 3.5], dtype=np.float32)
print(my_matrix.dtype)
print(my_matrix)
my_matrix_int = np.array(my_matrix, dtype=np.int32)
print(my_matrix_int.dtype)
print(my_matrix_int)

"""### Exercise 1

Create a 4x4 matrix with values 1,2,3,4 in the diagonal

### Exercise 2

RGB images are 3-D matrixes. We will deal with 3-D matrixes in future sessions. So first, create random 3 by 3 random matrix and create 3-D matrix with 3x3x3 matrix with values from 1 to 27 values and print created matrixes

# 3) Indexing Matrixes

Once we have a matrix we should be able to access particular element of part of matrix (similar to lists, we extracted value at particular index from a list)

In case of matrixes also, we use indexes to extract values from a matrix. It's similar to Sub-setting a Image in Remote Sensing context
"""

my_matrix = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])

print(my_matrix)

print('\n---------------------\n')

'''access only one value'''

print(my_matrix[0,0])
print(my_matrix[3,2])

print('\n---------------------\n')

'''access part of matrix'''

print(my_matrix[0:3,0:3])
print(my_matrix[1,:])
print(my_matrix[1:3,:])
print(my_matrix[2:,:])
print(my_matrix[:2,:])

"""### Exercise 3

Create a 4x4 matrix with values 1,2,3,4 in the diagonal and remove first , last columns and remove first , last rows and print final 2x2 matrix

# 4) Math Operations with Matrixes

Like numbers, we can perform mathematics operations with matrixes like Adding, Subtraction, Multiplication.. etc

Usually in matrixes operations perform in element-wise manner
"""

x = np.array([[1, 2, 3], [4, 5, 6]])
y = np.array([[1, 1, 1], [2, 2, 2]])

print(x)
print(y)

print('\n---------------------\n')

'''operatins with scalers'''

print(x * 0.1)
print(x + 10)
print(x / 10)

print('\n---------------------\n')

'''operatins between matrixes'''

print(x + y)
print(x * y)

print('\n---------------------\n')

'''we can use numpy fuctions to do advance element-wise operations on matrix'''

print(np.sqrt(x))
print(np.exp(x))

"""### Exercise 4

Create any 4by4 Matrix with decimal values and create and print matrix with rounded values of original matrix

### Exercise 5

Create any 4by4 Matrix and Calculate x^2+2x+1 for each element of the matrix

### Exercise 6

Create any 2 4by4 Matrix and Calculate (matrix 2 - matrix 1) / (matrix 2 + matrix 1) for each element of the matrix

# 5) Get Statistics of Matrixes

Now we can create, index, perform operations with matrixes. And there are another easy set of functions that allow us to calculate statistics parameters such as sum, mean, max, min, etc. of a matrix
"""

my_matrix = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])

print(my_matrix)

print('\n---------------------\n')

print(np.sum(my_matrix))
print(np.mean(my_matrix))
print(np.max(my_matrix))
print(np.min(my_matrix))

"""In above examples, we calculate statistics for whole matrix. furthermore we can specify particular direction that we can calculate statistics.

In this example, we calculate statistics vertically and horizontally
"""

my_matrix = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])

print(my_matrix)

print('\n---------------------\n')

print(np.sum(my_matrix, axis=0))
print(np.sum(my_matrix, axis=1))

"""Another important parameter of matrix is unique values in matrix.

Let's imagine, if someone has given us classified satellite image. so we want to know, what are the class value and home many of them are there. this this case, we have to first find unique values in given image (matrix)

"""

my_matrix = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4])
np.unique(my_matrix)

"""### Exercise 7

Create a 10x10 array with random values and find the minimum and maximum values

### Exercise 8

Create any 4by4 Matrix containing duplicates and print all unique values of that matrix and print number of unique values of the matrix

### Exercise 9

create matrix with 100 rows and 2 columns with random value, can calculate and print mean, standard deviation in each column

### Exercise 10

create 3-D matrix with 3x3x3 matrix with values from 1 to 27 values and print created matrixes. and calculate sum, mean, max, min in all 3 dimensions
"""


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
import cv2
print(tf.__version__)

"""## We already have

N = Number of Samples
D = Number of features or the dimensions

How will we represent the time-axis? By T

Our dataset will not be N x D now, it will be N x T x D

In TF and Keras, we usually deal with equal length sequences. Let's talk about:

## Stocks

We have one stock price so D = 1

To have a signal where D is greater than 1, we must have different inputs, e.g., GPS longitude and latitude

T will give us the window size of area-of-interest. This is the area we look at, to predict the next value

N will be the number of windows in the time series

Thus, for a sequence of length L and a window size of T, we have N = L - T + 1

What if we have D=200, i.e., we are looking at 200 stock prices at the same time

Window size = T
Stocks we watch = D
Sample size = T x D

Total samples = N = L - T + 1

We need data to be N x T x D because this is the pythonista staandard!

We use N x D for tabular data and N x H x W x C for images; N always corresponds to the samples, D is always the number of features, H is the height, W the width and C the channels; they can either be colors, or the # of feature maps in between CNN layers

## Forecasting

Forecasting refers to the prediction of next values in the time series. The length of prediction is the horizon i.e., if I want to predict the weather every 2 hours for the next 5 days; I will get a horizon of 5 * 24 = 120 ---> 120/2 = 60 steps

## Total windows

For length L 10

Window size T 4

N = L - T + 1

N = 10 - 4 + 1

N = 6 + 1

N = 7

Let's check them out!

1 2 3 4 5 6 7 8 9 10 -------> Full sequence

```
1 2 3 4 -----> 1

  2 3 4 5 -----> 2

    3 4 5 6 -----> 3

      4 5 6 7 -----> 4

        5 6 7 8 -----> 5

          6 7 8 9 -----> 6

            7 8 9 10 -----> 7
```
But wait a minute, isn't 10 the sample number we are using as the Y variable? We can not use that, thus total number of windows = L - T =  10 - 4 = 6

## How do we predict the time series?

Well now we're going to go into the details of the implementation;

```
x_pred_t = w0 + w1 * x_t-1 + w2 * x_t-2 + w3 * x_t-3 + w4 * x_t-4

x_pred_t+1 = w0 + w1 * x_pred_t + w2 * x_t-1 + w3 * x_t-2 + w4 * x_t-3
```

This is an autoregressive model now.

```
x_pred_5 = w0 + w1 * x_4 + w2 * x_3 + w3 * x_2 + w4 * x_1

x_pred_6 = w0 + w1 * x_pred_5 + w2 * x_4 + w3 * x_3 + w4 * x_2

```
"""

from tensorflow.keras.layers import Input, Dropout, Dense
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import SGD, Adam, Adamax

"""## Let's get some synthetic data"""

n = 501
x = 0.1 * np.arange(1,n)
data = np.cos(x) + np.random.randn(n-1) * 0.1

# Visualising the dataset
plt.plot(x, data, color = 'red')
plt.title('X Plot')
plt.xlabel('X')
plt.ylabel('y')
plt.show()

T = 40
X = []
y = []
print(len(data))
print("The last sample would be: 500 - 10 = " + str((len(data)-T)) )
print("BUT data[1000] can not be used! so, we must go from 1 to 979 ")

for i in range(len(data) - T):
  x = data[i:i+T]
  X.append(x)
  y_temp = data[i+T]
  y.append(y_temp)

X = np.array(X)
y = np.array(y)

print(X.shape)
print(y.shape)

N, T = X.shape

i_layer = Input(shape = (T, ))
o_layer = Dense(1)(i_layer)
model = Model(i_layer, o_layer)
model.compile(loss = 'mse',
              optimizer = Adam(lr = 0.3))

index = -N//4
report = model.fit(X[:index], y[:index], epochs=100, validation_data=(X[index:], y[index:]))

plt.plot(report.history['loss'], label='training_loss')
plt.plot(report.history['val_loss'], label='validation_loss')
plt.legend()

y_test = y[index:]
y_pred = []

X_end = X[index]
while len(y_pred) < len(y_test):
  pred = model.predict(X_end.reshape(1, -1))[0,0]
  y_pred.append(pred)
  X_end = np.roll(X_end, -1)
  X_end[-1] = pred

print(len(y_pred))
print(len(y_test))

plt.plot(y_test, label='y_test')
plt.plot(y_pred, label='y_pred')
plt.legend()


from scipy.stats import chisquare, norm, kstest
import numpy as np

def gof_test(sample, alpha=0.05, bins=256):
    """
    Use chi-square to create goodness of fit test for pseudo random numbers (test for
    uniformity) where:

    - H0 (null hypothesis) is that the sample is uniform
    - H1 (alternate hypothesis) the sample is not uniform

    To test for uniformity, the p-value should lie in the range of alpha < p < 1 - alpha

    :param sample: Generated samples from random generators
    :param alpha: Significance level, default of 0.05
    :param bins: The number of bins to divide the samples
    :return: True if we can't reject the null hypothesis of uniformity, False otherwise.
    Also the p-value of the statistic wih a chi-square distribution
    """

    intervals = np.linspace(0, 1, bins)
    observations, _ = np.histogram(sample, intervals)

    _, p_value = chisquare(observations)

    return True if alpha < p_value < 1 - alpha else False, p_value

def run_test_up_down(sample, alpha=0.05):
    """
    Run test for up and down.

    :param sample: Generated samples from random generators
    :param alpha: Significance level, default of 0.05
    :return: True if we fail to reject the null hypothesis of independence. Also returns
    the z0 statistic.
    """

    a = 1  # Initialize to one since there will always be at least one run
    up = True if sample[1] >= sample[0] else False  # First up, down comparison

    # Counting all the ups and downs
    for i, x in enumerate(sample[1:-1], start=1):
        next_up = True if sample[i + 1] >= x else False
        if next_up != up:
            a += 1
            up = next_up

    n = len(sample)
    mu_a = (2 * n - 1) / 3
    var_a = (16 * n - 29) / 90

    z0 = (a - mu_a) / np.sqrt(var_a)
    z = norm.ppf(1 - alpha / 2)

    return True if abs(z0) < z else False, z0

def run_test_above_below_mean(sample, alpha=0.05):
    """
    Run test for above and below the mean.

    :param sample: Generated samples from random generators
    :param alpha: Significance level, default of 0.05
    :return: True if we fail to reject the null hypothesis of independence. Also returns
    the z0 statistic.
    """

    above_below = sample >= 0.5
    n = len(sample)
    n1 = sum(above_below)
    n2 = n - n1

    b = 1
    # Counting all the ups and downs
    for i, x in enumerate(above_below[:-1]):
        if x != above_below[i + 1]:
            b += 1

    mu_b = ((2.0 * n1 * n2) / n) + 0.5
    var_b = (2.0 * n1 * n2 * (2.0 * n1 * n2 - n)) / ((n ** 2.0) * (n - 1))

    z0 = (b - mu_b) / np.sqrt(var_b)
    z = norm.ppf(1 - alpha / 2)

    return True if abs(z0) < z else False, z0

def ks_test(sample, alpha=0.05):
    """
    Kolmogorov-Smirnov test. It is basically the same implementation as the one in scipy
    with the added difference that a boolean is returned on whether the null hypothesis
    of uniformity is not rejected (True) and false otherwise.

    :param sample: Generated samples from random generators
    :param alpha: Significance level, default of 0.05
    :return: True if we fail to reject the null hypothesis of uniformity. Also returns
    the p-value corresponding to the Kolmogorov-Smirnov test.
    """

    d0, p_value = kstest(sample, "uniform")

    return True if alpha < p_value else False, p_value

def correlation_test(sample, alpha=0.05):
    """
    Correlation test using class notes

    :param sample: Generated samples from random generators
    :param alpha: Significance level, default of 0.05
    :return: True if we fail to reject the null hypothesis of independence, False
    otherwise.
    """

    rho = 0
    n = len(sample)

    for k, rk in enumerate(sample[:-1]):
        rho += rk * sample[k + 1]

    rho = (12 / (n - 1)) * rho - 3
    var_rho = (13 * n - 19) / (n - 1) ** 2

    z0 = rho / np.sqrt(var_rho)
    z = norm.ppf(1 - alpha / 2)

    return True if abs(z0) < z else False, z0


# solutions.py
"""Volume 1A: QR 2 (Least Squares and Computing Eigenvalues).Solutions file."""

import numpy as np
from cmath import sqrt
from scipy import linalg as la
from matplotlib import pyplot as plt

# Problem 1
def least_squares(A, b):
    """Calculate the least squares solutions to Ax = b using QR decomposition.

    Inputs:
        A ((m,n) ndarray): A matrix of rank n <= m.
        b ((m, ) ndarray): A vector of length m.

    Returns:
        x ((n, ) ndarray): The solution to the normal equation.
    """
    Q,R = la.qr(A, mode="economic")
    return la.solve_triangular(R, np.dot(Q.T, b))

    # Or do back substitution by hand:
    m,n = A.shape
    Q,R = la.qr(A, mode="economic")
    y = np.dot(Q.T, b)
    x = np.zeros(n)

    for k in reversed(range(n)):
        x[k] = (y[k] - np.dot(R[k,k:], x[k:])) / R[k,k]

    return x

# Problem 2
def line_fit():
    """Load the data from housing.npy. Use least squares to calculate the line
    that best relates height to weight.

    Plot the original data points and the least squares line together.
    """
    year, index = np.load("housing.npy").T
    A = np.column_stack((year, np.ones_like(year)))
    # Or use slicing:
    # A = np.ones((len(height), 2))
    # A[:,0] = height
    slope, intercept = least_squares(A, index)

    plt.plot(year, index, 'k*')
    plt.plot(year, year*slope + intercept, 'b-', lw=2)
    plt.show()

# Problem 3
def polynomial_fit():
    """Load the data from housing.npy. Use least squares to calculate
    the polynomials of degree 3, 6, 9, and 12 that best fit the data.

    Plot the original data points and each least squares polynomial together
    in individual subplots.
    """
    # Load the data and define a more refined domain for plotting.
    year, index = np.load("housing.npy").T
    domain = np.linspace(year.min(), year.max(), 200)

    for i,n in enumerate([3, 6, 9, 12]):
        # Use least squares to compute the coefficients of the polynomial.
        coeffs = la.lstsq(np.vander(year, n+1), index)[0]
        # coeffs = np.polyfit(x, y, deg=n)

        # Plot the polynomial and the data points in an individual subplot.
        plt.subplot(2,2,i+1)
        plt.plot(year, index, 'k*')
        plt.plot(domain, np.polyval(coeffs, domain), 'b-', lw=2)
        plt.title(r"$n = {}$".format(n))
        # plt.axis([x.min(),x.max(),y.min(),y.max()])

    plt.suptitle("Solution to Problem 3")
    plt.show()

def plot_ellipse(a, b, c, d, e):
    """Plot an ellipse of the form ax^2 + bx + cxy + dy + ey^2 = 1."""
    theta = np.linspace(0, 2*np.pi, 200)
    cos_t, sin_t = np.cos(theta), np.sin(theta)
    A = a*(cos_t**2) + c*cos_t*sin_t + e*(sin_t**2)
    B = b*cos_t + d*sin_t
    r = (-B + np.sqrt(B**2 + 4*A))/(2*A)

    plt.plot(r*cos_t, r*sin_t, lw=2)
    plt.gca().set_aspect("equal", "datalim")

# Problem 4
def ellipse_fit():
    """Load the data from ellipse.npy. Use least squares to calculate the
    ellipse that best fits the data.

    Plot the original data points and the least squares ellipse together.
    """
    # Load the data and construct the matrix A and the vector b.
    x, y = np.load("ellipse.npy").T
    A = np.column_stack((x**2, x, x*y, y, y**2))
    b = np.ones_like(x)

    # Use least squares to calculate the ellipse parameters.
    a, b, c, d, e = la.lstsq(A, b)[0]

    # Plot the results.
    plt.plot(x, y, 'k*')
    plot_ellipse(a, b, c, d, e)
    plt.show()

# Problem 5
def power_method(A, N=20, tol=1e-12):
    """Compute the dominant eigenvalue of A and a corresponding eigenvector
    via the power method.

    Inputs:
        A ((n,n) ndarray): A square matrix.
        N (int): The maximum number of iterations.
        tol (float): The stopping tolerance.

    Returns:
        (foat): The dominant eigenvalue of A.
        ((n, ) ndarray): An eigenvector corresponding to the dominant
            eigenvalue of A.
    """
    # Choose a random x_0 with norm 1.
    x = np.random.random(A.shape[0])
    x /= la.norm(x)

    for _ in xrange(N):
        # x_{k+1} = Ax_k / ||Ax_k||
        y = np.dot(A, x)
        x_new = y / la.norm(y)

        # Check for convergence.
        if la.norm(x_new - x) < tol:
            x = x_new
            break

        # Move to the next iteration.
        x = x_new

    return np.dot(x, np.dot(A, x)), x

# Problem 6
def qr_algorithm(A, N=50, tol=1e-12):
    """Compute the eigenvalues of A via the QR algorithm.

    Inputs:
        A ((n,n) ndarray): A square matrix.
        N (int): The number of iterations to run the QR algorithm.
        tol (float): The threshold value for determining if a diagonal block
            is 1x1 or 2x2.

    Returns:
        ((n, ) ndarray): The eigenvalues of A.
    """
    m,n = A.shape
    S = la.hessenberg(A)

    # TODO: introduce shifts.

    for i in xrange(N):
        Q,R = la.qr(S)
        S = np.dot(R,Q)

    eigs = []
    i = 0

    # Get the eigenvalues of each S_i.
    while i < n:
        if i == n-1:                # 1 x 1 block (final diagonal entry).
            eigs.append(S[i,i])
        elif abs(S[i+1,i]) < tol:   # 1 x 1 block.
            eigs.append(S[i,i])
        else:                       # 2 x 2 block.
            a, b, c, d = S[i:i+2,i:i+2].ravel()
            # Use the quadratic formula.
            B = -1*(a+d)
            C = a*d-b*c
            D = sqrt(B**2 - 4*C)
            eigs += [(-B + D)/2., (-B - D)/2.]
            i += 1
        i += 1
    return np.sort(eigs)

# Additional Material?
from matplotlib.animation import FuncAnimation
import warnings

def polynomial_fit_animation():

    warnings.simplefilter("ignore", np.RankWarning)
    x,y = np.load("housing.npy").T
    domain = np.linspace(x.min(), x.max(), 200)
    y_vals = np.array([np.polyval(np.polyfit(x, y, deg=n), domain)
                                                    for n in xrange(len(y))])
    warnings.simplefilter("default", np.RankWarning)

    plt.plot(x, y, 'k*')
    plt.plot(domain, 2*np.sin(domain), 'k--', lw=1)

    fig = plt.figure(1)
    drawing, = plt.plot([],[], lw=2)
    plt.axis([x.min()-1, x.max()+1, y.min()-1, y.max()+1])

    def update(index):
        drawing.set_data(domain, y_vals[index])
        plt.title(r"$n = {}$".format(index))
        return drawing,

    a = FuncAnimation(fig, update, frames=y_vals.shape[0], interval=1000)
    plt.show()


__author__ = "Tomasz Rybotycki"

import unittest

from numpy import conjugate, identity, ndarray, transpose, allclose

from src_tests import generate_haar_random_unitary_matrix

class TestQuantumComputationsUtilities(unittest.TestCase):

    def setUp(self) -> None:
        self.matrix_size = 5
        self.number_of_matrices_for_distinct_elements_check = 10  # Should be >= 2.
        pass

    def test_unitarity_of_matrices_generated_by_haar_random_unitary_method(self) -> None:
        random_matrix = generate_haar_random_unitary_matrix(self.matrix_size)
        random_matrix_hermitian_adjoint = transpose(conjugate(random_matrix))
        product_of_matrix_and_hermitian_adjoint = random_matrix_hermitian_adjoint.dot(random_matrix)

        identity_matrix = identity(self.matrix_size, dtype=complex)

        self.assertTrue(self.__are_matrices_elementwise_close(identity_matrix, product_of_matrix_and_hermitian_adjoint))

    @staticmethod
    def __are_matrices_elementwise_close(matrix1: ndarray, matrix2: ndarray) -> bool:
        #  I assume that there are only rectangular matrices
        if len(matrix2) != len(matrix1):
            return False
        if len(matrix2[0]) != len(matrix1[0]):
            return False

        return allclose(matrix1, matrix2)

    def test_haar_random_unitary_matrices_generation_differences(self) -> None:
        generated_unitaries_matrices = \
            [generate_haar_random_unitary_matrix(self.matrix_size) for _ in
             range(self.number_of_matrices_for_distinct_elements_check)]

        are_all_matrices_different = []

        for i in range(self.number_of_matrices_for_distinct_elements_check):
            for j in range(i + 1, self.number_of_matrices_for_distinct_elements_check):
                are_all_matrices_different.append(self.__are_matrices_elementwise_close(generated_unitaries_matrices[i],
                                                                                generated_unitaries_matrices[j])
                                                  )
        self.assertTrue(not any(are_all_matrices_different))


import numpy as np
import tensorflow as tf

def xavier_weight_init():
    """Returns function that creates random tensor.

    The specified function will take in a shape (tuple or 1-d array) and
    returns a random tensor of the specified shape drawn from the
    Xavier initialization distribution.

    Hint: You might find tf.random_uniform useful.
    """
    def _xavier_initializer(shape, **kwargs):
        """Defines an initializer for the Xavier distribution.
        Specifically, the output should be sampled uniformly from [-epsilon, epsilon] where
            epsilon = sqrt(6) / <sum of the sizes of shape's dimensions>
        e.g., if shape = (2, 3), epsilon = sqrt(6 / (2 + 3))

        This function will be used as a variable initializer.

        Args:
            shape: Tuple or 1-d array that species the dimensions of the requested tensor.
        Returns:
            out: tf.Tensor of specified shape sampled from the Xavier distribution.
        """
        ### YOUR CODE HERE
        epsilon = np.sqrt(6 / np.sum(shape))
        out=epsilon*tf.random_uniform(shape)
        ### END YOUR CODE
        return out
    # Returns defined initializer function.
    return _xavier_initializer

def test_initialization_basic():
    """Some simple tests for the initialization.
    """
    print ("Running basic tests...")
    xavier_initializer = xavier_weight_init()
    shape = (1,)
    xavier_mat = xavier_initializer(shape)
    assert xavier_mat.get_shape() == shape

    shape = (1, 2, 3)
    xavier_mat = xavier_initializer(shape)
    assert xavier_mat.get_shape() == shape
    print ("Basic (non-exhaustive) Xavier initialization tests pass")

if __name__ == "__main__":
    test_initialization_basic()

Stanford_CS224n NLP with Deep Learning/assignment2/q2_initialization.py


import numpy as np
import matplotlib.pyplot as plt
from tdma import tdma

# Determine error in FDM and FVM approaches for POISUELLE flow (Poisson equation)
# Create a tridiagonal matrix
def tridiag(a, b, c, k1, k2, k3): # ki is the ith diagonal relative to principal diagonal
    return np.diag(a, k1) + np.diag(b, k2) + np.diag(c, k3)

L = 1 # length of the domain
error_fdm = np.zeros(256-4);
error_fvm = np.zeros(256-4);
for N in range(4,256):

    # FINITE DIFFERENCE FORMULATION

    h = L/(N-1); # spacing
    x = np.linspace(0,L,N) # grid

    # Coefficent matrix
    a = np.ones(N-3);    # upper and lower diagonal
    b = -2*np.ones(N-2); # principal diagonal
    A = tridiag(a, b, a, -1, 0, 1)

    # Constant matrix
    X = -8*np.ones((N-2,1))*h*h; # Poisson equation RHS

    # Solve for variables at nodes
    T_num = tdma(A,X); # TDMA
    T_fdm = np.append(np.append(0,T_num),0) # Add Dirichlet BCs
    T_actual = -4*x*(x-1)

    err_fdm = np.sqrt(np.sum(np.power(T_fdm-T_actual,2)))/N;
    error_fdm[N-4] = err_fdm;

    # FINITE VOLUME FORMULATION

    dy = L/(N-1);   # spacing (dyn = dys = dy)
    dys = dy;
    dyn = dy;

    # Coefficent matrix
    a = np.ones(N-3)/dyn;    # upper diagonal
    b = -np.ones(N-2)*(1/dys+1/dyn); # principal diagonal
    a = np.ones(N-3)/dys;    # lower diagonal
    A = tridiag(a, b, a, -1, 0, 1)

    # Constant matrix
    X = -8*np.ones((N-2,1))*dy; # Poisson equation RHS

    # Solution
    T_num = tdma(A,X); # TDMA
    T_fvm = np.append(np.append(0,T_num),0) # Append BCs

    # Error
    err_fvm = np.sqrt(np.sum(np.power(T_fdm-T_actual,2)))/N;
    error_fvm[N-4] = err_fvm;

# Plot error
plt.plot((error_fdm),'r*')
plt.plot((error_fvm),'g.',markersize = 3)
plt.legend(('finite difference','finite volume'));
plt.xlabel('number of nodes');plt.ylabel('$L_2$  error');
plt.show()


import pandas as pd
from matplotlib import pyplot as plt
from sklearn import linear_model
import numpy as np

# loadding data using pandas

df = pd.read_csv("FuelConsumptionCo2.csv")

cdf = df[['ENGINESIZE','CYLINDERS','FUELCONSUMPTION_COMB','CO2EMISSIONS']]

plt.scatter(cdf.ENGINESIZE,cdf.CO2EMISSIONS,color='red')
plt.xlabel("ENGINESIZE")
plt.ylabel("CO2EMISSIONS")
plt.show()

# Training and test data-set

msk = np.random.rand(len(cdf)) < 0.7

train = cdf[msk]
test = cdf[~msk]

linr_model = linear_model.LinearRegression()
train_x = np.asanyarray(train[['ENGINESIZE','CYLINDERS','FUELCONSUMPTION_COMB']])
train_y = np.asanyarray(train[['CO2EMISSIONS']])
linr_model.fit(train_x,train_y)

print("Intercept : ",linr_model.intercept_)
print("coeffs :", linr_model.coef_)

y_hat = linr_model.predict(test[['ENGINESIZE','CYLINDERS','FUELCONSUMPTION_COMB']])

print("Predicted : ",y_hat)

test_x = np.asanyarray(test[['ENGINESIZE','CYLINDERS','FUELCONSUMPTION_COMB']])
test_y = np.asanyarray(test[['CO2EMISSIONS']])

print("Residual sum of squares: %.2f"
      % np.mean((y_hat - test_y) ** 2))

# Explained variance score: 1 is perfect prediction
print('Variance score: %.2f' % linr_model.score(test_x, test_y))


#codes are seperated by """ as multiline comments

"""
#Importing Important Library
import scipy.stats as stats

#Defining our Data
method_1 = [81,81,85,67,88,72,80,63,62,92,82,49,69,66,74,80]
method_2 = [85,53,80,75,64,39,60,61,83,66,75,66,90,93]
method_3 = [81,59,70,70,64,78,75,80,52,45,87,85,79]
method_4 = [86,90,81,61,84,72,56,68,82,98,79,74,82]

#Defining the Level of Significance
alpha = 0.05

#Performing the One Way ANOVA Test
outcome = stats.f_oneway(method_1, method_2, method_3, method_4)

#Printing the Outcome
print("F-Statistic Value is %f and P-Value is %f" %(outcome.statistic, outcome.pvalue))

#Checking the result
if outcome.pvalue<= alpha:
print( 'Null hypothesis can be rejected \n\n P-value is less than the level of Significance \n F-statistic is greater than F-critical')
else:
print( '\nNull hypothesis cannot be rejected \n\n P-value is greater than the level of Significance \n F-statistic is less than F-critical')
"""

"""
#Importing Important Library
import scipy.stats as stats

#Defining our Data
lean = [844.2,745,773.1,823.6,812,758.9,810.7,790.6]
mixed = [897.7,908.1,948.8,836.6,871.6,945.9,859.4,920.2]
higher_fat = [843.4,862.2,790.5,876.5,790.8,847.2,772,851.3]

#Defining the Level of Significance
alpha = 0.05

#Performing the One Way ANOVA Test
outcome = stats.f_oneway(lean, mixed, higher_fat)

#Printing the Outcome
print("F-Statistic Value is %f and P-Value is %f" %(outcome.statistic, outcome.pvalue))

#Checking the result
if outcome.pvalue<= alpha:
print( 'Null hypothesis can be rejected \n\n P-value is less than the level of Significance \n F-statistic is greater than F-critical')
else:
print( '\nNull hypothesis cannot be rejected \n\n P-value is greater than the level of Significance \n F-statistic is less than F-critical')
"""

"""
#importing necessary library
import pandas as pd

#converting our data into pandas dataframe
df = pd.DataFrame()
df['treatment1'] = lean
df['treatment2'] = mixed
df['treatment3'] = higher_fat
display(df)
"""

"""
#stacking everything into three columns – id, treatment, result
stacked_data = df.stack().reset_index()
stacked_data = stacked_data.rename(columns={'level_0': 'id',
                                            'level_1': 'treatment',
                                            0:'result'})
display(stacked_data)

"""

"""
#Applying Tukey Test
from statsmodels.stats.multicomp import pairwise_tukeyhsd, MultiComparison
MultiComp = MultiComparison(stacked_data['result'], stacked_data['treatment'])
print(MultiComp.tukeyhsd().summary())

"""

"""
#Preparing Data
data = [175,193,180,192,213,222,205,226,203,185,218,231]
gender = ["Male","Male","Female","Female"]*3
patient = ['1','2']*6
age = [["18-34"]*4,["35-54"]*4,["55+"]*4]

age_flattened = []
for sublist in age:
    for item in sublist:
age_flattened.append(item)

#Creating a DataFrame
a=pd.DataFrame()
a["Cholestrol_level"] = data
a["Gender"] = gender
a["Patient_No"] = patient
a["Age"] = age_flattened
display(a)

"""

"""
#Generating the Model to check for Interaction Effect
from statsmodels.formula.api import ols
model = ols('Cholestrol_level ~ C(Gender)*C(Age)', a).fit()
print(f"Overall model F({model.df_model: .0f},{model.df_resid: .0f}) = {model.fvalue: .3f}, p = {model.f_pvalue: .4f}")
"""

"""
#Checking Residual Summary
res = sm.stats.anova_lm(model, typ= 2)
display(res)
"""

"""
#Checking the Model to check for Main Effect
model = ols('Cholestrol_level ~ C(Gender)+C(Age)', a).fit()
print(f"Overall model F({model.df_model: .0f},{model.df_resid: .0f}) = {model.fvalue: .3f}, p = {model.f_pvalue: .4f}")

"""

"""

#Checking Residual Summary
res2 = sm.stats.anova_lm(model, typ= 2)
display(res2)

"""

"""
import pandas as pd
from statsmodels.multivariate.manova import MANOVA

group1 = [12,10,16,9,11,11,12,11,6,15,9,10,11,13,14]
group2 =[6,20,11,14,5,7,14,15,13,5,4,7,9,11,12]
group3=[12,13,14,12,11,10,10,15,15,8,9,7,6,11,13]
group4=[10,9,12,5,14,5,7,9,13,10,9,10,15,12,8]

b = pd.DataFrame()
b["group1"]=group1
b["group2"]=group2
b["group3"]=group3
b["group4"]=group4
b["Score"]=["BDI","BDI","BDI","BDI","BDI","HRS","HRS","HRS","HRS","HRS","SCR","SCR","SCR","SCR","SCR"]

display(b)
"""

"""
maov = MANOVA.from_formula('group1 + group2 + group3 + group4  ~ Score', data=b)
print(maov.mv_test())
"""


# -*- coding: utf-8 -*-
"""HW6_Q4.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1zR1N3xFVakUv7q8it72PAPzxg0xXOd_d
"""

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

"""a. Load the data and construct a table with 9 columns containing the numerical ratings. (Ignore the last 5 columns – they consist auxiliary information such as longitude/latitude, state, etc.)"""

data = pd.read_csv('places.txt', delim_whitespace=True)
# ignore last 5 columns
data_set = pd.DataFrame(data, columns=['Climate', 'HousingCost', 'HlthCare', 'Crime',  'Transp', 'Educ', 'Arts', 'Recreat', 'Econ'])
data_set.head(6)

"""b. Replace each value in the matrix by its base-10 logarithm. (This pre-processing is done for convenience since the numerical range of the ratings is large.) You should now have a data matrix X whose rows are 9-dimensional vectors representing the different cities."""

mat = np.array(data_set).astype('float')
data_z_score = (mat - np.mean(mat, axis=0)) / np.var(mat, axis=0) ** 0.5
data_z_score = data_z_score - np.mean(data_z_score, axis=0)
# do z-score
print(f'data after z-score process is:\n{data_z_score}\n')

for i in range(len(mat)):
  for j in range(len(mat[0])):
    mat[i][j] = math.log10(mat[i][j])
# print(mat)

mean_vec = []
center_mat = mat[:]
for col in range(len(mat[0])):
  sum = 0
  for row in range(len(mat)):
    sum += mat[row][col]
  mean_vec.append(sum / len(mat))

for row in range(len(mat)):
  for col in range(len(mat[0])):
    center_mat[row][col] = center_mat[row][col] - mean_vec[col]

print(f'data after log and center process: \n{center_mat}')

"""c. Perform PCA on the data. Remember to center the data points first by computing the mean data vector μ and subtracting it from every point. With the centered data matrix, do an SVD and compute the principal components.

pca with svd
"""

svd = PCA(n_components=2, svd_solver='auto')
new_data_svd = svd.fit_transform(center_mat)
# print(new_data_svd)
plt.scatter(new_data_svd[:, 0], new_data_svd[:, 1])
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.title('Projection on two principal components')
plt.show()

"""d. Write down the first two principal components v1 and v2. Provide a qualitative interpreta- tion of the components. Which among the nine factors do they appear to correlate the most with?"""

pca = PCA(n_components=2)
new_data = pca.fit_transform(center_mat)
pca_components = pca.components_.T

print(pca.explained_variance_ratio_)
print(pca_components)
print('\nArts most correlated to v1 and Hlthcare is most correlated to v2')

plt.scatter(new_data[:, 0], new_data[:, 1])
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.title('Projection on two principal components')
plt.show()

"""e. Project the data points onto the first two principal components. (That is, compute the highest 2 scores of each of the data points.) Plot the scores as a 2D scatter plot. Which cities correspond to outliers in this scatter plot?"""

# get city names
cities = []
city_name = data_set.index.values
for i in range(len(city_name)):
  cities.append(city_name[i])

pca_res = center_mat.dot(pca_components)
# print(pca_res)
city_res = []
for i, j in enumerate(pca_res):
  r1, r2 = j[0], j[1]
  # according to graph above, we can set up bounds to get strange pointers
  if r1 > 1.5 or r2 < -0.6 or r2 > 0.7:
    city_res.append(cities[i])
print(f'the outlier cities are \n{city_res}')

"""f. Repeat Steps 2-5, but with a slightly different data matrix – instead of computing the
base-10 logarithm, use the z-scores. (The z-score is calculated by computing the mean μ and standard deviation σ for each feature, and normalizing each entry x by x−μ ). How do your answers change?
"""

pca_z_score = PCA(n_components=2, svd_solver='auto')
pca_z_score.fit_transform(data_z_score)
pca_z_score_components = pca_z_score.components_.T
pca_z_score_res = data_z_score.dot(pca_z_score_components)
# print(len(pca_z_score_res))

plt.scatter(pca_z_score_res[:, 0], pca_z_score_res[:, 1])
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.title('Projection on two principal components')
plt.show()

"""inorder to get strange points in the graph, we can set bound to pc1 > 6 or pc2 < -2.5"""

city_res_z_score = []
for i, j in enumerate(pca_z_score_res):
  r1, r2 = j[0], j[1]
  # according to graph above, we can set up bounds to get strange pointers
  if r1 > 6 or r2 < -2.5:
    city_res_z_score.append(cities[i])
print(f'the outlier cities are \n{city_res_z_score}')

"""Analyse two methods"""

print(list(set(city_res).intersection(set(city_res_z_score))))
print(list(set(city_res).difference(set(city_res_z_score))))

"""we can see that the city New-york shows up in both methods"""


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

"""
2020 CUMCM B题代码
构建天气变化的马尔科夫链以求得不同天气出现的概率
Coder: 代春洋 胡文哲 刘子奕
"""

import numpy as np

def markov():
    init_array = np.array([0.5, 0.2, 0.3])
    transfer_matrix = np.array([[0.222, 0.556, 0.222],
                               [0.357, 0.429, 0.214],
                               [0.333, 0.5, 0.167]])
    restmp = init_array
    for i in range(25):
        res = np.dot(restmp, transfer_matrix)
        print(i, "\t", res)
        restmp = res

if __name__ == '__main__':
    markov()


import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import inv

N = 25
X = np.reshape(np.linspace(0, 0.9, N), (N, 1))
Y = np.cos(10*X**2) + 0.1 * np.sin(100*X)
# K = 12  # order of the func
listTrainning = []
for i in np.linspace(0, 0.9, N):
    listTrainning.append(np.cos(10*i**2) + 0.1 * np.sin(100*i))

def PsiiFill(K):
    Psii = np.zeros((N, 2*K + 1))
    for i in range(N):
        for j in range(0, 2*K+1):
            if j % 2 == 0:
                Psii[i][j] = np.cos(2 * np.pi * (j/2) * X[i][0])
            else:
                Psii[i][j] = np.sin(2 * np.pi * (j+1)/2 * X[i][0])

    theta = np.dot(np.dot(inv(np.dot(Psii.T, Psii)), Psii.T), Y)
    return theta

def f(x, order):
    fx = 0
    theta_tem = PsiiFill(order)
    #print(theta_tem)
    for k in range(2*order+1):
        if k % 2 == 0:
            fx = fx + np.dot((np.cos(2 * np.pi * (k//2) * x)), theta_tem[k][0])
        else:
            fx = fx + np.dot((np.sin(2 * np.pi * (k + 1)//2 * x)), theta_tem[k][0])

    return fx

testingX = np.linspace(-1, 1.2, 200)

list_Y_1 = []
for i in testingX:
    # print(f(i))
    list_Y_1.append(f(i, 1))

list_Y_11 = []
for i in testingX:
    # print(f(i))
    list_Y_11.append(f(i, 11))

font = {'family': 'serif',
        'color':  'black',
        'weight': 'normal',
        'size': 12,
        }

fontDot = {'family': 'serif',
        'color':  'red',
        'weight': 'normal',
        'size': 12,
        }
# print(testingX)
plt.plot(np.linspace(0, 0.9, N), listTrainning, 'ro')
plt.text(0.2, 1.5, r'Pink Dot: tranning data', fontdict=fontDot)

plt.plot(testingX, list_Y_1, 'g')
plt.text(0.9, -1.0, r'order 1:green', fontdict=font)

plt.plot(testingX, list_Y_11, 'm')
plt.text(-0.2, -1.0, r'order 11: magenta', fontdict=font)

plt.axis([-1, 1.2, -2, 2])
plt.show()


# exercise 2.2.4

# (requires data structures from ex. 2.2.1)
from ex2_1_1 import *

from scipy.linalg import svd

Y = X - np.ones((N,1))*X.mean(0)
U,S,Vh = svd(Y,full_matrices=False)
V=Vh.T
N,M = X.shape

# We saw in 2.1.3 that the first 3 components explaiend more than 90
# percent of the variance. Let's look at their coefficients:
pcs = [0,1,2]
legendStrs = ['PC'+str(e+1) for e in pcs]
c = ['r','g','b']
bw = .2
r = np.arange(1,M+1)
for i in pcs:
    plt.bar(r+i*bw, V[:,i], width=bw)
plt.xticks(r+bw, attributeNames)
plt.xlabel('Attributes')
plt.ylabel('Component coefficients')
plt.legend(legendStrs)
plt.grid()
plt.title('NanoNose: PCA Component Coefficients')
plt.show()

# Inspecting the plot, we see that the 2nd principal component has large
# (in magnitude) coefficients for attributes A, E and H. We can confirm
# this by looking at it's numerical values directly, too:
print('PC2:')
print(V[:,1].T)

# How does this translate to the actual data and its projections?
# Looking at the data for water:

# Projection of water class onto the 2nd principal component.
all_water_data = Y[y==4,:]

print('First water observation')
print(all_water_data[0,:])

# Based on the coefficients and the attribute values for the observation
# displayed, would you expect the projection onto PC2 to be positive or
# negative - why? Consider *both* the magnitude and sign of *both* the
# coefficient and the attribute!

# You can determine the projection by (remove comments):
print('...and its projection onto PC2')
print(all_water_data[0,:]@V[:,1])
# Try to explain why?


import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

# Training Data
train_X = np.asarray([3.3,4.4,5.5,6.71,6.93,4.168,9.779,6.182,7.59,2.167,7.042,10.791,5.313,7.997,5.654,9.27,3.1])
train_Y = np.asarray([1.7,2.76,2.09,3.19,1.694,1.573,3.366,2.596,2.53,1.221,2.827,3.465,1.65,2.904,2.42,2.94,1.3])

#Hyperparameters
n_size = len(train_X)
learning_rate = 0.01
epochs = 100
display_step = 10

#Creating a graph
X = tf.placeholder(float)
Y = tf.placeholder(float)
W = tf.Variable(np.random.normal(),name = 'weight')
b = tf.Variable(np.random.normal(),name = 'bias')

pred = tf.add(tf.multiply(W,X),b)
cost = tf.reduce_sum(tf.pow(tf.subtract(pred,Y),2))/n_size
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)

#initialising variables
init = tf.global_variables_initializer()

with tf.Session() as sess:
	sess.run(init)

	for epoch in range(epochs):
		for x,y in zip(train_X,train_Y):
			sess.run(optimizer,feed_dict={X: x, Y: y})

		if ((epoch+1) % display_step) == 0:
			print(sess.run(cost,feed_dict = {X: train_X, Y: train_Y}))
	print("Optimization finished")
	final_cost = sess.run(cost,feed_dict = {X:train_X,Y:train_Y})
	print("Training cost = ",final_cost,"W = ",sess.run(W),"b = ",sess.run(b))

	#Display output in a graph using matplotlib
	plt.plot(train_X,train_Y,'b*',label = 'train_points')
	plt.plot(train_X,train_X * sess.run(W) + sess.run(b),label = 'Predicted line')
	plt.show()


import numpy as np
def X(theta):
    '''X-rotation'''
    return np.array([[np.cos(theta/2),-1j*np.sin(theta/2)],[-1j*np.sin(theta/2),np.cos(theta/2)]])
def Y(theta):
    '''Y-rotation'''
    return np.array([[np.cos(theta/2),-np.sin(theta/2)],[np.sin(theta/2),np.cos(theta/2)]])

def angles_of_3_Euler_pulses(U):
    '''We now convert our unitary into three pulses with rotation angles 𝛼, 𝛽 and 𝛾'''
    x_1=np.real(U[0,0])
    x_2=np.imag(U[0,0])
    x_3=np.real(U[0,1])
    x_4=np.imag(U[0,1])

    if x_1==0:
        theta_x4_x1=np.inf
        theta_x3_x1=np.inf
    else:
        theta_x4_x1=x_4/x_1
        theta_x3_x1=x_3/x_1
    if x_3==0:
        theta_x2_x3=np.inf
    else:
        theta_x2_x3=x_2/x_3

    alpha=np.arctan(-theta_x4_x1)+np.arctan(theta_x2_x3)
    gamma=np.arctan(-theta_x4_x1)-np.arctan(theta_x2_x3)
    beta=2*np.arctan((-theta_x3_x1*np.cos((alpha+gamma)/2))/(np.cos((alpha-gamma)/2)))
    U_optimal_pulse_1=np.matmul(Y(beta),X(gamma))
    U_optimal_pulse=np.matmul(X(alpha),U_optimal_pulse_1)
    print('\n The overall rotation using optimal pulse sequence is the same: \n')
    print(U_optimal_pulse)
    return alpha,beta,gamma

def mainfunc(list_of_rotation_type,list_of_rotation_angle):
    '''Main function where we first make combined unitary before dividing it into pulses'''
    ### generating combination U
    U=np.array([[1,0],[0,1]])
    for i in range(len(list_of_rotation_type)):
        if list_of_rotation_type[i]=='X':
            U_x=X(list_of_rotation_angle[i]*(np.pi/180))
            U=np.matmul(U,U_x)
        else:
            U_y=Y(list_of_rotation_angle[i]*(np.pi/180))
            U=np.matmul(U,U_y)
    print('\n The overall rotation using input pulse sequence is: \n')
    print(U)
    ### Identifying three pulses now
    alpha,beta,gamma= angles_of_3_Euler_pulses(U)
    print('\n And the optimal pulse sequence is:\n')
    print('X ( ',alpha*(180/np.pi),' ) Y (',beta*(180/np.pi),') X (',gamma*(180/np.pi),')')


# This little solver works on LPs of the form
# maximize cx
# subject to: Ax <= b

from sympy import *

def solve(A, b, c, B, verbose):
        '''requires a feasible basis B for the LP'''
        m, n = A.rows, A.cols
        itr = 0

        # find vertex corresponding to feasible basis B
        AB = A.extract(B, range(n))
        bB = b.extract(B, [0])
        x = AB.LUsolve(bB)

        ABi = AB.inv()

        while True:
                itr += 1

                # compute lambda
                l = (c.T * ABi).T

                # check for optimality
                if all(e >= 0 for e in l):
                        return x, itr

                # find leaving index B[r]
                r = min(i for i in range(l.rows) if l[i] < 0)

                # compute direction to move int
                d = -ABi[:, r]

                # determine the set K
                K = [i for i in range(m) if (A[i, :] * d)[0] > 0]

                if not K:
                        return 'unbounded', itr

                # find entering index e
                e, v = None, None
                for k in K:
                        w = (b[k] - (A[k, :] * x)[0]) / ((A[k, :] * d)[0])
                        if v is None or w < v:
                                v = w
                                e = k

                # update basis
                B[r] = e
                AB[r, :] = A[e, :]
                bB[r, :] = b[e, :]

                # update inverse
                ABi = AB.inv()

                # move to the new vertex
                x = x + v*d

def simplex(A, b, c, B, verbose=False):
        x, itr = solve(A, b, c, B, verbose)

        if x == 'infeasible':
                print 'LP is infeasible'
        elif x == 'unbounded':
                print 'LP is unbounded'
        else:
                print 'Vertex', x.T, 'is optimal'
                print 'Optimal value is', (c.T * x)[0]
                print 'Found after', itr, 'simplex iterations'

if __name__ == '__main__':
    # example
    A = Matrix([[1, 0, 0, 0],
                [20, 1, 0, 0],
                [200, 20, 1, 0],
                [2000, 200, 20, 1],
                [-1, 0, 0, 0],
                [0, -1, 0, 0],
                [0, 0, -1, 0],
                [0, 0, 0, -1]])
    b = Matrix([1,100,10000,1000000, 0,0,0,0])
    c = Matrix([1000, 100, 10, 1])
    B = range(4, 8)

    simplex(A, b, c, B, verbose=True)


import numpy as np
from sklearn import neighbors
from mpl_toolkits.mplot3d import Axes3D
import random
from sklearn.decomposition import PCA
from PIL import Image
from sklearn.cluster import KMeans
import scipy.spatial.distance as dist
from matplotlib.colors import ListedColormap

class Question1(object):
    def pcaeig(self, data):
        """ Implement PCA via the eigendecomposition.

        Parameters:
        1. data     (N, d) numpy ndarray. Each row as a feature vector.

        Outputs:
        1. W        (d,d) numpy array. PCA transformation matrix (Note that each row of the matrix should be a principal component)
        2. s        (d,) numpy array. Vector consisting of the amount  of variance explained in the data by each PCA feature.
        Note that the PCA features are ordered in decreasing amount of variance explained, by convention.
        """
        covMatrix = np.dot(data.T, data) / data.shape[0]
        w, v = np.linalg.eigh(covMatrix)
        W = np.fliplr(v).T
        s = np.flip(w)
        # Remember to check your data types
        return (W, s)

    def pcadimreduce(self, data, W, k):
        """ Implements dimension reduction via PCA.

        Parameters:
        1. data     (N, d) numpy ndarray. Each row as a feature vector.
        2. W        (d,d) numpy array. PCA transformation matrix
        3. k        number. Number of PCA features to retain

        Outputs:
        1. reduced_data  (N,k) numpy ndarray, where each row contains PCA features corresponding to its input feature.
        """
        reduced_data = np.dot(W[0:k, :], data.T).T
        return reduced_data

    def pcareconstruct(self, pcadata, W, k):
        """ Implements dimension reduction via PCA.

        Parameters:
        1. pcadata     (N, k) numpy ndarray. Each row as a PCA vector. (e.g. generated from pcadimreduce)
        2. W        (d,d) numpy array. PCA transformation matrix
        3. k        number. Number of PCA features

        Outputs:
        1. reconstructed_data  (N,d) numpy ndarray, where the i-th row contains the reconstruction of the original i-th input feature vector (in `data`) based on the PCA features contained in `pcadata`.
        """
        reconstructed_data = np.dot(W[0:k, :].T, pcadata.T).T
        return reconstructed_data

    def pcasvd(self, data):
        """Implements PCA via SVD.

        Parameters:
        1. data     (N, d) numpy ndarray. Each row as a feature vector.

        Returns:
        1. Wsvd     (d,d) numpy array. PCA transformation matrix (Note that each row of the matrix should be a principal component)
        2. ssvd       (d,) numpy array. Vector consisting of the amount  of variance explained in the data by each PCA feature.
        Note that the PCA features are ordered in decreasing amount of variance explained, by convention.
        """
        _, s, v = np.linalg.svd(data)
        Wsvd = v
        ssvd = s*s / data.shape[0]
        return Wsvd, ssvd

class Question2(object):

    def unexp_var(self, X):
        """Returns an numpy array with the fraction of unexplained variance on X by retaining the first k principal components for k =1,...200.
        Parameters:
        1. X        The input image

        Returns:
        1. pca      The PCA object fit on X
        2. unexpv   A (200,) numpy ndarray, where the i-th element contains the percentage of unexplained variance on X by retaining i+1 principal components
        """
        for i in range(200):
            pca = PCA(n_components=i+1)
            pca.fit(X)
        unexpv = 1 - np.cumsum(pca.explained_variance_ratio_)
        return pca, unexpv

    def pca_approx(self, X_t, pca, i):
        """Returns an approimation of `X_t` using the the first `i`  principal components (learned from `X`).

        Parameters:
            1. X_t      The input image to be approximated
            2. pca      The PCA object to use for the transform
            3. i        Number of principal components to retain

        Returns:
            1. recon_img    The reconstructed approximation of X_t using the first i principal components learned from X (As a sanity check it should be of size (1,4096))
        """
        transX_t = pca.transform(X_t.reshape(1,-1))
        transX_t[0, i:] = 0
        recon_img = pca.inverse_transform(transX_t)
        return recon_img

class Question3(object):

    def pca_classify(self, traindata, trainlabels, valdata, vallabels):
        """Returns validation errors using 1-NN on the PCA features using 1,2,...,256 PCA features, the minimum validation error, and number of PCA features used.

        Parameters:
            traindata
            trainlabels
            valdata
            valabels

        Returns:
            ve      numpy array of length 256 containing the validation errors using 1,...,256 features
            min_ve  minimum validation error
            pca_feat Number of PCA features to retain. Integer.
        """
        from sklearn.neighbors import KNeighborsClassifier
        ve = np.zeros(256)
        for i in range(256):
            pca = PCA(n_components=i+1)
            pca.fit(traindata)
            classifier= KNeighborsClassifier(n_neighbors=1)
            classifier.fit(pca.transform(traindata), trainlabels)
            predlabels = classifier.predict(pca.transform(valdata))
            ve[i] = np.mean(predlabels != vallabels)
        min_ve = ve[np.argmin(ve)]
        pca_feat = np.argmin(ve) + 1
        return ve, min_ve, pca_feat


# The standard backtracing algorithm for the knapsack 0-1 problem.
# The item values and weights are provided through input lists.
# The algorithm has exponential time complexity in the number of items: O(2^n)

# import numpy as np

def knapsack(i, sol, val, opt_sol, opt_val, w_left, v, w, C):
	# Base case
	if i == len(sol):
		# Check if better than current best
		if val > opt_val:
			# Update optimal value and solution
			opt_val = val
			for k in range(0, len(sol)):
				opt_sol[k] = sol[k]
	else:
		# Generate candidates
		for k in range(0, 2):
			# Check constraints (pruning)
			if k * w[i] <= w_left:
				# Expand partial solution
				sol[i] = k
				# Update remaining capacity
				w_left = w_left - k * w[i]
				# Update partial value
				val = val + k * v[i]
				# Expand partial solution
				opt_val = knapsack(i + 1, sol, val, opt_sol, opt_val, w_left, v, w, C)
	return opt_val

def print_solution(opt_sol, opt_val, v, w, C):
	n = len(opt_sol)
	k = 0
	while k < n and opt_sol[k] == 0:
		k = k + 1

	total_weight = 0
	if k < n:
		print ('(', w[k], ',', v[k], ')', sep='', end='')
		total_weight = total_weight + w[k]
		for i in range(k + 1, n):
			if opt_sol[i] == 1:
				total_weight = total_weight + w[i]
				print (' + ', sep='', end='')
				print ('(', w[i], ',', v[i], ')', sep='', end='')

	print(' => ', '(', total_weight, ',', opt_val, ')', sep='')

def knapsack_0_1(v, w, C):
	sol = [None] * len(v)
	opt_sol = [None] * len(v)
	opt_val = knapsack(0, sol, 0, opt_sol, 0, C, v, w, C)
	print_solution(opt_sol, opt_val, v, w, C)
#	print(opt_val)

# List of item values
v = [7, 2, 10, 4]
# List of item weights
w = [3, 6, 9, 5]
# Knapsack capacity
C = 15
# v, w = np.loadtxt("knapsack_dataset.txt", unpack=True)
knapsack_0_1(v, w, C)


import statsmodels.api as sm

# data example
y = np.load('/home/martin/python/fhnw_lecture/scripts/regression_y.pickle.npy')
X = np.load('/home/martin/python/fhnw_lecture/scripts/regression_X.pickle.npy')

# the x (small x) is just for plotting purpose
x = np.arange(1, 12, 0.05).reshape((-1, 1))
x_intercept = np.c_[np.ones(x.shape[0]), x]

X_intercept = np.c_[np.ones(X.shape[0]), X]

ols_result_lin = sm.OLS(y, X_intercept).fit()
y_hat_lin = ols_result_lin.get_prediction(x_intercept)
print(ols_result_lin.summary()) # beta-coefficients

dt_lin = y_hat_lin.summary_frame()
mean_lin = dt_lin['mean']
meanCIs_lin = dt_lin[['mean_ci_lower', 'mean_ci_upper']]
obsCIs_lin = dt_lin[['obs_ci_lower', 'obs_ci_upper']]

### figure for linear plot
f = plt.figure(figsize=(5, 5), dpi=100)
plt.title(label='linear regression', fontdict={'fontsize':20})
axes = f.add_subplot(111)

axes.plot(X_intercept[:,1], y, 'ro')
axes.plot(x_intercept[:, 1], mean_lin.values.reshape((-1,)), color = "red", label = "regression line")
axes.plot(x_intercept[:, 1], obsCIs_lin.iloc[:, 0], color = "darkgreen", linestyle = "--",
         label = "Observations CI")
axes.plot(x_intercept[:, 1], obsCIs_lin.iloc[:, 1], color = "darkgreen", linestyle = "--")

axes.plot(x_intercept[:, 1], meanCIs_lin.iloc[:, 0], color = "blue", linestyle = "--",
         label = "Mean Prediction CI")
axes.plot(x_intercept[:, 1], meanCIs_lin.iloc[:, 1], color = "blue", linestyle = "--")
axes.legend()

axes.set_ylim([np.min(y)-10, np.max(y) +10])

plt.close('all')

# for quadratic term
X_intercept_quad = np.c_[X_intercept, X**2]

# for plotting:
x = np.arange(1, 12, 0.05).reshape((-1, 1))
x_intercept_quad = np.c_[np.ones(x.shape[0]), x, x**2]

ols_result_quad = sm.OLS(y, X_intercept_quad).fit()
print(ols_result_quad.summary())

y_hat_quad = ols_result_quad.get_prediction(x_intercept_quad)
dt_quad = y_hat_quad.summary_frame()
mean_quad = dt_quad['mean']
meanCIs_quad = dt_quad[['mean_ci_lower', 'mean_ci_upper']]
obsCIs_quad = dt_quad[['obs_ci_lower', 'obs_ci_upper']]

### figure for linear plot
f = plt.figure(figsize=(5, 5), dpi=100)
plt.title(label='regression with quadratic term', fontdict={'fontsize':20})
axes = f.add_subplot(111)

axes.plot(X_intercept_quad[:,1], y, 'ro')
axes.plot(x_intercept_quad[:, 1], mean_quad.values.reshape((-1,)), color = "red", label = "regression line")
axes.plot(x_intercept_quad[:, 1], obsCIs_quad.iloc[:, 0], color = "darkgreen", linestyle = "--",
         label = "Observations CI")
axes.plot(x_intercept_quad[:, 1], obsCIs_quad.iloc[:, 1], color = "darkgreen", linestyle = "--")

axes.plot(x_intercept_quad[:, 1], meanCIs_quad.iloc[:, 0], color = "blue", linestyle = "--",
         label = "Mean Prediction CI")
axes.plot(x_intercept[:, 1], meanCIs_quad.iloc[:, 1], color = "blue", linestyle = "--")
axes.legend()

axes.set_ylim([np.min(y)-10, np.max(y) +10])

plt.close('all')

## bootstrapping as a robust method
# data example
from sklearn.linear_model import ElasticNet
from random import choices
from sklearn.linear_model import Lasso

y = np.load('/home/martin/python/fhnw_lecture/scripts/regression_y.pickle.npy')
X = np.load('/home/martin/python/fhnw_lecture/scripts/regression_X.pickle.npy')

#X = np.c_[np.ones(X.shape[0]), X, X**2, X**3, X**4]
X = np.c_[X, X**2, X**3, X**4]
x = np.arange(1, 12, 0.05).reshape((-1, 1))
#x = np.c_[np.ones(x.shape[0]), x, x**2, x**3, x**4]
x = np.c_[x, x**2, x**3, x**4]
indices = np.arange(0, X.shape[0])

drew = choices(indices, k=len(indices))

sampler = (choices(indices, k = len(indices)) for i in range(200))

CIS = np.percentile(np.array([Lasso(alpha=2, fit_intercept=True).fit(X[drew,:], y[drew, :])\
                              .predict(x).tolist()
                              for drew in sampler]), [2.5, 97.5], axis = 0)

model = Lasso(alpha=2, fit_intercept=True)
model.fit(X, y)
y_hat = model.predict(x)
#params_lasso = model.coef_
#y_hat = np.dot(xc, model.coef_.reshape((-1,1))) + np.mean(y)
f = plt.figure(figsize=(5, 5), dpi=100)
plt.title(label='lasso regression for polynome of 7th degree and $\lambda=2$',
          fontdict={'fontsize':15})
axes = f.add_subplot(111)

axes.plot(X[:,0], y, 'ro')
axes.plot( x[:,0], y_hat.reshape((-1,)), 'b-', label='lasso regression')

axes.plot(x[:, 0], CIS[0, :], color = "blue", linestyle = "--",
         label = "Mean Prediction CI")
axes.plot(x[:, 0], CIS[1, :], color = "blue", linestyle = "--")
legend()


import numpy as np
import pandas as pd

#あ
DAT = 'data/carbon_nanotubes.csv'
CVN = 10
LAM = 0.1

np.set_printoptions(suppress = True)
#あ

def regression(x, y, λ):
	# Regulation term
	r = λ * np.eye(x.shape[1])

	# Compute weights
	w = np.linalg.inv(x.T.dot(x) + r).dot(x.T).dot(y.reshape(y.shape[0], 1))

	return w

def validation(flds, k, λ):
	re = []
	for f in range(k):
		# Regression for folder f
		e = np.concatenate([flds[0][i] for i in range(k) if i != f])
		b = np.ones([e.shape[0], 1])
		X = np.concatenate([e, b], axis = 1)
		Y = np.concatenate([flds[1][i] for i in range(k) if i != f])
		w = regression(X, Y, λ)

		# Validation for folder f
		eiv = flds[0][f]
		biv = np.ones([eiv.shape[0], 1])
		Xiv = np.concatenate([eiv, biv], axis = 1)
		Yiv = flds[1][f]
		Oiv = Xiv.dot(w)
		Err = (Yiv.reshape([Yiv.shape[0], 1]) - Oiv) ** 2

		# Mean and deviation of the square error
		me, de = np.mean(Err), np.std(Err)
		print("The accuracy of folder %d:" % f)
		print("Mean of SE\tDeviation of SE")
		print("%.10f\t%.10f" % (me, de))
		print("---")
		re.append([me, de])

	return np.array(re)

def fold_data(egb, ltg, k):
	# Shuffle the data
	schlurfen = np.random.permutation(egb.shape[0])
	egb = egb[schlurfen]
	ltg = ltg[schlurfen]

	# Fold k validations
	Größe = egb.shape[0] // k
	cuts = [Größe * i for i in range(1, k)]
	egbs = np.split(egb, cuts)
	ltgs = np.split(ltg, cuts)

	return egbs, ltgs

def main():
	# Read data
	dataset = pd.read_csv(DAT)

	data_eingeben = dataset.iloc[:,:-1].values
	data_leistung = dataset.iloc[:, -1].values

	eingeben = np.array(data_eingeben)
	leistung = np.array(data_leistung)

	# Cross Validation
	folders = fold_data(eingeben, leistung, CVN)
	results = validation(folders, CVN, LAM)

	# Print Result
	mfm, mfd = np.mean(results[:,0]), np.mean(results[:,1])
	print("")
	print("Results:")
	print("Mean of the folders' SE\t Mean of the SE's deviation")
	print("%.10f\t\t %.10f" % (mfm, mfd))
	print("---")

#あ
if __name__ == '__main__':
	main()
#あ


import numpy as np
import matplotlib.pyplot as plt
np.set_printoptions(threshold=np.nan)
np.set_printoptions(precision=16)

def exercise_1():
    h = 10**np.linspace(-1,-16,16)
    x = np.pi/6
    ans = -0.5 # should i use this or sin(x)

    fdq = (np.sin(x+h) + np.sin(x-h) - 2*np.sin(x))/h**2
    res = np.array([np.log10(h),fdq,fdq-ans])

    plt.scatter(res[0],np.log10(np.abs(res[2])))

    return np.transpose(res)

def exercise_2():
    def fdq(u,x,h):
        return (u(x+h) + u(x-h) - 2*u(x))/h**2

    x = np.pi/6
    ans = -0.5

    phi0 = fdq(np.sin,x,np.array([0.2,0.1,0.05]))
    phi1 = [(4*phi0[1]-phi0[0])/3, (4*phi0[2]-phi0[1])/3]
    phi2 = (16*phi1[1]-phi1[0])/15

    out = np.append(phi0,np.append(phi1,phi2))
    print(out)
    print(out-ans)

def exercise_6():
    for m in [10,100,1000,10000]:
        h = 1/m
        h2 = h/2

        x = np.linspace(0,1,m+1)
        f = 2*(3*x[1:]**2-2*x[1:]+1) # start at x[1] since we evaluate for j=1,2,...

        f[0] -= (1+(x[1]-h2)**2)/h**2

        A = np.zeros((m,m))
        A[0,0:2] = [-2*(1+x[2]**2+h2**2),(1+(x[2]+h2)**2)]
        for j in range(2,m):
            A[j-1,j-2:j+1] = [(1+(x[j]-h2)**2),-2*(1+x[j]**2+h2**2),(1+(x[j]+h2)**2)]
        A[m-1,m-2:m] = [2*(1+x[j]**2+h2**2),-2*(1+x[j]**2+h2**2)]

        u = np.linalg.solve(A/h**2,f)
        print(h,np.sqrt(h)*np.linalg.norm(u-(1-x[1:])**2))

        #plt.scatter(x[1:],((1-x[1:])**2)) #actual solution
        #plt.scatter(x[1:],u) # numerical solution


import numpy as np

def rotation_matrix(a):
    """Return a 3x3 2D geometric rotation matrix"""
    return np.array([[np.cos(a),  -np.sin(a), 0],
                     [np.sin(a),  np.cos(a), 0],
                     [0, 0, 1.0]])

def translation_matrix(xy):
    """Return a 3x3 2D geometric translation matrix"""
    return np.array([[1.0, 0, xy[0]],
                     [0, 1, xy[1]],
                     [0, 0, 1]])

def scaling_matrix(sx, sy):
    """Return a 3x3 geometric scaling matrix"""
    return np.array([[sx, 0, 0],
                     [0, sy, 0],
                     [0, 0, 1]])

def polar_polygon(nfaces, radius, npoints):
    """ Returns the (x,y) coordinates of n points regularly spaced
    along a regular polygon of `nfaces` faces and given radius.
    """
    theta = np.linspace(0, 2 * np.pi, npoints)[:-1]
    cos, pi, n = np.cos, np.pi, nfaces
    r = cos(pi / n) / cos((theta % (2 * pi / n)) - pi / n)
    d = np.cumsum(np.sqrt(((r[1:] - r[:-1])**2)))
    d = [0] + list(d / d.max())
    return zip(radius * r, theta, d)

def polar2cart(r, theta):
    """ Transforms polar coodinates into cartesian coordinates (x,y).
    If r or theta or both are vectors, returns a np. array of the list
    [(x1,y1),(x2,y2),etc...]
    """

    res = r * np.array([np.cos(theta), np.sin(theta)])
    return res if len(res.shape) == 1 else res.T


# Code made for Sergio Andrés Díaz Ariza
# 25 July 2021
# License MIT
# Transport Phenomena: Python Program-Assignment 2.1

from scipy.integrate import quad
import seaborn as sns
import numpy as np
import time

start_time = time.time()
sns.set()

# Tank Parameters

Vol = 1.5  # [L] Capacity o the Tank
Dt = 1.2  # [m] Diameter of the tank
# Vol = A * z_t  --> Area * height of tank
z_t = (4 * Vol) / (np.pi * (Dt ** 2))

# Bernoulli Eq for the floors

g = 9.89  # [m/s^2] Value of Gravity acceleration
Patm = 101325  # [Pa]
P1 = P2 = P3 = P4 = Patm
z_4 = 9 + z_t  # Height of the tank
z_3 = 6  # Height of the third floor
z_2 = 3  # Height of the second floor
z_1 = 0  # Height of the first floor

V_4 = 0
V_3 = np.sqrt(2 * g * (z_4 - z_3))
V_2 = np.sqrt(2 * g * (z_4 - z_2))
V_1 = np.sqrt(2 * g * (z_4 - z_1))

# Find the Caudal Qi
Ds = 0.0254  # [m] Diameter of outside 1 inch

Q_1 = (np.pi * (Ds ** 2) * V_1) / 4
Q_2 = (np.pi * (Ds ** 2) * V_2) / 4
Q_3 = (np.pi * (Ds ** 2) * V_3) / 4
Q_4 = (np.pi * (Ds ** 2) * V_4) / 4

print(V_4, V_3, V_2, V_1)
print(Q_4, Q_3, Q_2, Q_1)

# Time to empty the tank to floor 1

t_floor_1 = (-2 / np.sqrt(2 * g)) * ((Dt / Ds) ** 2) * (np.sqrt(z_t - z_1) - np.sqrt(9 - z_1))

print(t_floor_1 / 60)

# Time to empty he tank to the three floors

# Define the Integral
def Tim_tank(x, z_1, z_2, z_3):
    return 1 / (np.sqrt(x - z_1) + np.sqrt(x - z_2) + np.sqrt(x - z_3))

# Solve the Integrate
sol_I = quad(Tim_tank, 9, z_t, args=(z_1, z_2, z_3))

t_floor_all = (1 / np.sqrt(2 * g)) * ((Dt / Ds) ** 2) * sol_I[0]

print(t_floor_all / 60)

print("\n--- %s seconds ---" % (time.time() - start_time))


import numpy as np

def f(x):
    return x + np.exp(-2 * x) - 1

def dfdx(x):
    return 1 - 2 * np.exp(-2 * x)

def newton_raphson(f, x=1, num_iter=100, espilon=1e-8):

    for i in range(num_iter):
        x_last = x
        x -= f(x) / dfdx(x)

        if abs(x - x_last) < epsilon:
            print("x = {} after {} iterations".format(x, i + 1))
            return x

    raise ValueError("FAILURE")


"""Define 2D transforms (rotations and translations)"""
import jax
import jax.numpy as jnp

@jax.jit
def rotation_matrix_2d(theta: jnp.ndarray) -> jnp.ndarray:
    """Return the matrix for rotating by theta radians (positive = counterclockwise)
    around the z axis in the x-y plane

    args:
        theta: 1-element, 0-dimensional array containing the angle to rotate around
    returns: a (2, 2) rotation matrix
    """
    # Construct the rotation matrix
    R = jnp.array([[jnp.cos(theta), -jnp.sin(theta)], [jnp.sin(theta), jnp.cos(theta)]])
    return R


from configparser import ConfigParser
from array import *
from scipy import integrate
import matplotlib.pyplot as plt
from math import e
from scipy import integrate as inte
import numpy as np

def ReadConfig(Name):
    config = ConfigParser()

    print(config.sections())
    config.read(Name)

    beta = (float)(config['coefficient']['beta'])
    gamma = (float)(config['coefficient']['gamma'])
    N = (float)(config['coefficient']['N'])
    h = (float)(config['coefficient']['h'])

    S0 = (float)(config['initialcondition']['S0'])
    I0 = (float)(config['initialcondition']['I0'])
    R0 = (float)(config['initialcondition']['R0'])

    day = (int)(config['Days']['day'])

    return [beta , gamma , N , h , S0 , I0 , R0 , day]
[beta , gamma , N , h , S0 , I0 , R0 , day] = ReadConfig('config.ini')

def SIR_model(t, y ):

    S, I, R = y
    dS = -(beta * I * S)/N
    dI = beta * I * S / N - gamma * I
    dR = gamma*I
    return [dS,dI, dR]

def solution(S0 , I0 , R0 , day  , h):

    y0 = [S0,I0,R0]
    y1 = SIR_model(0, y0 )
    solution = integrate.RK45(SIR_model, 0, y0 ,day ,h, 0.001, e**-6)
    S = np.array([])
    I = np.array([])
    R = np.array([])
    T = np.array([])
    while (solution.t < day ):
    # get solution step state
      solution.step()
      T = np.append(T , solution.t)
      S = np.append(S , solution.y[0])
      I = np.append(I , solution.y[1])
      R = np.append(R , solution.y[2])
    return [S , I ,R ,T]

[S , I ,R ,T] = solution(S0 , I0 , R0 , day , h )
print(solution(S0 , I0 , R0 , day , h ))
plt.plot(T , S ,  label = 'the number of susceptible individuals at time t')
plt.plot(T , I ,  label = 'the number of infected individuals at time t')
plt.plot(T , R ,  label = 'the number of ill individuals at time t')
plt.show()


import numpy as np
import math
from math import factorial
import functools

# import matplotlib.pyplot as plt

# prolly wise to memoize
def nCk(n, k):
    numerator = factorial(n)
    denominator = factorial(k) * factorial(n - k)
    return numerator/denominator

class NumericalMethods:
    @classmethod
    def lagrange(cls, pts):
        k = len(pts) - 1

        # Lagrange polynomials are not defined when any two of the x coords over the set of points are the same
        if len(set(pt[0] for pt in pts)) < len(pts):
            raise ValueError('Lagrange polynomial cannot be defined.')

        def lj_of_x(j, x):
            ret = 1

            for m in range(0, k + 1):
                xm = pts[m][0]
                xj = pts[j][0]

                if m != j:
                    denom = xj - xm
                    ret *= (x - xm) / denom

            return ret

        def L(x):
            summ = 0
            for j in range(0, k + 1):
                yj = pts[j][1]
                summ += yj * lj_of_x(j, x)
            return summ

        if len(pts):
            xmin = min(pts, key=lambda pt: pt[0])[0]
            xmax = max(pts, key=lambda pt: pt[0])[0]

            return [(xi, L(xi)) for xi in np.arange(xmin, xmax + 1, 0.01)]
        else:
            return []

    @classmethod
    def bezier(cls, pts):
        # formula taken from hearn, baker, carithers pg 422/429

        points = np.array(pts)

        def P(u):
            summ = np.array([0, 0], dtype = 'float')
            n = len(points) - 1
            for k in range(0, n + 1):
                prod = points[k] * nCk(n, k) * u ** k * (1-u) ** (n-k)
                summ += prod
            return summ

        # calculating a 1000 output points for the bezier curve
        out_pts = []
        for u in np.linspace(0, 1, 1000):
            out_pts.append(P(u))
        return out_pts

    @classmethod
    def cardinal(cls, pts):
        if len(pts) < 4:
            raise ValueError('Insufficient points for Cardinal spline.')

        t = 0 # this Cardinal spline is an Overhauser spline
        s = (1 - t) / 2

        cardinal_matrix = np.array([
            [-s,        2 - s,          s - 2,      s],
            [2 * s,     s - 3,      3 - 2 * s,      -s],
            [-s,            0,              s,      0],
            [0,             1,              0,      0]
        ])

        def P(iu, out_pts):
            pos_u, u = iu
            ret = np.array([u**3, u**2, u, 1]).reshape([1, 4])
            ret = np.matmul(ret, cardinal_matrix)

            modified_pts = pts[-1:] + pts + pts[:2]
            for k in range(len(pts)):
                four_pts = np.array([
                    modified_pts[k], # p_k-1
                    modified_pts[k + 1], # p_k
                    modified_pts[k + 2], #p_k+1
                    modified_pts[k + 3], #p_k+2
                ]).reshape([4, 2])
                out_pts[k,pos_u,:] = np.matmul(ret, four_pts)

        nf_pieces_per_pair = 100
        out_pts = np.zeros([len(pts), nf_pieces_per_pair, 2])
        for i, u in enumerate(np.linspace(0, 1, nf_pieces_per_pair)): P((i, u), out_pts)

        out_pts = out_pts.reshape(len(pts) * nf_pieces_per_pair, 2)
        # plt.scatter(out_pts[:,0], out_pts[:, 1], color='blue')
        # pts = np.array(pts)
        # plt.scatter(pts[:,0], pts[:, 1], color='red')
        # plt.show()

        return out_pts

if __name__ == '__main__':

    ## figure 16
    # NumericalMethods.cardinal([
    #     [0, 0],
    #     [3, 6],
    #     [7, 6],
    #     [10, 0],
    # ])

    ## figure 17
    # NumericalMethods.cardinal([
    #     [0, 0],
    #     [5, 6],
    #     [5, 6],
    #     [10, 0],
    # ])

    ## figure 18
    # NumericalMethods.cardinal([
    #     [0, 0],
    #     [4.9, 6],
    #     [5.1, 6],
    #     [10, 0],
    # ])
    pass


import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
import math

x, y = np.loadtxt('munich_2.txt', unpack = True)

plt.plot(x, y)
plt.xlabel('Time (years)')
plt.ylabel('Temperature')
plt.show()

guess_amplitude = 14.0
guess_phase = math.pi-0.2
guess_offset = np.mean(y)

p0 = [guess_amplitude, guess_phase, guess_offset]

def my_cos(x, amplitude, phase, offset):
    return amplitude*np.cos(2*x*math.pi + phase) + offset

#now do the fit
fit = curve_fit(my_cos, x, y, p0=p0)

#do our first estimate
data_first_guess = my_cos(x, *p0)

#recreate fitted curve using optimized fitting parameters
data_fit = my_cos(x, *fit[0])

plt.plot(x, y)
plt.plot(x, data_first_guess, 'r')
plt.xlabel('Time (years)')
plt.ylabel('Temperature (Celsius)')
plt.title('Temperature in Munich')
plt.savefig('Munich.eps')
plt.show()

print('The best-fit values for the parameters are as follows: a = ', guess_amplitude\
      , ', b = ', round(guess_phase, 3), ', and c = ', round(guess_offset, 4))
print('The overall average temperature of Munich is: ', round(guess_offset, 4), 'degrees Celsius')
print('According to the model, the hottest temperature is: ', round(max(data_first_guess), 4), 'degrees Celsius')
print('According to the model, the coldest temperature is: ', round(min(data_first_guess), 4), 'degrees Celsius')

##################################################
#ANSWERS/OUTPUT
#  (a) The best-fit values for the parameters are as follows: a =  14.0 , b =  2.942 , and c =  9.4403
#      The plot of the data and fitted model is shown separately
#  (b) The overall average temperature of Munich is:  9.4403 degrees Celsius
#      According to the model, the hottest temperature is:  23.4402 degrees Celsius
#      According to the model, the coldest temperature is:  -4.5594 degrees Celsius
#  (c) The meaning of the b parameter is the left-right shift of the cosine function.
#      The value does make sense, because without it the cosine term will be at its maximum
#      value at the beginning of the year according to the model, which we know is incorrect


import numpy as np

def StandardMap(t_initial, u_initial, PARAMETERS=[0.3, 1]):
    """
    Chirikov standard map for initial conditions in a unit square, centred at the origin (as used in [1]_).
    The map is defined in a perioidic manner, but maps points outside the unit square (periodic domain).
    The Lagrangian descriptor calculations use a correction, so that points are mapped into the unit square.

    Number of model parameters: 1 . PARAMETERS = [K]
    Functional form:
    x_next  = x_initial + y_initial - (K/(2*np.pi))*np.sin(2*np.pi*x_initial
    y_next  = y_initial - (K/(2*np.pi))*np.sin(2*np.pi*x_initial))

    where u_initial = (x_initial, y_initial)

    Parameters
    ----------
    t_initial : float,
        Time corresponding to u_initial.

    u_initial : ndarray, shape(n,),
        Points to be mapped.

    PARAMETERS : list of floats,
        Map parameters.

    Returns
    -------
    u_next : ndarray, shape(n,)
        Array of forward images of u under Chirikov standard map (not in the unit square necessarily).

    References
    ----------
    .. [1] J.D. Meiss Visual explorations of dynamics: The standard map. Pramana - J Phys 70, 965–988 (2008). https://doi.org/10.1007/s12043-008-0103-3
    """
    x_initial, y_initial = u_initial.T
    # Map parameters
    K, time_step = PARAMETERS

    # Map components
    t_next = t_initial + time_step
    x_next = x_initial + y_initial - (K/(2*np.pi))*np.sin(2*np.pi*x_initial)
    y_next = y_initial - (K/(2*np.pi))*np.sin(2*np.pi*x_initial)

    # Map next iteration
    u_next = np.column_stack([ x_next, y_next])
    return t_next, u_next

def StandardMap_inverse(t_initial, u_initial, PARAMETERS=[0.3, 1]):
    """
    Inverse of Chirikov standard map for initial conditions in a unit square, centred at the origin (as used in [1]_).
    The map is defined in a perioidic manner, but maps points outside the unit square (periodic domain).
    The Lagrangian descriptor calculations use a correction, so that points are mapped into the unit square.

    Number of model parameters: 1 . PARAMETERS = [K, time_step]
    Functional form:

    t_next = t_initial - time_step
    x_next = x_initial - y_initial
    y_next = y_initial + (K/(2*np.pi))*np.sin(2*np.pi*(x_initial - y_initial))

    where u_initial = (x_initial, y_initial)

    Parameters
    ----------
    t_initial : float,
        Time corresponding to u_initial.

    u_initial : ndarray, shape(n,),
        Points to be mapped.

    PARAMETERS : list of floats,
        Map parameters.

    Returns
    -------
    t_next : float,
        Time corresponding to u_next.

    u_next : ndarray, shape(n,)
        Array of backward images of u under Chirikov standard map (not in the unit square necessarily).

    References
    ----------
    .. [1] J.D. Meiss Visual explorations of dynamics: The standard map. Pramana - J Phys 70, 965–988 (2008). https://doi.org/10.1007/s12043-008-0103-3
    """
    x_initial, y_initial = u_initial.T
    # Map parameters
    K, time_step = PARAMETERS

    # Map components
    t_next = t_initial - time_step
    x_next = x_initial - y_initial
    y_next = y_initial + (K/(2*np.pi))*np.sin(2*np.pi*(x_initial - y_initial))

    # Map next iteration
    u_next = np.column_stack([ x_next, y_next])

    return t_next, u_next

def HenonMap(t_initial, u_initial, PARAMETERS=[0.298, 1, 1]):
    """
    Henon map.

    Number of model parameters: 2 . PARAMETERS = [a, b, time_step]
    Functional form:

    t_next = t_initial + time_step
    x_next = a - x_initial^2 + b*y_initial
    y_next = x_initial

    where u_initial = (x_initial, y_initial)

    Parameters
    ----------
    t_initial : float,
        Time corresponding to u_initial.

    u_initial : ndarray, shape(n,),
        Points to be mapped.

    PARAMETERS : list of floats,
        Map parameters.

    Returns
    -------
    t_next : float,
        Time corresponding to u_next.

    u_next : ndarray, shape(n,)
        Array of forward images of u under Henon map.
    """
    x_initial, y_initial = u_initial.T
    # Map parameters
    a, b, time_step = PARAMETERS

    # Map components
    t_next = t_initial + time_step
    x_next = a - x_initial**2 + b*y_initial
    y_next = x_initial

    # Map next iteration
    u_next = np.column_stack([ x_next, y_next])

    return t_next, u_next

def HenonMap_inverse(t_initial, u_initial, PARAMETERS=[0.298, 1, 1]):
    """
    Inverse of Henon map.

    Number of model parameters: 2 . PARAMETERS = [a, b, time_step]
    Functional form:

    t_next = t_initial - time_step
    x_next = y_initial
    y_next = (x_initial - a + y_initial^2)/b

    where u_initial = (x_initial, y_initial)

    Parameters
    ----------
    t_initial : float,
        Time corresponding to u_initial.

    u_initial : ndarray, shape(n,),
        Points to be mapped.

    PARAMETERS : list of floats,
        Map parameters.

    Returns
    -------
    t_next : float,
        Time corresponding to u_next.

    u_next : ndarray, shape(n,)
        Array of backward images of u under Henon map.
    """
    x_initial, y_initial = u_initial.T
    # Map parameters
    a, b, time_step = PARAMETERS

    # Map components
    t_next = t_initial - time_step
    x_next = y_initial
    y_next = (x_initial - a + y_initial**2)/b

    # Map next iteration
    u_next = np.column_stack([ x_next, y_next])

    return t_next, u_next


import numpy as np
import matplotlib.pyplot as plt

def estimate_b0_b1(x, y):
  n = np.size(x)
  # Obtenemos los promedios de X y de Y
  m_x, m_y = np.mean(x), np.mean(y)

  # Calcular sumatoria de XY y mi sumatoria de XX
  sum_xy = np.sum((x-m_x)*(y-m_y))
  sum_xx = np.sum(x*(x-m_x))

  # Coeficientes de regresión
  b_1 = sum_xy/sum_xx
  b_0 = m_y - (b_1 * m_x)

  return(b_0, b_1)

def plot_regression(x, y, b):
  plt.scatter(x, y, color = "g", marker="o", s=30)

  y_pred = b[0] + b[1]*x
  plt.plot(x, y_pred, color="b")

  # Etiquetado
  plt.xlabel('x-independiente')
  plt.ylabel('y-dependiente')

  plt.show()

# Codigo Main
def main():
  # Dataset
  x = np.array([1, 2, 3, 4, 5])
  y = np.array([2, 3, 5, 6, 5])

  # Obtenemos b1 y b2
  b = estimate_b0_b1(x, y)
  print("Los valores b_0 = {}, b_1 = {}".format(b[0], b[1]))

  # Graficamos nuestra linea de regresión
  plot_regression(x, y, b)

if __name__ == "__main__":
  main()


from sympy import sqrt, Rational

def dot(v: list[int], w: list[int]) -> int:
    """
    Computes the dot product of two vectors.

    >>> dot([1, 2], [3, 4])
    11

    >>> dot([1, 2, 1], [3, 4, 3])
    14

    param v: a vector
    param w: a vector
    return: the dot product of v and w
    """
    return sum(v_i * w_i for v_i, w_i in zip(v, w))

def length(v: list[int]) -> float:
    """
    Computes the length of a vector.

    >>> length([3, 4])
    5.0

    >>> length([1, 2, 3])
    sqrt(14)

    param v: a vector
    return: the length of v
    """
    return sqrt(dot(v, v))

def gs(L: list[list[int]]) -> list[list[int]]:
    """
    Computes an orthogonal basis of span(L).

    >>> gs([[1, 0, -1], [1, -1, 0]])
    [[1.0, 0, -1.0], [0.5, 1.0, 0.5]]

    param L: a list of basis vectors
    return: an orthogonal basis using the Gram-Schmidt process
    """
    M = []
    for v in L:
        for w in M:
            mu = Rational(dot(w, v), dot(w, w))
            v = [v_i - mu * w_i for v_i, w_i in zip(v, w)]
        M.append(v)
    # Uncomment below if we want orthonormal basis:
    # M = [[v_i / length(v) for v_i in v] for v in M]
    return M


import numpy as np

from src.neural_networks.autoencoder import Autoencoder

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

# Creation of the network and training
# network = nn.NeuralNetwork(learning_rate=0.1)
# If the learning rate or the penalty wants to be changed
network = Autoencoder(learning_rate=0.1, regularization_penalty=0.0001)
network.gradient_descent_learning(array)

# Testing
test_input = np.array([[1, 0, 0, 0, 0, 0, 0, 0],
                       [0, 1, 0, 0, 0, 0, 0, 0],
                       [0, 0, 1, 0, 0, 0, 0, 0],
                       [0, 0, 0, 1, 0, 0, 0, 0],
                       [0, 0, 0, 0, 1, 0, 0, 0],
                       [0, 0, 0, 0, 0, 1, 0, 0],
                       [0, 0, 0, 0, 0, 0, 1, 0],
                       [0, 0, 0, 0, 0, 0, 0, 1]])

print('Test input:')
print(np.array_str(test_input))
network.forward_propagation(test_input)
print('Last layer activation:')
print(np.array_str(network.activations[-1], precision=3, suppress_small=True))
print('Positions where is located the one:')
print('For the input: {0}'.format(np.argmax(test_input, axis=0)))
print('For the output of the neural network: {0}'.format(np.argmax(network.activations[-1], axis=0)))
print('Weights and bias of the network')
print('Weights and bias from input to hidden layer:')
print(np.array_str(network.weights[0], precision=3, suppress_small=True))
print(np.array_str(network.biases[0], precision=3, suppress_small=True))
print('Weights and bias from hidden layer to output:')
print(np.array_str(network.weights[1], precision=3, suppress_small=True))
print(np.array_str(network.biases[1], precision=3, suppress_small=True))