""" Perform forward stepwise feature selection to narrow down predictors in linear regression
 Use k-fold cross-validation method and Root Mean Squared Error (RMSE) for evaluating models.
"""
import copy
import logging
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
from sklearn import datasets
from statsmodels.formula.api import ols

def forward_select(df: pd.DataFrame, response: str, num_folds=5, test_data_frac=0.25) -> list:
    """ Forward selection for linear regression
    :param df: pandas dataframe with all candidate predictors and the response variable
    :param response: response/independent variable
    :param num_folds: number of folds for dividing data to cross validation and train sets
    :param test_data_frac: fraction of input dataframe kept for final testing
    :return: an statsmoodel regression result with optimal predictors.
    Predictors are selected by forward stepwise selection method and evaluated by Root Mean Squared Error
    """
    remaining_predictors = set(df.columns)
    remaining_predictors.remove(response)
    selected_predictors = []
    test_data = df.sample(frac=test_data_frac)
    train_cv = df.drop(test_data.index)
    folds = kfold(train_cv, num_folds)
    best_predictors = []
    while remaining_predictors:
        rmses_candidates = []
        for candidate in remaining_predictors:
            formula = "{} ~ {} + 1".format(response, ' + '.join(selected_predictors + [candidate]))
            rmse = calculate_average_error(folds, formula, response)
            rmses_candidates.append((rmse, candidate))
        rmses_candidates.sort(key=lambda pair: -pair[0])
        cv_rmse, best_candidate = rmses_candidates.pop()
        selected_predictors = selected_predictors + [best_candidate]
        remaining_predictors.remove(best_candidate)
        formula = "{} ~ {} + 1".format(response, ' + '.join(selected_predictors))
        regression = ols(formula, train_cv).fit()
        test_rmse = calculate_rmse(regression, test_data, response)
        best_predictors.append((selected_predictors, cv_rmse, test_rmse))
    return best_predictors

def kfold(df: pd.DataFrame, k: int) -> dict:
    """ Form a dictionary of k folds. Each dictionary item is a dataframe
    :param df: input dataframe
    :param k: number of folds
    :return: dictionary of folds.
    """
    folds = {}
    fold_size = int(len(df)/k)
    df_copy = copy.deepcopy(df)
    for i in range(k - 1):
        folds[i] = df_copy.sample(n=fold_size)
        df_copy.drop(folds[i].index, inplace=True)
    folds[k - 1] = df_copy
    assert len(pd.concat([fold for fold in folds.values()], axis=0)) == len(df)
    return folds

def calculate_average_error(
        folds: dict,
        formula: str,
        response: str,
) -> np.ndarray:
    """ Calculate average RMSE of cross validation folds
    :param folds: dictionary of folds
    :param formula: regression formula
    :param response: response variable
    :return: average RMSE of folds
    """
    num_folds = len(folds)
    rmse_list = []
    for k in range(num_folds):
        regression = ols(formula, folds[k]).fit()
        cv_data = pd.concat([fold_df for (fold, fold_df) in folds.items() if fold != k], axis=0)
        rmse_list.append(calculate_rmse(regression, cv_data, response))

    avg_rmse = np.mean(rmse_list)
    return avg_rmse

def calculate_rmse(regression, data: pd.DataFrame, response: str) -> float:
    """ Calculate RMSE of the given regression on input data
    :param regression: regression results from running statsmodel ols
    :param data: dataframe
    :param response: response variable
    :return:
    """
    predicted = regression.predict(data)
    actual = data[f"{response}"]
    error = actual - predicted
    rss = np.square(error.values)
    rmse = np.sqrt(np.sum(rss)/len(error))
    return rmse

if __name__ == '__main__':
    data = datasets.load_diabetes()
    df = pd.DataFrame(data.data, columns=data.feature_names)
    response = "y_var"
    df[response]=data.target
    logging.debug(f"The dataframe: \n {df.head()}")

    # Run forward stepwise selection
    best_predictors = forward_select(df, response, num_folds=5, test_data_frac=0.2)
    best_predictors.sort(key=lambda formula_errors: formula_errors[1])
    best_formula, cv_error, test_errors = best_predictors[0]
    logging.debug(f"Best model (in terms of test RMSE): {best_formula} \n"
                 f" with test RMSE of {test_errors}"
                 )
    logging.debug(f"All models and their cv errors: \n {best_predictors}")

    # Plot the results
    best_predictors.sort(key=lambda formula_error: len(formula_error[0]))
    plt.figure()
    plt.xlabel("Number of predictors")
    plt.ylabel("RMSE")
    x = list(range(1, len(best_predictors) + 1))
    cv_errors = [formula_error[1] for formula_error in best_predictors]
    plt.xticks(ticks=x)
    plt.plot(x, cv_errors, "-rx", label="CV data")

    test_errors = [formula_error[2] for formula_error in best_predictors]
    plt.gcf()
    plt.plot(x, test_errors, "-bo", label="test data")
    plt.legend()
    plt.show()


import cv2
import numpy as np

'''
Numpy has an FFT package to do this.
np.fft.fft2() provides us the frequency transform which will be a complex array.
Its first argument is the input image, which is grayscale.
Second argument is optional which decides the size of output array.
If it is greater than size of input image, input image is padded with zeros before calculation of FFT.
If it is less than input image, input image will be cropped.
If no arguments passed, Output array size will be same as input.

Now once you got the result, zero frequency component (DC component) will be at top left corner.
If you want to bring it to center, you need to shift the result by \frac{N}{2} in both the directions.
This is simply done by the function, np.fft.fftshift().
(It is more easier to analyze).
Once you found the frequency transform, you can find the magnitude spectrum.
'''

def fourier_numpy(image):
    f = np.fft.fft2(image)
    fshift = np.fft.fftshift(f)
    return 20 * np.log(np.abs(fshift))

'''
OpenCV provides the functions cv2.dft() and cv2.idft() for this.
It returns the same result as previous, but with two channels.
First channel will have the real part of the result and second channel will have the imaginary part of the result.
The input image should be converted to np.float32 first.
'''

def fourier_open_cv(image):
    dft = cv2.dft(np.float32(image), flags=cv2.DFT_COMPLEX_OUTPUT)
    dft_shift = np.fft.fftshift(dft)
    return 20 * np.log(cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1]))


# reference to Tensorflow's implement
import numpy as np

def sigmoid_cross_entropy_loss(labels, logits):
    r"""used when objects is not mutually exclusive. For instance,
    a picture can have a dog and a cat at the same time

    for brevity, let `x = logits`, `z = labels`. The logistic loss is

        z * -log(sigmoid(x)) + (1 - z) * -log(1 - sigmoid(x))

    equivalent formulation:

        max(x, 0)  -  x * z + log(1 + exp(-abs(x)))
    """
    zeros = np.zeros_like(logits, dtype=logits.dtype)
    cond = (logits >= zeros)
    relu_logits = np.where(cond, logits, zeros)             # max(x, 0)
    neg_abs_logits = np.where(cond, -logits, logits)        # -abs(x)
    return relu_logits - logits * labels + np.log1p(np.exp(neg_abs_logits))

# real tensorflow implement
input = np.array([[.1, .2, .3, .4],
                  [.3, .5, .7, .8],
                  [.9, .3, .8, .1]])
target = np.array([[.1, .0, .2, .1],
                   [.3, .4, .6, .7],
                   [.0, .1, .9, .2]])
import tensorflow as tf
with tf.Session() as sess:
    loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=target, logits=input)
    loss1 = sess.run(loss)

loss2 = sigmoid_cross_entropy_loss(logits=input, labels=target)

print("loss compute by Tensorflow: \n", loss1)
print("loss compute by Mory: \n", loss2)

# test in pytorch
import torch
input = torch.from_numpy(input)
target = torch.from_numpy(target)
loss_fn = torch.nn.BCEWithLogitsLoss(reduce=False)
loss3 = loss_fn(input, target)
print(loss3)


from sympy import *
import math

def single_point_truncation(f, x_0, x_1, eps=0, eta=0, max_steps=20, verbose=False):
    """单点弦截法

    Args:
        f: function, 迭代函数
        x_0, x_1: float, 初值
        eps: float, 根的容许误差, default 0.
        eta: float, abs(f(x)) 的容许误差, default 0.

        max_steps: int, 最大迭代次数, default 20.
        verbose: bool, 打印出每一步的值, default False.

    Returns:
        x_final: float, 最终的近似根 x
    """

    f_x0 = f(x_0)

    x = x_1
    for i in range(max_steps):
        if verbose:
            print(i, x)

        x_next = x - f(x) / (f(x) - f_x0) * (x - x_0)

        if abs(x_next - x) <= eps or abs(f(x)) <= eta:
            break

        x = x_next

    return x


# Computational Linear Algebra Ep#2 ex1
# By: Nick Space Cowboy

import numpy as np
import time

if __name__ == "__main__":
	print("A:")
	# Generates a random 10x10  upper triangular matrix with values between zero to 100
	A = np.array(np.random.randint (0,100,(10,10)))
	A1 = np.triu(A)
	print(A)
	print("A1:")
	print(A1)
	print("")
	b = np.array(np.random.randint(0, 100, (10,1)))
	print("b: ")
	print(b)
	print("")
	s1 = time.time()
	# Solve the normal A matrix system
	x = np.linalg.solve(A,b)
	s1e = time.time()
	print("x:")
	print(x)
	print("Full A matrix time: " + str(s1e - s1))
	s2 = time.time()
	# Solve the Triangular matrix system
	x1 = np.linalg.solve(A1,b)
	s2e = time.time()
	print("x1:")
	print(x1)
	print("Triangle matrix time: " + str(s2e - s2))


"""
  Name     : c12_14_stock_price_movement.py
  Book     : Python for Finance (2nd ed.)
  Publisher: Packt Publishing Ltd.
  Author   : Yuxing Yan
  Date     : 6/6/2017
  email    : yany@canisius.edu
             paulyxy@hotmail.com
"""
import scipy as sp
import matplotlib.pyplot as plt
# input area
stock_price_today = 9.15 # stock price at time zero
T =1.                    # maturity date (in years)
n_steps=100.             # number of steps
mu =0.15                 # expected annual return
sigma = 0.2              # annualized volatility
sp.random.seed(12345)    # fixed our seed
n_simulation = 5         # number of simulations
dt =T/n_steps
#
S = sp.zeros([n_steps], dtype=float)
x = range(0, int(n_steps), 1)
for j in range(0, n_simulation):
    S[0]= stock_price_today
    for i in x[:-1]:
        e=sp.random.normal()
        S[i+1]=S[i]+S[i]*(mu-0.5*pow(sigma,2))*dt+sigma*S[i]*sp.sqrt(dt)*e;
    plt.plot(x, S)
#
plt.figtext(0.2,0.8,'S0='+str(S[0])+',mu='+str(mu)+',sigma='+str(sigma))
plt.figtext(0.2,0.76,'T='+str(T)+', steps='+str(int(n_steps)))
plt.title('Stock price (number of simulations = %d ' % n_simulation +')')
plt.xlabel('Total number of steps ='+str(int(n_steps)))
plt.ylabel('stock price')
plt.show()


import numpy as np

# the function that checks the validity of placing a Queen in a specific row and column
def is_valid(board,N,row,col):
    # checking if the current row has any other queen
    if max(board[row,:])==1:
        return False

    # checking upper left diagonal
    k = row-1
    l = col-1
    while (k>=0 and l>=0):
        if (board[k,l] == 1):
            return False
        k=k-1
        l=l-1

    # checking lower left diagonal
    k = row+1
    l = col-1
    while (k<N and l>=0):
        if (board[k,l] == 1):
            return False
        k=k+1
        l=l-1
    return True

# this function is called recursivly to explore the solutions and stops when we reach one of the solutions
def placeQueen(board,N,col):
    # if we placed all the queens correctly and we found a solution
    if (col==N):
        print()
        print(10*"="+"Done !!!"+10*"=")
        print(7*"="+"Board size : "+str (N)+7*"=")
        print()
        print(board)
        return True
    #for each row in the board do the folwoing
    for row in range(0,N):
        if(is_valid(board,N,row,col)):
            board[row,col]=1

            if(placeQueen(board,N,col+1)==True):
                return True
            board[row,col]=0
    return False    #this happens if no possible solution found (when 1< N < 4)

# this is a simple runner function that creates the board and call the placeQueenfunction for the first time
def main(N):
    board=np.zeros((N,N),dtype=int)
    if placeQueen(board,N,0)==False:
        print("no possible solution found for size {}".format(N))
    else:
        return True

if __name__=="__main__":
    # get the solution for N = 0 to N =10
    for i in range(0,11):
        main(i)


"""
Funzioni per il calcolo degli zeri di funzioni non lineari
"""
import numpy as np
import math

'''
Il core Python non possiede la funzione sign.
La funzione copysign(a,b)  del modulo math restituisce un valore numerico che ha il valore assoluto di
a e segno di b.
Per avere il segno di un valore numerico b si può usare math.copysign(1,b)
che resistuisce 1 se b>0, -1 se b<0, 0 se b è zero
'''

def sign(x): return math.copysign(1, x)

#Bisezione
def bisez(fname,a,b,tol):
    eps=np.spacing(1)      # np.spacing(x) Restituisce la distanza tra x e il numero adiacente più vicino.
                           # np.spacing(1)  restituisce quindi l' eps di macchina.
    fa=fname(a)
    fb=fname(b)
    if sign(fa)==sign(fb):
       print('intervallo non corretto --Metodo non applicabile')
       return [],0,[]
    else:
        maxit=int(math.ceil(math.log((b-a)/tol)/math.log(2)))
        print('n. di passi necessari=',maxit,'\n');
        xk=[]
        it=0
        while it<maxit and  abs(b-a)>=tol+eps*max(abs(a),abs(b)):
            c=a+(b-a)*0.5   #formula stabile per il calcolo del punto medio dell'intervallo
            xk.append(c)
            fxk=fname(c)
            if fxk==0:
                break
            elif sign(fxk)==sign(fa):
                a=c
                fa=fxk
            elif sign(fxk)==sign(fb):
                b=c
                fb=fxk

            it+=1

        x=c

    return x,it,xk

def regula_falsi(fname,a,b,tol,nmax):
#Regula Falsi
        eps=np.spacing(1)
        xk=[]
        fa=fname(a)
        fb=fname(b)
        if sign(fa)==sign(fb):
          print('intervallo non corretto --Metodo non applicabile')
          return [],0,[]
        else:
            it=0
            fxk=fname(a)
            while it<nmax and  abs(b-a)>=tol+eps*max(abs(a),abs(b)) and abs(fxk)>=tol :
                x1=a-fa*(b-a)/(fb-fa);
                xk.append(x1)
                fxk=fname(x1);
                if fxk==0:
                    break
                elif sign(fxk)==sign(fa):
                    a=x1;
                    fa=fxk;
                elif sign(fxk)==sign(fb):
                    b=x1;
                    fb=fxk;
                it+=1

            if it==nmax :
                print('Regula Falsi: Raggiunto numero max di iterazioni')

        return x1,it,xk

def corde(fname,fpname,x0,tolx,tolf,nmax):
 #Corde
        xk=[]
        m=fpname(x0)               #m= Coefficiente angolare della tangente in x0
        fx0=fname(x0)
        d=fx0/m
        x1=x0-d
        fx1=fname(x1)
        xk.append(x1)
        it=1
        while it<nmax and  abs(fx1)>=tolf and abs(d)>=tolx*abs(x1) :
           x0=x1
           fx0=fname(x0)
           d=fx0/m
           '''
           #x1= ascissa del punto di intersezione tra  la retta che passa per il punto
           (xi,f(xi)) e ha pendenza uguale a m  e l'asse x
           '''
           x1=x0-d
           fx1=fname(x1)
           it=it+1
           xk.append(x1)

        if it==nmax:
            print('raggiunto massimo numero di iterazioni \n')

        return x1,it,xk

#Secanti
def secanti(fname,xm1,x0,tolx,tolf,nmax):
        xk=[]
        fxm1=fname(xm1);
        fx0=fname(x0);
        d=fx0*(x0-xm1)/(fx0-fxm1)
        x1=x0-d;
        xk.append(x1)
        fx1=fname(x1);
        it=1

        while it<nmax and abs(fx1)>=tolf and abs(d)>=tolx*abs(x1):
            xm1=x0
            x0=x1
            fxm1=fname(xm1)
            fx0=fname(x0)
            d=fx0*(x0-xm1)/(fx0-fxm1)
            x1=x0-d
            fx1=fname(x1)
            xk.append(x1);
            it=it+1;

        if it==nmax:
           print('Secanti: raggiunto massimo numero di iterazioni \n')

        return x1,it,xk

def newton(fname,fpname,x0,tolx,tolf,nmax):
#Newton
        xk=[]
        fx0=fname(x0)
        dfx0=fpname(x0)
        if abs(dfx0)>np.spacing(1):
            d=fx0/dfx0
            x1=x0-d
            fx1=fname(x1)
            xk.append(x1)
            it=0

        else:
            print('Newton:  Derivata nulla in x0 - EXIT \n')
            return [],0,[]

        it=1
        while it<nmax and abs(fx1)>=tolf and  abs(d)>=tolx*abs(x1):
            x0=x1
            fx0=fname(x0)
            dfx0=fpname(x0)
            if abs(dfx0)>np.spacing(1):
                d=fx0/dfx0
                x1=x0-d
                fx1=fname(x1)
                xk.append(x1)
                it=it+1
            else:
                 print('Newton: Derivata nulla in x0 - EXIT \n')
                 return x1,it,xk

        if it==nmax:
            print('Newton: raggiunto massimo numero di iterazioni \n');

        return x1,it,xk

def stima_ordine(xk,iterazioni):
      p=[]

      for k in range(iterazioni-3):
         p.append(np.log(abs(xk[k+2]-xk[k+3])/abs(xk[k+1]-xk[k+2]))/np.log(abs(xk[k+1]-xk[k+2])/abs(xk[k]-xk[k+1])));

      ordine=p[-1]
      return ordine

#Newton Modificato
def newton_m(fname,fpname,x0,m,tolx,tolf,nmax):
        eps=np.spacing(1)
        xk=[]
        #xk.append(x0)
        fx0=fname(x0)
        dfx0=fpname(x0)
        if abs(dfx0)>eps:
            d=fx0/dfx0
            x1=x0-m*d
            fx1=fname(x1)
            xk.append(x1)
            it=0

        else:
            print('Newton:  Derivata nulla in x0  \n')
            return [],0,[]

        it=1
        while it<nmax and abs(fx1)>=tolf and  abs(d)>=tolx*abs(x1):
            x0=x1
            fx0=fname(x0)
            dfx0=fpname(x0)
            if abs(dfx0)>eps:
                d=fx0/dfx0
                x1=x0-m*d
                fx1=fname(x1)
                xk.append(x1)
                it=it+1
            else:
                 print('Newton Mod: Derivata nulla   \n')
                 return x1,it,xk

        if it==nmax:
            print('Newton Mod: raggiunto massimo numero di iterazioni \n');

        return x1,it,xk

def iterazione(gname,x0,tolx,nmax):

        xk=[]
        xk.append(x0)
        x1=gname(x0)
        d=x1-x0
        xk.append(x1)
        it=1
        while it<nmax and  abs(d)>=tolx*abs(x1) :
            x0=x1
            x1=gname(x0)
            d=x1-x0
            it=it+1
            xk.append(x1)

        if it==nmax:
            print('Raggiunto numero max di iterazioni \n')

        return x1, it,xk


from cvxpy import *
import numpy as np
from posdef import *

mu = np.matrix([[-0.01132331],[-0.05061149],[-0.00729714],[-0.06206554],[-0.01079347],[0.0025]])
Sigma = np.array(
	[[2.52879395e-03, 1.85425637e-03, 9.20436767e-04, 1.95914715e-03, 4.28396944e-03, 0.00000000e+00],
	 [1.85425637e-03, 2.15246031e-03, 9.42088127e-04, 1.58969365e-03, 3.30104182e-03, 0.00000000e+00],
	 [  9.20436767e-04, 9.42088127e-04, 2.17054891e-03, 7.91879289e-04, 1.39817285e-03, 0.00000000e+00],
	 [  1.95914715e-03, 1.58969365e-03, 7.91879289e-04, 1.67831424e-03, 3.77524505e-03, 0.00000000e+00],
	 [  4.28396944e-03, 3.30104182e-03, 1.39817285e-03, 3.77524505e-03, 8.72500053e-03, 0.00000000e+00],
	 [  0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.73472348e-18]])

print(isPD(Sigma))

min_return = 0.0
n = 6

w = Variable(n)
ret = mu.T*	w
risk = quad_form(w, Sigma)
min_ret = Parameter(sign='positive')
min_ret.value = min_return

prob = Problem(Minimize(risk),
               [ret >= min_ret,
               sum_entries(w) == 1,
               w >= 0])
prob.solve()
print(w.value)


""""
README
======
This file contains Python codes.
======
"""

""" An incremental search algorithm """
import numpy as np

def incremental_search(f, a, b, dx):
    """
    :param f: The function to solve
    :param a: The left boundary x-axis value
    :param b: The right boundary x-axis value
    :param dx: The incremental value in searching
    :return: The x-axis value of the root,
                number of iterations used
    """
    fa = f(a)
    c = a + dx
    fc = f(c)
    n = 1

    while np.sign(fa) == np.sign(fc):
        if a >= b:
            return a - dx, n

        a = c
        fa = fc
        c = a + dx
        fc = f(c)
        n += 1

    if fa == 0:
        return a, n
    elif fc == 0:
        return c, n
    else:
        return (a + c)/2., n

if __name__ == "__main__":
    """
    The keyword 'lambda' creates an anonymous function
    with input argument x
    """
    y = lambda x: x**3 + 2.0*x**2 - 5.
    root, iterations = incremental_search(y, -5., 5., 0.001)
    print "Root is:", root
    print "Iterations:", iterations


from scipy.io.wavfile import read
from scipy.signal import convolve
import numpy as np
import matplotlib.pyplot as plt
import time

# Answer to the question len(x) = 200, len(h) = 100. What is len(y)?
# Length of y would be: len(x) + len(h) - 1 = 299.
def myTimeConv(x,h):

    y = np.zeros(len(x) + len(h) - 1)

    padded_x = np.hstack((np.zeros(len(h)-1), x, np.zeros(len(h)-1)))
    reverse_h = np.flip(h)

    for i in range(len(y)):
        y[i] = np.dot(padded_x[i:i+len(h)], reverse_h)

    return y

def CompareConv(x, h):

    timer = np.zeros(2)

    current_time = time.time()
    my_conv = myTimeConv(x, h)
    timer[0] = time.time() - current_time

    current_time = time.time()
    scipy_conv = convolve(x, h)
    timer[1] = time.time() - current_time

    m = np.mean(my_conv - scipy_conv)
    mabs = np.mean(np.abs(my_conv - scipy_conv))
    stdev = np.std(my_conv - scipy_conv)

    return m, mabs, stdev, timer

def readwav(filename):
    fs, x = read(filename)
    if x.dtype == 'float32':
        audio = x
    else:
        # change range to [-1,1)
        if x.dtype == 'uint8':
            nbits = 8
        elif x.dtype == 'int16':
            nbits = 16
        elif x.dtype == 'int32':
            nbits = 32
        else:
            nbits = 1  # No conversion

        audio = x / float(2 ** (nbits - 1))

    # special case of unsigned format
    if x.dtype == 'uint8':
        audio = audio - 1.

    if audio.ndim > 1:
        audio = audio[:, 0]

    return audio

if __name__ == "__main__":

    x = np.ones(200)

    rampup = np.linspace(0,1, 26)
    rampdown = np.linspace(1,0,26)
    h = np.hstack((rampup[:-1],rampdown))

    y_time = myTimeConv(x, h)

    piano = readwav("piano.wav")
    impulse_response = readwav("impulse-response.wav")

    compConv = CompareConv(piano, impulse_response)

    fo = open("./results/02-convolutionStats.txt", "w+")

    fo.writelines("Mean: " + str(compConv[0]) + '\n')
    fo.writelines("Mean Absolute: " + str(compConv[1]) + '\n')
    fo.writelines("Standard Deviation: " + str(compConv[2]) + '\n')
    fo.writelines("Time of my convolution: " + str(compConv[3][0]) + '\n')
    fo.writelines("Time of Scipy convolution: " + str(compConv[3][1]) + '\n')

    time = np.linspace(0, len(y_time)-1, len(y_time))

    plt.plot(time, y_time)
    plt.xlabel("Time (In Samples)")
    plt.ylabel("Signal Amplitude")
    plt.title("Time Domain Convolution of two signals")
    plt.show()


from typing import Callable, List, Optional
from lab1.src.onedim.one_dim_search import dichotomy_method

import numpy as np

DEFAULT_EPS = 1e-6
DEFAULT_MAX_ITERS = 100

def conjugate_direction_method(q: np.ndarray,
                               b: np.ndarray,
                               start: np.ndarray,
                               max_iters=DEFAULT_MAX_ITERS,
                               eps: float = DEFAULT_EPS,
                               trajectory: Optional[List] = None):
    if np.all(b == 0):
        return b, 0

    if trajectory is not None:
        trajectory.append(start)
    w_prev = - q @ start - b
    u_prev = w_prev
    if np.linalg.norm(u_prev) == 0:
        return start, 0
    h_prev = np.dot(u_prev, u_prev) / np.dot(q @ u_prev, u_prev)
    x_prev = start + h_prev * u_prev
    if trajectory is not None:
        trajectory.append(x_prev)

    k = 1
    while k < max_iters:
        w_k = -q @ x_prev - b
        u_k = w_k - (np.dot(q @ u_prev, w_k) / np.dot(q @ u_prev, u_prev)) * u_prev
        if np.linalg.norm(u_k) < eps:
            return x_prev, k
        h_k = np.dot(w_k, u_k) / np.dot(q @ u_k, u_k)
        x_k = x_prev + h_k * u_k

        u_prev = u_k
        x_prev = x_k
        k += 1
        if trajectory is not None:
            trajectory.append(x_prev)

    return x_prev, k

def conjugate_gradient_method(f: Callable[[np.ndarray], float],
                              f_grad: Callable[[np.ndarray], np.ndarray],
                              start: np.ndarray,
                              eps=DEFAULT_EPS,
                              max_iters=DEFAULT_MAX_ITERS,
                              trajectory: Optional[List] = None):
    if trajectory is not None:
        trajectory.append(start)

    w_prev = (-1) * f_grad(start)
    u_prev = w_prev
    if np.linalg.norm(w_prev) < eps:
        return start, 0
    x_prev = start
    k = 1

    while k < max_iters:
        w_k = (-1) * f_grad(x_prev)
        y_k = max(0, np.dot(w_k - w_prev, w_k) / np.dot(w_prev, w_prev))
        u_k = w_k + y_k * u_prev
        h_k, _, _ = dichotomy_method(lambda h: f(x_prev + h * u_k), 0, 50, 1e-8)
        x_k = x_prev + h_k * u_k

        if np.linalg.norm(w_k) < eps or np.linalg.norm(x_k - x_prev) < eps:
            return x_prev, k

        x_prev = x_k
        u_prev = u_k
        w_prev = w_k
        k += 1

        if trajectory is not None:
            trajectory.append(x_prev)

    return x_prev, k


"""
Demonstration module for quadratic interpolation.

Sample solutions for Homework 2 problems #2 through #7.
"""

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

def quad_interp(xi,yi):
    """
    Quadratic interpolation.  Compute the coefficients of the polynomial
    interpolating the points (xi[i],yi[i]) for i = 0,1,2.
    Returns c, an array containing the coefficients of
      p(x) = c[0] + c[1]*x + c[2]*x**2.

    """

    # check inputs and print error message if not valid:

    error_message = "xi and yi should have type numpy.ndarray"
    assert (type(xi) is np.ndarray) and (type(yi) is np.ndarray), error_message

    error_message = "xi and yi should have length 3"
    assert len(xi)==3 and len(yi)==3, error_message

    # Set up linear system to interpolate through data points:

    A = np.vstack([np.ones(3), xi, xi**2]).T
    c = solve(A,yi)

    return c

def plot_quad(xi, yi):
    """
    Perform quadratic interpolation and plot the resulting function along
    with the data points.
    """

    # Compute the coefficients:
    c = quad_interp(xi,yi)

    # Plot the resulting polynomial:
    x = np.linspace(xi.min() - 1,  xi.max() + 1, 1000)
    y = c[0] + c[1]*x + c[2]*x**2

    plt.figure(1)       # open plot figure window
    plt.clf()           # clear figure
    plt.plot(x,y,'b-')  # connect points with a blue line

    # Add data points  (polynomial should go through these points!)
    plt.plot(xi,yi,'ro')   # plot as red circles
    plt.ylim(-2,8)         # set limits in y for plot

    plt.title("Data points and interpolating polynomial")

    plt.savefig('quadratic.png')   # save figure as .png file

def cubic_interp(xi,yi):
    """
    Cubic interpolation.  Compute the coefficients of the polynomial
    interpolating the points (xi[i],yi[i]) for i = 0,1,2,3
    Returns c, an array containing the coefficients of
      p(x) = c[0] + c[1]*x + c[2]*x**2 + c[3]*x**3.

    """

    # check inputs and print error message if not valid:

    error_message = "xi and yi should have type numpy.ndarray"
    assert (type(xi) is np.ndarray) and (type(yi) is np.ndarray), error_message

    error_message = "xi and yi should have length 4"
    assert len(xi)==4 and len(yi)==4, error_message

    # Set up linear system to interpolate through data points:

    A = np.vstack([np.ones(4), xi, xi**2, xi**3]).T
    c = solve(A,yi)

    return c

def plot_cubic(xi, yi):
    """
    Perform cubic interpolation and plot the resulting function along
    with the data points.
    """

    # Compute the coefficients:
    c = cubic_interp(xi,yi)

    # Plot the resulting polynomial:
    x = np.linspace(xi.min() - 1,  xi.max() + 1, 1000)
    y = c[0] + c[1]*x + c[2]*x**2 + c[3]*x**3

    plt.figure(1)       # open plot figure window
    plt.clf()           # clear figure
    plt.plot(x,y,'b-')  # connect points with a blue line

    # Add data points  (polynomial should go through these points!)
    plt.plot(xi,yi,'ro')   # plot as red circles
    plt.ylim(-2,8)         # set limits in y for plot

    plt.title("Data points and interpolating polynomial")

    plt.savefig('cubic.png')   # save figure as .png file

def poly_interp(xi,yi):
    """
    General polynomial interpolation.

    Compute the coefficients of the polynomial
    interpolating the points (xi[i],yi[i]) for i = 0,1,2,...,n-1
    where n = len(xi) = len(yi).

    Returns c, an array containing the coefficients of
      p(x) = c[0] + c[1]*x + c[2]*x**2 + ... + c[N-1]*x**(N-1).

    """

    # check inputs and print error message if not valid:

    error_message = "xi and yi should have type numpy.ndarray"
    assert (type(xi) is np.ndarray) and (type(yi) is np.ndarray), error_message

    error_message = "xi and yi should have the same length "
    assert len(xi)==len(yi), error_message

    # Set up linear system to interpolate through data points:
    # Uses a list comprehension, see
    # http://docs.python.org/2/tutorial/datastructures.html#list-comprehensions

    n = len(xi)
    A = np.vstack([xi**j for j in range(n)]).T
    c = solve(A,yi)

    return c

def plot_poly(xi, yi):
    """
    Perform polynomial interpolation and plot the resulting function along
    with the data points.
    """

    # Compute the coefficients:
    c = poly_interp(xi,yi)

    # Plot the resulting polynomial:
    x = np.linspace(xi.min() - 1,  xi.max() + 1, 1000)

    # Use Horner's rule:
    n = len(xi)
    y = c[n-1]
    for j in range(n-1, 0, -1):
        y = y*x + c[j-1]

    plt.figure(1)       # open plot figure window
    plt.clf()           # clear figure
    plt.plot(x,y,'b-')  # connect points with a blue line

    # Add data points  (polynomial should go through these points!)
    plt.plot(xi,yi,'ro')   # plot as red circles
    plt.ylim(yi.min()-1, yi.max()+1)       # set limits in y for plot

    plt.title("Data points and interpolating polynomial")

    plt.savefig('poly.png')   # save figure as .png file

def test_quad1():
    """
    Test code, no return value or exception if test runs properly.
    """
    xi = np.array([-1.,  0.,  2.])
    yi = np.array([ 1., -1.,  7.])
    c = quad_interp(xi,yi)
    c_true = np.array([-1.,  0.,  2.])
    print "c =      ", c
    print "c_true = ", c_true
    # test that all elements have small error:
    assert np.allclose(c, c_true), \
        "Incorrect result, c = %s, Expected: c = %s" % (c,c_true)

    # Also produce plot:
    plot_quad(xi,yi)

def test_quad2():
    """
    Test code, no return value or exception if test runs properly.
    """

    # Generate a test by specifying c_true first:
    c_true = np.array([7., 2., -3.])
    # Points to interpolate:
    xi = np.array([-1.,  0.,  2.])
    # Function values to interpolate:
    yi = c_true[0] + c_true[1]*xi + c_true[2]*xi**2

    # Now interpolate and check we get c_true back again.
    c = quad_interp(xi,yi)
    print "c =      ", c
    print "c_true = ", c_true
    # test that all elements have small error:
    assert np.allclose(c, c_true), \
        "Incorrect result, c = %s, Expected: c = %s" % (c,c_true)

    # Also produce plot:
    plot_quad(xi,yi)

def test_cubic1():
    """
    Test code, no return value or exception if test runs properly.
    """

    # Generate a test by specifying c_true first:
    c_true = np.array([7., -2., -3., 1.])
    # Points to interpolate:
    xi = np.array([-1.,  0.,  1., 2.])
    # Function values to interpolate:
    yi = c_true[0] + c_true[1]*xi + c_true[2]*xi**2 + c_true[3]*xi**3

    # Now interpolate and check we get c_true back again.
    c = cubic_interp(xi,yi)
    print "c =      ", c
    print "c_true = ", c_true
    # test that all elements have small error:
    assert np.allclose(c, c_true), \
        "Incorrect result, c = %s, Expected: c = %s" % (c,c_true)

    # Also produce plot:
    plot_cubic(xi,yi)

def test_poly1():
    """
    Test code, no return value or exception if test runs properly.
    Same points as test_cubic1.
    """
    # Generate a test by specifying c_true first:
    c_true = np.array([7., -2., -3., 1.])
    # Points to interpolate:
    xi = np.array([-1.,  0.,  1., 2.])
    # Function values to interpolate:
    # Use Horner's rule:
    n = len(xi)
    yi = c_true[n-1]
    for j in range(n-1, 0, -1):
        yi = yi*xi + c_true[j-1]

    # Now interpolate and check we get c_true back again.
    c = poly_interp(xi,yi)

    print "c =      ", c
    print "c_true = ", c_true
    # test that all elements have small error:
    assert np.allclose(c, c_true), \
        "Incorrect result, c = %s, Expected: c = %s" % (c,c_true)

    # Also produce plot:
    plot_poly(xi,yi)

def test_poly2():
    """
    Test code, no return value or exception if test runs properly.
    Test with 5 points (quartic interpolating function).
    """
    # Generate a test by specifying c_true first:
    c_true = np.array([0., -6., 11., -6., 1.])
    # Points to interpolate:
    xi = np.array([-1.,  0.,  1., 2., 4.])
    # Function values to interpolate:
    # Use Horner's rule:
    n = len(xi)
    yi = c_true[n-1]
    for j in range(n-1, 0, -1):
        yi = yi*xi + c_true[j-1]

    # Now interpolate and check we get c_true back again.
    c = poly_interp(xi,yi)

    print "c =      ", c
    print "c_true = ", c_true
    # test that all elements have small error:
    assert np.allclose(c, c_true), \
        "Incorrect result, c = %s, Expected: c = %s" % (c,c_true)

    # Also produce plot:
    plot_poly(xi,yi)

if __name__=="__main__":
    print "Running test..."
    test_quad1()
    test_quad2()
    test_cubic1()
    test_poly1()
    test_poly2()


import numpy as np
import torch
import torch.nn

def sum_of_squares_error(y, t):
    return 0.5 * torch.sum((y-t)**2)

t = torch.tensor([0, 0, 1, 0, 0, 0, 0, 0, 0, 0])
y = torch.tensor([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
print(sum_of_squares_error(y, t), "'2'일 확률이 가장 높은 경우")

y = torch.tensor([0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0])
print(sum_of_squares_error(y, t), "'7'일 확률이 가장 높은 경우")
print("---------------------------------------------------")

def default_cross_entropy_error(y, t):
    delta = 1e-7
    return -torch.sum(t * torch.log(y + delta))

t = torch.tensor([0, 0, 0, 0, 0, 0, 0, 1, 0, 0])
y = torch.tensor([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
print(default_cross_entropy_error(y, t))

y = torch.tensor([0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0])
print(default_cross_entropy_error(y, t))
print("---------------------------------------------------")

def numpy_cross_entropy_error(y, t):
    if y.ndim == 1:
        y = y.reshape(1, y.size)
        t = t.reshape(1, t.size)

    batch_size = y.shape[0]
    return -np.sum(t * np.log(y + 1e-7)) / batch_size

t = np.array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0])
y = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
print(numpy_cross_entropy_error(y, t))

def torch_cross_entropy_error(y, t):
    if y.dim() == 1:
        y = y.view(1, y.size()[0])
        t = t.view(1, t.size()[0])

    batch_size = y.shape[0]
    return -torch.sum(t * torch.log(y + 1e-7)) / batch_size

t = torch.tensor([0, 0, 0, 0, 0, 0, 0, 1, 0, 0])
y = torch.tensor([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
print(torch_cross_entropy_error(y, t))

def numpy_cross_entropy_error_1(y, t):
    if y.ndim == 1:
        y = y.reshape(1, y.size)
        t = t.reshape(1, t.size)

    if t.size == y.size:
        t = t.argmax(axis=1)

    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size

t = np.array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0])
y = np.array([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
print(numpy_cross_entropy_error_1(y, t))

def cross_entropy_error_1(y, t):
    if y.dim() == 1:
        y = y.view(1, y.size()[0])
        t = t.view(1, t.size()[0])

    if t.size() == y.size():
        t = t.argmax(axis=1)

    batch_size = y.shape[0]
    return -torch.sum(torch.log(y[torch.arange(batch_size), t] + 1e-7)) / batch_size

t = torch.tensor([0, 0, 0, 0, 0, 0, 0, 1, 0, 0])
y = torch.tensor([0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0])
print(cross_entropy_error_1(y, t))
print("---------------------------------------------------")


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

# In[1]:

import math
import scipy.stats as st

def ExpectedLoss(PD, EA, LR):
    ## PD is the probability of default or Expected Default frequency (EDF) ##
    ## EA is the Exposure Amount (Total loan amount) ##
    ## LR is the loss rate (severity of default) ##

    EL = EA*PD*LR

    return EL

def RecoveryRate(LR):
    RR = 1 - LR

    return RR

def UnexpectedLoss(EA, PD, LR, stdLR):
    ## Assuming 2 state model ##

    VarPD = PD*(1 - PD)

    UL = EA*math.sqrt(PD*(stdLR**2) + (LR**2)*VarPD)

    return UL

def PortfolioExpectedLoss(PD1, EA1, LR1, PD2, EA2, LR2):
    EL1 = ExpectedLoss(PD1, EA1, LR1)
    EL2 = ExpectedLoss(PD2, EA2, LR2)

    ELp = EL1 + EL2

    return ELp

def PortfolioUnexpectedLoss(EA1, PD1, LR1, stdLR1, EA2, PD2, LR2, stdLR2, rho):
    ## rho is the correlation between the assets ##

    UL1 = UnexpectedLoss(EA1, PD1, LR1, stdLR1)
    UL2 = UnexpectedLoss(EA2, PD2, LR2, stdLR2)

    ULp = math.sqrt((UL1**2) + (UL2**2) + 2*rho*UL1*UL2)

    return ULp

def RiskContribution(EA1, PD1, LR1, stdLR1, EA2, PD2, LR2, stdLR2, rho):

    ## Enter x as 1 or 2 for risk contribution of those assets ##
    x = int(input('Enter a number: '))
    UL1 = UnexpectedLoss(EA1, PD1, LR1, stdLR1)
    UL2 = UnexpectedLoss(EA2, PD2, LR2, stdLR2)
    ULp = PortfolioUnexpectedLoss(EA1, PD1, LR1, stdLR1, EA2, PD2, LR2, stdLR2, rho)

    if x == 1:

        RC1 = UL1*(UL1 + (rho*UL2))/ULp

        return RC1

    elif x == 2:

        RC2 = UL2*(UL2 + (rho*UL1))/ULp

        return RC2

def FirmSizeScaleAdjustement(Xr, Yl, Yr):

    ## Operational Risk ##
    ## This is a formula when you want to see your scale of severity by viewing data from others banks ##
    ## Xr is the Bank X revenue ##
    ## Yl is the Bank Y loss from that event ##
    ## Yr is the Bank Y revenue ##
    ## We want to calculate the Bank X loss from that event by readjusting the scale ##

    Xl = Yl*((Xr/Yr)**0.23)

    return Xl

def ValueAtRisk(V, alpha, mu, sigma):
    ## Assuming VAR as Normal Distribution ##
    ## V is portfolio value ##
    ## mu is the Expected Portfolio return ##
    ## alpha is the significance level ##

    z = st.norm.ppf(alpha)

    var = (mu - z*sigma)*V

    return var

def ExpectedShortFall(V, alpha, mu, sigma):
    ES = (-mu + sigma * stats.norm.pdf(stats.norm.ppf(alpha))/(1-(alpha)))*V

    return ES

def LognormalValueAtRisk(V, alpha, mu, sigma):
    Lvar = V*(1 - math.exp(mu - (st.norm.ppf(alpha))*sigma ))

    return Lvar


"""
Created by Joseph Edradan
Github: https://github.com/josephedradan

Date created: 12/28/2020

Purpose:
    Robert talked about a sequence equation solver and I thought it was easy so I made it...

Details:

Description:
    Solves the equation for the given sequence and assumes the x values list is relative to 0 and goes up though,
    you can explicitly make the x values list

Notes:
    This file uses matrices and numpy because it makes like easier...

IMPORTANT NOTES:

Explanation:
    Example:
        Given a sequence:
            [4, 14, 40, 88, 164]

        Find the differences between them and between them differences themselves as a list
            [10, 26, 48, 76]
            [16, 22, 28]
            [6, 6]
            [0]

        Select a degree based on the the list of differences with the same difference
            [6, 6]
            Degree == Row == Row index + 1 == 3

        Create the polynomial equation using degree 3
            (a)*(x)^3 + (b)*(x)^2 + (c)*(x)^1 + (d)*(x)^0 == y

        Solve for the coefficients by plugging in x values to equal the y values (y values are the in the sequence).
        x values are not stated so it is assumed that they start at 0 and to the length of the sequence.
        However, you can make your own x values list.

            Assuming that the x values list corresponds to the length of the sequence:
                [0, 1, 2, 3, 4]

                from

                [4, 14, 40, 88, 164]

            Now solve for the coefficients mathematically...

        Solve for the coefficients using a matrix instead:
            Recall the degree is 3 so the amount of rows in the matrix should be 3 + 1 == 4 because of
            coefficients a, b, c, d

            So

            [4, 14, 40, 88]

            based on

            [0, 1, 2, 3]

            Recall the equation:
                (a)*(x)^3 + (b)*(x)^2 + (c)*(x)^1 + (d)*(x)^0 == y

            Pre matrix:
                x = 0
                    a*(0)^3 + b*(0)^2 + c*(0)^1 + d*(0)^0 == 4
                x = 1
                    a*(1)^3 + b*(1)^2 + c*(1)^1 + d*(1)^0 == 14
                x = 2
                    a*(2)^3 + b*(2)^2 + c*(2)^1 + d*(2)^0 == 40
                x = 3
                    a*(3)^3 + b*(3)^2 + c*(3)^1 + d*(3)^0 == 88

            So the matrix representation is
                [[ 0  0  0  1]        [[a]        [[4]
                 [ 1  1  1  1]    .    [b]    =    [14]
                 [ 8  4  2  1]         [c]         [40]
                 [27  9  3  1]]        [d]]        [88]]

            Let represent the matrix in form: A . Z = B
            Now rearrange the matrix to form: A^-1 . B = Z
            Now solve for Z which will give you the values of the coefficients.

Reference:
    1st, 2nd and 3rd differences and Polynomials
        https://www.youtube.com/watch?v=PhcQvPITG3A
            Notes:
                Learning what differences are and how they relate to polynomials

    Determine Polynomial Equation From Table of Values Using Finite Difference
        https://www.youtube.com/watch?v=ORH3TwgvJgI
            Notes:
                How to find the differences and get create the polynomial equation

    What is a Coefficient Matrix, Augmented Matrix
        https://www.youtube.com/watch?v=BUSsrbMehPI
            Notes:
                Basically, we are trying to solve for a, b, c, d, ... instead of x if you watch this video.
                The below reference is a better example of what we are trying to do.

    Solving Linear Systems Using Matrices
        https://www.youtube.com/watch?v=C2QI3eeIiVc
            Notes:
                This is a better example of what we are trying to do.
                Basically, replace x, y, z, ... with a, b, c, ...

    Solve Linear Equations with Python
        https://www.youtube.com/watch?v=44pAWI7v5Zk
            Notes:
                How to solve linear equations in python using numpy

    Python 🐍 Solve Linear Equations
        https://www.youtube.com/watch?v=NO20jcoHH4I
            Notes:
                 The numpy functions to find the inverse matrix and do the dot product.
                 This is used to solve for the coefficients using a matrix
                    https://youtu.be/NO20jcoHH4I?t=167
"""
import math
from typing import List, Union

import numpy as np

EQUATION_FORMAT = "({:.2f})*({})^{} + "

def recursive_difference_solver(list_sequence: list, list_list_difference: List[List[int]] = None) -> List[List[int]]:
    """
    Find the finite differences

    :param list_sequence: list containing the sequence
    :param list_list_difference: list containing the differences
    :return: list_list_difference
    """

    # If there is no list_list_difference given then make one
    if list_list_difference is None:
        # List of differences
        list_list_difference = []

        # Append the given list_sequence to list_list_difference
        # list_list_difference.append(list_sequence)

    # If the current list_sequence is of size 1
    if len(list_sequence) == 1:
        # You can return nothing here as well!
        return list_list_difference

    # Make a temp difference list
    list_difference_temp = []

    # Loop through list_sequence comparing list_sequence[n] - list_sequence[n]
    for index in range(len(list_sequence) - 1):
        # Find the difference
        difference = list_sequence[index + 1] - list_sequence[index]

        # Append the difference to list_difference_temp
        list_difference_temp.append(difference)

    # Append list_difference_temp to list_list_difference
    list_list_difference.append(list_difference_temp)

    # Recursive call to find the other differences
    recursive_difference_solver(list_difference_temp, list_list_difference)

    # return the difference at end of the recursive call (eventually it will return to the caller)
    if len(list_list_difference[-1]) == 1:
        return list_list_difference

def find_row_index_with_same_values(list_list_difference: List[List]) -> int:
    """
    Find the row containing the similar values which determines the degree of the polynomial

    :param list_list_difference: list of differences
    :return: return the (index + 1) AKA the degree
    """
    for index, row in enumerate(list_list_difference):
        if len(set(row)) == 1:
            return index + 1

def get_polynomial_equation(degree: int, list_coefficient_values: Union[List, np.ndarray]) -> str:
    """
    Given the degree and the list_coefficient_values make the equation and return it as a string

    :param list_coefficient_values: the values of for the coefficients in the equation
    :param degree: the polynomial degree
    :return: return the equation
    """

    # Temp string of the polynomial
    equation_temp = ""

    """
    Loop through the degree and the coefficient value at the same time.
    Note that the degrees are reversed and that the reversed iterator is like a generator and can be used 1 time
    """
    for degree, coefficient_value in zip(reversed(range(0, degree + 1)), list_coefficient_values):
        equation_temp += EQUATION_FORMAT.format(coefficient_value, "x", degree)

    # Strip the space and the extra "+" at the end of the string
    equation_temp = equation_temp.strip().rstrip(" + ")

    return equation_temp

def get_x_values_matrix(degree: int, list_x_values: List[int] = None) -> List[List[int]]:
    """
    Get the matrix of the x values with their coefficients

    Notes:
        Ya i know that you can have any size list_x_values because the degree will be the limiter

    :param degree: degree of the polynomial
    :param list_x_values: list of x values that could be anything really...
    :return: matrix of the x values by their degree
    """

    # If you don't give a list_x_values then we'll just assume that it starts from 0 to the degree
    if list_x_values is None:
        list_x_values = list(range(degree + 1))

    # If the degree + 1 does not match the length of list_x_values
    if degree + 1 != len(list_x_values):
        print(
            "Degree + 1 and length of list_x_values do not match! x values: {}".format(str(list_x_values[degree + 1:])))
        # exit(1)

    # Temp Matrix
    matrix_temp = []

    # Note that reverse iterators get exhausting to make it into a list because reverse iterators are a 1 time use
    list_degrees_reversed = list(reversed(range(0, degree + 1)))

    # For value in list of x values
    for value in list_x_values:

        # Make a temp row
        row_temp = []

        # For degree in list of degrees revered
        for degree in list_degrees_reversed:
            # Append to row_temp the value^degree
            row_temp.append(value ** degree)

        # Add row_temp to the temp matrix
        matrix_temp.append(row_temp.copy())

    return matrix_temp

def check_if_solver_is_correct(equation_polynomial, matrix_column_coefficients, degree, list_x_values, list_sequence):
    """
    Check if sequence_equation_solver is correct

    :param equation_polynomial: The polynomial equation
    :param matrix_column_coefficients: column of coefficient values
    :param degree: degree of the polynomial
    :param list_x_values: list of x values for the given sequence
    :param list_sequence: sequence as a list
    :return:
    """
    list_degrees_reversed = list(reversed(range(degree + 1)))

    print("Polynomial Equation: {}".format(equation_polynomial))
    print("Checking if the values in list_sequence equal the Mathematical values...")
    print()
    for sequence_value, x_value in zip(list_sequence, list_x_values):

        # 1 liner arithmetic_expression_reduced_sum
        # arithmetic_expression_reduced_sum = sum([coefficient * (x_value ** degree) for coefficient, degree in
        #                                          zip(matrix_column_coefficients, list_degrees_reversed)])

        equation_temp = ""

        arithmetic_expression_reduced_sum = 0

        for coefficient, degree in zip(matrix_column_coefficients, list_degrees_reversed):
            equation_temp += EQUATION_FORMAT.format(coefficient, x_value, degree)

            arithmetic_expression_reduced_sum += coefficient * (x_value ** degree)

        # Strip the space and the extra "+" at the end of the string
        equation_temp = equation_temp.strip().rstrip(" + ")

        equation_temp += " = {}".format(arithmetic_expression_reduced_sum)
        print(equation_temp)
        print("Does Sequence value: {} == Arithmetic value: {} ?".format(sequence_value,
                                                                         arithmetic_expression_reduced_sum))
        print("Using math.isclose():", math.isclose(sequence_value, arithmetic_expression_reduced_sum))
        print("Using np.allclose():", np.allclose(sequence_value, arithmetic_expression_reduced_sum))

        print()

def sequence_equation_solver(list_sequence: List[int], list_x_values: List[int] = None):
    """
    Solve to find the sequence equation_polynomial

    :param list_sequence: List of the sequence
    :param list_x_values: list of x values
    :return: equation_polynomial
    """
    # Get the list of differences
    list_list_difference = recursive_difference_solver(list_sequence)

    print("List of differences:")
    for row in list_list_difference:
        print(row)
    print()

    row_index = find_row_index_with_same_values(list_list_difference)
    degree = row_index

    print("Find the row with the same difference value (row == degree):")
    print(row_index)
    print()

    # If you don't give a list_x_values then we'll just assume that it starts from 0 to the degree
    if list_x_values is None:
        list_x_values = list(range(degree + 1))

    # Create the x values matrix limited by the degree + 1
    matrix_x_values = get_x_values_matrix(degree, list_x_values[:degree + 1])

    print("Create the matrix of x values with their corresponding coefficient:")
    print(np.array(matrix_x_values))
    print()

    matrix_column_y = list_sequence[0:degree + 1]
    print("Create the Column matrix for the y values (Matches the size the degree + 1):")
    """
    Reference:
        Numpy print a 1d array as a column
            https://stackoverflow.com/questions/48724936/numpy-print-a-1d-array-as-a-column

    """
    print(np.array(matrix_column_y)[:, None])
    print()

    matrix_x_values_inverse = np.linalg.inv(matrix_x_values)
    print("Create the Inverse matrix of the x values:")
    print(matrix_x_values_inverse)
    print()

    matrix_column_coefficients = np.dot(matrix_x_values_inverse, matrix_column_y)
    print("The Dot product of the Inverse matrix of x values and the Column matrix for the y values, "
          "this gets the values of the coefficients:")
    print(matrix_column_coefficients)
    print()

    equation_polynomial = get_polynomial_equation(degree, matrix_column_coefficients)
    print("The Polynomial Equation:")
    print(equation_polynomial)
    print()

    return equation_polynomial, matrix_column_coefficients, degree, list_x_values, list_sequence

def test_example():
    # Example sequence
    list_sequence = [4, 14, 40, 88, 164]

    # This should be the length of the list as a list
    list_sequence_corresponding_x_values = list(range(len(list_sequence)))

    # Use this list to test any other values
    # list_sequence_corresponding_x_values = [-4, -2, 0, 2, 4]

    # Result of the solver
    result = sequence_equation_solver(list_sequence, list_sequence_corresponding_x_values)
    print("-" * 100)
    print()

    # Check if the solver is correct...
    check_if_solver_is_correct(*result)

if __name__ == '__main__':
    test_example()


"""Useful math utilities."""

import numpy as np

def softmax(x, t=1.0, axis=-1):
    x_ = x / t
    x_max = np.max(x_, axis=axis, keepdims=True)
    exps = np.exp(x_ - x_max)
    return exps / np.sum(exps, axis=axis, keepdims=True)

def log_softmax(x, t=1.0, axis=-1):
    x_ = x / t
    x_max = np.max(x_, axis=axis, keepdims=True)
    exps = np.exp(x_ - x_max)
    exp_sum = np.sum(exps, axis=axis, keepdims=True)
    return x_ - x_max - np.log(exp_sum)

def sigmoid(x):
    x = np.asarray(x)
    ret = np.zeros_like(x, dtype=float)
    ret[x > 0] = 1.0 / (1.0 + np.exp(-x[x > 0]))
    a = np.exp(x[x <= 0])
    ret[x <= 0] = a / (1.0 + a)
    return ret


import math
import numpy
import sympy

def function(x):
    return math.cos(x) + 3 * x + 1

def function_d(x):
    return 3 - math.sin(x)

def to_fixed(number):
    return f"{number:.{16}f}"

def results_output(results):
    print("---------------------------------------------------------")
    print("n \t| xn \t\t\t| f(xn) \t\t|")

    for i in range(len(results)):
        print("--------|-----------------------|-----------------------|")
        print(i, "\t|", results[i][0], "\t|", results[i][1], "\t|")

def dichotomy_method(a, b, eps):
    n = int(math.log2((b - a) / eps)) + 1
    results = []
    x = (a + b) / 2
    fx = function(x)

    results.append([x, to_fixed(fx)])

    if numpy.sign(a) == numpy.sign(fx):
        a = x
    else:
        b = x
    prev = x
    x = (a + b) / 2
    fx = function(x)
    results.append([x, to_fixed(fx)])

    while abs(x - prev) >= 2 * eps:
        if numpy.sign(a) == numpy.sign(fx):
            a = x
        else:
            b = x
        prev = x
        x = (a + b) / 2
        fx = function(x)
        results.append([x, to_fixed(fx)])

    print("-------------------Dichotomy Results---------------------")
    print("A priory mark: ", n)
    print("A posteriori mark: ", len(results))
    results_output(results)
    print("---------------------------------------------------------")

def find_max(x1, x2):
    maximum = 0
    i = x1
    while i < x2:
        maximum = function_d(i) if function_d(i) > maximum else maximum
        i += 0.001
    return maximum

def relaxation_method(a, b, eps):
    fda = abs(function_d(a))
    fdb = abs(function_d(b))
    min1 = fdb if fda > fdb else fda
    max1 = math.ceil(find_max(a, b))
    print("Min: ", min1, "Max: ", max1)
    x = a
    prev = 100
    z0 = abs(x)
    q = (max1 - min1)/(max1 + min1)
    t0 = 2/(max1 + min1)
    n = int(numpy.log(abs(z0)/eps)/numpy.log(1/q)) + 1
    fx = function(x)

    results = [[x, to_fixed(fx)]]
    while abs(prev - x) >= eps:
        prev = x
        x = prev - t0 * function(prev)
        fx = function(x)
        results.append([x, to_fixed(fx)])

    print("-------------------Relaxation Results---------------------")
    print("A priory mark: ", n)
    print("A posteriori mark: ", len(results))
    results_output(results)
    print("---------------------------------------------------------")

def main():
    a = -1*math.pi
    b = 0.5
    eps = 0.0001
    dichotomy_method(a, b, eps)
    relaxation_method(a, b, eps)

main()


# Question 03, Lab 05
# AB Satyaprakash - 180123062

# imports ----------------------------------------------------------------------------
from math import log, sin, pi
from sympy.abc import t
import numpy as np
import pandas as pd
import sympy as sp

# global dictionaries ----------------------------------------------------------------
phi = {-1: 0, 0: 1}
alpha = {}
beta = {0: 0}

# functions --------------------------------------------------------------------------

def simpsonRule(f, a, b, h):
    return ((h/3)*(f.subs(t, a)+4*f.subs(t, (a+b)/2)+f.subs(t, b))).evalf()

def compositeSimpsonRule(X):
    sum = 0
    a, b = X[0], X[-1]
    n = X.shape[0]
    h = (b-a)/(n-1)
    for i in range(X.shape[0]):
        x = X[i]
        if(i == 0 or i == n-1):
            sum += getFuncVal(x)
        else:
            if(i % 2 == 0):
                sum += 2*getFuncVal(x)
            else:
                sum += 4*getFuncVal(x)
    return (h*sum)/3

def getFuncVal(x):
    return 1/(1+x)

def getInnerProduct(a, b):
    poly = np.poly1d(np.polyint(np.polymul(a, b)))
    return poly(1) - poly(-1)

def getPhi(n):
    # The value of ϕ(n) = (x-α(n-1))ϕ(n-1) - β(n)ϕ(n-2)
    if n in phi:
        return phi[n]

    a = getAlpha(n-1)
    b = getBeta(n-1)
    phi_n_1 = getPhi(n-1)
    phi_n_2 = getPhi(n-2)

    secondTerm = np.polymul([b], phi_n_2)
    firstTerm = np.polymul(np.polysub([1, 0], a), phi_n_1)
    phi[n] = np.polysub(firstTerm, secondTerm)
    return phi[n]

def getAlpha(n):
    # The value of α(n) = <xϕ(n), ϕ(n)>/<ϕ(n) , ϕ(n)>
    if n in alpha:
        return alpha[n]

    phi_n = getPhi(n)
    xphi_n = np.polymul([1, 0], phi_n)
    num = getInnerProduct(xphi_n, phi_n)
    denom = getInnerProduct(phi_n, phi_n)
    alpha[n] = num/denom

    return alpha[n]

def getBeta(n):
    # The value of β(n) = <ϕ(n), ϕ(n)>/<ϕ(n-1) , ϕ(n-1)>
    if n in beta:
        return beta[n]

    phi_n = getPhi(n)
    phi_n_1 = getPhi(n-1)
    num = getInnerProduct(phi_n, phi_n)
    denom = getInnerProduct(phi_n_1, phi_n_1)
    beta[n] = num/denom

    return beta[n]

def getGaussian(roots, W, limits):
    a, b = limits
    I = 0
    for x, w in zip(roots, W):
        I += w*f(x, a, b)
    return I

def f(x, a, b):
    c1, c2 = (b-a)/2, (b+a)/2
    x = c1*x + c2
    return c1*getFuncVal(x)

# program body
# using 3 point Gaussian Quadrature rule!
n = 3
poly = np.poly1d(getPhi(n))
roots = poly.r
roots.sort()
temp = [[1] + [0]*(i) for i in range(n)]

output = []
for P in temp:
    P = (np.polyint(P))
    P = np.poly1d(P)
    I = P(1) - P(-1)
    output.append(I)

X = []
for i in range(n):
    temp = [x**i for x in roots]
    X.append(temp)
X_ = np.linalg.inv(X)
W = np.dot(X_, output)

# Given integral = ∫1/(1+x) from 0 to 1
limits = (0, 1)
result = getGaussian(roots, W, limits)
print("Using 3 point Gaussian Quadrature rule approx. value of integral is {}".format(result))

h = 0.125  # (given in question)
X = np.arange(0, 1+h/2, h)
simpsonValue = compositeSimpsonRule(X)
print("Using Simpson's 1/3 rule with h = {} approximate value of the integral is {}".format(h, simpsonValue))

func = 1/(1+t)
actualIntegratedValue = sp.integrate(func, (t, 0, 1)).evalf()
print("Actual value of integral is {}".format(
    actualIntegratedValue))

print('\n------------------------------------------------------------\n')
print("Error in estimation for Gaussain Quadrature rule = {}".format(
    abs(actualIntegratedValue-result)))
print("Error in estimation for Simpson's rule = {}".format(
    abs(actualIntegratedValue-simpsonValue)))

Semester 6/MA 322 (Scientific Computing Theory)/Labs/Lab 5/Code/q4.py


"""Is matrix a unitary matrix."""
import numpy as np

from toqito.matrix_props import is_square

def is_unitary(mat: np.ndarray, rtol: float = 1e-05, atol: float = 1e-08) -> bool:
    r"""
    Check if matrix is unitary [WikUnitary]_.

    A matrix is unitary if its inverse is equal to its conjugate transpose.

    Alternatively, a complex square matrix :math:`U` is unitary if its conjugate transpose
    :math:`U^*` is also its inverse, that is, if

    .. math::
        \begin{equation}
            U^* U = U U^* = \mathbb{I},
        \end{equation}

    where :math:`\mathbb{I}` is the identity matrix.

    Examples
    ==========

    Consider the following matrix

    .. math::
        X = \begin{pmatrix}
            0 & 1 \\
            1 & 0
            \end{pmatrix}

    our function indicates that this is indeed a unitary matrix.

    >>> from toqito.matrix_props import is_unitary
    >>> import numpy as np
    >>> A = np.array([[0, 1], [1, 0]])
    >>> is_unitary(A)
    True

    We may also use the `random_unitary` function from `toqito`, and can verify that a randomly
    generated matrix is unitary

    >>> from toqito.matrix_props import is_unitary
    >>> from toqito.random import random_unitary
    >>> mat = random_unitary(2)
    >>> is_unitary(mat)
    True

    Alternatively, the following example matrix :math:`B` defined as

    .. math::
        B = \begin{pmatrix}
            1 & 0 \\
            1 & 1
            \end{pmatrix}

    is not unitary.

    >>> from toqito.matrix_props import is_unitary
    >>> import numpy as np
    >>> B = np.array([[1, 0], [1, 1]])
    >>> is_unitary(B)
    False

    References
    ==========
    .. [WikUnitary] Wikipedia: Unitary matrix.
        https://en.wikipedia.org/wiki/Unitary_matrix

    :param mat: Matrix to check.
    :param rtol: The relative tolerance parameter (default 1e-05).
    :param atol: The absolute tolerance parameter (default 1e-08).
    :return: Return :code:`True` if matrix is unitary, and :code:`False` otherwise.
    """
    if not is_square(mat):
        return False

    uc_u_mat = mat.conj().T @ mat
    u_uc_mat = mat @ mat.conj().T
    id_mat = np.eye(len(mat))

    # If U^* * U = I U * U^*, the matrix "U" is unitary.
    return np.allclose(uc_u_mat, id_mat, rtol=rtol, atol=atol) and np.allclose(
        u_uc_mat, id_mat, rtol=rtol, atol=atol
    )


import numpy as np
from math import log

class Normalizer(object):
  """
  Default normalizer (no normalisation)
  """

  @staticmethod
  def normalize(matrix):
    return matrix

class TFIDF(Normalizer):
  @staticmethod
  def normalize(matrix):
    """
    Normalizes the frequency counts as per the TF-IDF scheme (Salton and McGill, 1986)
    (term frequency–inverse document frequency)

    :param matrix: The source/term frequency matrix
    :type  matrix: numpy.matrix
    :return: The normalized source/term frequency matrix
    """
    # create a copy of it
    tfidf_matrix = matrix.copy()
    rows, cols = matrix.shape
    # gives the words for each document
    words_per_doc = np.sum(matrix, axis=0)
    # gives how many documents the word appears in
    docs_per_word = np.sum(np.asarray(matrix > 0, 'i'), axis=1)

    for i in range(rows):
      for j in range(cols):
        # calculate tfidf
        tfidf_matrix[i][j] = (matrix[i][j] / words_per_doc[j]) * log(float(cols) / docs_per_word[i])

    return tfidf_matrix


# -*- coding: utf-8 -*-
"""
Created on Sun Nov 22 21:08:04 2020

@author: franklin

https://aaronschlegel.me/black-scholes-formula-python.html
"""

import numpy as np
import scipy.stats as si
import itertools

def euro_vanilla(S, K, T, r, sigma, option = 'call'):

    #S: spot price
    #K: strike price
    #T: time to maturity
    #r: interest rate
    #sigma: volatility of underlying asset

    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    d2 = (np.log(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))

    if option == 'call':
        result = (S * si.norm.cdf(d1, 0.0, 1.0) - K * np.exp(-r * T) * si.norm.cdf(d2, 0.0, 1.0))
    if option == 'put':
        result = (K * np.exp(-r * T) * si.norm.cdf(-d2, 0.0, 1.0) - S * si.norm.cdf(-d1, 0.0, 1.0))

    return result

S, K, T, r, sigma = (50, 100, 1, 0.05, 0.25)
retCall = euro_vanilla(S, K, T, r, sigma)
retPut = euro_vanilla(S, K, T, r, sigma, option = 'put')
print(retCall)
print(retPut)

arrayS = list(range(1,101))
arraySigma = [x * 0.1 for x in range(1,101)]

#直積
#A={a, b, c}, B={d, e}
#A×B={(a,d),(a,e),(b,d),(b,e),(c,d),(c,e)}A×B={(a,d),(a,e),(b,d),(b,e),(c,d),(c,e)}
combi = list(itertools.product(arrayS, arraySigma))

def calc():
    results = []
    for S, sigma in combi:
        pv = euro_vanilla(S, K, T, r, sigma)
        # print(pv)
        results.append(pv)
    return results

#%timeit calc()
PVs = calc()

# import numpy as np
# output=np.array(combi)
# np.savetxt('combi.csv', output, delimiter=',', fmt='%f')


import numpy as np

def reg_poly(n, orientation):
    """Returns coordinates of a regular polygon

    Parameters
    ----------
    orientation: float
        The angle/orientation of the polygon

    n: positive integer
        number of sides

    Returns
    -------
    center: 1d numpy array of two elements
        center of the polygon
    vertices: list of 1d numpy arrays of two elements
        vertices of the polygon, going counterclockwise
    """
    # calculate n angles evenly spaces between zero and 2pi and then add the orientation
    angs = orientation + np.linspace(start=0, stop=2*np.pi*(n-1)/n, num=n)

    # define the center of the polygon as the origin
    center = np.array([0,0]).reshape(1,-1)

    # calculate x-y coords where each angle meets the unit circle
    vertices = np.concatenate( [np.cos(angs).reshape(-1,1), np.sin(angs).reshape(-1,1)], axis = 1 )
    return center, vertices

def iterate_shape(center, vertices, iters, scaling=0.5, rotation=0):
    """Replaces vertices of shape with scaled and
    rotated copies of the original shape. Can repeat
    process many times.

    Parameters
    ----------
    center: 1x2 numpy array
        The center of the original shape
    vertices: nx2 numpy array
        shape points
    iters: int
        number of times to repeat process
    scaling: float
        how much point-replacing copies
        of shape get scaled down from prev
        iteration
    rotation: float
        how much point-replacing copies
        of shape get rotated relative to
        prev iteration

    Returns
    -------
    all_coords: ?x2 numpy array
        array of new points in shape generated
        by applied the transformations
    """

    # initialize all_coords with the center
    all_coords = center.reshape(1,-1)
    # count number of vertices
    n_vertices = vertices.shape[0]

    # calculate vars for rotation matrix
    if rotation != 0:
        cos = np.cos(rotation)
        sin = np.sin(rotation)

    # for each iteration...
    for i in range(iters):
        # define an array to contain the next iteration of coordinates
        new_coords = np.ndarray(shape = (all_coords.shape[0]*n_vertices, 2))

        # rescale the vertices
        vertices = vertices * scaling
        # rotate the vertices if necessary
        if rotation != 0:
            vertices = np.array( [cos*vertices[:,0] - sin*vertices[:,1],
                                  sin*vertices[:,0] + cos*vertices[:,1]] ).T

        # create counter to record where in the new_coords array to input coords
        counter = 0

        # for every coordinate in all_coords,
        # record coords of a shape with vertices centered at that coordinate
        for coord in all_coords:
            new_coords[counter:(counter+n_vertices)] = coord + vertices
            counter += n_vertices

        # update all_coords with new_coords
        all_coords = new_coords
    return all_coords

def reg_poly_fractal(n_vertices, iters, scaling=0.5, rotation=0):
    """Produces iterated shape of regular
    polygon with n_vertices

    Parameters
    ----------
    n_vertices: int
        number of sides of regular polygon
    iters: int
        number of times to repeat process
    scaling: float
        how much point-replacing copies
        of shape get scaled down from prev
        iteration
    rotation: float
        how much point-replacing copies
        of shape get rotated relative to
        prev iteration

    Returns
    -------
    all_coords: ?x2 numpy array
        array of new points in shape generated
        by applied the transformations
    """
    c,v = reg_poly(n_vertices, np.pi/2)
    shape = iterate_shape(c, v, iters=iters, scaling=scaling, rotation=rotation)
    return shape


import numpy as np
from  scipy import sparse
import random
import networkx as nx
import matplotlib.pyplot as plt
from itertools import count
import time

Filename = "Wiki-Vote.txt"
NODES = 9000
EDGES = 103689

#function to compute Page Rank for the given adjacency matrix of the graph
#beta and epsilon is feeded into the function as constants
#return the number of iterations and rank matrix
def Estimate_PageRank(M, beta=0.85, epsilon=10**-4):

#as given matrix is adjacency matrix
#adjusting the matrix to get the stochastic adjacency matrix

	#calculating the outdegrees of each node with the help of sum function
	#incorporating even the beta value here i.e. di/beta
	#Transpose is needed as sum at axis=0 returns row vector but ranks are column vectors
	OutDegree_beta = M.sum(axis=0).T/beta
	n,_ = M.shape					#number of nodes
	ranks = np.ones((n,1))/n 		#Initial rank matrix to start the iterations i.e. 1/n
	iterations = 0					#number of iterations
	check = True					#Variable to loop the iteration

	#Declarations reqiured for Graph Visualisation:
	G=nx.DiGraph()					#Directed Graph using networkx for plotting the visualisations
	nodes=[]						#Stores the list of random nodes generated for plotting the graph
	size=[]							#List of sizes of the nodes which is scaled up factor of their ranks
	labels={}						#Labels of the nodes which is scaled up factor of their ranks

	#while loop for Page rank iterations
	while check:
	    iterations +=1
	    with np.errstate(divide='ignore'):				#Ignore division by 0 on ranks/OutDegree_beta
	    	#newranks=Beta*M*r(t-1)
	    	rank_next = M.dot((ranks/OutDegree_beta))	#Multiplying the ranks from previous iterations here
	        											#Injecting Stochastic behaviour by dividing rank with earlier computed outdegrees

	    #Next update ranks with (1-Beta)*r(t-1)/N

	    #rank_sum stores the matrix after the
	    rank_sum=np.ones((n,1))*ranks.sum()
	    rank_next=rank_next+rank_sum*(1-beta)/n

	    #Stop condition: if difference is less than epsilon then stop iterating
	    if np.linalg.norm(ranks-rank_next,ord=1)<=epsilon:
	        check = False
	    ranks = rank_next

	for x in range(100):					 #Generating 100 random nodes
		t=random.randint(1,8000)
		nodes.append(t)						 #appending the nodes in list
		size.append(10000000000*ranks[t])	 #storing their corresponding ranks as sizes
		labels[t]=(int)(10000000000*ranks[t])#labels as scaled up ranks

	for key in nodes:						 #adding the nodes and their corresponding edges in G garph
	 	G.add_node(key)
	 	for j in nodes:
	 		if M[j,key]==1:					 #edges are given by the adjacency matrix
	 			G.add_edge(key,j)
	'''
	#to remove isolated nodes from the graph
	for x in nx.isolates(G):
		G.remove_node(x)
		nodes.remove(x)
		size.remove(10000000000*ranks[x])
		del labels[x]
	'''

	nx.draw_random(G,node_list=nodes,node_size=size,labels=labels,with_labels=True)
	plt.show()
	return(ranks,iterations)

def sparse_Dic():
    with open(Filename,'r') as f:
        sp_dic_mat = sparse.dok_matrix((NODES,NODES),dtype=np.bool)
        for line in f.readlines()[4:]:
            from_node, to_node = (int(x)-1 for x in line.split())
            sp_dic_mat[to_node,from_node]=True
    return(sp_dic_mat.tocsr())

print('Estimating page rank:')
sp_csr=sparse_Dic()
start_time = time.time()
pr , iterate = Estimate_PageRank(sp_csr)
print('\nIterations: {0}'.format(iterate))
print('Node with maximum pagerank is: {0}'.format(np.argmax(pr)+1))
print("%s"% (time.time()-start_time))


# https://www.youtube.com/watch?v=ffSlRUmc7Ew

import numpy as np
import scipy.io.wavfile as wav

def makeWave(length, amp, freq, phase, rate=44100):
   input = np.arange(0.0, length, 1.0/rate)
   print("Sample Array Length and Values: "); print( len(input)) ; print(input)
   result = amp * np.sin(2*np.pi * freq * input + phase)
   return result

# In a second period what can we achieve

period = 1.0 # In seconds
pitchfrequency = 440.0 # Concert Pitch
amplitude = 1.0
phase = 0

# Case 1
# samplerate = 44100 # Sample per second
# wave = makeWave(period, amplitude, pitchfrequency, phase, samplerate)

# Case 2
# samplerate = 1000 # Sample per second
# period = 1.0 # In seconds
# phase = 0.5*np.pi # causing anti-aliasing
# wave = makeWave(period, amplitude, pitchfrequency, phase, samplerate)

# Case 3
# samplerate = 440 # Sample per second
# pitchfrequency = 294.0 # D3

# Case 4
samplerate = 440 # same sample rate as pitch frequency

# Case 5
# samplerate = 3 # Sample per second
# amplitude = 2.0

# Case 6
# samplerate = 10 # Sample per second

# Main Program
wave = makeWave(period, amplitude, pitchfrequency, phase, samplerate)
wav.write("test.wav", samplerate, wave)


#!/usr/bin/env python3
import numpy as np
import sklearn.preprocessing as preprocessing

input_data = np.array([[2.1, -1.9, 5.5],
                      [-1.5, 2.4, 3.5],
                      [0.5, -7.9, 5.6],
                      [5.9, 2.3, -5.8]])
#Binarization
data_binarized = preprocessing.Binarizer(threshold = 0.5).transform(input_data)
print("\nBinarized data:\n", data_binarized)

#https://wiki.multimedia.cx/index.php/Mean_Removal
print('\nMean Removal\n')
print("Mean = ", input_data.mean(axis = 0))
print("Std deviation = ", input_data.std(axis = 0))
data_scaled = preprocessing.scale(input_data)
print("Mean =", data_scaled.mean(axis=0))
print("Std deviation =", data_scaled.std(axis = 0))
print('\nMin Max Scaling\n')
data_scaler_minmax = preprocessing.MinMaxScaler(feature_range=(0,1))
data_scaled_minmax = data_scaler_minmax.fit_transform(input_data)
print ("Min max scaled data:\n", data_scaled_minmax)

print('\nNormalize data\n')
data_normalized_l1 = preprocessing.normalize(input_data, norm = 'l1')
print("\nL1 (Least Absolute) normalized data:\n", data_normalized_l1)
# Normalize data
data_normalized_l2 = preprocessing.normalize(input_data, norm = 'l2')
print("\nL2 (Least square) normalized data:\n", data_normalized_l2)


import numpy as np
import matplotlib.pyplot as plt

# import tensorflow as tf
# from tensorflow.keras.layers import Layer
# from tensorflow.keras.initializers import RandomUniform, Initializer,

def gaussian_rbf(x, landmark, gamma=1):
    return np.exp(-gamma * np.linalg.norm(x - landmark) ** 2)

def end_to_end(X1, X2, ys, mu1, mu2):
    from_1 = [gaussian_rbf(i, mu1) for i in zip(X1, X2)]
    from_2 = [gaussian_rbf(i, mu2) for i in zip(X1, X2)]
    # plot

    plt.figure(figsize=(13, 5))
    plt.subplot(1, 2, 1)
    plt.scatter((x1[0], x1[3]), (x2[0], x2[3]), label="Class_0")
    plt.scatter((x1[1], x1[2]), (x2[1], x2[2]), label="Class_1")
    plt.xlabel("$X1$", fontsize=15)
    plt.ylabel("$X2$", fontsize=15)
    plt.title("Xor: Linearly Inseparable", fontsize=15)
    plt.legend()
    plt.subplot(1, 2, 2)
    plt.scatter(from_1[0], from_2[0], label="Class_0")
    plt.scatter(from_1[1], from_2[1], label="Class_1")
    plt.scatter(from_1[2], from_2[2], label="Class_1")
    plt.scatter(from_1[3], from_2[3], label="Class_0")
    plt.plot([0, 0.95], [0.95, 0], "k--")
    plt.annotate("Seperating hyperplane", xy=(0.4, 0.55), xytext=
    (0.55, 0.66),
                 arrowprops=dict(facecolor='black', shrink=0.05))
    plt.xlabel(f"$mu1$: {(mu1)}", fontsize=15)
    plt.ylabel(f"$mu2$: {(mu2)}", fontsize=15)
    plt.title("Transformed Inputs: Linearly Seperable", fontsize=15)
    plt.legend()
    # solving problem using matrices form
    # AW = Y
    A = []
    for i, j in zip(from_1, from_2):
        temp = []
        temp.append(i)
        temp.append(j)
        temp.append(1)
        A.append(temp)

    A = np.array(A)
    W = np.linalg.inv(A.T.dot(A)).dot(A.T).dot(ys)
    print(np.round(A.dot(W)))
    print(ys)
    print(f"Weights: {W}")
    return W

def predict_matrix(point, weights):
    gaussian_rbf_0 = gaussian_rbf(np.array(point), mu1)
    gaussian_rbf_1 = gaussian_rbf(np.array(point), mu2)
    A = np.array([gaussian_rbf_0, gaussian_rbf_1, 1])
    return np.round(A.dot(weights))

# points
x1 = np.array([0, 0, 1, 1])
x2 = np.array([0, 1, 0, 1])
ys = np.array([0, 1, 1, 0])
# centers
mu1 = np.array([0, 1])
mu2 = np.array([1, 0])
w = end_to_end(x1, x2, ys, mu1, mu2)
# testing
print(f"Input:{np.array([0, 0])}, Predicted:{predict_matrix(np.array([0, 0]), w)}")
print(f"Input:{np.array([0, 1])}, Predicted:{predict_matrix(np.array([0, 1]), w)}")
print(f"Input:{np.array([1, 0])}, Predicted:{predict_matrix(np.array([1, 0]), w)}")
print(f"Input:{np.array([1, 1])}, Predicted:{predict_matrix(np.array([1, 1]), w)}")


import scipy.integrate as spi
import numpy as np

print('Double integral computed by SciPy dblquad')
print('Example 2-01 dblquad')
print('Integral of 2xye^-xy from y=1 to y=5 and from x=y-1 to x=y+1')

integrand = lambda x, y : 2 * x * y * np.exp(-x * y)
ya = 1.
yb = 5.

result, error = spi.dblquad(integrand, ya, yb, lambda y: y-1, lambda y: y+1)
print('Result is ', result, 'with error ', error)


import numpy as np
from numpy import linalg as LA

def outerProduct(X):
    """Computer outer product and indicate which locations in matrix are undefined"""
    O=np.outer(X,X)
    N=1-np.isnan(O)
    return (O,N)

def sumWithNan(M1,M2):
    """Add two pairs of (matrix,count)"""
    (X1,N1)=M1
    (X2,N2)=M2
    N=N1+N2
    X=np.nansum(np.dstack((X1,X2)),axis=2)
    return (X,N)

### HW: Replace the RHS of the expressions in this function (They need to depend on S and N.
def HW_func(S,N):
    E=      np.ones([365]) # E is the sum of the vectors
    NE=     np.ones([365]) # NE is the number of not-nan antries for each coordinate of the vectors
    Mean=   np.ones([365]) # Mean is the Mean vector (ignoring nans)
    O=      np.ones([365,365]) # O is the sum of the outer products
    NO=     np.ones([365,365]) # NO is the number of non-nans in the outer product.
    return  E,NE,Mean,O,NO

def computeCov(RDDin):
    """computeCov recieves as input an RDD of np arrays, all of the same length,
    and computes the covariance matrix for that set of vectors"""
    RDD=RDDin.map(lambda v:np.array(np.insert(v,0,1),dtype=np.float64)) # insert a 1 at the beginning of each vector so that the same
                                           #calculation also yields the mean vector
    OuterRDD=RDD.map(outerProduct)   # separating the map and the reduce does not matter because of Spark uses lazy execution.
    (S,N)=OuterRDD.reduce(sumWithNan)

    E,NE,Mean,O,NO=HW_func(S,N)

    Cov=O/NO - np.outer(Mean,Mean)
    # Output also the diagnal which is the variance for each day
    Var=np.array([Cov[i,i] for i in range(Cov.shape[0])])
    return {'E':E,'NE':NE,'O':O,'NO':NO,'Cov':Cov,'Mean':Mean,'Var':Var}

if __name__=="__main__":
    # create synthetic data matrix with j rows and rank k

    V=2*(np.random.random([2,10])-0.5)
    data_list=[]
    for i in range(1000):
        f=2*(np.random.random(2)-0.5)
        data_list.append(np.dot(f,V))
    # compute covariance matrix
    RDD=sc.parallelize(data_list)
    OUT=computeCov(RDD)

    #find PCA decomposition
    eigval,eigvec=LA.eig(OUT['Cov'])
    print('eigval=',eigval)
    print('eigvec=',eigvec)

Big Data Analytics Using Spark/Section2-Weather-PCA_PART1/lib/spark_PCA_HW.py


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Weighted residual methods in 1D

@author: Nicolas Guarin-Zapata
"""
from __future__ import division, print_function
from sympy import zeros, symbols, S
from sympy import integrate, diff, linsolve
from sympy import sin, pi

def least_squares(lhs, rhs, basis, nterms, domain=(0, 1)):
    """
    Return matrices for least squares solution of differential
    equations
    """
    x0, x1 = domain
    x = symbols("x")
    A_mat = zeros(nterms, nterms)
    b_vec = zeros(nterms, 1)
    for row in range(nterms):
        phi_i = basis(x, row)
        b_vec[row] = integrate(rhs(x)*lhs(phi_i, x), (x, x0, x1))
        for col in range(nterms):
            phi_j = basis(x, col)
            A_mat[row, col] = integrate(lhs(phi_i, x)*lhs(phi_j, x),
                                       (x, x0, x1))
    return A_mat, b_vec

def collocation(lhs, rhs, basis, nterms, domain=(0, 1), x_col=None):
    """
    Return matrices for least squares solution of differential
    equations
    """
    x0, x1 = domain
    if x_col is None:
        dx = S(x1 - x0)/(nterms - 2)
        x_col = [dx + dx*cont for cont in range(nterms)]
    x = symbols("x")
    A_mat = zeros(nterms, nterms)
    b_vec = zeros(nterms, 1)
    for row in range(nterms):
        b_vec[row] = rhs(x_col[row])
        for col in range(nterms):
            phi_j = basis(x, col)
            A_mat[row, col] = lhs(phi_j, x).subs(x, x_col[row])
    return A_mat, b_vec

def galerkin(lhs, rhs, basis, nterms, domain=(0, 1)):
    """
    Return matrices for Galerkin solution of differential
    equations
    """
    x0, x1 = domain
    x = symbols("x")
    A_mat = zeros(nterms, nterms)
    b_vec = zeros(nterms, 1)
    for row in range(nterms):
        phi_i = basis(x, row)
        b_vec[row] = integrate(rhs(x)*phi_i, (x, x0, x1))
        for col in range(nterms):
            phi_j = basis(x, col)
            A_mat[row, col] = integrate(lhs(phi_i, x)*phi_j, (x, x0, x1))
    return A_mat, b_vec

if __name__ == "__main__":
    basis = lambda x, k: x*(1 - x)*x**k
    lhs = lambda u, x: diff(u, x, 2) + u
    rhs = lambda x: -x
    x = symbols("x")
    u_e = sin(x)/sin(1) - x
    nterms = 10
    c = symbols('c0:%d' % nterms)
#    A, b = least_squares(lhs, rhs, basis, nterms)
#    A, b = collocation(lhs, rhs, basis, nterms)
    A, b =  galerkin(lhs, rhs, basis, nterms)
    sol = linsolve((A, b), c)
    subs = dict(zip(c, sol.args[0]))
    u = sum(c[cont]*basis(x, cont) for cont in range(nterms)).subs(subs)


"""

    This module calculates a linear system by Gaussian elimination with pivoting.
    Almost a copy of on Mike Zingale's code, spring 2013.

"""

import numpy as npy

def gaussElim(A, b):
    """ perform gaussian elimination with pivoting, solving A x = b A
        is an NxN matrix, x and b are an N-element vectors.  Note: A
        and b are changed upon exit to be in upper triangular (row
        echelon) form """

    # b is a vector
    if not b.ndim == 1:
        print "ERROR: b should be a vector"
        return None

    N = len(b)

    # A is square, with each dimension of length N
    if not (A.shape[0] == N and A.shape[1] == N):
        print "ERROR: A should be square with each dim of same length as b"
        return None

    # allocation the solution array
    x = npy.zeros((N), dtype=A.dtype)

    # find the scale factors for each row -- this is used when pivoting
    scales = npy.max(npy.abs(A), 1)

    # keep track of the number of times we swapped rows
    numRowSwap = 0

    # main loop over rows
    for k in range(N):

        # find the pivot row based on the size of column k -- only consider
        # the rows beyond the current row
        rowMax = npy.argmax(A[k:, k]/scales[k:])
        if (k > 0): rowMax += k  # we sliced A from k:, correct for total rows

        # swap the row with the largest scaled element in the current column
        # with the current row (pivot) -- do this with b too!
        if not rowMax == k:
            A[[k, rowMax],:] = A[[rowMax, k],:]
            b[[k, rowMax]] = b[[rowMax, k]]
            numRowSwap += 1

        # do the forward-elimination for all rows below the current
        for i in range(k+1, N):
            coeff = A[i,k]/A[k,k]

            for j in range(k+1, N):
                A[i,j] += -A[k,j]*coeff

            A[i,k] = 0.0
            b[i] += -coeff*b[k]

    # last solution is easy
    x[N-1] = b[N-1]/A[N-1,N-1]

    for i in reversed(range(N-1)):
        isum = b[i]
        for j in range(i+1,N):
            isum += -A[i,j]*x[j]
        x[i] = isum/A[i,i]

    return x


"""This file contains code used in "Think Stats",
by Allen B. Downey, available from greenteapress.com

Copyright 2014 Allen B. Downey
License: GNU GPLv3 http://www.gnu.org/licenses/gpl.html
"""

from __future__ import print_function

import numpy as np

import density
import hinc
import thinkplot
import thinkstats2

"""This file contains a solution to an exercise in Think Stats:

The distribution of income is famously skewed to the right.  In this
exercise, we'll measure how strong that skew is.
...

Compute the median, mean, skewness and Pearson's skewness of the
resulting sample.  What fraction of households reports a taxable
income below the mean?  How do the results depend on the assumed
upper bound?

My results with log_upper=6

mean 74278.7075312
std 93946.9299635
median 51226.4544789
skewness 4.94992024443
pearson skewness 0.736125801914
cdf[mean] 0.660005879567

With log_upper=7

mean 124267.397222
std 559608.501374
median 51226.4544789
skewness 11.6036902675
pearson skewness 0.391564509277
cdf[mean] 0.856563066521

With a higher upper bound, the moment-based skewness increases, as
expected.  Surprisingly, the Pearson skewness goes down!  The reason
seems to be that increasing the upper bound has a modest effect on the
mean, and a stronger effect on standard deviation.  Since std is in
the denominator with exponent 3, it has a stronger effect on the
result.

So this is apparently an example where Pearson skewness is not working
well as a summary statistic.  A better choice is a statistic that has
meaning in context, like the fraction of people with income below the
mean.  Or something like the Gini coefficient designed to quantify a
property of the distribution (like the relative difference we expect
between two random people).

"""

def InterpolateSample(df, log_upper=6.0):
    """Makes a sample of log10 household income.

    Assumes that log10 income is uniform in each range.

    df: DataFrame with columns income and freq
    log_upper: log10 of the assumed upper bound for the highest range

    returns: NumPy array of log10 household income
    """
    # compute the log10 of the upper bound for each range
    df['log_upper'] = np.log10(df.income)

    # get the lower bounds by shifting the upper bound and filling in
    # the first element
    df['log_lower'] = df.log_upper.shift(1)
    df.log_lower[0] = 3.0

    # plug in a value for the unknown upper bound of the highest range
    df.log_upper[41] = log_upper

    # use the freq column to generate the right number of values in
    # each range
    arrays = []
    for _, row in df.iterrows():
        vals = np.linspace(row.log_lower, row.log_upper, row.freq)
        arrays.append(vals)

    # collect the arrays into a single sample
    log_sample = np.concatenate(arrays)
    return log_sample

def main():
    df = hinc.ReadData()
    log_sample = InterpolateSample(df, log_upper=6.0)

    log_cdf = thinkstats2.Cdf(log_sample)
    thinkplot.Cdf(log_cdf)
    thinkplot.Show(xlabel='household income',
                   ylabel='CDF')

    sample = np.power(10, log_sample)
    mean, median = density.Summarize(sample)

    cdf = thinkstats2.Cdf(sample)
    print('cdf[mean]', cdf[mean])

    pdf = thinkstats2.EstimatedPdf(sample)
    thinkplot.Pdf(pdf)
    thinkplot.Show(xlabel='household income',
                   ylabel='PDF')

if __name__ == "__main__":
    main()

DSC 530 - Data Exploration and Analysis/ThinkStats2/code/chap06soln.py


# -*- coding: utf-8 -*-#
'''
# Name:         LeastSquare
# Description:  LeastSquare 最小二乘法
# Author:       super
# Date:         2020/5/8
'''

# 用最小二乘法得到解析解LSE

import numpy as np
import matplotlib.pyplot as plt
from pathlib import Path

from HelperClass.DataReader_1_0 import *

file_name = "../data/ch04.npz"

# 根据公式15
def method1(X,Y,m):
    x_mean = X.mean()
    p = sum(Y*(X-x_mean))
    q = sum(X*X) - sum(X)*sum(X)/m
    w = p/q
    return w

# 根据公式16
def method2(X,Y,m):
    x_mean = X.mean()
    y_mean = Y.mean()
    p = sum(X*(Y-y_mean))
    q = sum(X*X) - x_mean*sum(X)
    w = p/q
    return w

# 根据公式13
def method3(X,Y,m):
    p = m*sum(X*Y) - sum(X)*sum(Y)
    q = m*sum(X*X) - sum(X)*sum(X)
    w = p/q
    return w

# 根据公式14
def calculate_b_1(X,Y,w,m):
    b = sum(Y-w*X)/m
    return b

# 根据公式9
def calculate_b_2(X,Y,w):
    b = Y.mean() - w * X.mean()
    return b

if __name__ == '__main__':

    reader = DataReader_1_0(file_name)
    reader.ReadData()
    X,Y = reader.GetWholeTrainSamples()
    m = X.shape[0]
    w1 = method1(X,Y,m)
    b1 = calculate_b_1(X,Y,w1,m)

    w2 = method2(X,Y,m)
    b2 = calculate_b_2(X,Y,w2)

    w3 = method3(X,Y,m)
    b3 = calculate_b_1(X,Y,w3,m)

    print("w1=%f, b1=%f" % (w1,b1))
    print("w2=%f, b2=%f" % (w2,b2))
    print("w3=%f, b3=%f" % (w3,b3))