import numpy as np
import numpy.random as npr

def OPV(S0, K, r, T, option_type):

    M = 50
    I = 10000
    sigma = 0.25

    def standard_normal_dist(M, I, anti_paths=True, mo_match=True):
        if anti_paths is True:
            sn = npr.standard_normal((M + 1, int(I / 2)))
            sn = np.concatenate((sn, -sn), axis=1)
        else:
            sn = npr.standard_normal((M + 1, I))
        if mo_match is True:
            sn = (sn - sn.mean()) / sn.std()
        return sn

    def monte_carlo_brownian_motion(S0, K, r, T, option_type):
        try:
            S0 = float(S0)
        except:
            return 'Error: Initial Price needs to be a number!'
        try:
            K = float(K)
        except:
            return 'Error: Strike Price needs to be a number!'
        try:
            if '%' in r:
                r = float(r[:r.index('%')]) / 100
            else:
                r = float(r)
        except:
            return 'Error: Risk Free Interest Rate needs to be a number!'
        try:
            T = float(T)
        except:
            return 'Error: Time Horizon needs to be a number!'
        if option_type == 'Call Option':
            option_type = 'Call'
        else:
            option_type = 'Put'

        dt = T / M
        S = np.zeros((M + 1, I))
        S[0] = S0
        sn = standard_normal_dist(M, I)
        for t in range(1, M + 1):
            S[t] = S[t - 1] * np.exp((r - 0.5 * sigma ** 2) * dt + sigma * np.sqrt(dt) * sn[t])
        if option_type == 'Call':
            hT = np.maximum(S[-1] - K, 0)
        else:
            hT = np.maximum(K - S[-1], 0)
        C0 = np.exp(-r * T) * np.mean(hT)

        Title = 'Option Valuation with the following parameters:\n\n'
        S0_desc = 'Initial Price: {}\n'.format(str(S0))
        K_desc = 'Strike Price: {}\n'.format(str(K))
        r_desc = 'Risk Free Interest Rate: {}\n'.format(str(format(r, '.2%')))
        T_desc = 'Time Horizon: {} year\n'.format(str(T))
        option_type_desc = 'Option Type: {} option \n\n'.format(option_type)
        valuation_desc = 'Stochastic differential equation:\ndS(t) = rS(t)dt + σS(t)dZ(t)\n\n'
        distribution_desc = 'Distribution method:\nStandard Normal Distribution\n\n'
        valuation_res = '{} option value: {}'.format(option_type, str(C0.round(2)))

        return '{}{}{}{}{}{}{}{}{}'.format(Title, S0_desc, K_desc, r_desc, T_desc, option_type_desc,
                                           valuation_desc, distribution_desc, valuation_res)

    return monte_carlo_brownian_motion(S0, K, r, T, option_type)


import numpy as np
import matplotlib.pyplot as plt

N=10001
initial=-np.pi
final=np.pi
x=np.linspace(initial,final,N)
h=(final-initial)/(N-1)

y=np.sin(x)
dy=np.cos(x)
ddy=-np.sin(x)

#first differential
dy_2=[]
for i in range(0,N-1):
    dy_2.append((y[i+1]-y[i])/h)

dx2=np.delete(x,[N-1])

#second differential
ddy_3=[]
for i in range(1,N-1):
    ddy_3.append((y[i+1]-2*y[i]+y[i-1])/h/h)

ddx3=np.delete(x,[0,N-1])

# get the extrema
y_max=[]
y_min=[]
for i in range(0,len(dy_2)-1):
    if dy_2[i]*dy_2[i+1]<=0:
        if ddy_3[i]>0:
            y_min.append(dx2[i])
        else:
            y_max.append(dx2[i])

#visualize
fig, axs = plt.subplots(3,sharex=True)

axs[0].plot(x,y)
axs[0].plot(y_min,np.sin(y_min),"r.")
axs[0].plot(y_max,np.sin(y_max),"k.")
axs[0].set_title("$y=sinx$")

axs[1].plot(x,dy)
axs[1].plot(dx2,dy_2,'r.')
axs[1].set_title("$y'=cosx$")

axs[2].plot(x,ddy)
axs[2].plot(ddx3,ddy_3,'r.')
axs[2].set_title("$y''=sinx$")
plt.show()


from math import sqrt, exp, log, pi
from scipy.stats import norm #normal distribution function
import numpy as np
import matplotlib.pyplot as plt

# Function for calculating d1 and d2 for option calculation in Black Scholes model
def d(sigma, S, K, r, t):
    d1 = 1 / (sigma * sqrt(t)) * ( log(S/K) + (r + sigma**2/2) * t)
    d2 = d1 - sigma * sqrt(t)
    return d1, d2

#Enter function for the call price

def callprice(sigma, S, K, r, t, d1, d2):
    C = norm.cdf(d1) * S - norm.cdf(d2) * K * exp(-r * t)
    return C

S = 100.0
K = 105.0
r = 0.01
t = 30.0/365
C0 = 2.30

#  We need a starting guess for the implied volatility.  We chose 0.5
#  arbitrarily.
vol = 0.5

epsilon = 1.0          #  Define variable to check stopping conditions
tol = 1e-4             #  Stop calculation when abs(epsilon) < this number

i = 0                  #  Variable to count number of iterations
max_iter = 1e3         #  Max number of iterations before aborting

##debug
sigma = np.linspace(0,1)
d1,d2 = d(sigma, S, K, r, t)
C = callprice(sigma, S, K, r, t, d1, d2)

plt.plot(sigma, C - C0)
plt.show()

while epsilon > tol:
    i = i + 1
    if i > max_iter:
        print ('Program failed to find a root.  Exiting.')
        break;

    orig = vol
    d1, d2 = d(vol, S, K, r, t)
    function_value = callprice(vol, S, K, r, t, d1, d2) - C0
    vega = S * norm.pdf(d1) * sqrt(t)
    vol = -function_value/vega + vol
    epsilon = abs(function_value)

print ('Implied volatility = ',  vol)
print ('Code required', i, 'iterations.')


import numpy as np

u = np.array([1, 3, 5])
v = np.array([7, 9, 11])

print(np.dot(u, v)) #内積

'''
89
'''

print(np.dot(v, u)) #内積

'''
89
'''

print(u.dot(v)) #内積

'''
89
'''

print(u @ v) #内積

'''
89
'''


#!/usr/bin/python3
def adam_bashforth_two_step(f, n, h, t=[1.0, 2.0], w0=4.0):
    W    = zeros((int(n),), dtype=float)
    t    = linspace(t[0], t[1], int(n))
    W[0] = w0
    W[1] = W[0] + h * f(t[0], W[0])    # w[1] evaluated by euler's method
    for i in range(1, int(n - 1)):
        W[i+1] = W[i] + (0.5*h)*(3*f(t[i], W[i]) - f(t[i-1], W[i-1]))
    return W[-1]

def adam_bashforth_mul_step(f, n, h, t=(1., 2.0), w0=4.0):
    wn   = lambda w0, w1, t0, t1 : -4.0*w0 + 5.0*w1 + h*(4*f(t0, w0) + 2*f(t1, w1))
    W    = zeros((int(n),), dtype=float)
    t    = linspace(t[0], t[1], int(n))
    W[0] = w0
    W[1] = W[0] + h * f(t[1], W[0])    # w[1] evaluated by euler's method
    for i in range(1, int(n - 1)):
        W[i+1] = -4.0*W[i] + 5.0*W[i-1] + h*(4*f(t[i], W[i]) + 2*f(t[i-1], W[i-1]))
    MULTI_STEP_SOLUTIONS.append(W)
    return W[-1]

def plot_solution_function():
    x2 = linspace(1, 2, len(MULTI_STEP_SOLUTIONS[0]))
    plt.subplot(211)
    plt.title("The Approximation of\n dy/dt = -ty by Adam BashForth Multi-Step\nn = 100, h = 0.01")
    plt.ylabel("[LINEAR] Approximation of dy/dt = -ty")
    plt.xlim([1, 2])
    plt.plot(x2, MULTI_STEP_SOLUTIONS[0], 'k-', lw=5, label="h = 0.0025")

    plt.subplot(212)
    plt.xlim([1, 2])
    plt.ylabel("[LOG] Approximation of dy/dt = -ty")
    plt.xlabel("time = t")
    plt.yscale('log')
    plt.plot(x2, MULTI_STEP_SOLUTIONS[0], 'k-', lw=5, label="h = 0.0025")
    plt.show()

def debug(H, N, AE, W, message, debug_status=True):
    if debug_status == True:
        if(message == "2_Step"):
            print("Adam BashForth Two(2) Step Algorithm")
            print("H \t N  \t\tAbs_Err \t W[-1] approx @ t=2")
            for h, n, ae, w in zip(H, N, AE, W):
                print n, "\t{:.4f}\t".format(h), "\t{:.15f}".format(ae), "\t{:.15f}".format(w)
        elif message == "M_Step":
            print("Adam BashForth Multi Step Algorithm")
            print("H \t N  \t\tAbs_Err \t W[-1] approx @ t=2")
            for h, n, ae, w in zip(H, N, AE, W):
                print n, "  {:.4f}  ".format(h), "  {:15E}".format(ae), "  {:15E}".format(w)

# Global Variable
MULTI_STEP_SOLUTIONS = []
if __name__ == "__main__":
    from numpy import exp, zeros, linspace, arange, shape
    import matplotlib.pyplot as plt

    f       = lambda t, y : -t * y
    I       = 4.0*exp(0.5*(1-((2)**2.0)))
    N       = [100.0, 200.0, 400.0]
    H       = [1/ N[0], 1/N[1], 1/N[2]]

    # do for the Adam Bashforth two step Method
    w_ad2s  = [adam_bashforth_two_step(f, n, h) for n, h in zip(N, H)]
    ae_ad2s = [abs(w - I) for w in w_ad2s]
    debug(H, N, ae_ad2s, w_ad2s, "2_Step")

    # do for the Adam Bashforth Multi step Method
    w_adms  = [adam_bashforth_mul_step(f, n, h) for n, h in zip(N, H)]
    ae_adms = [abs(w - I) for w in w_adms]
    debug(H, N, ae_adms, w_adms, "M_Step")
    plot_solution_function()
else:
    from sys import exit
    exit("USAGE: question3.py")


# two dimensional FFT example

# following http://matlabgeeks.com/tips-tutorials/how-to-do-a-2-d-fourier-transform-in-matlab/

import matplotlib.cm
import pylab
import numpy
import math

# get the figure
f = pylab.imread("luna_bw.png")

# two dimension FFT -- F is complex
F = numpy.fft.fft2(f)

print f.shape
print F.shape

# find the mag and phase -- shift to put 0 wavenumber at the center
F_mag = numpy.abs(numpy.fft.fftshift(F))
F_phase = numpy.angle(numpy.fft.fftshift(F))

pylab.rc("font", size=9)

pylab.subplot(131)
pylab.imshow(f, cmap=matplotlib.cm.Greys_r)
pylab.title("original image")

pylab.subplot(132)
pylab.imshow(numpy.log(F_mag))
pylab.title("|F(k)|")

pylab.subplot(133)
pylab.imshow(F_phase)
pylab.title("phase of F(k)")

f = pylab.gcf()
f.set_size_inches(10.0,6.0)

pylab.savefig("fft2d.png", bbox_inches="tight")

#-------------------------------------------------------------------------------
# scramble phase

pylab.clf()

Fnew_phase = 2.0*math.pi*numpy.random.rand(F_phase.shape[0], F_phase.shape[1])

# back to the complex representation
Fnew = F_mag*numpy.exp(1j*Fnew_phase)

fnew = numpy.fft.ifft2(numpy.fft.ifftshift(Fnew))

pylab.imshow(numpy.real(fnew), cmap=matplotlib.cm.Greys_r)
pylab.title(r"F$^{-1}$(F(k)) with scrampled phases")
pylab.savefig("fft2d_phasescamble.png", bbox_inches="tight")

#-------------------------------------------------------------------------------
# scramble amplitude

pylab.clf()

Fnew_mag = numpy.max(F_mag)*numpy.random.rand(F_mag.shape[0], F_mag.shape[1])

# back to the complex representation
Fnew = Fnew_mag*numpy.exp(1j*F_phase)

fnew = numpy.fft.ifft2(numpy.fft.ifftshift(Fnew))

pylab.imshow(numpy.real(fnew), cmap=matplotlib.cm.Greys_r)
pylab.title(r"F$^{-1}$(F(k)) with scrampled amplitudes")
pylab.savefig("fft2d_magscamble.png", bbox_inches="tight")

#-------------------------------------------------------------------------------
# filter out high frequencies

pylab.clf()

# http://glowingpython.blogspot.com/2011/08/fourier-transforms-and-image-filtering.html

F_orig = numpy.fft.fftshift(F)

P = numpy.zeros(F.shape, dtype=numpy.complex128)

frac = 0.25
rad = frac*int(min(F.shape)/2)

ic = F.shape[0]/2
jc = F.shape[1]/2

for i in range(F.shape[0]):
    for j in range(F.shape[1]):

        if math.sqrt( (i-ic)**2 + (j-jc)**2) < rad:
            P[i,j] = F_orig[i,j]

f_filtered = numpy.real(numpy.fft.ifft2(numpy.fft.ifftshift(P)))

pylab.subplot(131)
pylab.imshow(numpy.log(numpy.abs(F_orig)))
pylab.title("original |F(k)|")

pylab.subplot(132)
pylab.imshow(numpy.log(numpy.abs(P)))
pylab.title("filtered |F(k)|")

pylab.subplot(133)
pylab.imshow(f_filtered, cmap=matplotlib.cm.Greys_r)
pylab.title(r"filtered F$^{-1}$(F(k))")

f = pylab.gcf()
f.set_size_inches(10.0,6.0)

pylab.savefig("fft2d_filtered.png", bbox_inches="tight")


#!/usr/bin/python3

"""
    Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.

For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 × 53 = 49714.

What is the total of all the name scores in the file?
"""

import numpy as np

def euler22() -> int:
    data = open("p022_names.txt", "r").read()

    lt = data.split("\"")
    lt = lt[1::2]
    lt.sort()

    tot = 0
    for i in range(len(lt)):
        tot = tot + (i+1) * sum(np.array(list(map(ord, list(lt[i]))))-64)

    return tot

total = euler22()
print(total)


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from perceptron import *
from adaline_gd import *
from adaline_sgd import *

def scatter_data(X, y):
    # plot data
    plt.scatter(X[:50, 0], X[:50, 1],
                color='red', marker='o', label='setosa')
    plt.scatter(X[50:100, 0], X[50:100, 1],
                color='blue', marker='x', label='versicolor')

    plt.xlabel('sepal length [cm]')
    plt.ylabel('petal length [cm]')
    plt.legend(loc='upper left')

    plt.tight_layout()
    #plt.savefig('./images/02_06.png', dpi=300)
    plt.show()

def plot_error(data):

    plt.plot(range(1, len(data) + 1), data, marker='o')
    plt.xlabel('Epochs')
    plt.ylabel('Number of misclassifications')

    plt.tight_layout()
    # plt.savefig('./perceptron_1.png', dpi=300)
    plt.show()

def plot_decision_regions(X, y, classifier, resolution=0.02, xlabel='', ylabel='', title=''):

    # setup marker generator and color map
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])

    # plot the decision surface
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
                           np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())

    # plot class samples
    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
                    alpha=0.8, c=cmap(idx),
                    marker=markers[idx], label=cl)

    plt.title(title)
    plt.xlabel(xlabel)
    plt.ylabel(ylabel)
    plt.legend(loc='upper left')

    plt.tight_layout()
    # plt.savefig('./perceptron_2.png', dpi=300)
    plt.show()

def plot_adaline(ada, xlabel='', ylabel=''):

    plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')

    plt.xlabel(xlabel)
    plt.ylabel(ylabel)

    plt.tight_layout()
    # plt.savefig('./adaline_3.png', dpi=300)
    plt.show()

def plot_adalines(ada1, ada2, eta1, eta2):

    fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(8, 4))

    ax[0].plot(range(1, len(ada1.cost_) + 1), np.log10(ada1.cost_), marker='o')
    ax[0].set_xlabel('Epochs')
    ax[0].set_ylabel('log(Sum-squared-error)')
    ax[0].set_title('Adaline - Learning rate ' + str(eta1))

    ax[1].plot(range(1, len(ada2.cost_) + 1), ada2.cost_, marker='o')
    ax[1].set_xlabel('Epochs')
    ax[1].set_ylabel('Sum-squared-error')
    ax[1].set_title('Adaline - Learning rate ' + str(eta2))

    plt.tight_layout()
    # plt.savefig('./adaline_1.png', dpi=300)
    plt.show()

# main

df = pd.read_csv('../datasets/iris/iris.data', header=None)
df.tail()
#print(df[-5:])

# select setosa and versicolor
y = df.iloc[0:100, 4].values
y = np.where(y == 'Iris-setosa', -1, 1)

# extract sepal length and petal length
X = df.iloc[0:100, [0, 2]].values

# plot data
scatter_data(X, y)

# training
ppn = Perceptron(eta=0.1, n_iter=10)

ppn.fit(X, y)

plot_error(ppn.errors_)

plot_decision_regions(X, y, classifier=ppn, xlabel = 'sepal length [cm]', ylabel = 'petal length [cm]')

# adaline gd
eta1 = 0.01
eta2 = 0.0001

ada1 = AdalineGD(n_iter=10, eta=eta1).fit(X, y)
ada2 = AdalineGD(n_iter=10, eta=eta2).fit(X, y)

plot_adalines(ada1, ada2, eta1, eta2)

# standardize features
X_std = np.copy(X)
for col in range(X_std.shape[1]):
    X_std[:, col] = (X[:, col] - X[:, col].mean()) / X[:, col].std()

ada = AdalineGD(n_iter=15, eta=0.01)
ada.fit(X_std, y)

plot_decision_regions(X_std, y, classifier=ada, title='Adaline - Gradient Descent', xlabel='sepal length [standardized]', ylabel = 'petal length [standardized]')

plot_adaline(ada, xlabel='Epochs', ylabel='Sum-squared-error')

# adaline sgd
ada = AdalineSGD(n_iter=15, eta=0.01, random_state=1)
ada.fit(X_std, y)

plot_decision_regions(X_std, y, classifier=ada, title='Adaline - Stochastic Gradient Descent', xlabel = 'sepal length [standardized]', ylabel='petal length [standardized]')

plot_adaline(ada, xlabel='Epochs', ylabel='Sum-squared-error')

# online learning example
ada.partial_fit(X_std[0, :], y[0])


#           //////,           _____ _
#         */@&/////*         | __  |_|___ ___ ___ ___ ___ ___ ___
#         *//////***         | __ -| |_ -|_ -| -_|  _|  _| .'| . |
#     //////////**** &&&&    |_____|_|___|___|___|___|___|__,|___|
#    /////////****** &&&
#    //////......./&&&&&&&    Algoritmo de Bissecção
#    *//// &&&&&&&&&&&&&&(    Desenvolvido Por Luiz Gustavo Benicio Neves e Leonardo Soares
#     ///*/&&&&&&&&&&&&&%     Para a Discliplina de Calculo Numérico
#         /&&&&&&&&&
#          &&&&&&@@&
#            #&&

import numpy as np
import random
import matplotlib.pyplot as plt
from prettytable import PrettyTable

eps = np.finfo(float).eps

tabela = PrettyTable(['Iteração', 'a', 'b', 'x', 'f(a)', 'f(b)', 'f(x)'])

def f(x):
    return x*x-1

def bisseccao(a, b, eps, it, iteracoes):
    while(it < iteracoes):
        if(b-a < eps):
            return (random.uniform(a, b))
        else:
            x = (a+b)/2
            if(f(x) == 0):
                return x
            if(f(a) < 0 and f(b) > 0):
                if(f(x) < 0):
                    tabela.add_row([it+1, a, b, x, f(a), f(b), f(x)])
                    a = x
                    it = it+1
                else:
                    tabela.add_row([it+1, a, b, x, f(a), f(b), f(x)])
                    b = x
                    it = it+1
            elif(f(a) > 0 and f(b) < 0):
                if(f(x) > 0):
                    tabela.add_row([it+1, a, b, x, f(a), f(b), f(x)])
                    b = x
                    it = it+1
                else:
                    tabela.add_row([it+1, a, b, x, f(a), f(b), f(x)])
                    a = x
                    it = it+1
            else:
                print("erro")
    return None

# Exemplo da Tabela 3.1 realizado do livro da UFRGS
a = float(0)
b = float(3)
bisseccao(a, b, (1e-3), 0, 300)
print(tabela)


import numpy as np
import pandas
from ggplot import *

"""
In this question, you need to:
1) implement the compute_cost() and gradient_descent() procedures
2) Select features (in the predictions procedure) and make predictions.

"""

def normalize_features(df):
    """
    Normalize the features in the data set.
    """
    mu = df.mean()
    sigma = df.std()

    if (sigma == 0).any():
        raise Exception("One or more features had the same value for all samples, and thus could " + \
                         "not be normalized. Please do not include features with only a single value " + \
                         "in your model.")
    df_normalized = (df - df.mean()) / df.std()

    return df_normalized, mu, sigma

def compute_cost(features, values, theta):
    """
    Compute the cost function given a set of features / values,
    and the values for our thetas.

    This can be the same code as the compute_cost function in the lesson #3 exercises,
    but feel free to implement your own.
    """

    # your code here
    m = len(values)
    sum_of_square_errors = np.square(np.dot(features, theta) - values).sum()
    cost = sum_of_square_errors / (2*m)
    return cost

def gradient_descent(features, values, theta, alpha, num_iterations):
    """
    Perform gradient descent given a data set with an arbitrary number of features.

    This can be the same gradient descent code as in the lesson #3 exercises,
    but feel free to implement your own.
    """

    m = len(values)
    cost_history = []

    for i in range(num_iterations):
        # your code here
        predicted_values = np.dot(features, theta)
        theta = theta - alpha / m * np.dot((predicted_values - values), features)

        cost = compute_cost(features, values, theta)
        cost_history.append(cost)
    return theta, pandas.Series(cost_history)

def predictions(dataframe):
    '''
    The NYC turnstile data is stored in a pandas dataframe called weather_turnstile.
    Using the information stored in the dataframe, let's predict the ridership of
    the NYC subway using linear regression with gradient descent.

    You can download the complete turnstile weather dataframe here:
    https://www.dropbox.com/s/meyki2wl9xfa7yk/turnstile_data_master_with_weather.csv

    Your prediction should have a R^2 value of 0.40 or better.
    You need to experiment using various input features contained in the dataframe.
    We recommend that you don't use the EXITSn_hourly feature as an input to the
    linear model because we cannot use it as a predictor: we cannot use exits
    counts as a way to predict entry counts.

    Note: Due to the memory and CPU limitation of our Amazon EC2 instance, we will
    give you a random subet (~15%) of the data contained in
    turnstile_data_master_with_weather.csv. You are encouraged to experiment with
    this computer on your own computer, locally.

    If you'd like to view a plot of your cost history, uncomment the call to
    plot_cost_history below. The slowdown from plotting is significant, so if you
    are timing out, the first thing to do is to comment out the plot command again.

    If you receive a "server has encountered an error" message, that means you are
    hitting the 30-second limit that's placed on running your program. Try using a
    smaller number for num_iterations if that's the case.

    If you are using your own algorithm/models, see if you can optimize your code so
    that it runs faster.
    '''
    # Select Features (try different features!)
    features = dataframe[['rain', 'precipi', 'Hour', 'meantempi']]

    # Add UNIT to features using dummy variables
    dummy_units = pandas.get_dummies(dataframe['UNIT'], prefix='unit')
    features = features.join(dummy_units)

    # Values
    values = dataframe['ENTRIESn_hourly']
    m = len(values)

    features, mu, sigma = normalize_features(features)
    features['ones'] = np.ones(m) # Add a column of 1s (y intercept)

    # Convert features and values to numpy arrays
    features_array = np.array(features)
    values_array = np.array(values)

    # Set values for alpha, number of iterations.
    alpha = 0.1 # please feel free to change this value
    num_iterations = 75 # please feel free to change this value

    # Initialize theta, perform gradient descent
    theta_gradient_descent = np.zeros(len(features.columns))
    theta_gradient_descent, cost_history = gradient_descent(features_array,
                                                            values_array,
                                                            theta_gradient_descent,
                                                            alpha,
                                                            num_iterations)

    plot = None
    # -------------------------------------------------
    # Uncomment the next line to see your cost history
    # -------------------------------------------------
    # plot = plot_cost_history(alpha, cost_history)
    #
    # Please note, there is a possibility that plotting
    # this in addition to your calculation will exceed
    # the 30 second limit on the compute servers.

    predictions = np.dot(features_array, theta_gradient_descent)
    return predictions, plot

def plot_cost_history(alpha, cost_history):
   """This function is for viewing the plot of your cost history.
   You can run it by uncommenting this

       plot_cost_history(alpha, cost_history)

   call in predictions.

   If you want to run this locally, you should print the return value
   from this function.
   """
   cost_df = pandas.DataFrame({
      'Cost_History': cost_history,
      'Iteration': range(len(cost_history))
   })
   return ggplot(cost_df, aes('Iteration', 'Cost_History')) + \
      geom_point() + ggtitle('Cost History for alpha = %.3f' % alpha )


# -*- coding: utf-8 -*-
'''Python code developed running Canopy (Free Academic License)
https://www.enthought.com/products/canopy/'''
from __future__ import division
import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import odeint
#np.set_printoptions(threshold=np.inf)

def vectorfield(w, t, par):

    """
    *Problem 8-05 Part (a)
    {Elements of Chemical Reaction Engineering, Fogler (5th Ed.)}

    Arguments:
        w :  vector of the state variables:
                  w = [Ca,Cb]
        t :  time
        par :  vector of the parameters:
                  par = [k1,k2]
    """

    Ca, Cb = w
    k1,k2 = par

    #EtOH absorbed and cleared remaining hours
    # Create f = (dCa/dt,dCb/dt)
    f = [-k1*Ca, k1*Ca-k2]

    return f

def solver():
    # Use ODEINT to solve the differential equations defined by the vector field
    #from scipy.integrate import odeint

    k1=10
    k2=0.192

    # ODE solver parameters
    abserr = 1.0e-8
    relerr = 1.0e-6

    stopx = 11
    numpoints = 80

    # Create the x-axis samples for the output of the ODE solver.
    t = [stopx * float(i) / (numpoints - 1) for i in range(numpoints)]

    # Initial conditions before 1st hour
    Ca0 = 2
    Cb0 = 0

    # Pack up the parameters and initial conditions:
    par = [k1,k2]
    w0 = [Ca0,Cb0]

    # Call the ODE solver.
    wsol = odeint(vectorfield, w0, t, args=(par,), atol=abserr, rtol=relerr)

    with open('BAC805x.dat', 'w') as f:
        # Print & save the solution.
        for t1, w1 in zip(t, wsol):
            print >> f, t1, w1[0], w1[1]

    # Plot the solution that was generated

    from numpy import loadtxt
    from pylab import savefig
    from matplotlib.font_manager import FontProperties

    t, Ca, Cb = loadtxt('BAC805x.dat', unpack=True)

    lw = 1

    # Two subplots, unpack the axes array immediately
    f, (ax1) = plt.subplots(1, 1, sharex=True)
    #grid(True)
    ax1.plot(t, Ca, 'r', linewidth=2)
    ax1.plot(t, Cb, 'b', linewidth=lw)
    ax1.legend((r'$C_A$', r'$C_B$'), prop=FontProperties(size=16))
    #ax1.set_title('')
    ax1.set_xlabel('$t$')
    ax1.set_ylim(0)

    f.subplots_adjust(hspace=0,wspace=0.19,left=0.06,right=0.96,top=0.94,bottom=.10)

    savefig('BAC805a.png', dpi=100)


#!/usr/bin/env python

"""
Show how Casteljau's algorithm works.
"""

import numpy as np

def de_casteljau(n, b, u):
    """
    De Casteljau's algorithm to evaluate Bernstein polynomials.

    Parameters
    ----------
    n : int
        Degree of the Bernstein polynomial
    b : list of tuples of floats
        Controll points
    u : float in [0, 1]
        Place where to evaluate the Bernstein polynomial

    Examples
    --------
    >>> de_casteljau(3, [(0, 0), (1, 0), (0, 1), (1, 1)], 0)
    (0.0, 0.0)
    >>> de_casteljau(3, [(0, 0), (1, 0), (0, 1), (1, 1)], 1)
    (1.0, 1.0)
    """
    assert 0 <= u <= 1
    assert len(b) == n+1
    b = np.array(b)

    # Initialize p with the values of b
    p = []
    p.append([b[i] for i in range(n + 1)])

    # Get the value by a series of linear interpolations.
    for j in range(1, n+1):
        p.append([])
        for i in range(n-j+1):
            # Put a line through the i-th and the (i+1)-th point.
            # Take the point which is u% of the distance between i and i+1
            # on the line.
            p[j].append((1.0-u)*p[j-1][i] + u*p[j-1][i+1])
    return tuple(p[n][0])

def bernstein_value(n, i, u):
    """
    Calculate value of the i-the Bernstein polynomial at u.

    Parameters
    ----------
    n : int
        Degree of the Bernstein polynomial
    b : list of tuples of floats
        Controll points
    u : float in [0, 1]
        Place where to evaluate the Bernstein polynomial

    Examples
    --------
    >>> bernstein_value(3, 0, 0)
    1.0
    """
    import scipy.special
    u = float(u)
    return scipy.special.binom(n, i) * u**i * (1-u)**(n-i)

def exact(n, b, u):
    """
    Calculate the exact value of the Bernstein polynomial b at u.

    Parameters
    ----------
    n : int
        Degree of the Bernstein polynomial
    b : list of tuples of floats
        Controll points
    u : float in [0, 1]
        Place where to evaluate the Bernstein polynomial

    Examples
    --------
    >>> exact(3, [(0, 0), (1, 0), (0, 1), (1, 1)], 0)
    (0.0, 0.0)
    >>> exact(3, [(0, 0), (1, 0), (0, 1), (1, 1)], 1)
    (1.0, 1.0)
    """
    res = sum([bernstein_value(n, i, u) * np.array(b[i]) for i in range(n+1)])
    return tuple(res)

def plot(b, interpolation_points=50):
    """
    Show a plot of a polynomial.

    Parameters
    ----------
    b : list of tuples of floats
        Controll points
    """
    import matplotlib.pyplot as plt
    us = np.linspace(0, 1, interpolation_points)
    points = [de_casteljau(3, b, u) for u in us]
    xs = [point[0] for point in points]
    ys = [point[1] for point in points]
    plt.plot(xs, ys, 'ro')

    # Plot control points
    xs = [point[0] for point in b]
    ys = [point[1] for point in b]
    plt.plot(xs, ys, 'bo')
    plt.show()

if __name__ == '__main__':
    controll_points = [(0, 0), (200, 100), (-100, 100), (100, 0)]
    plot(controll_points)
    import doctest
    doctest.testmod()


import numpy as np
from scipy.stats import norm

def bs_d1(sigma, time_to_maturity, rf_rate, spot, strike):
    return 1 / (sigma * np.sqrt(time_to_maturity)) \
        * (np.log(spot/strike) + (rf_rate + (sigma**2) / 2) * time_to_maturity)

def bs_d2(sigma, time_to_maturity, rf_rate, spot, strike):
    return bs_d1(sigma, time_to_maturity, rf_rate, spot, strike) \
        - sigma * np.sqrt(time_to_maturity)

def pv(strike, rate, time_to_maturity):
    return strike * np.exp(-rate * (time_to_maturity))

def european_call_value(sigma, time_to_maturity, rf_rate, spot, strike):
    """Black-Scholes formula for calculating European call option.

    Args:
        sigma: volatility
        time_to_maturity: T - t where T is exercise date and t is current (pricing) date
        rf_rate: risk-free rate
        spot: Spot price, price of the underlying at t
        strike: Strike price, exercise price of option at T

    sigma, time_to_maturity and rf_rate should be on the same time scale,
    e.g. annualized.
    """
    d1 = bs_d1(sigma, time_to_maturity, rf_rate, spot, strike)
    d2 = bs_d2(sigma, time_to_maturity, rf_rate, spot, strike) # Note: d1 calc made twice
    return norm.cdf(d1) * spot - norm.cdf(d2) * pv(strike, rf_rate, time_to_maturity)

def european_put_value(sigma, time_to_maturity, rf_rate, spot, strike):
    """Put option price with put-call parity.

    Refer to european_call_value.
    """
    call = european_call_value(sigma, time_to_maturity, rf_rate, spot, strike)
    return call - spot + strike * pv(1, rf_rate, time_to_maturity)


import numpy as np

def average_difference(xs):
    n = len(xs)
    return sum([abs(xi - xj) for xj in xs for xi in xs]) / (n * n)

def GI(xs):
    me = np.mean(xs)
    ad = average_difference(xs)
    return ad / (2 * me)

if __name__ == '__main__':
    A = [0, 3, 3, 5, 5, 5, 5, 7, 7, 10]
    B = [0, 1, 2, 3, 5, 5, 7, 8, 9, 10]
    C = [3, 4, 4, 5, 5, 5, 5, 6, 6, 7]
    print('Aの平均差 = {:.2f}, ジニ係数 = {:.3f}'.format(average_difference(A), GI(A)))
    print('Bの平均差 = {:.2f}, ジニ係数 = {:.3f}'.format(average_difference(B), GI(B)))
    print('Cの平均差 = {:.2f}, ジニ係数 = {:.3f}'.format(average_difference(C), GI(C)))


"""
bayesian test for periodicity in equally spaced spatial/time data (ti,yi) etc
following Jaynes, 'Probability Theory: The Logic of Science' section 17.6
#======================================
MODEL: y(t) = A.cos wt + B.sin wt + mu + Gaussian_noise
       n data points
PRIORS: Jeffrey's priors, p(mu) = const., p(sigma) = 1/sigma
        p(w) = const. over w=0 to Nyqvist limit pi/dt
        p(A,B) = const.exp(-(A^2 + B^2)/2.delta^2)
        delta is width for coefficient priors, on the order of several times range of y
        with 'radial' symmetry for R^2 = A^2 + B^2, i.e. uniform in phase 0-2pi of periodicity
LIKELIHOOD
after marginalizing over offset mu, and magnitude of noise sigma
the likelihood is p(Data|A,B,w)  = 1/s^(n-1)
where
      s^2 = (<d^2> - <d>^2) is variance of derived 'data'
      d(t) = y(t) - A.cos wt - B.sin wt
POSTERIOR
      p(A,B,w|Data)  = const.exp(-(A^2 + B^2)/2.delta^2)/s^(n-1)
      finally we need to marginalize over A, B to get
      p(w|Data)
      maximum in this gives frequency, and then we can back calculate A,B
#======================================
"""
import math
import numpy as np
import matplotlib.pyplot as plt
from SciInf_utilities import *
import sys

def sum_sq(Acoeff,Bcoeff,freq,y,ndata):
    d_sum = 0.
    d_sum_sq = 0.
    for i in range(ndata):
        d_i = y[i] - Acoeff*math.cos(freq*i) - Bcoeff*math.sin(freq*i)
        d_sum = d_sum + d_i
        d_sum_sq = d_sum_sq + d_i**2
    s2 = d_sum_sq/ndata - (d_sum/ndata)**2
    return s2
""" main
"""
#
print("bayesian test for periodicity in equally spaced spatial/time data (ti,yi) etc")
print("following Jaynes, 'Probability Theory: The Logic of Science' section 17.6 \n")
# get data
#
if(len(sys.argv) == 2):
  input_file = sys.argv[1]
else:
  input_file = input("file with one t, y data pair per line> ")
#input_file = 'CparkT_1930.dat' # average january temp in Central Park NY
#input_file = 'cos4.dat'
print('input file: ',input_file)
t = []
y = []
ndata = read_xy(t,y,input_file)
#
# basic averages, etc
#
av_t = average_x(t)
av_y = average_x(y)
print('av  t %12.5f   y %12.5f ' % (av_t,av_y))
min_t = min(t)
min_y = min(y)
print('min t %12.5f   y %12.5f ' % (min_t,min_y))
max_t = max(t)
max_y = max(y)
print('max t %12.5f   y %12.5f ' % (max_t,max_y))
#
t_span = t[ndata-1] - t[0]
dt = t_span/(ndata -1)
print('t span %11.5f   dt %11.5f ' % (t_span,dt))
#
## shift y data so <y> = 0
#for i in range(ndata):
#  y[i] = y[i] - av_y
#
# set up frequency range from 0 to Nyqvist upper limit =
# = minimum period of 2 time intervals
# use unitless time intervals dt = 1 for frequency,
# and convert to 'real' time only for period axis for output
#
freq_axis = np.zeros(ndata+1,'float')
period_axis = np.zeros(ndata+1,'float')
freq_pdf = np.zeros(ndata+1,'float')
for i in range(ndata+1):
  freq_axis[i] = math.pi*i/ndata
for i in range(1,ndata+1):
  period_axis[i] = dt*2.*math.pi/freq_axis[i]
period_axis[0] = period_axis[1] + 1. # dummy value for infinite period- i.e. constant value
#
delta = 2.*(max_y - min_y) # width of gaussian prior for A,B
#ngrid = 51 # grid for marginalization over coefficient magnitudes
ngrid = 37 # grid for marginalization over coefficient magnitudes
r_up = 2.*delta
dr = r_up/(ngrid - 1)
#print(r_up,dr)
dtheta = 2.*math.pi/(ngrid-1)
expnt = -0.5*(float(ndata) - 1.)
#print(expnt)
#
# find posterior p(freq|Data)
#
print("doing marginalization integrals, please wait...")
for k in range(0,ndata+1):
  freq_pdf[k] = 0.
  freq = freq_axis[k]
  # for each frequency marginalize over A,B
  for i in range(ngrid):
    r_val = i*dr
    #print(" {:12.5f}".format(r_val))
    for j in range(ngrid):
      theta = j*dtheta
      Acoeff = r_val*math.cos(theta)
      Bcoeff = r_val*math.sin(theta)
      probAB = math.exp(-0.5*(r_val/delta)**2)
      #print(" {:12.5f} {:12.5f} {:12.5f} {:12.5f}".format(theta,Acoeff,Bcoeff,probAB))
      s2 = sum_sq(Acoeff,Bcoeff,freq,y,ndata)
      probABw = probAB*s2**expnt
      freq_pdf[k] += probABw*dtheta*dr
pdf_max = max(freq_pdf)
freq_pdf /= pdf_max
#
# find most probable frequency
# and get best A,B
#
pdf_max = 0.
for k in range(1,ndata+1):
  if(freq_pdf[k] > pdf_max):
    pdf_max = freq_pdf[k]
    freq_max = freq_axis[k]
period_max = dt*2.*math.pi/freq_max
print("max pdf {:12.5f} for frequency {:12.5f}, period{:12.5f} ".format(pdf_max,freq_max,period_max))
pdf_max = 0.
for i in range(ngrid):
  r_val = i*dr
  for j in range(ngrid):
    theta = j*dtheta
    Acoeff = r_val*math.cos(theta)
    Bcoeff = r_val*math.sin(theta)
    probAB = math.exp(-0.5*(r_val/delta)**2)
    #print(" {:12.5f} {:12.5f} {:12.5f} {:12.5f}".format(theta,Acoeff,Bcoeff,probAB))
    s2 = sum_sq(Acoeff,Bcoeff,freq_max,y,ndata)
    probABw = probAB*s2**expnt
    if(probABw > pdf_max):
      pdf_max = probABw
      Acoeff_best = Acoeff
      Bcoeff_best = Bcoeff
      # print('new max: ',pdf_max,Acoeff_best,Bcoeff_best)
print("best p(ABw) {:12.5f} best parameters {:12.5f} {:12.5f}".format(pdf_max,Acoeff_best,Bcoeff_best))
y_calc = np.zeros(ndata,'float')
for i in range(ndata):
  y_calc[i] = Acoeff_best*math.cos(freq_max*i) + Bcoeff_best*math.sin(freq_max*i) + av_y
#
# plot original data
#
#for i in range(ndata):
#  y[i] = y[i] + av_y
freq_pdf[0] = freq_pdf[1]
MAKEPLOT = True
if(MAKEPLOT):
  plt.figure(1)
  plt.subplot(211)
  plt.scatter(t,y,color='red',marker='o')
  plt.plot(t,y_calc,color='blue')
  plt.xlabel('t')
  plt.ylabel('y')
  #plt.ylim(ymin=0.)
  plt.title('T Series ')
  plt.grid(True)
  #
  # plot posterior pdf of frequency/period
  #
  plt.subplot(212)
  #plt.plot(freq_axis,freq_pdf,color='red')
  #plt.xlabel('frequency')
  plt.plot(period_axis,freq_pdf,color='red')
  plt.xlabel('period')
  plt.ylabel('pdf(period)')
  plt.title('PDF ')
  plt.grid(True)
  plt.show()


"""
1) Start in the leftmost column
2) If all queens are placed
    return true
3) Try all rows in the current column.
   Do following for every tried row.
    a) If the queen can be placed safely in this row
       then mark this [row, column] as part of the
       solution and recursively check if placing
       queen here leads to a solution.
    b) If placing the queen in [row, column] leads to
       a solution then return true.
    c) If placing queen doesn't lead to a solution then
       unmark this [row, column] (Backtrack) and go to
       step (a) to try other rows.
3) If all rows have been tried and nothing worked,
   return false to trigger backtracking.
"""

import numpy

solN = 0

def printBoard(board):
	global solN
	solN = solN + 1
	print("--------------------------------------\nPossibility #",solN)
	for i in range(len(board)):
		for j in range(len(board)):
			if board[i][j] == 1:
				print("Q", end = " ")
			else:
				print("x", end = " ")
		print()
	print("--------------------------------------")

def isSafe(board, row, col):

	for i in range(col):
		if board[row][i] == 1:
			return False

	for i, j in zip(range(row, -1, -1),
					range(col, -1, -1)):
		if board[i][j] == 1:
			return False

	for i, j in zip(range(row, len(board), 1),
					range(col, -1, -1)):
		if board[i][j] == 1:
			return False

	return True

def placeQueen(board, col):

	if col >= len(board):
		printBoard(board)
		return True

	for i in range(len(board)):

		isValid = False
		for i in range(len(board)):
			if isSafe(board, i, col):

				board[i][col] = 1

				isValid = placeQueen(board, col + 1) or isValid

				board[i][col] = 0
		return False

def createBoard(N):
	return numpy.zeros(shape=(N, N))

def solveNQueen(N):

	board = createBoard(N)

	if placeQueen(board, 0) == False:
		print("Can't find any solution.")
		return board

	return board

def main():
	n = input("Size of board: ")
	solveNQueen(int(n))

if __name__ == '__main__':
    main()


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

# In[28]:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import scipy.stats as st
import statsmodels.api as sm
import pingouin as pg

# In[53]:

import statsmodels.stats.outliers_influence as sms
from functools import reduce

# In[29]:

import warnings
warnings.filterwarnings('ignore')

# # Regression

# ### i) Simple Regression
#
# #### Outcome = Model + Error
# #### Sum of Squares, SSt, SSm , SSr

# In[30]:

data = pd.read_csv('/home/atrides/Desktop/R/statistics_with_Python/07_Regression/Data_Files/Album Sales 1.dat', sep='\t')
print(data.head())

# In[31]:

_ = sns.lmplot(x='adverts', y='sales', data=data)
plt.show()

# In[32]:

model = sm.OLS.from_formula('sales ~ adverts',data=data)
res = model.fit()
print(res.summary())

# ### ii) Multiple Regression

# In[33]:

df = pd.read_csv('/home/atrides/Desktop/R/statistics_with_Python/07_Regression/Data_Files/Album Sales 2.dat', sep='\t')
print(df.head())

# In[34]:

# with one predictor variable
model_1 = sm.OLS.from_formula("sales~adverts", data=df)
res_1 = model_1.fit()
print(res_1.summary())

# In[35]:

# with all predictor variables
model_2 = sm.OLS.from_formula("sales~adverts+airplay+attract", data=df)
res_2 = model_2.fit()
print(res_2.summary())

# ##### see the inrcrease in R^2 and Adjusted R^2 in model_2 w.r.t model_1

# ### Standarized regression coeffecients (beta coeffecients)
# #####  refers to how many standard deviations a dependent variable will change, per standard deviation increase in the predictor variable.

# In[36]:

df_ = pd.DataFrame()
df_['adverts'] = (df['adverts']-df['adverts'].mean())/df['adverts'].std()
df_['airplay'] = (df['airplay']-df['adverts'].mean())/df['airplay'].std()
df_['attract'] = (df['attract']-df['adverts'].mean())/df['attract'].std()
df_['sales'] = (df['sales']-df['adverts'].mean())/df['sales'].std()

# In[37]:

model = sm.OLS.from_formula("sales~adverts+airplay+attract", data=df_)
res = model.fit()
print(res.summary())

# ### Comparing models using python

# In[38]:

from statsmodels.formula.api import ols
from statsmodels.stats.anova import anova_lm

m01 = ols('sales~adverts', data=df).fit()
m02 = ols('sales~adverts+airplay+attract', data=df).fit()
anovaResults = anova_lm(m01, m02)
print(anovaResults)

# ### Outliers and Influential cases

# #### references
#
# https://www.statsmodels.org/stable/generated/statsmodels.stats.outliers_influence.OLSInfluence.html#statsmodels.stats.outliers_influence.OLSInfluence
#
# https://www.statsmodels.org/dev/generated/statsmodels.regression.linear_model.OLS.html
#
# https://stackoverflow.com/questions/46304514/access-standardized-residuals-cooks-values-hatvalues-leverage-etc-easily-i
#
# https://www.geeksforgeeks.org/reduce-in-python/

# In[71]:

summary_frame = sms.OLSInfluence(m02).summary_frame()
print(summary_frame.head())

# In[72]:

summary_frame = summary_frame[['cooks_d','standard_resid', 'student_resid', 'hat_diag' ]]
print(summary_frame.head())

# In[73]:

resid = pd.DataFrame(df['sales'] - m02.fittedvalues)
resid.columns = ['residual']

# In[74]:

dfbeta = pd.DataFrame(pd.DataFrame(sms.OLSInfluence(m02).dfbeta)[0])
dfbeta.columns = ['dfbeta']

# In[75]:

df_ = [df, resid, summary_frame, dfbeta]
final_summary = reduce(lambda left,right: pd.merge(left,right, left_index=True, right_index=True), df_)
print(final_summary.head())

# In[76]:

cov_ratio = pd.DataFrame(sms.OLSInfluence(m02).cov_ratio)
cov_ratio.columns = ['cov_ratio']

# In[77]:

# these cases have somewhat large residuals
large_resid  = final_summary[(final_summary['standard_resid']>=2) | (final_summary['standard_resid']<=-2)]
large_resid = pd.merge(large_resid, cov_ratio, how = 'left', right_index=True, left_index=True)
print(large_resid)

# In[78]:

# now let's look at cooks distance, leverage, covariance Ratio for these cases
k = 3 #number of predictors
n = 200 #number of objervations

average_leverage = (k+1)/n
print(average_leverage)

# In[79]:

cvr_limit_high = 1+3*average_leverage
cvr_limit_low  = 1-3*average_leverage

print(cvr_limit_low, cvr_limit_high)

# #### from this large residual model we conclude that
# #### Most of our 12 potential outliers have CVR values within or just outside the boundaries.
# #### none of them has a Cook’s distance greater than 1,  so none of the cases is having an undue influence on the model.
#
#
# #### So , Note:
#
# #### i) Look at standardized residuals and check that no more than 5% of cases have absolute values above 2,
# ####    and that no more than about 1% have absolute values above 2.5. Any case with a value above about 3 could be an outlier.
#
# #### ii)Look at the values of Cook’s distance: any value above 1 indicates a case that might be influencing the model.
#
# #### iii)Calculate the average leverage (the number of predictors plus 1, divided by the sample size)
# ####      and then look for values greater than twice or three times this average value
#
# #### iv)Calculate the upper and lower limit of acceptable values for the covariance ratio, CVR.
# ####        The upper limit is 1 plus three times the average leverage, whereas
# ####        the lower limit is 1 minus three times the average leverage.
# ####        Cases that have a CVR falling outside these limits may be problematic

# ## Testing Various Assumptions

# ### i) Assumptions of Independent Errors

# In[80]:

from statsmodels.stats.stattools import durbin_watson
print(durbin_watson(m02.resid))

# The closer to 2 that the value is, the better, and for these data the value is 1.950,
# which is so close to 2 that the assumption has almost certainly been met.

# ### ii) Assumption of no multicollinearity

# In[81]:

from statsmodels.tools.tools import add_constant
from statsmodels.stats.outliers_influence import variance_inflation_factor

df_ = add_constant(df)
df_.drop(['sales'], inplace=True,axis=1)  # dropping Dependent variable

# In[82]:

vif = pd.Series([variance_inflation_factor(df_.values, i)
               for i in range(1, df_.shape[1])],
              index=df_.columns[1:])

# In[83]:

print(vif)

# In[84]:

avg_vif  = np.mean(vif)
print(avg_vif)

# In[85]:

tolerance  = 1/vif
print(tolerance)

# #####  the assumption of multicollinearity is followed too

# ### iii) Assumption about the Residuals

# In[86]:

prediction = pd.DataFrame(m02.fittedvalues)
prediction.columns = ['predicted']

# In[87]:

prediction['standarized_prediction']  = (prediction['predicted']-prediction['predicted'].mean())/prediction['predicted'].std()
final_summary.head()

# In[89]:

_ = sns.scatterplot(x= final_summary['standard_resid'], y = prediction['standarized_prediction'] )
_ = plt.axhline(y=0)
plt.show()

# In[90]:

_ = pg.qqplot(final_summary['standard_resid'])
plt.show()

# In[99]:

fig,ax = plt.subplots(figsize=(6, 4))
ax = plt.hist(final_summary['student_resid'],density=True,bins=30, edgecolor='black', linewidth=1.4)
plt.xlabel('student_resid', fontsize=14)
plt.show()

# ##### this assumption was also met

# In[ ]:

import numpy,import scipy,import statsmodels,from statsmodels


import numpy as np
import math

# Write a function that takes as input two lists Y, P,
# and returns the float corresponding to their cross-entropy.

'''Below is the method that is thought by myself'''
# def cross_entropy(Y, P):
#     crossEntropy = 0
#     for i in range(len(Y)):
#         crossEntropy -= Y[i] * math.log(P[i]) + (1 - Y[i]) * math.log(1 - P[i])
#     return crossEntropy
#     pass
"""
Below is the right way to calculate cross_entropy
"""
def cross_entropy(Y, P):
    Y = np.float_(Y)
    P = np.float_(P)
    return -np.sum(Y * np.log(P) + (1 - Y) * np.log(1 - P))


import statsmodels.tsa.stattools as smts
import statsmodels.api as sm
import numpy as np
import itertools
import platform

if platform.system() == "Darwin":
    import matplotlib
    matplotlib.use('PS')

import matplotlib.pyplot as plt

def coint(df, intercept = True, sig_level = 0.01):
    """
    Find pairs (of 2 time series) that passes the cointegration test.

    Parameters
    ----------
    df: pandas dataframe
        each column is the time series of a certain stock

    intercept: boolean
        if True, OLS and ADF test are done manually
        if False, the coint() function from statsmodels.tsa.stattools, which
        does not include intercept term while doing OLS regression, is used.

    sig_level: if p_value of cointegration test is below this level, then we
        can reject the NULL hypothesis, which says that the two series are not
        cointegrated

    Return
    ------
    A list of tuples of the form (name of stock 1, name of stock 2, p_value of
    cointegration test).

    """
    cointegrated_pairs = []

    stock_names = df.columns.values.tolist()
    N = len(stock_names)

    stock_pairs = list(itertools.combinations(stock_names, 2))

    for pair in stock_pairs:
        stock_1, stock_2 = pair

        p_value = 0

        if not intercept:
            p_value = smts.coint(df[stock_1].values.astype(float), df[stock_2].values.astype(float), trend='c')[1]
        else:
            Y = df[stock_1].values.astype(float)
            X = df[stock_2].values.astype(float)
            X = sm.add_constant(X)

            model = sm.OLS(Y, X)
            results = model.fit()
            intercept, slope = results.params

            p_value = smts.adfuller(results.resid)[1]

        if p_value < sig_level and slope > 0:
            cointegrated_pairs.append(tuple([stock_1, stock_2, p_value]))

    return cointegrated_pairs

def select_pairs_for_all_combin(train_df, test_df, config, plot=True):
    """
    Find the desired pairs of stock name either by thresholding the score of
    each pair or pick the first n pairs with the lowest score.

    Parameters
    ----------
    train_df: pandas dataframe
        For training data, each column is the time series of a stock
    test_df: pandas dataframe
        For testing data, each column is the time series of a stock
    config: map
        It should contains either "threshold" or "n". The value of "threshold"
        will be used to determine whether a particular pair will be returned.
        If the score of a pair is lower than the "threshold" value, the pair
        will be returned as desired pair. The value of "n" will indicate the
        maximum number of pairs to return. The n returned pairs have the lowest
        scores.

        It should also contain a function associated with the key
        "score_function". The function should accept two series (in type pandas
        Series or numpy arrays) and return a score. The lower the score is
        indicates the better the pair are.

        It should contain another function associated with the key
        "series_transform". The function should accept two pairs of series (in
        type pandas Series or numpy arrays). The first pair consists of two
        training price series and the second pair consists of two corresponding
        testing price series. This function should return two pairs of
        transformed series corresponding to the parameter pairs. Spread should
        be formed by subtracting one series by another within the same pair.
    plot: boolean
        if True, plot the returned pairs for visualization. Do not plot
        otherwise

    Return
    ----------
    A list of tuples of the form (name of stock 1, name of stock 2) sorted by
    distance in assending order.
    """

    # config checking
    if not (("threshold" in config) ^ ("n" in config)):
        raise Exception(
            "Please include either the key 'threshold' or 'n' in config.")
    elif "score_function" not in config:
        raise Exception("Please include a key 'score_function' in config.")
    elif "series_transform" not in config:
        raise Exception("Please include a key 'series_transform' in config.")
    score_function = config['score_function']
    series_transform = config['series_transform']

    stock_names = train_df.columns.values.tolist()
    N = len(stock_names)

    scores = np.zeros(N*(N-1)//2)
    pairs = []

    # compute scores for all possible pairs
    i = 0
    stock_pairs = list(itertools.combinations(stock_names, 2))
    for pair in stock_pairs:
        price_series = (train_df[pair[0]], train_df[pair[1]])

        # use the provided transform function before compute score
        score = score_function(*series_transform(price_series))
        scores[i] = score

        pairs.append(pair)
        i += 1

    # obtain the result pairs by either thresholding the score or choose the
    # first n pairs
    result_pairs = []
    if "threshold" in config:
        result_indices = np.where(scores < config['threshold'])
        result_pairs = [pairs[i] for i in result_indices]
    else:
        n = config['n']
        if len(scores) > n:
            first_n_indices = np.argpartition(scores, n)[:n]
            result_pairs = [pairs[i] for i in first_n_indices]
        else:
            print('n is larger than the number of combinations of pairs!!!')
            result_pairs = pairs

    # plot for eyeballing
    if plot == True:
        for pair in result_pairs:
            training_price_series = (train_df[pair[0]], train_df[pair[1]])
            testing_price_series = (test_df[pair[0]], test_df[pair[1]])

            trans_training_series, trans_testing_series = \
                series_transform(training_price_series, testing_price_series)

            plot_two_series(*price_series, *pair,
                title='Training Phase Data')

            plot_two_series(*trans_training_series, *pair,
                title='Normalized Training Price Series')

            plot_two_series(*trans_testing_series, *pair,
                title='Normalized Testing Price Series')

            plot_spread(*trans_testing_series, *pair,
                title='Normalized Testing Spread Series')

    return result_pairs

def plot_two_series(x1, x2, label1, label2, title, plt_width=20, plt_height=5):
    """
    Helper function for visualizing two series
    """
    plt.rcParams['figure.figsize'] = [plt_width, plt_height]
    plt.plot(x1, marker='.', label=label1)
    plt.plot(x2, marker='.', label=label2)
    plt.title(title)
    plt.legend(loc='best')
    plt.show()

def plot_spread(x1, x2, label1, label2, title, plt_width=20, plt_height=5):
    """
    Helper function for visualizing two series
    """
    plt.rcParams['figure.figsize'] = [plt_width, plt_height]
    plt.plot(x1-x2, marker='.', label=label1)
    plt.title(title)
    plt.legend(loc='best')
    plt.show()

def distance_score(p1, p2):
    # compute distance
    diff = p1 - p2
    return (diff * diff).sum()

def compute_stat(p):
    return np.mean(p), np.std(p)

def distance_transform(training_pair, testing_pair=None):
    training_P1, training_P2 = training_pair

    # compute_stat should not change the series
    mean1, std1 = compute_stat(training_P1)
    mean2, std2 = compute_stat(training_P2)

    # normalize training
    p1 = (training_P1 - mean1) / std1
    p2 = (training_P2 - mean2) / std2
    trans_training = (p1, p2)

    # normalize testing
    if testing_pair != None:
        p1 = (testing_pair[0] - mean1) / std1
        p2 = (testing_pair[1] - mean2) / std2
        trans_testing = (p1, p2)

        # return a tuple if testing_pairs is provided
        return trans_training, trans_testing

    return trans_training

def intersection(train_df, test_df, n = 10, plot=True):
    """
    Find the closest n pairs (of 2 time series) computed based on their
    normalized price.

    Parameters
    ----------
    train_df: pandas dataframe
        for training data, each column is the time series of a certain stock
    test_df: pandas dataframe
        for testing data, each column is the time series of a certain stock
    n: int
        the number maximum number of pairs to return
    plot: boolean
        if True, plot the result for visualization. Do not plot otherwise

    Return
    ----------
    A list of tuples of the form (name of stock 1, name of stock 2) sorted by
    distance in assending order.
    """

    scores_to_pairs = []

    stock_names = train_df.columns.values.tolist()
    N = len(stock_names)

    stock_pairs = list(itertools.combinations(stock_names, 2))

    for pair in stock_pairs:
        P1, P2 = train_df[pair[0]].values, train_df[pair[1]].values

        # # build linear model
        # P1 = sm.add_constant(P1)
        # model = sm.OLS(P2, P1)
        # model_results = model.fit()

        # # get residul sign
        # residual_sign = np.sign(model_results.resid)

        # # compute number of intersection
        # rolled_sign = np.roll(residual_sign, 1)
        # rolled_sign[0] = 0
        # num_of_intersection = ((residual_sign * rolled_sign) == 1).sum()

        # scores_to_pairs.append((num_of_intersection, pair))

        mean1, std1 = compute_stat(P1)
        mean2, std2 = compute_stat(P2)

        p1 = (P1 - mean1) / std1
        p2 = (P2 - mean2) / std2

        # compute distance
        diff = p1 - p2

        # get residul sign
        residual_sign = np.sign(diff)

        # compute number of intersection
        rolled_sign = np.roll(residual_sign, 1)
        rolled_sign[0] = 0
        num_of_intersection = ((residual_sign * rolled_sign) == 1).sum()

        scores_to_pairs.append((num_of_intersection, pair))

    scores_to_pairs = sorted(scores_to_pairs, key=lambda x: x[0])

    results = None
    if len(scores_to_pairs) < n:
        results = [x[1] for x in scores_to_pairs]
    else:
        results = [x[1] for x in scores_to_pairs[:n]]

    # plot for eyeballing
    if plot == True:
        for pair in results:
            plot_two_series(train_df[pair[0]], train_df[pair[1]], *pair,
                title='Training Phrase Data')

            # P1, P2 = train_df[pair[0]].values, train_df[pair[1]].values

            # # build linear model
            # P1 = sm.add_constant(P1)
            # model = sm.OLS(P2, P1)
            # model_results = model.fit()

            # p1 = train_df[pair[0]] * model_results.params[1] + model_results.params[0]
            # p2 = train_df[pair[1]]
            # plot_two_series(p1, p2, *pair, title='Normalized Training Price Series')

            # p1 = test_df[pair[0]] * model_results.params[1] + model_results.params[0]
            # p2 = test_df[pair[1]]
            # plot_two_series(p1, p2, *pair, title='Normalized Testing Price Series')

            P1, P2 = train_df[pair[0]].values, train_df[pair[1]].values

            mean1, std1 = compute_stat(P1)
            mean2, std2 = compute_stat(P2)

            p1 = (train_df[pair[0]] - mean1) / std1
            p2 = (train_df[pair[1]] - mean2) / std2
            plot_two_series(p1, p2, *pair,
                title='Normalized Training Price Series')

            p1 = (test_df[pair[0]] - mean1) / std1
            p2 = (test_df[pair[1]] - mean2) / std2
            plot_two_series(p1, p2, *pair,
                title='Normalized Testing Price Series')

    return results

import numpy,import statsmodels,from statsmodels


__all__ = ['optimalSVHT']

import numpy as np

def optimalSVHT(matrix):
	"""
	Returns the optimal threshold of the singular values of a matrix, i.e., it computes the optimal number
	of singular values to keep or the optimal rank of the matrix.
	Given a matrix Y=X+sigma*Z, with Y the observed matrix, X the matrix that we want to find, Z an matrix whose elements are iid Gaussian
	random numbers with zero mean and unit variance and sigma is the standard deviation of the noise, the matrix X can be recovered in the
	least squares sense using a truncated SVD (compute the SVD of the matrix, keep only the relevant singular values and reconstruct the
	matrix). The problem is estimate the number of such singular values to keep. This function uses the theory of Gavish & Donoho (2014)
	that is valid for matrices with sizes larger than its rank, i.e., for low-rank matrices

	Input:
	matrix: matrix to estimate the rank

	Output:
	thrKnownNoise: in case sigma is known, multiply this value with sigma and this gives the threshold
	thrUnknownNoise: returns the threshold directly
	noiseEstimation: returns the estimation of the noise
	sv: returns the singular values of the matrix
	"""

	m, n = matrix.shape
	beta = 1.0 * m / n

	w = (8.0 * beta) / (beta + 1 + np.sqrt(beta**2 + 14 * beta +1))
	lambdaStar = np.sqrt(2.0 * (beta + 1) + w)

	omega = 0.56*beta**3 - 0.95*beta**2 + 1.82*beta + 1.43
	uSVD, wSVD, vSVD = np.linalg.svd(matrix)
	medianSV = np.median(wSVD)

	thrKnownNoise = lambdaStar * np.sqrt(n)
	thrUnknownNoise = omega * medianSV

	muSqrt = lambdaStar / omega
	noiseEstimation = medianSV / (np.sqrt(n) * muSqrt)

	return thrKnownNoise, thrUnknownNoise, noiseEstimation, wSVD

if __name__ == "__main__":
# Generate a matrix of given rank
	rank = 3
	m = 80
	n = 80
	sigma = 0.02
	X1 = np.random.randn(m,rank)
	X2 = np.random.randn(rank,n)

	Y = np.dot(X1, X2) + sigma * np.random.randn(m,n)

	thrKnownNoise, thrUnknownNoise, noiseEstimation, wSVD = optimalSVHT(Y)
	rankKnownNoise = len(np.where(wSVD > thrKnownNoise*sigma)[0])
	rankUnknownNoise = len(np.where(wSVD > thrUnknownNoise)[0])

	print "Known sigma : {0} - rank={1}".format(thrKnownNoise * sigma, rankKnownNoise)
	print "Unknown sigma : {0} - rank={1} - sigmaNoise={2}".format(thrUnknownNoise, rankUnknownNoise, noiseEstimation)


# Importing Necessary Libraries
#%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = (20.0, 10.0)

# Reading Data
data = pd.read_csv('headbrain.csv')
print(data.shape)

# Collecting X and Y
X = data['Head Size(cm^3)'].values
Y = data['Brain Weight(grams)'].values

# Mean X and Y
mean_x = np.mean(X)
mean_y = np.mean(Y)

# Total number of values
m = len(X)

# Using the formula to calculate b1 and b2
numer = 0
denom = 0
for i in range(m):
    numer += (X[i] - mean_x) * (Y[i] - mean_y)
    denom += (X[i] - mean_x) ** 2
b1 = numer / denom
b0 = mean_y - (b1 * mean_x)

# Plotting Values and Regression Line

max_x = np.max(X) + 100
min_x = np.min(X) - 100

# Calculating line values x and y
x = np.linspace(min_x, max_x, 1000)
y = b0 + b1 * x

# Ploting Line
plt.plot(x, y, color='#58b970', label='Regression Line')
# Ploting Scatter Points
plt.scatter(X, Y, c='#ef5423', label='Scatter Plot')

plt.xlabel('Head Size in cm3')
plt.ylabel('Brain Weight in grams')
plt.legend()
plt.show()

# Calculating Root Mean Squares Error
rmse = 0
for i in range(m):
    y_pred = b0 + b1 * X[i]
    rmse += (Y[i] - y_pred) ** 2
rmse = np.sqrt(rmse/m)
print(rmse)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Mar 11 23:08:36 2022

@author: jimmy
"""

""" 31. Write a Pandas program to compute the Euclidean distance between two given series"""

import pandas as pd
from scipy.spatial import distance
import numpy as np

dataset = pd.Series([1,2,3,4,5,6,7,8,9,10])
dataset_1 = pd.Series([11,8,7,5,6,5,3,4,7,1])
print(f"{dataset}, \n{dataset_1}")
distance = distance.euclidean(dataset, dataset_1)
distance_2 = np.linalg.norm(dataset-dataset_1)
print(f"Euclidean distance between two said series: {distance.round(3)}  \nLinalg option: {distance_2.round(3)}")

""" 32.Write a Pandas program to find the positions of the values neighboured by smaller values on both sides in a given series"""

dataset_2 = pd.Series([1,8,7,5,6,5,3,4,7,1])

temp = np.diff(np.sign(np.diff(dataset_2)))
result = np.where(temp == -2)[0] + 1
print(f"Positions of the values surrounded by smaller values on both sides: {result}")

""" 33. Write a Pandas program to replace missing white spaces in a given string with the least frequent character"""

str1 = 'abc def abcdef icd'
print(str1)
ser = pd.Series(list(str1))
element_freq = ser.value_counts()
print(element_freq)
current_freq = element_freq.dropna().index[-1]
result = "".join(ser.replace(' ', current_freq))
print(result)

""" 34. Write a Pandas program to compute the autocorrelations of a given numeric series."""
dataset_4 = pd.Series(np.arange(15) + np.random.normal(1, 10, 15))
print(F"Original series: {dataset_4}")

autocorrelations = [dataset_4.autocorr(i).round(2) for i in range(11)]
print("\nAutocorrelations of the said series:")
print(autocorrelations[1:])


# Program to illustrate simple Backpropagation example #

# Step 1. Use simple forward propagation technique using intial values of w1,w2 and b1,b2 to find z1,z2,a,a2
# Step 2. Assume Ground truth T different than predicted output
# Step 3. Calculate MSE - E with respect to a2 (output) for propagating back into the network.
# Step 4. Update w2,b2,w1,b1
# Step 5. Repeat number of steps till E --> 0

# Assumptions: number of iterations = 1000, predefined threshold = 0.001, Learning Rate - 0.4.

## Forward propagation to calculate z1,a1,z2,a2
import numpy as np
weights=[0.15,0.45]
biases=[0.4,0.65]

# Given x1
x1=0.1

#Computing z1 and a1
z1=x1*weights[0]+biases[0]
a1=1.0/(1.0+np.exp(-z1))

# Computing z2 and a2
z2=a1*weights[1]+biases[1]
a2=1.0/(1.0+np.exp(-z2))

with open ("back_propagation_results.txt",'a') as f:
    print('z1 is {}'.format(z1, decimals=3),file=f)
    print('a1 is {}'.format(a1, decimals=3),file=f)
    print('z2 is {}'.format(z2, decimals=3),file=f)
    print('a2 is {}'.format(a2, decimals=3),file=f)

# Info parameters
T=0.25
n_iter=1000
ep=0.001
Lr=0.4

#Differentiation parameters
from sympy import *
a_2 = Symbol('a_2')
z_2 = Symbol('z_2')
a_1 = Symbol('a_1')
z_1 = Symbol('z_1')
b_2 = Symbol('b_2')
b_1 = Symbol('b_1')
w_2 = Symbol('w_2')
w_1 = Symbol('w_1')
x_1=Symbol('x_1')

E=0.5*((T-a_2)**2)
E_a2_prime=E.diff(a_2)

a_2_exp=1.0/(1.0+exp(-z_2))
a2_z2_prime=a_2_exp.diff(z_2)

z_2_exp1=a1*w_2+biases[1]
z_2_exp2=a1*weights[1]+b_2
z_2_exp3=a_1*weights[1]+biases[1]

z2_w2_prime=z_2_exp1.diff(w_2)
z2_b2_prime=z_2_exp2.diff(b_2)
z2_a1_prime=z_2_exp3.diff(a_1)

a_1_exp=1.0/(1.0+exp(-z_1))
a1_z1_prime=a_1_exp.diff(z_1)

z_1_exp1=x1*w_1+biases[0]
z_1_exp2=x1*weights[0]+b_1

z1_w1_prime=z_1_exp1.diff(w_1)
z1_b1_prime=z_1_exp2.diff(b_1)

# Calculation the differentation

E=lambdify(a_2, E)
E_a2_prime=lambdify(a_2, E_a2_prime)
a2_z2_prime=lambdify(z_2, a2_z2_prime)
z2_w2_prime=lambdify(w_2, z2_w2_prime)
z2_b2_prime=lambdify(b_2, z2_b2_prime)
z2_a1_prime=lambdify(a_1, z2_a1_prime)
a1_z1_prime=lambdify(z_1, a1_z1_prime)
z1_w1_prime=lambdify(w_1, z1_w1_prime)
z1_b1_prime=lambdify(b_1, z1_b1_prime)
## Updating w2,b2,w1,w2

w2_updated=weights[1]-Lr*(E_a2_prime(a2)*a2_z2_prime(z2)*z2_w2_prime(weights[1]))
b2_updated=biases[1]-Lr*(E_a2_prime(a2)*a2_z2_prime(z2)*z2_b2_prime(biases[1]))
w1_updated=weights[0]-Lr*(E_a2_prime(a2)*a2_z2_prime(z2)*z2_a1_prime(a1)*a1_z1_prime(z1)*z1_w1_prime(weights[0]))
b1_updated=biases[0]-Lr*(E_a2_prime(a2)*a2_z2_prime(z2)*z2_a1_prime(a1)*a1_z1_prime(z1)*z1_b1_prime(biases[0]))

with open ("back_propagation_results.txt",'a') as f:
    print('Updated w2 is {}'.format(w2_updated, decimals=3),file=f)
    print('Updated b2 is {}'.format(b2_updated, decimals=3),file=f)
    print('Updated w1 is {}'.format(w1_updated, decimals=3),file=f)
    print('Updated b1 is {}'.format(b1_updated, decimals=3),file=f)

# Computing new error

#Computing z1_new and a1_new
z1_updated=x1*w1_updated+b1_updated
a1_updated=1.0/(1.0+np.exp(-z1_updated))

# Computing z2 and a2
z2_updated=a1_updated*w2_updated+b2_updated
a2_updated=1.0/(1.0+np.exp(-z2_updated))

E_old=0.5*((T-a2)**2)
E_new=0.5*((T-a2_updated)**2)

with open ("back_propagation_results.txt",'a') as f:
    print('a2 output before single iteration is {}'.format(a2, decimals=3),file=f)
    print('a2 output after single iteration is {}'.format(a2_updated, decimals=3),file=f)
    print('Error before single iteration is {}'.format(E_old, decimals=3),file=f)
    print('Error after single iteration is {}'.format(E_new, decimals=3),file=f)

## Using loops of iteration, the error can be approached to zero to find optimum weights and biases

Introduction to Deep Learning & Neural Networks with Keras/Module1/Back_propagation_example.py


"""
Given a irregular, closed, convex polygon
P with n−1 sides and m circle-centers {(xi,yi)}mi contained within that polygon, compute the radii, 0≤ri, of m circles
centered at those m points such that the sum of the areas of the circles is minimized (approximately) and that
any vertex in P is also contained in at least one of the m circles.

Here is the function signature: find_convex_cover(pvertices,clist) where pvertices is a
(n−1)-long iterable of polygon vertices and clist is a list of (xi,yi) tuples of circle-centers.
The output of find_convex_cover is a m long list of radii, ri, corresponding to the m circle-centers.

Example:

->>> pvertices = array([[ 0.573,  0.797],
                        [ 0.688,  0.402],
                        [ 0.747,  0.238],
                        [ 0.802,  0.426],
                        [ 0.757,  0.796],
                        [ 0.589,  0.811]])

 ->>> clist = [(0.7490863467660889, 0.4917635308023209),
              (0.6814339441396109, 0.6199470305156477),
              (0.7241617773773865, 0.6982813914515696),
              (0.6600700275207232, 0.7516911829987891),
              (0.6315848053622062, 0.7730550996176769),
              (0.7348437356868305, 0.41342916986639894),
              (0.7597683050755328, 0.31729154508140384)]

 ->>> find_convex_cover(pvertices,clist) # note some radii == 0
 [0, 0, 0.10297280518543134, 0, 0.06374182913818943, 0.0684588720095565, 0.07987784828713643]

Hints:

m can be very large so use Numpy broadcasting effectively.
For your own understanding, use Matplotlib to visualize the polygons and circles.
Numpy is the only third-party module you can use with this assignment.
Since the n-polygon is closed, the first and last vertices are the same so that only n−1
vertices need be specified.
Your solution can be an approximation to the minimum.
"""
import numpy as np
from collections import defaultdict

EPSILON = 1e-3

def find_convex_cover(pvertices,clist):
    """
    Finds the optimum radius of circles such that all vertices are contained
    :param pvertices:
    :param clist:
    :return:
    """

    assert isinstance(clist, list)
    for elem in clist:
        assert isinstance(elem, tuple)
        assert len(elem) == 2
        for num in elem:
            assert isinstance(num, (float, int))

    for elem in pvertices:
        assert len(elem) == 2
        for num in elem:
            assert isinstance(num, (float, int))

    pvertices = np.array(pvertices)
    clist = np.array(clist)

    r = pvertices[:, None] - clist
    D = np.apply_along_axis(np.linalg.norm, -1, r)
    argmins = np.argmin(D, axis=-1)

    radii = defaultdict(int)

    for i, argmin in enumerate(argmins):
        radii[argmin] = max(D[i, argmin], radii[argmin])

    return [radii[i] for i in range(len(clist))]

if __name__ == '__main__':
    import matplotlib.pyplot as plt

    ##### Arguments
    pvertices = [[0.573, 0.797],
                       [0.688, 0.402],
                       [0.747, 0.238],
                       [0.802, 0.426],
                       [0.757, 0.796],
                       [0.589, 0.811]]

    clist = [(0.7490863467660889, 0.4917635308023209),
                  (0.6814339441396109, 0.6199470305156477),
                  (0.7241617773773865, 0.6982813914515696),
                  (0.6600700275207232, 0.7516911829987891),
                  (0.6315848053622062, 0.7730550996176769),
                  (0.7348437356868305, 0.41342916986639894),
                  (0.7597683050755328, 0.31729154508140384)]
    ######## End Arguments

    figure, axes = plt.subplots()
    x, y = zip(*pvertices)
    axes.scatter(x, y)
    xc, yc = zip(*clist)
    axes.scatter(xc, yc)

    result = find_convex_cover(pvertices, clist)

    print("Test Case Provided\n")
    print("prediction | label | error | threshold")
    print("-" * 15)
    for predict, label in zip(result, [0, 0, 0.10297280518543134, 0, 0.06374182913818943, 0.0684588720095565, 0.07987784828713643]):
        error = predict - label
        row = [str(predict), str(label), str(error), str(error < EPSILON)]
        print(" | ".join(row))

    for c, radius in zip(clist, result):
        cc = plt.Circle(c, radius, alpha=0.2)
        axes.add_artist(cc)

    plt.xlim(0.2, 1)
    plt.ylim(0.2, 1)
    plt.title("Minimum-area Circles Covering All Vertices")
    plt.legend(["Vertices", "Circle Centers"])
    plt.show()


"""
.. versionadded:: 0.7

Implemented functions:

* **Mean absolute error** (MAE, also  known as MAD - mean absolute deviation)

  :math:`\\textrm{MAE}=\\frac{1}{n} \sum _{i=1}^{n}(e_{i})`.

* **Mean squared error** (MSE, also known as MSD)

  :math:`\\textrm{MSE}=\\frac{1}{n} \sum _{i=1}^{n}(e_{i})^{2}`.

* **Root-mean-square error** (RMSE, also known as RMSD)

  :math:`\\textrm{RMSE} = \\sqrt{\\textrm{MSE}}`.

* **Logarithmic squared error** (returns a vector of values in dB!)

  :math:`\\textbf{logSE} = 10 \log_{10} (\\textbf{e}^{2})`

all functions are often used for evaluation of an error rather than just
the error itself or its mean value.

Usage instructions
====================

For MAE evaluation from two time series use

.. code-block:: python

    mse = pa.misc.MAE(x1, x2)

If you have the error already calculated, then just

.. code-block:: python

    mse = pa.misc.MAE(e)

The same instructions apply for the MSE, RMSE a logarithmic squared error

.. code-block:: python

    mse = pa.misc.MSE(x1, x2)
    rmse = pa.misc.RMSE(x1, x2)
    logse = pa.misc.logSE(x1, x2)

and from error

.. code-block:: python

    mse = pa.misc.MSE(e)
    rmse = pa.misc.RMSE(e)
    logse = pa.misc.logSE(e)

Minimal working examples
==========================

In the following example is estimated MSE for two series
(:code:`x1` and :code:`x1`):

.. code-block:: python

    import numpy as np
    import padasip as pa

    x1 = np.array([1, 2, 3, 4, 5])
    x2 = np.array([5, 4, 3, 2, 1])
    mse = pa.misc.MSE(x1, x2)
    print(mse)

You can easily check that the printed result :code:`8.0` is correct MSE for
given series.

The following example displays, that you can use directly the error series
:code:`e` if you already have it.

.. code-block:: python

    import numpy as np
    import padasip as pa

    # somewhere else in your project
    x1 = np.array([1, 2, 3, 4, 5])
    x2 = np.array([5, 4, 3, 2, 1])
    e = x1 - x2
    # you have just the error - e
    mse = pa.misc.MSE(e)
    print(mse)

Again, you can check the correctness of the answer easily.

Code Explanation
====================
"""
import numpy as np

def get_valid_error(x1, x2=-1):
    """
    Function that validates:

    * x1 is possible to convert to numpy array

    * x2 is possible to convert to numpy array (if exists)

    * x1 and x2 have the same length (if both exist)
    """
    # just error
    if type(x2) == int and x2 == -1:
        try:
            e = np.array(x1)
        except:
            raise ValueError('Impossible to convert series to a numpy array')
    # two series
    else:
        try:
            x1 = np.array(x1)
            x2 = np.array(x2)
        except:
            raise ValueError('Impossible to convert one of series to a numpy array')
        if not len(x1) == len(x2):
            raise ValueError('The length of both series must agree.')
        e = x1 - x2
    return e

def logSE(x1, x2=-1):
    """
    10 * log10(e**2)
    This function accepts two series of data or directly
    one series with error.

    **Args:**

    * `x1` - first data series or error (1d array)

    **Kwargs:**

    * `x2` - second series (1d array) if first series was not error directly,\\
        then this should be the second series

    **Returns:**

    * `e` - logSE of error (1d array) obtained directly from `x1`, \\
        or as a difference of `x1` and `x2`. The values are in dB!

    """
    e = get_valid_error(x1, x2)
    return 10*np.log10(e**2)

def MAE(x1, x2=-1):
    """
    Mean absolute error - this function accepts two series of data or directly
    one series with error.

    **Args:**

    * `x1` - first data series or error (1d array)

    **Kwargs:**

    * `x2` - second series (1d array) if first series was not error directly,\\
        then this should be the second series

    **Returns:**

    * `e` - MAE of error (float) obtained directly from `x1`, \\
        or as a difference of `x1` and `x2`

    """
    e = get_valid_error(x1, x2)
    return np.sum(np.abs(e)) / float(len(e))

def MSE(x1, x2=-1):
    """
    Mean squared error - this function accepts two series of data or directly
    one series with error.

    **Args:**

    * `x1` - first data series or error (1d array)

    **Kwargs:**

    * `x2` - second series (1d array) if first series was not error directly,\\
        then this should be the second series

    **Returns:**

    * `e` - MSE of error (float) obtained directly from `x1`, \\
        or as a difference of `x1` and `x2`

    """
    e = get_valid_error(x1, x2)
    return np.dot(e, e) / float(len(e))

def RMSE(x1, x2=-1):
    """
    Root-mean-square error - this function accepts two series of data
    or directly one series with error.

    **Args:**

    * `x1` - first data series or error (1d array)

    **Kwargs:**

    * `x2` - second series (1d array) if first series was not error directly,\\
        then this should be the second series

    **Returns:**

    * `e` - RMSE of error (float) obtained directly from `x1`, \\
        or as a difference of `x1` and `x2`

    """
    e = get_valid_error(x1, x2)
    return np.sqrt(np.dot(e, e) / float(len(e)))

def get_mean_error(x1, x2=-1, function="MSE"):
    """
    This function returns desired mean error. Options are: MSE, MAE, RMSE

    **Args:**

    * `x1` - first data series or error (1d array)

    **Kwargs:**

    * `x2` - second series (1d array) if first series was not error directly,\\
        then this should be the second series

    **Returns:**

    * `e` - mean error value (float) obtained directly from `x1`, \\
        or as a difference of `x1` and `x2`
    """
    if function == "MSE":
        return MSE(x1, x2)
    elif function == "MAE":
        return MAE(x1, x2)
    elif function == "RMSE":
        return RMSE(x1, x2)
    else:
        raise ValueError('The provided error function is not known')


import numpy as np

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

def binary_search(f, x1=-1, x2=1, num_iter=100, espilon=1e-8):

    for i in range(num_iter):
        xm = (x1 + x2) / 2
        if np.sign(f(xm)) == np.sign(f(x1)):
            x1 = xm
        else:
            x2 = xm
        if x2 - x1 < epsilon:
            print("x = {} after {} iterations".format(xm, i + 1))
            return xm

    raise ValueError("FAILURE")


from mpl_toolkits.mplot3d import Axes3D
import scipy.io as sio
import matplotlib.image as img
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
from numpy.linalg import svd

def feature_normalize(X):
    means = np.mean(X, axis=0)
    X_norm = X - means
    stds = np.std(X_norm, axis=0)
    X_norm = X_norm / stds

    return means, stds, X_norm

def compute_covariance_matrix(X):
    return X.T.dot(X) / X.shape[0]

def pca(X):
    covariance_matrix = compute_covariance_matrix(X)
    U, S, V = svd(covariance_matrix, full_matrices=True, compute_uv=True)

    return U, S

def project_data(X, U, K):
    return X.dot(U[:, :K])

def recover_data(Z, U, K):
    return Z.dot(U[:, :K].T)

def grid_plot(X, dim):
    fig = plt.figure(figsize=(6, 6))
    M, N = X.shape

    gs = gridspec.GridSpec(dim, dim)
    gs.update(bottom=0.01, top=0.99, left=0.01, right=0.99,
              hspace=0.05, wspace=0.05)

    k = 0
    for i in range(dim):
        for j in range(dim):
            ax = plt.subplot(gs[i, j])
            ax.axis('off')
            ax.imshow(-X[k].reshape(int(np.sqrt(N)), int(np.sqrt(N))).T,
                      cmap=plt.get_cmap('Greys'),  # vmin=-1, vmax=1,
                      interpolation='nearest')  # ,alpha = 1.0)
            k += 1

    plt.show()

def main():
    # 1
    file_path = 'ex7data1.mat'
    dataset = sio.loadmat(file_path)
    X = dataset["X"]

    # 2
    # X[:, 0] - first column
    plt.scatter(X[:, 0], X[:, 1], marker="o")
    plt.show()

    # 3
    covariance_matrix = compute_covariance_matrix(X)
    print(covariance_matrix)

    # 4
    # Feature normalize
    # mu, sigma
    means, stds, X_norm = feature_normalize(X)
    # Run SVD
    U, S = pca(X_norm)
    print(U, S)

    # 5
    #  Draw the eigenvectors centered at mean of data. These lines show the
    #  directions of maximum variations in the dataset.
    fig, ax = plt.subplots()
    ax.plot(X[:, 0], X[:, 1], 'o', mew=0.25)

    for i in range(len(S)):
        ax.arrow(means[0], means[1], 1.5 * S[i] * U[0, i], 1.5 * S[i] * U[1, i],
                 head_width=0.25, head_length=0.2, fc='k', ec='k', lw=2, zorder=1000)

    ax.axis([0.5, 6.5, 2, 8])
    ax.set_aspect('equal')
    ax.grid(False)

    plt.show()

    print('Top principal component: U[:, 0] = [{:.6f} {:.6f}]'.format(U[0, 0], U[1, 0]))
    print(' (you should expect to see [-0.707107 -0.707107])')

    # 6
    # Project the data onto K = 1 dimension
    K = 1
    Z = project_data(X_norm, U, K)
    print('Projection of the first example: {:.6f}'.format(Z[0, 0]))
    print('(this value should be about    : 1.481274)')

    # 7
    X_rec = recover_data(Z, U, K)
    print('Approximation of the first example: [{:.6f} {:.6f}]'.format(X_rec[0, 0], X_rec[0, 1]))
    print('       (this value should be about  [-1.047419 -1.047419])')

    # 8
    plt.figure(figsize=(6, 6))
    plt.plot(X_norm.T[0], X_norm.T[1], 'bo', mfc='none', mec='b', ms=8, label='Original Data Points')
    plt.plot(X_rec.T[0], X_rec.T[1], 'ro', mfc='none', mec='r', ms=8, label='PCA Reduced Data Points')
    plt.xlabel('x1', fontsize=14)
    plt.ylabel('x2', fontsize=14)
    plt.legend(loc=4)
    for (x, y), (x_rec, y_rec) in zip(X_norm, X_rec):
        plt.plot([x, x_rec], [y, y_rec], 'k--', lw=1)
    plt.xlim(-4, 3)
    plt.ylim(-4, 3)
    plt.show()

    # 9
    file_path = 'ex7faces.mat'
    dataset = sio.loadmat(file_path)
    X = dataset['X']

    # 10
    grid_plot(X, 10)

    # 11
    # mu, sigma
    means, stds, X_norm = feature_normalize(X)
    U, S = pca(X_norm)

    # 12, 13
    grid_plot(U.T, 6)

    # 14-15
    grid_plot(U.T, 10)

    # 16
    A = img.imread('output.jpg')
    X = A.reshape(-1, 3)

    # 17
    # Sample 1000 random indexes (since working with all the data is
    #  too expensive. If you have a fast computer, you may increase this.
    sel = np.random.choice(X.shape[0], size=1000)

    fig = plt.figure(figsize=(6, 6))
    ax = fig.add_subplot(111, projection='3d')
    idx = np.loadtxt('output.txt')
    ax.scatter(X[sel, 0], X[sel, 1], X[sel, 2], cmap='rainbow', c=idx[sel], s=10)
    ax.set_title('Pixel dataset plotted in 3D.\nColor shows centroid memberships')

    plt.show()

    # 18
    mu, sigma, X_norm = feature_normalize(X)

    # PCA and project the data to 2D
    U, S = pca(X_norm)
    Z = project_data(X_norm, U, 2)

    fig = plt.figure(figsize=(6, 6))
    ax = fig.add_subplot(111)

    ax.scatter(Z[sel, 0], Z[sel, 1], cmap='rainbow', c=idx[sel], s=32)
    ax.set_title('Pixel dataset plotted in 2D, using PCA for dimensionality reduction')
    ax.grid(False)

    plt.show()

if __name__ == '__main__':
    main()


import numpy as np

"""
This module calculates the mean value and smoothes the data.

"""
### Running mean/Moving average
def running_mean(l, N):
    sum = 0
    result = list( 0 for x in l)

    for i in range( 0, N ):
        sum = sum + l[i]
        result[i] = sum / (i+1)

    for i in range( N, len(l) ):
        sum = sum - l[i-N] + l[i]
        result[i] = sum / N

    return result

### Neighbor Mean/Moving Average
def neighbor_mean(input_list, N):
    """
    inputs:
        input_list --- []
        N --- number of neighbors to be averaged
    outputs:
        result --- []
    """
    if  type(input_list) != list:
        raise TypeError("The input list must be a list!")

    if type(N) != int:
        raise TypeError("The input type must be an int!")

    result = []
    radius = (N-1)/2

    for i in range(len(input_list)):

        if (i-radius)<0:
            result.append(np.mean(input_list[:i+1]))

        elif (i+radius)>len(input_list)-1:
            result.append(np.mean(input_list[i:]))

        else:
            temp = []
            for j in range(i-radius, i+radius+1):
                temp.append(input_list[j])
            result.append(np.mean(temp))

    return result

if __name__== "__main__":
    print "This is a test!"
    x = [i for i in range(-10,11)]
    a = [i**2 for i in range(-10,11)]
    print a
    sa = neighbor_mean(a,5)
    print sa
    import matplotlib.pyplot as plt
    plt.figure(0)
    plt.plot(x,a,'r',x,sa,'b')
    plt.show()


# softmax(yi) = exp(yi) / sum_j(exp(yj))

import numpy
import math

def softmax(x):
	array = numpy.transpose(x)
	shape = array.shape
	if len(shape) == 1:
		print "1D Array"
		temp = []
		for value in x:
			temp.append(math.exp(value))

		sum_of_x = sum(temp)

		result = []
		for value in temp:
			result.append(value / sum_of_x)

		return result
	elif len(shape) == 2:
		print "2D Array"
		rows = shape[0]
		cols = shape[1]
		result = []
		for row in range(rows):
			temp1 = []
			for col in range(cols):
				temp1.append(math.exp(x[col][row]))

			sum_of_x = sum(temp1)

			temp2 = []
			for value in temp1:
				temp2.append(value / sum_of_x)

			result.append(temp2)
		return numpy.transpose(result)
	else:
		return None

# Or using numpy more effectively:
def softmax2(x):
	return numpy.exp(x) / numpy.sum(numpy.exp(x), axis=0)

scores = [1.0, 2.0, 3.0]

print softmax2(scores), "\n"

scores = [[1, 2, 3, 6], [2, 4, 5, 6], [3, 8, 7, 6]]

print softmax2(scores)


import numpy as np

def exponential(o1, o2):
    return np.linalg.norm(o1 - o2)

def hotaling_matrix(b, dtype=np.double):
    H = np.array([[(b + 1) / 2, (b - 1) / 2],
                  [(b - 1) / 2, (b + 1) / 2]], dtype=dtype)
    return H

def hotaling(o1, o2, b):
    H = hotaling_matrix(b)
    return (o2 - o1) @ H @ (o2 - o1).T

def hotaling_S_from_D(D, phi1, phi2):
    return np.eye(D.shape[0]) - phi2 * np.exp(-phi1 * D ** 2)

def hotaling_D(M, b):
    D = np.zeros((M.shape[0], M.shape[0]))
    for i in range(M.shape[0]):
        for j in range(M.shape[0]):
            D[i][j] = hotaling(M[i], M[j], b)
    return D

def hotaling_S(M, phi1, phi2, b):
    D = hotaling_D(M, b)
    return hotaling_S_from_D(D, phi1, phi2)


import numpy as np
import matplotlib.pyplot as plt

f_wave = 2 #actual frequency of the wave
omega = 2*np.pi*f_wave
t = np.arange(0, 2, 0.001)

#signal = np.sin(omega*t)
signal = np.cos(2*omega*t)+np.sin(10*omega*t)

# plt.plot(t, signal, color='b')
# plt.savefig('Signal_Wrap/cos2+sin10.png')

min_freq = 0
max_freq = 10

f_list = np.arange(min_freq, max_freq, 0.2)

for f_idx, f in enumerate(f_list):

	r, theta = [], []

	for idx in range(len(t)):
		r.append(signal[idx])
		theta.append(2*np.pi*f*t[idx])

	x, y = [], []

	for idx in range(len(t)):
		x.append(r[idx]*np.cos(theta[idx]))
		y.append(r[idx]*np.sin(theta[idx]))

	plt.figure(figsize=(5,5))
	plt.xlim(-2.1,2.1)
	plt.ylim(-2.1,2.1)
	plt.plot(x, y, color='r')
	plt.title("Frequency = "+str(round(f_list[f_idx],1))+" Hz", size=15)
	plt.savefig('signal_wrap_%d.png'%f_idx)
	plt.clf()

#Convert to GIF in order
#convert -delay 30 signal_wrap_{0..49..1}.png sine.gif


import numpy as np
from scipy.linalg import eig
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # <--- This is important for 3d plotting
# from mpl_toolkits import mplot3d

if __name__ == "__main__":

    X = np.loadtxt('data-dimred-X.csv', dtype=np.float, delimiter=',')
    y = np.loadtxt('data-dimred-y.csv', dtype=np.float)

    # X = X.T
    X = X-np.expand_dims(X.mean(axis=1),1)

    C = np.dot(X,X.T)/y.shape[0]
    l, U = eig(C)
    sorted_idxs = np.argsort(np.real(l))[::-1]
    l, U = l[sorted_idxs], U[:, sorted_idxs]

    # 2D PCA Projections
    dim = 2
    X_trans = np.dot(U.T[0:dim], X)

    plt.scatter(X_trans[0, y == 1], X_trans[1, y == 1], c='red', label='Class 1', alpha=0.75)
    plt.scatter(X_trans[0, y == 2], X_trans[1, y == 2], c='blue', label='Class 2', alpha=0.75)
    plt.scatter(X_trans[0, y == 3], X_trans[1, y == 3], c='green', label='Class 3', alpha=0.75)
    plt.title("PCA for dimension = 2 for 'data-dimred-X.csv'")
    plt.savefig("PCA_dim2.pdf", facecolor='w', edgecolor='w', papertype=None, format='pdf',
                transparent=False, bbox_inches='tight', pad_inches=0.1)
    plt.legend()
    plt.show()

    # 3D PCA Projections
    dim = 3
    X_trans = np.real(np.dot(U.T[0:dim], X))
    # print(X_trans)
    fig = plt.figure()
    ax = plt.axes(projection = '3d')
    ax.scatter(X_trans[0, y == 1], X_trans[1, y == 1], X_trans[2, y == 1], c='red', label='Class 1', alpha=0.75)
    ax.scatter(X_trans[0, y == 2], X_trans[1, y == 2], X_trans[2, y == 2], c='blue', label='Class 2', alpha=0.75)
    ax.scatter(X_trans[0, y == 3], X_trans[1, y == 3], X_trans[2, y == 3], c='green', label='Class 3', alpha=0.75)
    ax.set_title("PCA for dimension = 3 for 'data-dimred-X.csv'")
    plt.savefig("PCA_dim3.pdf", facecolor='w', edgecolor='w', papertype=None, format='pdf',
                transparent=False, bbox_inches='tight', pad_inches=0.1)
    ax.legend()
    plt.show()


print("-----Gauss-Jordan Elimination-----")

## in this method we transform our nxn matrix to a identity matrix and then don't need to do back substitution

import numpy as np

a=np.array([[1,3,2],
            [2,7,7],
            [2,5,2]],float)
b=np.array([2,-1,7],float)
# a= np.array([[1,3,-2,4],
#              [2,6,0,5],
#              [4,11,8,0],
#              [1,3,2,1]],float)
# b=np.array([7,5,7,-2],float)
n= len(b)

## if there is zero or negligible element on the main diagonal, then code for interchanging the rows
for k in range(n):
    if abs(a[k,k])<1.0e-10:
        for i in range(k+1,n):
            if abs(a[i,k])>abs(a[k,k]): # We can also write abs(a[k,k])=1.0e-10 because we are looking for non zero element on the main diagonal
                a[[k,i]]=a[[i,k]] ## changeing rows of matrix
                b[i,k]=b[k,i]## changeing elements in the RHS constant vector
                ##Or
                # for j in range(k,n):
                #     a[k,j],a[i,j]=a[i,j],a[k,j]
                # b[k],b[i]=b[i],b[k]

                break

    for l in range(n):
        a[k,:]=a[k,:]/a[k,k]
    b[k]=b[k]/a[k,k]

    # #Or
    # for k in range(n):
    #     pivot= a[k,k]
        # for l in range(n):
        #     a[k,l]=a[k,l]/pivot
        # b[k]=b[k]/pivot

    for i in range(n):
        # b[k],b[i]=b[i],b[k]
        if i==k or a[i,k]==0: ##we skip that row if there is zero and also i==k element(diagonal element) because we have already set that to 1.
            continue

        factor =a[i,k] ## we have to predefine the factor, because in every iteration it changes.(although sometimes it doesn't matter)
        b[i] -= b[k]*factor ## we can define this vector also after the j loop.
        for j in range(k,n):
            a[i,j]-= factor * a[k,j]

print("Transformed Identity matrix: ")
print(a)

print("The solution vector is: ")
print(b)