'''

Machine Learning - Data Distribution
Data Distribution

Earlier in this tutorial we have worked with very small amounts of data in our examples, just to understand the different concepts.

In the real world, the data sets are much bigger, but it can be difficult to gather real world data, at least at an early stage of a project.
How Can we Get Big Data Sets?

To create big data sets for testing, we use the Python module NumPy, which comes with a number of methods to create random data sets, of any size.
Example

Create an array containing 250 random floats between 0 and 5:
import numpy

x = numpy.random.uniform(0.0, 5.0, 250)

print(x)
'''
import numpy as r

e=r.random.uniform(0.5,5,250)
print(e)
'''
Histogram

To visualize the data set we can draw a histogram with the data we collected.

We will use the Python module Matplotlib to draw a histogram.

Learn about the Matplotlib module in our Matplotlib Tutorial.
Example

Draw a histogram:
import numpy
import matplotlib.pyplot as plt

x = numpy.random.uniform(0.0, 5.0, 250)

plt.hist(x, 5)
plt.show()

note: The array values are random numbers and will not show the exact same result on your computer.
'''
import  matplotlib.pyplot as plt
import numpy as np

x=np.random.uniform(0.0,5,250)

plt.hist(x,5)
plt.show()

'''
Histogram Explained

We use the array from the example above to draw a histogram with 5 bars.

The first bar represents how many values in the array are between 0 and 1.

The second bar represents how many values are between 1 and 2.

Etc.

Which gives us this result:

    52 values are between 0 and 1
    48 values are between 1 and 2
    49 values are between 2 and 3
    51 values are between 3 and 4
    50 values are between 4 and 5

Note: The array values are random numbers and will not show the exact same result on your computer.
Big Data Distributions

An array containing 250 values is not considered very big, but now you know how to create a random set of values, and by changing the parameters, you can create the data set as big as you want.
Example

Create an array with 100000 random numbers, and display them using a histogram with 100 bars:
import numpy
import matplotlib.pyplot as plt

x = numpy.random.uniform(0.0, 5.0, 100000)

plt.hist(x, 100)
plt.show()
'''


import numpy as np
import os

import matplotlib as mpl
import matplotlib.pyplot as plt

from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.decomposition import PCA
from sklearn.decomposition import IncrementalPCA

import time

####################################################################################################################################################
### Prepare MNIST dataset ##########################################################################################################################
####################################################################################################################################################
mnist = fetch_openml('mnist_784', version=1)
mnist.target = mnist.target.astype(np.uint8)

X = mnist['data']       # Load data from MNIST dataset
y = mnist['target']     # Load target values from MNIST dataset

X_train, X_test, y_train, y_test = train_test_split(X, y)   # Split the dataset between training and test

####################################################################################################################################################
### PCA, IPCA, Randomized PCA under Different Number of Principle Components #######################################################################
####################################################################################################################################################
for n_components in (2, 10, 154):   # Conduct principle component analysis with different number of PCs

    print('n_components = ', n_components)

    regular_pca = PCA(n_components=n_components)        # Regular PCA with different number of PCS
    inc_pca = IncrementalPCA(n_components=n_components, batch_size=500)     # Incremental PCA with different number of PCs
    rnd_pca = PCA(n_components=n_components, random_state=42, svd_solver='randomized')      # Randomized PCA with different number of PCs

    for pca in (regular_pca, inc_pca, rnd_pca):

        # Measure the time taken for principle component analysis
        t1 = time.time()    # Measure time before PCA
        pca.fit(X_train)    # Acquire principle components with current MNIST training set
        t2 = time.time()    # Measure time after PCA

        print('     {} : {:.1f} seconds'.format(pca.__class__.__name__, t2-t1))

####################################################################################################################################################
### PCA vs Randomized PCA under Different Number of Samples ########################################################################################
####################################################################################################################################################
times_rpca = []     # Time measurements with Randomized PCA
times_pca = []      # Time measurements with PCA
sizes = [1000, 10000, 20000, 30000, 40000, 50000, 70000, 100000, 200000, 500000]    # Number of samples

for n_samples in sizes:

    X = np.random.randn(n_samples, 5)       # Prepare the random dataset with 5 features

    pca = PCA(n_components=2, svd_solver='randomized', random_state=42)     # Randomized PCA object for producing 2 principle components
    t1 = time.time()            # Measure time before PCA
    pca.fit(X)                  # Acquire principle components with current random dataset with 5 features
    t2 = time.time()            # Measure time after PCA
    times_rpca.append(t2-t1)    # Save time measurements of Randomized PCA

    pca = PCA(n_components=2)   # PCA object for producing 2 principle components
    t1 = time.time()            # Measure the time before PCA
    pca.fit(X)                  # Acquire principle components with current random dataset with 5 features
    t2 = time.time()            # Measure the time after PCA
    times_pca.append(t2-t1)     # Save time measurements of PCA

# Plot the time complexity of PCA and Randomized PCA
plt.plot(sizes, times_rpca, "b-o", label="RPCA")
plt.plot(sizes, times_pca, "r-s", label="PCA")
plt.xlabel("n_samples")
plt.ylabel("Training time")
plt.legend(loc="upper left")
plt.title("PCA and Randomized PCA time complexity ")
plt.show()

####################################################################################################################################################
### PCA vs Randomized PCA under Different Number of Features #######################################################################################
####################################################################################################################################################
times_rpca = []     # Time measurements with Randomized PCA
times_pca = []      # Time measurements with PCA
sizes = [1000, 2000, 3000, 4000, 5000, 6000]        # Number of features

for n_features in sizes:

    X = np.random.randn(2000, n_features)       # Prepare the random dataset with different number of features

    pca = PCA(n_components=2, random_state=42, svd_solver='randomized')     # Randomized PCA object for producing 2 principle components
    t1 = time.time()                # Measure time before PCA
    pca.fit(X)                      # Acquire principle components with current random dataset with different number of features
    t2 = time.time()                # Measure time after PCA
    times_rpca.append(t2-t1)        # Save time measurements of Randomized PCA

    pca = PCA(n_components=2)       # PCA object for producing 2 principle components
    t1 = time.time()                # Measure the time before PCA
    pca.fit(X)                      # Acquire principle components with current random dataset with different number of features
    t2 = time.time()                # Measure the time after PCA
    times_pca.append(t2-t1)         # Save time measurements of PCA

# Plot the time complexity of PCA and Randomized PCA
plt.plot(sizes, times_rpca, "b-o", label="RPCA")
plt.plot(sizes, times_pca, "r-s", label="PCA")
plt.xlabel("n_features")
plt.ylabel("Training time")
plt.legend(loc="upper left")
plt.title("PCA and Randomized PCA time complexity ")
plt.show()


import math

import numpy as np
import pandas as pd
import reader
from sklearn.linear_model import RidgeCV
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import KFold, RepeatedKFold, train_test_split

# file path constants
FILE_PATH_TRAIN = "train1b.csv"
TEST_SIZE = 0.2

# feature transformation functions
functions = [lambda x: float(x), lambda x: math.pow(x, 2), lambda x: math.exp(x), lambda x: math.cos(x), lambda x: float(1)]

# read input data
data = reader.read_csv(FILE_PATH_TRAIN, False)

# drop the first column
data = pd.DataFrame.drop(data, columns='Id')

# splitting the data set into x & y values
# y-values
Y = pd.DataFrame(data, columns=['y'], copy=True)
Y = Y['y'].values

# x-values
X = pd.DataFrame(data, columns=['x1', 'x2', 'x3', 'x4', 'x5'], copy=True)

# new data frames for feature transformations
quad = pd.DataFrame(data, columns=['x6', 'x7', 'x8', 'x9', 'x10'])
exp = pd.DataFrame(data, columns=['x11', 'x12', 'x13', 'x14', 'x15'])
cos = pd.DataFrame(data, columns=['x16', 'x17', 'x18', 'x19', 'x20'])
const = pd.DataFrame(data, columns=['x21'])

# performing the feature transformations
for index, row in X.iterrows():
    # 1. transformation: quadratic
    quad['x6'][index] = functions[1](X['x1'][index])
    quad['x7'][index] = functions[1](X['x2'][index])
    quad['x8'][index] = functions[1](X['x3'][index])
    quad['x9'][index] = functions[1](X['x4'][index])
    quad['x10'][index] = functions[1](X['x5'][index])

    # 2. transformation: exponential
    exp['x11'][index] = functions[2](X['x1'][index])
    exp['x12'][index] = functions[2](X['x2'][index])
    exp['x13'][index] = functions[2](X['x3'][index])
    exp['x14'][index] = functions[2](X['x4'][index])
    exp['x15'][index] = functions[2](X['x5'][index])

    # 3. transformation: cosine
    cos['x16'][index] = functions[3](X['x1'][index])
    cos['x17'][index] = functions[3](X['x2'][index])
    cos['x18'][index] = functions[3](X['x3'][index])
    cos['x19'][index] = functions[3](X['x4'][index])
    cos['x20'][index] = functions[3](X['x5'][index])

    # 4. transformation: constant
    const['x21'][index] = functions[4](1)

# concatenating all data frames
X_transformed = pd.concat([X, quad, exp, cos, const], axis=1)
X_transformed = X_transformed.values

# intermediate / test split
x_intermediate, x_test, y_intermediate, y_test = train_test_split(X_transformed, Y, test_size=TEST_SIZE, shuffle=False)

# storing the evaluation scores
eval = []

# storing the coefficients
av_coeffs = []

# alpha parameter values
alphas = [10.0e-4, 10.0e-3, 10.0e-2, 10.0e-1, 10.0e0, 10.0, 20.0, 100.0]

# creating the 10-fold split
ten_fold = KFold(n_splits=10, shuffle=False)
repeated_ten_fold = RepeatedKFold(n_splits=10, n_repeats=5)

# create ridge cross validation model
ridge = RidgeCV(alphas=alphas, fit_intercept=True, normalize=False,
                cv=repeated_ten_fold, gcv_mode='auto')

# training the model
ridge.fit(x_intermediate, y_intermediate)

coeffs = []

# remember the coefficients (weight vector in the cost function)
coeffs.append(ridge.coef_)

# evaluate with validation set
y_val_predictions = ridge.predict(x_test)

# compute root mean square error
rmse = math.sqrt(mean_squared_error(y_test, y_val_predictions))

# Print Out
print()
print("Error Estimate on Validation Set")
print("RMSE:", rmse)
print()
print("Model Info:", "Ridge Cross Validation")
print("Alpha:", ridge.alpha_)
print()
print("Coefficients:", ridge.coef_)

# preparing to write the coefficients to file
out = {"Coefficients": coeffs[0]}

# output data frame
best_coeffs = pd.DataFrame(data=out)

# printing test output
print()
print("Result Written To File:")
print(best_coeffs.head(5))

# write to csv-file
# best_coeffs.to_csv("task1b_elastic-net_10-fold-cv_Nr3.csv", sep=',', index=False, header=False)


import argparse
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.patches import Rectangle, Arc
from matplotlib.collections import PatchCollection
import numpy as np

def fib(n):
    """Short summary.

    Parameters
    ----------
    n : type
        Description of parameter `n`.

    Returns
    -------
    type
        Description of returned object.

    """
    a, b = 1, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

def plot_fibonacci_spiral(
    number_of_squares,
    numbers=True,
    arc=True,
    cmap="Blues",
    alpha=1,
    golden_ratio=False,
    filename="plot.png",
):
    """Short summary.

    Parameters
    ----------
    number_of_squares : type
        Description of parameter `number_of_squares`.
    numbers : type
        Description of parameter `numbers`.
    arc : type
        Description of parameter `arc`.
    cmap : type
        Description of parameter `cmap`.
    alpha : type
        Description of parameter `alpha`.
    golden_ratio : type
        Description of parameter `golden_ratio`.

    Returns
    -------
    type
        Description of returned object.

    """
    fibs = list(fib(number_of_squares))
    x = 0
    y = 0
    angle = 180
    center = (x + fibs[0], y + fibs[0])
    rectangles = []
    xs, ys = [], []

    fig, ax = plt.subplots(1, figsize=(16, 16))
    for i, side in enumerate(fibs):

        rectangles.append(Rectangle([x, y], side, side))
        if numbers and i > number_of_squares - 8:
            ax.annotate(side, xy=(x + 0.45 * side, y + 0.45 * side), fontsize=14)

        if arc:
            this_arc = Arc(
                center,
                2 * side,
                2 * side,
                angle=angle,
                theta1=0,
                theta2=90,
                edgecolor="black",
                antialiased=True,
            )
            ax.add_patch(this_arc)
        angle += 90

        xs.append(x)
        ys.append(y)
        if i == 0:
            x += side
            center = (x, y + side)
        elif i == 1:
            x -= side
            y += side
            center = (x, y)
        elif i in range(2, i + 1, 4):
            x -= side + previous_side
            y -= previous_side
            center = (x + side + previous_side, y)
        elif i in range(3, i + 1, 4):
            y -= side + previous_side
            center = (x + side + previous_side, y + side + previous_side)
        elif i in range(4, i + 1, 4):
            x += side
            center = (x, y + side + previous_side)
        elif i in range(5, i + 1, 4):
            x -= previous_side
            y += side
            center = (x, y)
        previous_side = side

    col = PatchCollection(rectangles, alpha=alpha, edgecolor="black")
    try:
        col.set(array=np.asarray(range(number_of_squares + 1)), cmap=cmap)
    except ValueError:
        print(
            f" '{cmap}' is an invalid colormap, choose a valid one from "
            "https://matplotlib.org/examples/color/colormaps_reference.html"
            " - returning to default 'Blues' colormap"
        )
        col.set(array=np.asarray(range(number_of_squares + 1)), cmap="Blues")

    ax.add_collection(col)
    ax.set_aspect("equal", "box")
    ax.set_xticks([])
    ax.set_yticks([])

    xmin = np.min(xs)
    ymin = np.min(ys)
    xmax = np.max(xs) + fibs[np.argmax(xs)]
    ymax = np.max(ys) + fibs[np.argmax(ys)]
    ax.set_xlim(xmin, xmax)
    ax.set_ylim(ymin, ymax)
    gr = str(fibs[i] / fibs[i - 1])
    if golden_ratio:
        plt.title(r"$\varphi$ = " + gr)
    plt.tight_layout()
    plt.savefig(filename)

if __name__ == "__main__":

    description = "Creates a plot for a fibonacci spiral"
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument(
        "-n",
        "--number_of_squares",
        type=int,
        help="number of squares in spiral",
        required=True,
    )

    parser.add_argument(
        "-o",
        "--output",
        type=str,
        help="Plot file name",
        required=False,
        default="plot.png",
    )

    parser.add_argument(
        "--no-label",
        dest="labels",
        help="Remove label showing side lenght at the center of each square",
        action="store_false",
        default=True,
        required=False,
    )

    parser.add_argument(
        "--no-arc",
        dest="arc",
        help="Remove arc of fibonacci spiral",
        action="store_false",
        default=True,
        required=False,
    )

    parser.add_argument(
        "-c",
        "--cmap",
        dest="cmap",
        type=str,
        help="Colormap applied to fibonacci squares",
        default="Blues",
        required=False,
    )

    parser.add_argument(
        "-a",
        "--alpha",
        dest="alpha",
        type=float,
        help="Transparency",
        default=0.95,
        required=False,
    )

    args = parser.parse_args()

    plot_fibonacci_spiral(
        args.number_of_squares,
        numbers=bool(args.labels),
        arc=bool(args.arc),
        cmap=args.cmap,
        alpha=args.alpha,
        filename=args.output,
    )


import numpy as np
import matplotlib.pyplot as plt
import math
import matplotlib.mlab as mlab
import matplotlib.lines as mlines
import scipy.stats as stats

## Background Class H0 Definition

mean0=[0,1]
sigmax0=1.5
sigmay0=1.5
rho=0.7
cov0=[[sigmax0**2,rho*sigmax0*sigmay0],[rho*sigmax0*sigmay0,sigmay0**2]]
n0=1000

## Signal Class H1 Definition

mean1=[4,4]
sigmax1=1
sigmay1=1
cov1=[[sigmax1**2,0],[0,sigmay1**2]]
n1=1000

## Pseudo-Random generation for H0 e H1 gaussians with defined parameters

x0,y0=np.random.multivariate_normal(mean0,cov0,n0).T
T0=np.column_stack((x0,y0))*1.0 ## Data on two columns
m0=np.sum(T0,axis=0)/n0 ## Mean over rows

x1,y1=np.random.multivariate_normal(mean1,cov1,n1).T
T1=np.column_stack((x1,y1))*1.0 ## Data on two columns
m1=np.sum(T1,axis=0)/n1 ## Mean over rows

## Covariance matrices calculation

S_w=(n1)*np.cov(T1,rowvar=False,bias=1)+(n0)*np.cov(T0,rowvar=False,bias=1) ## S_w=S0+S1
S_inv_w=np.linalg.inv(S_w) ## S_w inversion with linear algebra numpy library
S_b=np.outer(m1-m0,m1-m0)

## Fisher vector definition

v=np.matmul(S_inv_w, m1-m0) ## ROWxCOL product by numpy package

## Data projection on \vec{v}

x11=np.matmul(v,T1.transpose()) ## Signal data projection
x00=np.matmul(v,T0.transpose()) ## Background data projection

## Plotting Data, \vec{v} and projections

plt.figure('Data and v')

plt.scatter(x1,y1,color='red', edgecolor='black')
plt.scatter(x0,y0, color='yellow', edgecolor='black')
plt.xlabel('x')
plt.ylabel('y')

def newline(p1, p2): ## Straight line from two given points...
    ax = plt.gca()
    xmin, xmax = ax.get_xbound()

    if(p2[0] == p1[0]):
        xmin = xmax = p1[0]
        ymin, ymax = ax.get_ybound()
    else:
        ymax = p1[1]+(p2[1]-p1[1])/(p2[0]-p1[0])*(xmax-p1[0])
        ymin = p1[1]+(p2[1]-p1[1])/(p2[0]-p1[0])*(xmin-p1[0])

    l = mlines.Line2D([xmin,xmax], [ymin,ymax], color='black', linestyle='-')
    ax.add_line(l)
    return l
newline([0,0], v)

plt.figure('Data projections') ## (bins choosen for graphic-only purposes)

plt.hist(x11, bins=33, color='red', edgecolor='black', alpha=0.8)
plt.hist(x00, bins=66, color='yellow', edgecolor='black', alpha=0.8)
plt.xlabel('Projected Data')
plt.ylabel('Counts')

## Showing plots

plt.show()

## Significance and Specificity optimization and consequent t_cut determination

t=np.concatenate((x11,x00),axis=0)  ## Definition of Fisher Statistic
q=np.linspace(min(t),max(t),len(t)) ## Homogeneuous domain for optimum-value search
alpha=np.zeros(len(t))              ## alpha ~ 1 - E_1 -> #{False Negatives}
beta=np.zeros(len(t))               ## beta  ~ E_0 -----> #{False Positives}

for i in range(0,len(q)):
 alpha[i]=(x11<q[i]).sum()/n1 ## Rejection of H1 when H1 is true
 beta[i]=(x00>q[i]).sum()/n0  ## Acceptance of H1 when H1 is false

ToMinimize=alpha+beta
best=min(ToMinimize)

t_cut=np.mean(q[ToMinimize==best]) ## There can be more than one best-match...
print (round(t_cut,6) , ': t_cut optimum value')

plt.axvline(t_cut)
plt.xlabel('Projected Data')
plt.ylabel('Counts')

## Plotting alpha+beta as a function of trial t_cut (i.e. q)

plt.figure('Minimization Functional')
plt.plot(q,ToMinimize, linewidth = 5)
plt.xlabel('Trial Boundary [t]')
plt.ylabel('(False Positives + False Negatives)')
plt.axvline(np.mean(q[ToMinimize==best]))
plt.show()

## Identified signal purity computation

bestalpha=np.mean(alpha[np.where(((q-t)**2)**0.5==np.min((q-t)**2)**0.5)])
bestbeta=np.mean(beta[np.where(((q-t)**2)**0.5==np.min((q-t)**2)**0.5)])

print (round(bestalpha,6), ': alpha optimum value')
print (round(bestbeta,6), ': beta optimum value')
print (round(1-bestalpha,6)/(round(bestbeta,6)+round(1-bestalpha,6)), ': obtained signal purity')

## ROC curve determination

plt.figure('ROC curve')
plt.plot(beta,1-alpha, linewidth = 5, color='green')
plt.xlabel('False Positive Rate [Background Efficiency]')
plt.ylabel('True Positive Rate [Signal Efficiency]')
plt.title('ROC curve')
plt.show()

## Area under the ROC curve

SamplingPts = beta.shape[0]

# Integrating in [0.1] with "trapezoid-rule"

I = 0.5*alpha[0] + 0.5*alpha[beta.shape[0]-1]
for j in range(1,SamplingPts):
    I += alpha[j]
    dx = beta[j] - beta[j-1]
    I *= dx
I += 1
print('ROC area: ', I)


import matplotlib
matplotlib.use('Agg')

import numpy as np
import matplotlib.pyplot as plt

def prior(x, f="flat"):
    n_points = len(x)
    if f=="flat":
        p = np.ones(n_points)
    return p

def likelihood(s, p_a):
    n_a = s.count('a')
    n_b = s.count('b')
    return (p_a)**n_a * (1-p_a)**n_b

def max_prob(x, pdf_x):
    ii = np.argmax(pdf_x)
    return x[ii]

def mean(x, pdf_x):
    return np.trapz(pdf_x*x, x)

def sigma(x, pdf_x):
    m = mean(x, pdf_x)
    s = np.trapz(pdf_x*x*x, x)
    return np.sqrt(s - m**2)

def posterior(s):
    n_points = 1000
    p_a = np.linspace(0.0, 1.0, n_points)

    p =  prior(p_a)
    l = likelihood(s, p_a)

    post = p * l # Bayes

    norm = np.trapz(post, p_a)
    post = post/norm

    mp = max_prob(p_a, post)
    m = mean(p_a, post)
    sig = sigma(p_a, post)

    values = 'Max Prob = {:.2f}, Mean = {:.2f}, Sigma={:.2f}'.format(mp, m, sig)

    plt.plot(p_a, post , label="data= {}".format(s))
    plt.title(values)
    plt.legend()
    plt.xlabel('$p_a$')
    plt.ylabel('$PDF (p_a|data)$')
    plt.savefig('posterior.pdf')


# search for the roots by secants method

import numpy, matplotlib
import matplotlib.pyplot as plt
from prettytable import PrettyTable
from math import *

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

# def f1(x):
# 	return math.sin(x) * math.cos(x / 20) * math.cos(x / 80)
# 	#return 1 / abs(x) if abs(x) > 1 else 2 - x * x
# 	#return math.e * math.sin(x / 100) / \
# 	#(abs(math.log(abs(math.sin(x) + 1))) + 1) - 1

# def f2(x):
# 	return math.sin(x / 65) * 0.43 - 0.4
# 	return x / 300

def derivative(func, x, power=1):
	dx = 0.001
	derivFunc = lambda x: (func(x + dx) - func(x)) / dx
	if power == 1:
		return derivFunc(x)
	elif power > 1:
		return derivative(derivFunc, x, power - 1)

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

# [ root, f(root), iterations, error ]
def findRootBySecants(func, p1, p2, eps, nMax):
	n = 1
	error = None

	while abs(func(p2)) > eps and abs(p1 - p2) > eps:
		if n > nMax:
			error = "Maximim of n"
			break

		fX1 = func(p1)
		fX2 = func(p2)

		if fX1 == fX2:
			error = "Horisontal"
			break

		if abs(fX1) < abs(fX2):
			fX1, fX2 = fX2, fX1
			p2, p1 = p1, p2

		p1, p2 = p2, p2 - (p2 - p1) * fX2 / (fX2 - fX1)

		n += 1

	return [ p2, func(p2), n, error ]

# [ №, A, B, root, f(root), iterations, error ]
def findRoots(func, a, b, step, eps, nMax):
	result = []
	aNext = min(a + step, b)
	i = 1
	lastRoot = None
	while True:
		if func(a) * func(aNext) <= 0:
			r = findRootBySecants(func, a, aNext, eps, nMax)

			# error handling
			if not r[0] is None:
				if not lastRoot is None and abs(lastRoot - r[0]) < eps:
					r[3] = "Dublicate"
				elif not (a <= r[0] <= aNext):
					r[3] = "Out of interval"
				else:
					lastRoot = r[0]

			if not r[0] is None or not r[3] is None:
				result.append([i, a, aNext] + r)
				i += 1
		a += step;
		if aNext >= b:
			break
		aNext = min(aNext + step, b)

	return result

def findExtremums(func, a, b, step, eps, nMax, power=1):
	result = findRoots(lambda x: derivative(func, x, power), a, b, step, eps, nMax)
	for i in result:
		i[4] = func(i[3])
	return result

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

def findIntersactionPoints(func1, func2, a, b, step, eps, nMax):
	return [ i[3] for i in findRoots(lambda x: func1(x) - func2(x), \
		a, b, step, eps, nMax) ]

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

def getIntegral(func, a, b, intervLength=1e-2):
	result = 0
	while a < b:
		aNext = min(a + intervLength, b)

		result += (func(a) + func(aNext)) * (aNext - a) / 2

		a += intervLength
	return result

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

def drawRoots(roots, col="red"):
	result, = plt.plot([i[3] for i in roots if not i[3] is None], \
		[i[4] for i in roots if not i[3] is None], 'ro', color=col)
	return result

def drawGraph(func, xRange, col="blue"):
	plt.grid(True)

	graph, = plt.plot(xRange, [ func(x) for x in xRange ], \
		linewidth=3, color=col)

	return graph

def drawExtremums(ext, col="green"):
	result, = plt.plot([i[3] for i in ext if not i[3] is None], \
		[i[4] for i in ext if not i[3] is None], 'ro', color=col)
	return result

def drawInflections(infl, col="black"):
	result, = plt.plot([i[3] for i in infl if not i[3] is None], \
		[i[4] for i in infl if not i[3] is None], 'ro', color=col)
	return result

def drawIntervals(func1, func2, intersactPoints, eps):
	if not intersactPoints: return
	last = intersactPoints[0]
	for point in intersactPoints[1:]:
		xRange = numpy.arange(last, point, 0.001)
		plt.fill_between(xRange, [ func1(x) for x in xRange ],\
		 [ func2(x) for x in xRange ], color='blue', alpha=.1)

	result, = plt.plot(intersactPoints, [func1(point) for point in intersactPoints]\
		, 'ro', color="pink")

	return result

def showPlot():
	plt.show()

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

def printRoots(roots):
	table = PrettyTable(["№", "A", "B", "Root", "f(x)",\
	 "Loops Count", "Error"])

	for i in roots:
		if not i[6] is None:
			i[3] = None
			i[4] = None

		n = i[0]
		A = "{:.3f}".format(i[1])
		B = "{:.3f}".format(i[2])
		root = "{:7f}".format(i[3]) if not (i[3] is None) else '-'
		fx = "{:3e}".format(i[4]) if not (i[4] is None) else '-'
		loops = i[5] if not (i[5] is None) else '-'
		error = i[6]

		table.add_row([ n, A, B, root, fx, loops, error])

	print(table)

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

f1Code = input("Enter first  math function: f(x) = ")
f2Code = input("Enter second math function: f(x) = ")

f1 = lambda x: eval(f1Code)
f2 = lambda x: eval(f2Code)

print()

x1 = float(input("Enter the first point  (float): "))
while True:
	x2 = float(input("Enter the second point (float): "))
	if x1 < x2:
		break
	else:
		print("\tError: x1 must be less then x2.")
while True:
	eps = float(input("Enter epsilon (float): "))
	if eps > 0:
		break
	else:
		print("\tError: value must be positive.")
while True:
	step = float(input("Enter step (float): "))
	if 0 < step:
		break
	else:
		print("\tError: value must be positive.")
while True:
	nMax = float(input("Enter max n (integer): "))
	if 0 < nMax:
		break
	else:
		print("\tError: value must be positive.")

xRange = numpy.arange(x1, x2, 0.001)

roots1 = findRoots(f1, x1, x2, step, eps, nMax)
extem1 = findExtremums(f1, x1, x2, step, eps, nMax)
infle1 = findExtremums(f1, x1, x2, step, eps, nMax, 2)

roots2 = findRoots(f2, x1, x2, step, eps, nMax)
extem2 = findExtremums(f2, x1, x2, step, eps, nMax)
infle2 = findExtremums(f2, x1, x2, step, eps, nMax, 2)

intersactions = findIntersactionPoints(f1, f2, x1, x2, step, eps, nMax)
square = sum([ abs(getIntegral(lambda x: f1(x) - f2(x), intersactions[i], \
	intersactions[i + 1])) for i in range(len(intersactions) - 1)] )

graph1Obj = drawGraph(f1, xRange, "blue")
extem1Obj = drawExtremums(extem1)
infle1Obj = drawInflections(infle1)
roots1Obj = drawRoots(roots1)

graph2Obj = drawGraph(f2, xRange, "orange")
extem2Obj = drawExtremums(extem2)
infle2Obj = drawInflections(infle2)
roots2Obj = drawRoots(roots2)

intervalsObj = drawIntervals(f1, f2, intersactions, eps)
print()
printRoots(roots1)

# некрасиво, т.к. использую матплотлиб из вне функций
plt.title("Area: " + str(square))
plt.legend([ graph1Obj, graph2Obj, roots1Obj, extem1Obj, infle1Obj, intervalsObj ], \
	[ "$f1(x) = " + f1Code + "$", "$f2(x) = " + f2Code + "$", "$Roots$", "$Extremums$", "$Inflections$", "$Intersections$"])

showPlot()


from sympy import cos, cosh, diag, exp, sin, sinh, symbols

from einsteinpy.symbolic.metric import MetricTensor

def AntiDeSitter():
    """
    Anti-de Sitter space

    Hawking and Ellis (5.9) p131

    """
    coords = symbols("t chi theta phi")
    t, ch, th, ph = coords
    metric = diag(
        -1,
        cos(t) ** 2,
        cos(t) ** 2 * sinh(ch) ** 2,
        cos(t) ** 2 * sinh(ch) ** 2 * sin(th) ** 2,
    ).tolist()
    return MetricTensor(metric, coords, "ll", name="AntiDeSitterMetric")

def AntiDeSitterStatic():
    """
    Static form of Anti-de Sitter space

    Hawking and Ellis (5.9) p131

    """
    coords = symbols("t r theta phi")
    t, r, th, ph = coords
    metric = diag(-cosh(r) ** 2, 1, sinh(r) ** 2, sinh(r) ** 2 * sin(th) ** 2).tolist()
    return MetricTensor(metric, coords, "ll", name="AntiDeSitterStaticMetric")

def DeSitter():
    """
    de Sitter space

    Hawking and Ellis p125

    """
    coords = symbols("t x y z")
    t = coords[1]
    al = symbols("alpha")
    expr = exp(2 * t / al)
    metric = diag(-1, expr, expr, expr).tolist()
    return MetricTensor(metric, coords, "ll", name="DeSitterMetric")


# -*- coding: utf-8 -*-
"""
Created on Fri Jan 15 16:03:05 2021
@author: MarlaJahari
"""
import numpy as np
import matplotlib.pyplot as ourplot

"PROBLEM: To solve the given diff eqn using finite difference method"
"y2=y'+x(x-4)  p(x)=1 q(x)=0 r(x)=x(x-4) 0<x<4 y(0)=y(4)=0"
'[a,b]=[0,4]'

a=0                   #upper limit
b=4                   #lower limit
n=int(input('no of steps YOU WISH'))
h=(b-a)/n
p=1                   #co-efficient of first derivative
q=0                   #co-efficient of y

'(2-p*h)y[i+1]+ (-4)y[i] + (2+p*h)y[i-1]=2rh^2 (substituting our equation in FDM)'

c=[]                 #vector to store the constants on right

for i in range(1,n,1):
    r=2*i*h*((i*h)-4)#since x=0+i*h
    C= r*h**2        #the constant part of equation
    c.append(C)      #producing elements in loop and adding them to c

A=-4                 #(-2*q*h**2-4) co-efficient of y[i] throughout the loop
B=2-p*h              #co-efficient of y[i+1] "
E=2+p*h              #co-efficient of y[i-1] "
x=[]                 #for storing A for diff values of i
y=[]                 #for storing B for "
z=[]                 #for storing E for "

for i in range(n-1):
    x.append(A)      #adding B to vector x for diff i's

for i in range(n-2):
    y.append(B)      #adding A to vector y for diff i's
    z.append(E)

def tridiag(x,y,z, k1=-1,k2=0,k3=1): #creating a function for triD matrix

     return np.diag(x,k2) + np.diag(z,k1)+ np.diag(y,k3) #main+off+off

M=tridiag(x, y, z)                   #built matrix
P=np.array([[c]]).T                  #converting const array to soln column vector
print("Our co-efficient matrix:")
print(M)                             #printing matrix (*not printed with the command for spacing)
print("Our constant matrix:")
print(P)                             #printing soln vector

'Algorithm for Thomas method to solve tri-diagonal matrixes'

"""
here consider our reference matrix is of form

   [b1 c1 0
   a2 b2 c2
   0  a3 b2]

"""

v=len(c)                   #extracting the length of const mtrx
f=np.zeros(v-1)            #creating an array of zeros length v-1
g=np.zeros(v)
d=np.zeros(v)

'~Matrix Operations~'

# for an eq b1x1+ c1x2=r1, div throughout by b1(1st element of main D)>>

f[0]=y[0]/x[0] #dividing 1st elm(Up-D) by 1st elm(M-D)
g[0]=c[0]/x[0]

#row2- eqn a2x1+b2x2+c2x3, to eliminate a2x1>>
#take the 1st element of off-D below(a2) and multiply by the 1st row
#repeat it down the rows until  all the MD elms=1, lD elms=0, uD elms=k
#we divide throughout by b2-a2*(k) k=previous uD modified elm>>

for i in range(1,v-1):

      f[i]=y[i]/(x[i]-z[i-1]*f[i-1]) #co-efficients of xi throughout

for i in range(1,v):

      #now we modify const Vectr in sync with the rest of our operations
      #modifying constant Vectr>> c1=r1/b1, c2=(r2-a2r1)/(b2-a2k1),c3=..etc

      g[i]=(c[i]-z[i-1]*g[i-1])/(x[i]-z[i-1]*f[i-1])

      #equating modified const vector w/ final soln vector

      d[v-1]=g[v-1]

#d stores the final solution for each elm simultaneously by backward subst

'Final Backward Substitution'

for i in range(v-1,0,-1):

      d[i-1]=g[i-1]-f[i-1]*d[i]      #backw subst (x1=r1-x2*k1, x2=r2-""..)

T=d                                  #soln by Thomas' algorithm
W=np.linalg.solve(M,c)               #soln by in-built funcn

print("The solution vector by inbuilt numpy func: ",W)

print("The solution vector by Thomas' Algorithm:",d)

'PLOTTING'

#for plotting Y, we create a zero vectr w/ soln values in between

Y=np.zeros(n+1)
for i in range(1,n):
    Y[i]=d[i-1]

#for plotting X, we create a vector to store subsequent values in a loop

X=[]
for i in range(n+1):
        x=i*h
        X.append(x)

ourplot.title("FINITE DIFFERENCE GRAPH")
ourplot.xlabel("X")
ourplot.ylabel("Plotting discrete y-values")
ourplot.plot(X,Y)
ourplot.show()


def centrAggClust(X, Y):
    """This function uses centroid distances for agglomerative clustering, plotting all cluster
    assignments for 2 clusters up to n - 1 clusters, where n = len(X) = len(Y). It returns the
    suggested number of clusters (based on the shortest minimum distance used for agglomeration)."""

    # Import some necessary tools
    import numpy as np
    from matplotlib import pyplot as plt

    # Set the number of plots
    rows = int((len(X)-2) / 4)
    if (len(X) - 2) % 4 != 0:
        rows += 1
    if len(X) > 5:
        cols = 4
    else:
        cols = len(X)
    fig, ax = plt.subplots(rows, cols, figsize=(8,2*rows))
    plt.subplots_adjust(hspace=0.5)

    # Define the datapoints
    pts = list(zip(X, Y))
    clusts = [[pt] for pt in pts]
    end = len(clusts)

    # Keep track of minimum distances
    mins = []

    # We'll show assignments until we're down to 2 clusters
    while end > 2:

        # Initialize the minimum distance
        min_dist = 0
        for ptx in clusts[0]:
            for pty in clusts[1]:
                min_dist += np.sqrt((ptx[0] - pty[0])**2 + (ptx[1] - pty[1])**2)
        min_dist /= (len(clusts[0])*len(clusts[1]))

        # Record the clusters between which the distance is minimal
        nearest1 = 0
        nearest2 = 1

        # Start measuring distances
        # Select the first cluster
        for clust1 in range(end - 1):
            arr_clust1 = np.array(clusts[clust1])

            # Select the second cluster
            for clust2 in range(clust1 + 1, end):
                arr_clust2 = np.array(clusts[clust2])

                dist = 0
                for pt1 in arr_clust1:
                    for pt2 in arr_clust2:
                        dist += np.sqrt((pt1[0] - pt2[0])**2 + (pt1[1] - pt2[1])**2)
                dist /= (len(arr_clust1)*len(arr_clust2))

                # Update if appropriate
                if dist < min_dist:
                    min_dist = dist
                    nearest1 = clust1
                    nearest2 = clust2

        # Record all minimal distances
        mins.append(min_dist)

        # Consolidate the nearest clusters
        clusts[nearest1].extend(clusts[nearest2])

        # Drop the absorbed cluster
        del clusts[nearest2]

        # Plot
        for clust in clusts:
            num = len(X) - end
            p_row = int(num / 4)
            p_col = num % 4
            if p_row < rows and p_col < cols and rows > 1:
                ax[p_row, p_col].set_title(f'{end - 1} clusters')
                ax[p_row, p_col].scatter(np.array(clust)[:, 0], np.array(clust)[:, 1])
            else:
                if p_row < rows and p_col < cols:
                    ax[p_col].set_title(f'{end - 1} clusters')
                    ax[p_col].scatter(np.array(clust)[:, 0], np.array(clust)[:, 1])

        # Update end
        end=len(clusts)

    # Find the suggested number of clusters
    if len(X) <= 2:
        out = 2
    else:
        out = len(X) - mins.index(np.max(mins))
    return out


# imports
import math
import scipy.stats as st

def conf_int(mean, var, n, p=0.95):
    """
    Calculate a confidence interval
    :param mean: mean of simulations
    :param var: variance of simulations
    :param n: amount of simulations
    :param p: certainty percentage
    :return:
    """
    pnew = (p+1)/2
    zval = st.norm.ppf(pnew)
    sigma = math.sqrt(var)
    alambda = (zval*sigma)/math.sqrt(n)
    min_lambda = mean - alambda
    plus_lambda = mean + alambda
    return f"Confidence interval: [{min_lambda:.4f} < X < {plus_lambda:.4f}] with p = {p}"

def calc_rho(mu, lbda, c):
    return lbda/(c*mu)

def pwait(c, rho):
    """
    Probability that a job has to wait

    :param c: amount of servers
    :param rho: occupation rate per server
    :return: probability
    """
    fixed = ((c*rho)**c)/math.factorial(c)

    sum = 0
    for n in range(c):
        sum += ((c*rho)**n)/math.factorial(n)

    return fixed/((1-rho)*sum + fixed)

def expw(mu, c, rho):
    """
    Expected waiting time

    :param mu: server processing time
    :param c: amount of servers
    :param rho: occupation rate per server
    :return: Exp. waiting time
    """

    piw = pwait(c, rho)
    return piw * (1/(1-rho)) * 1/(c*mu)

def expquel(c, rho):
    """
    Expected queue length

    :param c: amount of servers
    :param rho: occupation rate per server
    :return: Exp. queue length
    """
    piw = pwait(c, rho)
    return piw * (rho/(1-rho))

# print(f'Probability that a job has to wait: {pwait(c, rho):.2f}')
# print(f'Expected waiting time E(W): {expw(mu, c, rho):.2f} time units')
# print(f'Expected queue length E(Lq): {expquel(c, rho):.2f} customers')
# print dataframe with data
# print(data)
# run_data.loc[round(SIM_TIME/5)] = [rho, SIM_TIME, data["AVG_WAITING"].mean()]
# print(f'Expected waiting time E(W): {expw(MU, SERVERS, RHO):.3f} time units')
# print(f'AVG waiting: {data["AVG_WAITING"].mean():.3f} time units')
# print(conf_int(data["AVG_WAITING"].mean(), data["AVG_WAITING"].var(), SIMULATIONS, p=0.95))
# print()
# print(f'AVG arriving: {data["AVG_ARRIVING"].mean():.3f} per time unit')
# print(conf_int(data["AVG_ARRIVING"].mean(), data["AVG_ARRIVING"].var(), SIMULATIONS, p=0.95))
# print()
# print(f'AVG leaving: {data["AVG_LEAVING"].mean():.3f} per time unit')
# print(conf_int(data["AVG_LEAVING"].mean(), data["AVG_LEAVING"].var(), SIMULATIONS, p=0.95))
# print(f'Simulation {s+1}')
# print(f'Average waiting time: {avg_waiting:.3f} time units')
# print(f'Avg customers arriving per time unit: {avg_arrivals:.3f} time units')
# print(f'Avg customers leaving per time unit: {avg_leavers:.3f} time units\n')

# print("EXPECTED VALUES AND PROBABILITIES")
#
# print(f'Rho: {RHO}\nMu: {MU}\nLambda: {LAMBDA}\nExpected interarrival time: {1 / LAMBDA:.2f} time units')
# print(f'Expected processing time per server: {1 / MU:.2f} time units\n')
# print(f'Probability that a job has to wait: {pwait(SERVERS, RHO):.2f}')
# print(f'Expected waiting time E(W): {expw(MU, SERVERS, RHO):.2f} time units')
# print(f'Expected queue length E(Lq): {expquel(SERVERS, RHO):.2f} customers\n')


# blackbox_function.py
"""Volume 2: Optimization Packages I (scipy.optimize). Auxiliary File."""

import numpy as np
from scipy import linalg as la

def blackbox(y_free):
    """
    Finds the length of a curve approximated piece-wise by a set of points.
    Accepts:
        y_free (1xn ndarray): the non-endpoint y-values of the curve.

    Returns:
        total_length (float): the length of the approximated curve.
    """
    # Initialize local constants.
    m = len(y_free) + 2 # Number points: free variables, origin, and endpoint.
    a, b = 40, 30       # Coordinates of endpoint.

     # Generate the evenly-spaced x-values of the curve.
    x = np.linspace(0,a,m)

     # Pad the free variables with the fixed endpoint values, 0 and b.
    y = np.hstack((0,y_free, b))

     # Calculate and return the line integral of the approximated curve.
    partial_norms = []
    for i,item in enumerate(y[:-1]):
        partial_norms.append(la.norm(np.array([x[i+1]-x[i],y[i+1] - item])))
    return np.sum(partial_norms)


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

# code starts here
#Load dataset using pandas read_csv api in variable df
df=pd.read_csv(path)

#Calculate the probability p(A)for the event that fico credit score is greater than 700. and store it in variable 'p_a'.
p_a=len(df[df['fico']>700])/len(df)

#Calculate the probability p(B) for the event that purpose == 'debt_consolation' and store it in variable 'p_b'.
p_b=len(df[df['purpose'] == 'debt_consolidation'])/len(df)

#Calculate the purpose == 'debt_consolidation' and store it in dataframe df1.
df1=df[df['purpose'] == 'debt_consolidation']

#Calculate the probablity p(B|A) for the event purpose == 'debt_consolidation' given 'fico' credit score is greater than 700
#and store it in variable p_a_b.
p_a_b=len(df1[(df1['purpose'] == 'debt_consolidation') & df1['fico']>700])/len(df1)

#formula to check the independency P(A|B) == P(A)
#check the independency store it in variable result.
result=(p_a_b==p_b)

#Print result
print(result)

# code ends here

# --------------
# code starts here
#Calculate the probability p(A) for the event that paid.back.loan == Yes and store it in variable called prob_lp.
prob_lp=len(df[df['paid.back.loan']== 'Yes'])/len(df)

#Calculate the probability p(B) for the event that credit.policy == Yes and store it in variable prob_cs.
prob_cs=len(df[df['credit.policy']== 'Yes'])/len(df)

#Calculate ['paid.back.loan'] == 'Yes' and store it in variable new_df
new_df=df[df['paid.back.loan']== 'Yes']

#Calculate the probablityp(B|A) for the event paid.back.loan == 'Yes' given credit.policy == 'Yes' and store it in variable prob_pd_cs
prob_pd_cs=len(new_df[(new_df['paid.back.loan']== 'Yes') & (new_df['credit.policy']== 'Yes')])/len(new_df)

#Calculate the conditional probability where the formala is given below:
#P(A∣B)= P(B∣A).P(A)/P(B)
#Store the result of the event P(A|B) it in variable bayes
bayes=(prob_pd_cs*prob_lp)/prob_cs

#Print the bayes
print(prob_lp,prob_cs,prob_pd_cs,bayes)

# code ends here

# --------------
# code starts here
#Visualize the bar plot for the feature purpose.
print(df['purpose'].value_counts().plot(kind='bar'))
#Calculate the paid.back.loan == No and the store the result in dataframe df1
df1=df[df['paid.back.loan'] == 'No']

#Visualize the bar plot for the feature purpose where paid.back.loan == No
print(df1['purpose'].value_counts().plot(kind='bar'))

# code ends here

# --------------
# code starts here
#Calculte the median for installment and store it in variable inst_median.
inst_median=df['installment'].median()

#Calculate the mean for installmentand store it in variable inst_mean
inst_mean=df['installment'].mean()

#plot the histogram for installment
print(df['installment'].plot(kind='hist'))

#plot the histogram for log anual income
df['log.annual.inc'].plot(kind='hist')

# code ends here


import numpy as np
import pandas as pd
from sklearn.metrics import r2_score

def mean_square_error(y_test, ytest_Pred):
    '''calculate mean square error'''
    return np.mean((y_test - ytest_Pred)**2)

def mean_absolute_error(y_test, ytest_Pred):
    '''calculate mean absolute error'''
    return np.mean(abs(y_test - ytest_Pred))

def mean_absolute_percentage_error(y_test, ytest_Pred):
    '''calculate mean absolute percentage error'''
    return np.mean(abs(y_test - ytest_Pred)/y_test)

def r2_score(y_test, ytest_Pred):
    '''calculate R2'''
    return r2_score(y_test, ytest_Pred)


from __future__ import division
import numpy as np
'''-----------------------------------------------------------------------------
Newton diferences class
    Calculates the divided diferences
    Calculates the polinomial aproximation for a value
-----------------------------------------------------------------------------'''
class NewtonDiferences():
    def __init__(self,x,y):
        self.x = x
        self.y = y
    def dividedDiferences(self):
        #Calculates all the divided diferences for the list of points
        x = self.x
        y = self.y
        n = len(x)
        a = []
        for i in range(n):
            a.append(y[i])
        for j in range(1,n):
            for i in range(n-1,j-1,-1):
                a[i] = (a[i]-a[i-1])/(x[i]-x[i-j])

        return np.array(a)
    def calInterpolation(self,a,x,value_to_interpolate):
        #given a value_to_interpolate aproximates the value through the polinomial
        n = len(a)-1
        tmp = a[n]
        for i in range(1,n+1):
            tmp = tmp*(value_to_interpolate-x[n-i])+a[n-i]
        return tmp


import numpy as np

'''def corall(src, dst):
    "Correlation Alignment"
    src_flat = src.reshape(-1, 3)
    src_flat_mean = np.mean(src_flat, 0, keepdims=True)
    src_flat_std = np.std(src_flat, 0, keepdims=True)
    src_flat_norm = (src_flat - src_flat_mean) / src_flat_std
    src_flat_cov_eye = np.matmul(src_flat_norm.T, src_flat_norm) + np.eye(3)

    dst_flat = dst.reshape(-1, 3)
    dst_flat_mean = np.mean(dst_flat, 0, keepdims=True)
    dst_flat_std = np.std(dst_flat, 0, keepdims=True)
    dst_flat_norm = (dst_flat - dst_flat_mean) / dst_flat_std
    dst_flat_cov_eye = np.matmul(dst_flat_norm.T, dst_flat_norm) + np.eye(3)

    src_flat_norm_transfer = np.matmul(src_flat_norm, np.matmul(
        np.linalg.inv(_mat_sqrt(src_flat_cov_eye)),
        _mat_sqrt(dst_flat_cov_eye)
    ))
    src_flat_transfer = src_flat_norm_transfer * dst_flat_std + dst_flat_mean
    return src_flat_transfer.reshape(src.shape)

def _mat_sqrt(m):
    u, s, v = np.linalg.svd(m)
    return np.matmul(np.matmul(u, np.diag(np.sqrt(s))), v)'''

def matSqrt_numpy(x):
    U,D,V = np.linalg.svd(x)
    result = U.dot(np.diag(np.sqrt(D))).dot(V.T)
    return result

def corall(source, target):
    n_channels = source.shape[-1]

    source = np.moveaxis(source, -1, 0)  # HxWxC -> CxHxW
    target = np.moveaxis(target, -1, 0)  # HxWxC -> CxHxW

    source_flatten = source.reshape(n_channels, source.shape[1]*source.shape[2])
    target_flatten = target.reshape(n_channels, target.shape[1]*target.shape[2])

    source_flatten_mean = source_flatten.mean(axis=1, keepdims=True)
    source_flatten_std = source_flatten.std(axis=1, keepdims=True)
    source_flatten_norm = (source_flatten - source_flatten_mean) / source_flatten_std

    target_flatten_mean = target_flatten.mean(axis=1, keepdims=True)
    target_flatten_std = target_flatten.std(axis=1, keepdims=True)
    target_flatten_norm = (target_flatten - target_flatten_mean) / target_flatten_std

    source_flatten_cov_eye = source_flatten_norm.dot(source_flatten_norm.T) + np.eye(n_channels)
    target_flatten_cov_eye = target_flatten_norm.dot(target_flatten_norm.T) + np.eye(n_channels)

    source_flatten_norm_transfer = matSqrt_numpy(target_flatten_cov_eye).dot(np.linalg.inv(matSqrt_numpy(source_flatten_cov_eye))).dot(source_flatten_norm)
    source_flatten_transfer = source_flatten_norm_transfer * target_flatten_std + target_flatten_mean

    coraled = source_flatten_transfer.reshape(source.shape)
    coraled = np.moveaxis(coraled, 0, -1)  # CxHxW -> HxWxC
    return coraled


import numpy as np

class AbstractDistance(object):
	def __init__(self, name):
		self._name = name

	def __call__(self,p,q):
		raise NotImplementedError("Every AbstractDistance must implement the __call__ method.")

	@property
	def name(self):
		return self._name

	def __repr__(self):
		return self._name

class EuclideanDistance(AbstractDistance):

	def __init__(self):
		AbstractDistance.__init__(self,"EuclideanDistance")

	def __call__(self, p, q):
		p = np.asarray(p).flatten()
		q = np.asarray(q).flatten()
		return np.sqrt(np.sum(np.power((p-q),2)))

class CosineDistance(AbstractDistance):

	def __init__(self):
		AbstractDistance.__init__(self,"CosineDistance")

	def __call__(self, p, q):
		p = np.asarray(p).flatten()
		q = np.asarray(q).flatten()
		return -np.dot(p.T,q) / (np.sqrt(np.dot(p,p.T)*np.dot(q,q.T)))


import numpy as np

def sigmoid(z):
    return 1/(1 + np.exp(-z))

def J(yhat, y):
    return sum(0.5*(y - yhat)**2)

def y_estim(x_i, w_hat, b_hat):
    return sigmoid(np.dot(w_hat, x_i) + b_hat)

def y_estim(x_i, w_hat, b_hat):
    return sigmoid(np.dot(w_hat, x_i) + b_hat)

def y_estim_all(x_data, w_hat, b_hat):
    y_estim = np.zeros(shape=(100, 1))
    for i in range(x_data.shape[0]):
        i_data = x_data[i]
        y_estim[i] = sigmoid(np.dot(i_data, w_hat) + b_hat)
    return y_estim

def log_regression(x_data, y_data, **kwargs):
    N = x_data.shape[0]
    w = kwargs.get('w0', np.zeros(shape=(x_data.shape[1], 1)))
    b = kwargs.get('b0', 0)
    alpha = kwargs.get('alpha', 1)
    epsilon = kwargs.get('epsilon', 1e-6)

    # w_hist = np.arr
    # b_hist = []
    # w_hist.append(w.flatten())
    # b_hist.append(b.flatten())

    y_hat = y_estim_all(x_data, w, b)
    err = np.sum((y_hat - y_data)**2)/N
    prev_err = 1000
    delta_err = prev_err - err

    while delta_err > epsilon or delta_err < 0:

        prev_err = err

        dw = np.sum((y_hat-y_data)*y_hat*(np.ones(shape=y_data.shape) - y_hat)*x_data, axis=0)/N
        db = np.sum((y_hat-y_data)*y_hat*(np.ones(shape=y_data.shape) - y_hat), axis=0)/N

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

        # print(dw, w, db, b)

        w -= alpha*dw
        b -= alpha*db

        # w_hist.append(w)
        # b_hist.append(b)

        y_hat = y_estim_all(x_data, w, b)
        err = np.sum((y_hat - y_data)**2)/N
        delta_err = prev_err - err

    return w, b


import numpy as np
import matplotlib.pyplot as pl
from scipy.sparse import spdiags, linalg

def five_pt_laplacian_sparse(m):
    e = np.ones(m ** 2)
    e2 = ([1] * (m - 1) + [0]) * m
    e3 = ([0] + [1] * (m - 1)) * m
    h = 1. / (m + 1)
    A = spdiags([-4 * e, e2, e3, e, e], [0, -1, 1, -m, m], m ** 2, m ** 2)
    A /= h ** 2
    return A

# Define the RHS function:
f = lambda x, y: (2 - (np.pi ** 2) * (x ** 2)) * np.cos(np.pi * y);

#let calc rate of convergence and all the solutions and error

normMaxValues = np.zeros(8);
hValues = np.zeros(len(normMaxValues));
for i in range(0, len(normMaxValues)):
    m = 9 + 2 ** i;
    h = 1. / (m + 1);
    x = np.linspace(0, 1, m + 2); x = x[1:-1];
    y = np.linspace(0, 1, m + 2); y = y[1:-1];
    hValues[i] = x[1] - x[0];
    X, Y = np.meshgrid(x, y);

    #Set up and solve the linear system
    A = five_pt_laplacian_sparse(m).tocsr();

    F = f(X, Y);#.reshape([m**2]);
    #y index is inversed! and don't forget to divide by h^2
    F[:, 0] -= 0;
    F[:, -1] -= np.cos(np.pi * y) / h ** 2;
    F[-1, :] -= -x ** 2 / h ** 2;
    F[0, :] -= x ** 2 / h ** 2;
    F = F.reshape([m ** 2]);

    U = linalg.spsolve(A, F)
    U = U.reshape([m, m]);

    U_exact = X ** 2 * np.cos(np.pi * Y)
    #U_exact = U_exact.reshape([m**2]);
    error = U - U_exact
    #don't forget to reshape, otherwise norm will be wrong
    normMaxValues[i] = np.linalg.norm(error.reshape([m ** 2]), np.inf);

pl.clf();
pl.subplots_adjust(hspace=1);

pl.subplot(4, 1, 1);
pl.pcolor(X, Y, U)
pl.colorbar();
pl.xlabel('x');
pl.ylabel('y');
pl.title('Figure 7a. Numerical solution');

pl.subplot(4, 1, 2);
pl.pcolor(X, Y, U_exact);
pl.xlabel('x');
pl.ylabel('y');
pl.title('Figure 7b. Exact solution');
pl.colorbar();

pl.subplot(4, 1, 3);
pl.pcolor(X, Y, error);
pl.xlabel('x');
pl.ylabel('y');
pl.title('Figure 7c. Error');
pl.colorbar();

# pl.subplot(4, 1, 4);
# pl.pcolor(X, Y, F.reshape([m,m]));
# pl.xlabel('x');
# pl.ylabel('y');
# pl.title('Figure 7c. forcing');
# pl.colorbar();

pl.subplot(4, 1, 4);
pl.loglog(hValues, normMaxValues, label='Max norm');
pl.xlabel('h');
pl.ylabel('Max norm');
pl.legend(loc='best');
pl.title('Figure 7d. Convergence');

pl.show();


import sys
import scipy.io as sio
from pprint import pprint
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D

mat_fname = "data_logistic.mat"
mat_dict = sio.loadmat(mat_fname)

samples = mat_dict["logistic_data"]

# m = features number
# n = samples number
# hθ = sigmond(θT x)

# J(θ) = -1/m * sum(Y(i) * log(hθ(X(i)) - (1 - Y(i)) * log(1 - hθ(X(i))))) + L * sum(θj ^ 2)
# θj :=  θj * (1 - (alpha * L) /m) - alpha/m * (hθ(X(i) - Y(i)) * X(i)j
# j = 0,1,..,n

def sigmoid(z):
	return 1 / (1 + np.exp(-z))

def loss(h, y):
    return (-y * np.log(h) - (1 - y) * np.log(1 - h)).mean()

X = []
Y = []
m = 0
for sample in samples:
	X.append(sample[0:2])
	Y.append(sample[2])
	m += 1
X = np.array(X)
Y = np.array(Y)

alpha = 0.01
num_iter = 10000
theta = np.zeros(X.shape[1])
L = 0.01 #L2-norm effect here

for i in range(num_iter):
	z = np.dot(X, theta)
	h = sigmoid(z)
	gradient = np.dot(X.T, (h - Y)) / m
	theta = theta * (1 - (alpha * L) / m) - alpha * gradient  #L2-norm effect here

z = np.dot(X, theta)
h = sigmoid(z)

term = 0
for t in theta:
	term = t**2
term = L * term #L2-norm effect here

print(' L:', L, '\n\n Optimal Loss:', loss(h, Y) + term, '\n')
print(' Theta: ', theta)


import sys
import random
import math
import numpy as np

# num_shoots is N from the exercise sheet.
def shoot_pi(num_shoots = 10, verbose = True):

    if verbose:
        print('Shooting PI with ' + str(num_shoots) + ' samples...')

    # shoot randomly (uniform) at 1x1 area at count hits of inner quarter circle.
    num_hits = 0
    for _ in range(num_shoots):
        x = random.random()
        y = random.random()
        point = np.array([x, y])
        if (np.linalg.norm(point) < 1):
            num_hits += 1

    # compute pi as ratio of hits to all samples
    # (factor 4 necessary, since we're only shooting at a quarter circle)
    pi = (num_hits / num_shoots) * 4

    if verbose:
        print('PI is approximately ', str(pi), '!', sep='')

    return pi

if __name__ == '__main__':
    if len(sys.argv) == 2:
        shoot_pi(int(sys.argv[1]))
    else:
        shoot_pi()


'''
'''
# Standard library imports
from math import pi

# Third party imports
import numpy as np

def rebar_coordinates(r_rebars, n_rebars):
    '''
    Return evenly spaced rebars on a circle perimeter.

    Parameters
    ----------
    r_rebars : ...
        ...

    Returns
    -------
        ...
    '''

    theta = np.linspace(0, 2*pi-2*pi/n_rebars, n_rebars)

    return r_rebars * np.cos(theta), r_rebars * np.sin(theta)

def neutral_axis_locs(bounds, n_locations, traverse_upwards=True):
    '''
    Parameters
    ----------

    Yields
    ------
    number
        ...

    Todo
    ----
    '''
    # Unpack boundary values for traversal
    ymin, ymax = bounds

    # Generate points over the interval
    y_locations = np.linspace(ymin, ymax, n_locations)

    y_locations[0] = -99999
    y_locations[-1] = 99999

    return y_locations if traverse_upwards else np.flip(y_locations)


import numpy as np

def mean_square_error(labels, predictions,derivative=False):
  if derivative==False:
    mse=np.mean((labels-predictions)**2)
    return mse
  else:
    dmse=-2*np.mean(labels-predictions)
    return dmse

def binary_cross_entropy(labels,predictions, derivative=False):
  if derivative==False:
    bce=-np.sum(labels*np.log(predictions) + (1-labels)*np.log(1-predictions))
    return bce
  else:
    dbce=-np.sum(labels/predictions + (labels-1)/(1-predictions))
    return dbce

def categorical_cross_entropy(labels, predictions):
  pass


import numpy as np
import matplotlib.pyplot as plt
import random

# Cost function
def cost(m, x, y, z):
	err=0.0
	for i in range(0, m):
		err += ((hypothesis(i, x, z) - y[i])**2)
	err = err/(2*m)
	return float(err)

# Hypothesis
def hypothesis(i, x, z):
	h =  z[0]*1+z[1]*x[i]
	return h

# Generate linear function
def graph_gen(low, high, size):
	g=np.arange(size, dtype=float)
	for i in range(0 , size):
		g[i] = i + random.uniform(low,high)
	return g

# Input used for tranning
#x=np.array([0,1,2,3,4,5])
x=np.arange(100,dtype=float)

# Output used for tranning
#y=np.array([0,1,2,3,4,5])
y=np.random.normal(5,1,100)
#y=graph_gen(0,2,100)

# Initiaize theta
z=np.array([0,0])

# Range of theta value
theta_range=50

# Size of rows or Columns
theta_sz=2*theta_range+1 #1 for including 0 value

# Number of input elements
m=x.size

# Results of Squared Error
result_squared_err = np.ones(((2*theta_range)+1, (2*theta_range)+1), dtype=float)

# calculate squared error in order to find minimal squared error value
for z0 in range(-theta_range ,theta_range+1):
	z[0] = z0
	for z1 in range(-theta_range ,theta_range+1):
		z[1] = z1
		result_squared_err[z0+theta_range][z1+theta_range] = cost(m, x, y, z)

# Find the position of minimal squared error
pos_theta = np.unravel_index(result_squared_err.argmin(),result_squared_err.shape)

# Transfrom to one-dimensional arrays
result_squared_err_1d = result_squared_err.reshape((1,theta_sz*theta_sz))

print "***** Mininal Squared Error *****"
print "---------------------------------"
print "Position of theta : %s           " %(str(pos_theta))
print "---------------------------------"
print "minimal squared error   : %f"  %(result_squared_err.min())
print "Theta(%d,%d)            : %f" %(pos_theta [0]-theta_range, pos_theta [1]-theta_range, result_squared_err[pos_theta [0]][pos_theta [1]])

#print result_squared_err
#print result_squared_err_1d

# Plot original data
plt.plot(x,y,'rs')

# Plot linear regression function
x_grph=np.arange(m);
plt.plot(x_grph, 1*(pos_theta [0]-theta_range)+x_grph*(pos_theta [1]-theta_range), 'b-')

# Plot squared error
# new_row = ((row+1)*row_sz)-(row_sz-(col+1)))
#row_sz = 2*theta_range+1
#px = ((pos_theta [0]+1)*row_sz)-(row_sz-(pos_theta [1]+1))
#plt.plot(result_squared_err_1d[0], 'go', px,result_squared_err.min(),'rs')

# Display Graph
plt.axis([0.,100.,0.,100.])
plt.show()


import numpy as np
import pandas as pd
import logging
import matplotlib.pyplot as plt
from numpy.linalg import inv, multi_dot

logger = logging.getLogger(__name__)

def load_dataset(csv_path):
    return pd.read_csv(csv_path)

class BatchLeastSquares:
    """バッチ型最小２乗法.

    Attributes:
        estimated_x (float): 推定値x.
    """
    def __init__(self, z, h, r):
        """
        Args:
            z (array_like, 1-D): 観測値リスト.
            h (array_like, 2-D): 変換行列.
            r (array_like, 1-D): 共分散リスト.
        """
        z = z.reshape(-1, 1)
        r = np.diag(r)
        self.estimated_x = multi_dot([inv(multi_dot([h.T, inv(r), h])), h.T, inv(r), z])

class IterLeastSquares:
    """逐次型最小２乗法.

    Attributes:
        estimated_x (float): 最終的な推定値x.
        p (array_like, 2-D): 最終的な推定誤差共分散p.
        x_list (array_like, 2-D): 各時刻における推定値xのリスト.
    """
    def __init__(self, z, h, r, init_x, init_p):
        """
        Args:
            z (array_like, 1-D): 観測値リスト.
            h (array_like, 2-D): 変換行列.
            r (array_like, 1-D): 共分散リスト.
            init_x (array_like, 1-D): 推定値xの初期値.
            init_p (array_like, 2-D): 推定誤差共分散pの初期値.
        """
        xi = init_x.reshape(-1, 1)
        pi = init_p

        self.x_list = []

        for i in range(z.size):
            hi = h[i].reshape(1, -1)  # shape (1, 3)
            ri = r[i]  # scalar
            zi = z[i]  # scalar
            si = multi_dot([hi, pi, hi.T]) + ri  # shape (1, 1)
            wi = multi_dot([pi, hi.T, inv(si)])  # shape (3, 1)
            xi = xi + np.dot(wi, (zi - np.dot(hi, xi)))  # shape (3, 1)
            pi = pi - multi_dot([wi, si, wi.T])  # shape (3, 3)

            self.x_list.append(xi.T[0])

        self.x_list = np.array(self.x_list)
        self.estimated_x = xi
        self.p = pi

def main():
    # logger設定
    logging.basicConfig(
        level=logging.INFO,
        filemode='w',
        filename='log/least_squares.log'
    )
    # データセットの読み込み
    dataset_path = 'dataset.csv'
    dataset_df = load_dataset(dataset_path)

    # 行列生成
    k = dataset_df['k'].to_numpy()
    z = dataset_df['z'].to_numpy()
    h = np.stack([np.ones(k.size), k, k*k], axis=1)
    r = np.where(k % 2 == 0, 4, 1)
    logger.info(f'K: \n{k}\n')
    logger.info(f'Z: \n{z}\n')
    logger.info(f'H: \n{h}\n')
    logger.info(f'R: \n{r}\n')

    """
    ************
    --- （1) ---
    ************
    """
    # バッチ型最小２乗法
    x = BatchLeastSquares(z, h, r).estimated_x
    print(f'推定値x（バッチ型）: \n{x}\n')
    logger.info(f'推定値x（バッチ型）: \n{x}\n')

    # 逐次型最小２乗法
    init_x = np.zeros(3)
    init_p = np.identity(3) * 10**6
    x = IterLeastSquares(z, h, r, init_x, init_p).estimated_x
    print(f'推定値x（逐次型）: \n{x}\n')
    logger.info(f'init X: \n{init_x}\n')
    logger.info(f'init P: \n{init_p}\n')
    logger.info(f'推定値x（逐次型）: \n{x}\n')

    """
    ************
    --- （2）---
    ************
    """
    # 推定誤差共分散pの初期値を変えて，逐次型最小２乗法を適用
    label_list = ['10**3', '10**0',  '10**-3']
    init_p_list = [np.identity(3) * 10**3, np.identity(3) * 10**0, np.identity(3) * 10**-3]
    x_list = []
    for init_p in init_p_list:
        x_list.append(IterLeastSquares(z, h, r, init_x, init_p).x_list)

    # グラフ作成
    for i in range(3):
        fig, ax = plt.subplots()
        ax.set_xlabel('k')  # x軸ラベル
        ax.set_ylabel(f'x{i}')  # y軸ラベル
        ax.set_title('iter least squares')

        for j, x in enumerate(x_list):
            ax.plot(k, x[:, i], label=label_list[j])

        ax.legend(loc=0)
        plt.savefig(f'graph/iter_least_squares_graph_x{i}.png')

if __name__ == '__main__':
    main()


import numpy
from numba import autojit

@autojit(nopython=True)
def poisson1d_GS_SingleItr(nx, dx, p, b):
    '''
    Gauss-Seidel method for 1D Poisson eq. with Dirichlet BCs at both
    ends. Only a single iteration is executed. **blitz** is used.

    Parameters:
    ----------
    nx: int, number of grid points in x direction
    dx: float, grid spacing in x
    p: 1D array of float, approximated soln. in last iteration
    b: 1D array of float, 0th-order derivative term in Poisson eq.

    Returns:
    -------
    p: 1D array of float, approximated soln. in current iteration
    '''

    for i in range(1,len(p)-1):
        p[i] = 0.5 * (p[i+1] + p[i-1] - dx**2 * b[i])

    return p

def RMS(p):
    '''
    Return the root mean square of p.

    Parameters:
    ----------
    p:   array

    Returns:
    -------
    Root mean square of p
    '''
    return numpy.sqrt(numpy.sum(p**2) / p.size)

def residual(dx, pn, b, r):
    '''
    Calculate the residual for the 1D Poisson equation.

    Parameters:
    ----------
    pn: 1D array, approximated solution at a certain iteration n
    b:  1D array, the b(x) in the Poisson eq.

    Return:
    ----------
    The residual r
    '''

    # r[0] = 0
    r[1:-1] = b[1:-1] - (pn[:-2] - 2 * pn[1:-1] + pn[2:]) / dx**2
    # r[-1] = 0

    return r

def full_weighting_1d(vF, vC):
    '''
    Transfer a vector on a fine grid to a coarse grid with full weighting
    .  The number of elements (not points) of the coarse grid is
    half of that of the fine grid.

    Parameters:
    ----------
    vF: 1D numpy array, the vector on the fine grid
    vC: 1D numpy array, the vector on the coarse grid,
        size(vC) = (size(vF) + 1) / 2

    Output: vC
    '''

    vC[0] = vF[0]
    vC[1:-1] = 0.25 * (vF[1:-3:2] + 2. * vF[2:-2:2] + vF[3:-1:2])
    vC[-1] = vF[-1]

    return vC

def interpolation_1d(vC, vF):
    '''
    Transfer a vector on a coarse grid to a fine grid by linear
    interpolation. The number of elements (not points) of the coarse
    grid is a half of that of the fine grid.

    Parameters:
    ----------
    vC: 1D numpy array, the vector on the coarse grid,
    vF: 1D numpy array, the vector on the fine grid
        size(vF) = size(vC) * 2 - 1

    Output: vF
    '''

    vF[::2] = vC[:];
    vF[1:-1:2] = 0.5 * (vC[:-1] + vC[1:])

    return vF


# Week 1: Analysis of Algorithms
# Question 1

"""
(seed = 932025)
Suppose that you time a program as a function of N and produce
the following table.

        N   seconds
-------------------
    16384     0.000
    32768     0.000
    65536     0.001
   131072     0.004
   262144     0.009
   524288     0.025
  1048576     0.068
  2097152     0.181
  4194304     0.482
  8388608     1.287
 16777216     3.436
 33554432     9.171
 67108864    24.490
134217728    65.380
268435456   174.542
536870912   465.976

Estimate the order of growth of the running time as a function of N.
Assume that the running time obeys a power law T(N) ~ a N^b. For your
answer, enter the constant b. Your answer will be marked as correct
if it is within 1% of the target answer - we recommend using
two digits after the decimal separator, e.g., 2.34.
"""
from pylab import *

data = """    16384     0.000
    32768     0.000
    65536     0.001
   131072     0.004
   262144     0.009
   524288     0.025
  1048576     0.068
  2097152     0.181
  4194304     0.482
  8388608     1.287
 16777216     3.436
 33554432     9.171
 67108864    24.490
134217728    65.380
268435456   174.542
536870912   465.976"""

vals = data.split()

N = array(map(int, vals[::2]))
T = array(map(float, vals[1::2]))

from scipy.optimize import curve_fit

def func(x, a, b, c):
    return a * np.power(x, b) + c

popt, pcov = curve_fit(func, N, T)

a, b, c = popt

print "b =", b

plot(N, T, 'r.')
plot(N, a * N ** b + c )

show()


import numpy as np

def L1Loss(y_predicted, y_ground_truth, reduction="None"):
    """returns l1 loss between two arrays

    :param y_predicted: array of predicted values
    :type y_predicted: ndarray
    :param y_ground_truth: array of ground truth values
    :type y_ground_truth: ndarray
    :param reduction: reduction mode, defaults to "mean"
    :type reduction: str, optional
    :return: l1-loss
    :rtype: scalar if reduction is sum or mean, else ndarray
    """
    # Calculate the absolute difference array
    absolute_difference = np.abs(y_predicted - y_ground_truth)
    # L1 distance is the reduced form of the absolute difference array
    if reduction == "sum":
        # Reduction can be done by summing up all the values in the difference array (this is known as "L1-Loss")
        l1_distance = np.sum(absolute_difference)
        return l1_distance
    elif reduction == "mean":
        # Reduction can also be done by taking the mean (this is known as "Mean Absolute Error")
        mean_absolute_error = np.mean(absolute_difference)
        return mean_absolute_error
    elif reduction == "None":
        return absolute_difference
    else:
        print('ValueError: reduction should be "sum" / "mean" / "None"')

def main():
    print("Initializing predicted and ground truth arrays:\n")
    print('(NOTE: Enter the values in a space-separated format. Ex: "5.36 1.02 2.03")')
    y_predicted = [
        float(item) for item in input("Enter the predicted values: ").split()
    ]
    y_ground_truth = [
        float(item)
        for item in input("Enter the corresponding ground truth values: ").split()
    ]
    assert len(y_predicted) == len(
        y_ground_truth
    ), "Number of predicted values {} and ground truth {} values should match".format(
        len(y_predicted), len(y_ground_truth)
    )
    y_predicted = np.array(y_predicted)
    y_ground_truth = np.array(y_ground_truth)
    reduction = str(input('Enter the reduction mode: "sum" / "mean" / "None": '))
    loss = L1Loss(y_predicted, y_ground_truth, reduction=reduction)
    print("L1-Loss with {}-reduction: {}".format(reduction, loss))

if __name__ == "__main__":
    main()


"""
Module: libfmp.c1.c1s3_audio_rep
Author: Meinard Müller
License: The MIT license, https://opensource.org/licenses/MIT

This file is part of the FMP Notebooks (https://www.audiolabs-erlangen.de/FMP)
"""
import numpy as np
from matplotlib import pyplot as plt
import librosa
import IPython.display as ipd

def f_pitch(p):
    """Compute center frequency for (single or array of) MIDI note numbers

    Notebook: C1/C1S3_FrequencyPitch.ipynb

    Args:
        p (float or np.ndarray): MIDI note numbers

    Returns:
        freq_center (float or np.ndarray): Center frequency
    """
    freq_center = 2 ** ((p - 69) / 12) * 440
    return freq_center

def difference_cents(freq_1, freq_2):
    """Difference between two frequency values specified in cents

    Notebook: C1/C1S3_FrequencyPitch.ipynb

    Args:
        freq_1 (float): First frequency
        freq_2 (float): Second frequency

    Returns:
        delta (float): Difference in cents
    """
    delta = np.log2(freq_1 / freq_2) * 1200
    return delta

def generate_sinusoid(dur=5, Fs=1000, amp=1, freq=1, phase=0):
    """Generation of sinusoid

    Notebook: C1/C1S3_FrequencyPitch.ipynb

    Args:
        dur (float): Duration (in seconds) (Default value = 5)
        Fs (scalar): Sampling rate (Default value = 1000)
        amp (float): Amplitude of sinusoid (Default value = 1)
        freq (float): Frequency of sinusoid (Default value = 1)
        phase (float): Phase of sinusoid (Default value = 0)

    Returns:
        x (np.ndarray): Signal
        t (np.ndarray): Time axis (in seconds)

    """
    num_samples = int(Fs * dur)
    t = np.arange(num_samples) / Fs
    x = amp * np.sin(2*np.pi*(freq*t-phase))
    return x, t

def compute_power_db(x, Fs, win_len_sec=0.1, power_ref=10**(-12)):
    """Computation of the signal power in dB

    Notebook: C1/C1S3_Dynamics.ipynb

    Args:
        x (np.ndarray): Signal (waveform) to be analyzed
        Fs (scalar): Sampling rate
        win_len_sec (float): Length (seconds) of the window (Default value = 0.1)
        power_ref (float): Reference power level (0 dB) (Default value = 10**(-12))

    Returns:
        power_db (np.ndarray): Signal power in dB
    """
    win_len = round(win_len_sec * Fs)
    win = np.ones(win_len) / win_len
    power_db = 10 * np.log10(np.convolve(x**2, win, mode='same') / power_ref)
    return power_db

def compute_equal_loudness_contour(freq_min=30, freq_max=15000, num_points=100):
    """Computation of the equal loudness contour

    Notebook: C1/C1S3_Dynamics.ipynb

    Args:
        freq_min (float): Lowest frequency to be evaluated (Default value = 30)
        freq_max (float): Highest frequency to be evaluated (Default value = 15000)
        num_points (int): Number of evaluation points (Default value = 100)

    Returns:
        equal_loudness_contour (np.ndarray): Equal loudness contour (in dB)
        freq_range (np.ndarray): Evaluated frequency points
    """
    freq_range = np.logspace(np.log10(freq_min), np.log10(freq_max), num=num_points)
    freq = 1000
    # Function D from https://bar.wikipedia.org/wiki/Datei:Acoustic_weighting_curves.svg
    h_freq = ((1037918.48 - freq**2)**2 + 1080768.16 * freq**2) / ((9837328 - freq**2)**2 + 11723776 * freq**2)
    n_freq = (freq / (6.8966888496476 * 10**(-5))) * np.sqrt(h_freq / ((freq**2 + 79919.29) * (freq**2 + 1345600)))
    h_freq_range = ((1037918.48 - freq_range**2)**2 + 1080768.16 * freq_range**2) / ((9837328 - freq_range**2)**2
                                                                                + 11723776 * freq_range**2)
    n_freq_range = (freq_range / (6.8966888496476 * 10**(-5))) * np.sqrt(h_freq_range / ((freq_range**2 + 79919.29) *
                                                                         (freq_range**2 + 1345600)))
    equal_loudness_contour = 20 * np.log10(np.abs(n_freq / n_freq_range))
    return equal_loudness_contour, freq_range

def generate_chirp_exp(dur, freq_start, freq_end, Fs=22050):
    """Generation chirp with exponential frequency increase

    Notebook: C1/C1S3_Dynamics.ipynb

    Args:
        dur (float): Length (seconds) of the signal
        freq_start (float): Start frequency of the chirp
        freq_end (float): End frequency of the chirp
        Fs (scalar): Sampling rate (Default value = 22050)

    Returns:
        x (np.ndarray): Generated chirp signal
        t (np.ndarray): Time axis (in seconds)
        freq (np.ndarray): Instant frequency (in Hz)
    """
    N = int(dur * Fs)
    t = np.arange(N) / Fs
    freq = np.exp(np.linspace(np.log(freq_start), np.log(freq_end), N))
    phases = np.zeros(N)
    for n in range(1, N):
        phases[n] = phases[n-1] + 2 * np.pi * freq[n-1] / Fs
    x = np.sin(phases)
    return x, t, freq

def generate_chirp_exp_equal_loudness(dur, freq_start, freq_end, Fs=22050):
    """Generation chirp with exponential frequency increase and equal loudness

    Notebook: C1/C1S3_Dynamics.ipynb

    Args:
        dur (float): Length (seconds) of the signal
        freq_start (float): Starting frequency of the chirp
        freq_end (float): End frequency of the chirp
        Fs (scalar): Sampling rate (Default value = 22050)

    Returns:
        x (np.ndarray): Generated chirp signal
        t (np.ndarray): Time axis (in seconds)
        freq (np.ndarray): Instant frequency (in Hz)
        intensity (np.ndarray): Instant intensity of the signal
    """
    N = int(dur * Fs)
    t = np.arange(N) / Fs
    intensity, freq = compute_equal_loudness_contour(freq_min=freq_start, freq_max=freq_end, num_points=N)
    amp = 10**(intensity / 20)
    phases = np.zeros(N)
    for n in range(1, N):
        phases[n] = phases[n-1] + 2 * np.pi * freq[n-1] / Fs
    x = amp * np.sin(phases)
    return x, t, freq, intensity

def compute_adsr(len_A=10, len_D=10, len_S=60, len_R=10, height_A=1.0, height_S=0.5):
    """Computation of idealized ADSR model

    Notebook: C1/C1S3_Timbre.ipynb

    Args:
        len_A (int): Length (samples) of A phase (Default value = 10)
        len_D (int): Length (samples) of D phase (Default value = 10)
        len_S (int): Length (samples) of S phase (Default value = 60)
        len_R (int): Length (samples) of R phase (Default value = 10)
        height_A (float): Height of A phase (Default value = 1.0)
        height_S (float): Height of S phase (Default value = 0.5)

    Returns:
        curve_ADSR (np.ndarray): ADSR model
    """
    curve_A = np.arange(len_A) * height_A / len_A
    curve_D = height_A - np.arange(len_D) * (height_A - height_S) / len_D
    curve_S = np.ones(len_S) * height_S
    curve_R = height_S * (1 - np.arange(1, len_R + 1) / len_R)
    curve_ADSR = np.concatenate((curve_A, curve_D, curve_S, curve_R))
    return curve_ADSR

def compute_envelope(x, win_len_sec=0.01, Fs=4000):
    """Computation of a signal's envelopes

    Notebook: C1/C1S3_Timbre.ipynb

    Args:
        x (np.ndarray): Signal (waveform) to be analyzed
        win_len_sec (float): Length (seconds) of the window (Default value = 0.01)
        Fs (scalar): Sampling rate (Default value = 4000)

    Returns:
        env (np.ndarray): Magnitude envelope
        env_upper (np.ndarray): Upper envelope
        env_lower (np.ndarray): Lower envelope
    """
    win_len_half = round(win_len_sec * Fs * 0.5)
    N = x.shape[0]
    env = np.zeros(N)
    env_upper = np.zeros(N)
    env_lower = np.zeros(N)
    for i in range(N):
        i_start = max(0, i - win_len_half)
        i_end = min(N, i + win_len_half)
        env[i] = np.amax(np.abs(x)[i_start:i_end])
        env_upper[i] = np.amax(x[i_start:i_end])
        env_lower[i] = np.amin(x[i_start:i_end])
    return env, env_upper, env_lower

def compute_plot_envelope(x, win_len_sec, Fs, figsize=(6, 3), title=''):
    """Computation and subsequent plotting of a signal's envelope

    Notebook: C1/C1S3_Timbre.ipynb

    Args:
        x (np.ndarray): Signal (waveform) to be analyzed
        win_len_sec (float): Length (seconds) of the window
        Fs (scalar): Sampling rate
        figsize (tuple): Size of the figure (Default value = (6, 3))
        title (str): Title of the figure (Default value = '')

    Returns:
        fig (mpl.figure.Figure): Generated figure
    """
    t = np.arange(x.size)/Fs
    env, env_upper, env_lower = compute_envelope(x, win_len_sec=win_len_sec, Fs=Fs)
    fig = plt.figure(figsize=figsize)
    plt.plot(t, x, color='gray', label='Waveform')
    plt.plot(t, env_upper, linewidth=2, color='cyan', label='Upper envelope')
    plt.plot(t, env_lower, linewidth=2, color='blue', label='Lower envelope')
    plt.plot(t, env, linewidth=2, color='red', label='Magnitude envelope')
    plt.title(title)
    plt.xlabel('Time (seconds)')
    plt.ylabel('Amplitude')
    plt.xlim([t[0], t[-1]])
    plt.ylim([-0.7, 0.7])
    plt.legend(loc='lower right')
    plt.show()
    ipd.display(ipd.Audio(data=x, rate=Fs))
    return fig

def generate_sinusoid_vibrato(dur=5, Fs=1000, amp=0.5, freq=440, vib_amp=1, vib_rate=5):
    """Generation of a sinusoid signal with vibrato

    Notebook: C1/C1S3_Timbre.ipynb

    Args:
        dur (float): Duration (in seconds) (Default value = 5)
        Fs (scalar): Sampling rate (Default value = 1000)
        amp (float): Amplitude of sinusoid (Default value = 0.5)
        freq (float): Frequency (Hz) of sinusoid (Default value = 440)
        vib_amp (float): Amplitude (Hz) of the frequency oscillation (Default value = 1)
        vib_rate (float): Rate (Hz) of the frequency oscillation (Default value = 5)

    Returns:
        x (np.ndarray): Generated signal
        t (np.ndarray): Time axis (in seconds)

    """
    num_samples = int(Fs * dur)
    t = np.arange(num_samples) / Fs
    freq_vib = freq + vib_amp * np.sin(t * 2 * np.pi * vib_rate)
    phase_vib = np.zeros(num_samples)
    for i in range(1, num_samples):
        phase_vib[i] = phase_vib[i-1] + 2 * np.pi * freq_vib[i-1] / Fs
    x = amp * np.sin(phase_vib)
    return x, t

def generate_sinusoid_tremolo(dur=5, Fs=1000, amp=0.5, freq=440, trem_amp=0.1, trem_rate=5):
    """Generation of a sinusoid signal with tremolo

    Notebook: C1/C1S3_Timbre.ipynb

    Args:
        dur (float): Duration (in seconds) (Default value = 5)
        Fs (scalar): Sampling rate (Default value = 1000)
        amp (float): Amplitude of sinusoid (Default value = 0.5)
        freq (float): Frequency (Hz) of sinusoid (Default value = 440)
        trem_amp (float): Amplitude of the amplitude oscillation (Default value = 0.1)
        trem_rate (float): Rate (Hz) of the amplitude oscillation (Default value = 5)

    Returns:
        x (np.ndarray): Generated signal
        t (np.ndarray): Time axis (in seconds)
    """
    num_samples = int(Fs * dur)
    t = np.arange(num_samples) / Fs
    amps = amp + trem_amp * np.sin(t * 2 * np.pi * trem_rate)
    x = amps * np.sin(2*np.pi*(freq*t))
    return x, t

def generate_tone(p=60, weight_harmonic=np.ones([16, 1]), Fs=11025, dur=2):
    """Generation of a tone with harmonics

    Notebook: C1/C1S3_Timbre.ipynb

    Args:
        p (float): MIDI pitch of the tone (Default value = 60)
        weight_harmonic (np.ndarray): Weights for the different harmonics (Default value = np.ones([16, 1])
        Fs (scalar): Sampling frequency (Default value = 11025)
        dur (float): Duration (seconds) of the signal (Default value = 2)

    Returns:
        x (np.ndarray): Generated signal
        t (np.ndarray): Time axis (in seconds)
    """
    freq = 2 ** ((p - 69) / 12) * 440
    num_samples = int(Fs * dur)
    t = np.arange(num_samples) / Fs
    x = np.zeros(t.shape)
    for h, w in enumerate(weight_harmonic):
        x = x + w * np.sin(2 * np.pi * freq * (h + 1) * t)
    return x, t

def plot_spectrogram(x, Fs=11025, N=4096, H=2048, figsize=(4, 2)):
    """Computation and subsequent plotting of the spectrogram of a signal

    Notebook: C1/C1S3_Timbre.ipynb

    Args:
        x: Signal (waveform) to be analyzed
        Fs: Sampling rate (Default value = 11025)
        N: FFT length (Default value = 4096)
        H: Hopsize (Default value = 2048)
        figsize: Size of the figure (Default value = (4, 2))

    """
    N, H = 2048, 1024
    X = librosa.stft(x, n_fft=N, hop_length=H, win_length=N, window='hanning')
    Y = np.abs(X)
    plt.figure(figsize=figsize)
    librosa.display.specshow(librosa.amplitude_to_db(Y, ref=np.max),
                             y_axis='linear', x_axis='time', sr=Fs, hop_length=H, cmap='gray_r')
    plt.ylim([0, 3000])
    # plt.colorbar(format='%+2.0f dB')
    plt.xlabel('Time (seconds)')
    plt.ylabel('Frequency (Hz)')
    plt.tight_layout()
    plt.show()


'''
Created on Mar 12, 2021

@author: vladislavkargin

A collection of functions for Dyck paths.
A Dyck path is an array of +1 and -1, such that the total sum is zero and
the partial sums are always non-negative.
'''
import numpy as np
import matplotlib.pyplot as plt

def randomDyckPath(n, seed = None):
    '''
     * Generates a random Dyck path with 2n steps
     *
     * @param n half-size of path
     * @return a sequence of -1 and 1 steps.
    '''

    if seed != None:
        np.random.seed(seed)
    path = [1] * n + [-1] * (n + 1)
    #shuffle randomly
    np.random.shuffle(path)

    #do a cyclic shift.
    #Find the first occurrence of the minimum
    S = np.cumsum(np.array([0] + path))
    '''
    fig1, ax1 = plt.subplots(nrows=1, ncols=1)
    ax1.plot(S)
    ax1.grid(True)
    '''
    m = np.min(S)
    positions = np.where(S == m)[0]
    pos = positions[0]
    #print(pos)
    path1 = path[pos:] + path[:pos]
    del path1[-1]
    return path1

def plotDyckPath(path, ax = None, method = "upperLatticePath"):
    ''' plots a Dyck path. Path is either list of 1, -1 or numpy array
    of 1, - 1'''
    if isinstance(path, list):
        n = int(len(path)/2)
    else:
        n = int(path.shape[0]/2)
    X, Y = buildPlanePath(path, method = method)
    if ax == None:
        fig = plt.figure()
        ax = fig.add_subplot(1, 1, 1)
    major_ticks = np.arange(0, n + 1, 1)
    #minor_ticks = np.arange(0, 101, 5)
    ax.set_xticks(major_ticks)
    #ax.set_xticks(minor_ticks, minor=True)
    ax.set_yticks(major_ticks)
    #ax.set_yticks(minor_ticks, minor=True)
    # And a corresponding grid
    ax.grid(which='both')
    ax.plot(X, Y)
    Z = range(n + 1)
    ax.plot(Z)
    return ax

def areaDyckPath(path):
    ''' calculate the area of the given Dyck path, defined as the number
    of unit squares under the path but above the line y = x'''
    if isinstance(path, list):
        n = int(len(path)/2)
    else:
        n = int(path.shape[0]/2)
    x = 0
    y = 0
    S = [(x, y)]
    for i in range(2 * n):
        if path[i] == 1:
            y += 1
        else:
            x += 1
        S.append((x,y))
    area = 0
    y_prev = 0
    for p in S: #every time as y increases, we add y - x - 1 to the area
        if p[1] > y_prev:
            area += p[1] - p[0]- 1
            y_prev = p[1]
    return area

def valleys(path):
    '''counts the number of valleys of the given Dyck path,
    and the list of valleys '''
    if isinstance(path, list):
        n = len(path)//2
    else:
        n = path.shape[0]//2
    valleys = []
    for i in range(2 * n - 1):
        if path[i] == - 1 and path[i + 1] == 1:
            valleys.append(i)
    return valleys

def peaks(path):
    '''find peaks of the given Dyck path,
    and returns their list'''
    if isinstance(path, list):
        n = len(path)//2
    else:
        n = path.shape[0]//2
    peaks = []
    for i in range(2 * n - 1):
        if path[i] == 1 and path[i + 1] == -1:
            peaks.append(i)
    return peaks

def buildPlanePath(path, method = 'upperLatticePath'):
    ''' creates the path in the plane '''
    if isinstance(path, list):
        n = int(len(path)/2)
    else:
        n = int(path.shape[0]/2)
    x = 0
    y = 0
    S = [(x, y)]
    if method == "upperLatticePath":
        for i in range(2 * n):
            if path[i] == 1:
                y += 1
            else:
                x += 1
            S.append((x,y))
    else:
        for i in range(2 * n):
            if path[i] == 1:
                x += 1
            else:
                y += 1
            S.append((x,y))
    #print(S)
    X, Y = list(zip(*S))

    return X, Y

def pathTo231perm(path):
    '''converts a Dyck path to 231 avoiding permutation
    I am using the description of the bijection from Peterson's "Eulerian paths"
    '''
    #TODO
    #first build the reflected path
    X, Y = buildPlanePath(path, method = 'lowerLatticePath')
    n = (len(X) - 1)//2
    #One-by-one, for every column from right to left,
    #Find the lowest unoccupied row
    perm = [0] * n
    used_rows = []
    for x in reversed(range(1, n + 1)):
        y = Y[X.index(x)] # this is the bound from below that the path gives us
        while y in used_rows:
            y += 1
        used_rows.append(y)
        perm[x - 1] = y
    return perm

'''
For testing methods
'''
def main():

    n = 5
    seed = 3
    path = randomDyckPath(n, seed = seed)
    peaks = peaks(path)
    print(path)
    print(peaks)
    plotDyckPath(path, method = 'upperLatticePath')
    perm = pathTo231perm(path)
    print(perm)

    plt.show()

    pass

if __name__ == '__main__':
    main()


# -*- coding: utf-8 -*-
"""
Solution to Project Euler problem 587

https://projecteuler.net/problem=587

Author: Jaime Liew
https://github.com/jaimeliew1/Project_Euler_Solutions

First the point of intersection between the circle and the line is found (x0, y0)

Next, the area under the lower circle is found up to a point, say, x.

The area below the straight line is also found up to x.

The difference of these two areas is found to give the answer. x is chosen to be y0,
which essentially flips the problem on its side to give a single integral.

The integral was solved analytically.
"""

from numpy import pi, arcsin, sqrt

def AreaUnderCurve(N, x0):
    # calculates the area under the curve from 0 to x0, where x0 is the point
    # where the line intersects the first circle. Assumes radius of 1
    r = 1
    a = 1/N # slope of the straight line

    return r*x0 - r**2/2*(arcsin((x0-r)/r) + (x0-r)*sqrt(2*x0*r - x0**2)/r**2 + pi/2)

def AreaUnderLine(N, x0):
    # actually, this is the area to the left of the line
    a = 1/N
    return 1/(a*2)*x0**2

def IntersectionPoint(N):
    a = 1/N
    r = 1
    x0 = 2*r*(a+1) - sqrt(4*r**2*(a+1)**2 - 4*r**2*(1+a**2))
    x0 = x0/(2*(1+a**2))

    y0 = x0/N

    return x0, y0

def areaPerc(N):
    r = 1

    x0, y0 = IntersectionPoint(N)
    # by passing y0 instead of x0, the problem is turned on its side.
    Ac = AreaUnderCurve(N, y0)
    Al = AreaUnderLine(N, y0)

    Atotal = r**2 - pi*r**2/4

    return (Ac-Al)/Atotal

def run():
    N = 1
    while areaPerc(N) > 0.001:
        N += 1
    return N

if __name__ == "__main__":
    print(run())


import numpy as np

from fastats.maths.correlation.pearson import pearson_pairwise
from fastats.scaling.scaling import rank

def spearman(x, y):
    """
    Calculates the Spearman rank correlation
    coefficient for the inputs `x` and `y`.

    If there are any Nan values in the data,
    they will be ignored in the rank for that
    variable, and therefore may skew the results.
    See the test_spearman unit-tests for an
    example.

    The provided inputs must have no ties.

    Example
    -------

    >>> import numpy as np
    >>> x = np.array([1, 2, 3, 4])
    >>> y = np.array([2, 3, 4, 3])
    >>> spearman(x, y)  # doctest: +ELLIPSIS
    0.800000000...

    :param x: A `numpy.array` of floats or ints
    :param y: A `numpy.array` of floats or ints
    :return: A float representing the correlation
    """
    assert x.shape == y.shape

    n = len(x)
    rank_x = np.argsort(x)
    rank_y = np.argsort(y)

    d = rank_x - rank_y
    d2 = d ** 2
    return 1 - (6 * np.sum(d2)) / (n**3 - n)

def spearman_pairwise(A):
    """
    Calculates the Spearman rank correlation
    coefficient between pairs of columns of
    the supplied matrix A (similar to
    pandas.DataFrame.corr(method='spearman').

    Ties are dealt with using the 'average'
    method, as described in rank_data.
    """
    assert A.ndim > 1
    assert A.shape[1] > 1

    A_rank = rank(A)
    return pearson_pairwise(A_rank)

if __name__ == '__main__':
    import pytest
    pytest.main([__file__])


"""
Tests for ivp_4_ode.py
"""
from nma.ivp_4_ode import runge_kutta_o4
from numpy.testing import assert_almost_equal

def test_runge_kutta_o4():
    """
    This test is Example 3 in chapter 5 of the textbook.
    """

    # setup
    f = lambda t, y: y - t ** 2 + 1
    a = 0
    b = 2
    N = 10
    y_initial = 0.5

    # exercise
    result, _ = runge_kutta_o4(f, a, b, N, y_initial)
    actual = 5.305363000692653  # @ t = 2

    # verify
    assert_almost_equal(result, actual, 6)

    # teardown - no needed


''' Statistics helper-functions
'''
import numpy as np

def iqr(values, percentiles=[75, 25]):
    '''
    Compute the inter-quartile range. This is the (default) window in which half of the datapoints reside.
    The iqr is to the median, what the standard deviation is to the mean.

    Parameters
    ----------
    values : list
        data to compute the iqr for
    percentiles : list
        2-list with the top and bottom percentile

    Returns
    -------
    float
        the iqr value for the given data
    '''
    q3, q1 = np.percentile(values, percentiles)
    return q3 - q1

def rmse(values, cmp=0):
    '''
    Root Mean Square Error-like value for a given fixed mean
    (often 0 if we compare the value to a desired symmetry value of 0)

    Parameters
    ----------
    values : list
        data
    cmp : float
        expected outcome value in the sample

    Returns
    -------
    float
        the error value
    '''
    return np.sqrt(np.mean((cmp - values)**2))

def mae(values, cmp=0):
    '''
    Mean Absolute Error-like value for a given fixed mean
    (often 0 if we compare the value to a desired symmetry value of 0)

    Parameters
    ----------
    values : list
        data
    cmp : float
        expected outcome value in the sample

    Returns
    -------
    float
        the error value
    '''
    return np.mean(np.abs(cmp - values))

def autocorrelate(data, unbiased=True):
    '''
    Compute the autocorrelation for given data.

    Parameters
    ----------
    data : list
        The data to compute the autocorrelation for
    unbiased : bool
        Whether the biased or unbiased autocorrelation should be computed.
        The biased version tapers off with lag, while the unbiased version does not.

    Returns
    -------
    list
        List of autocorrelation values with 0 and positive lags
    '''
    import numpy as np

    autocorrelation = np.correlate(data, data, 'full')
    N = autocorrelation.size

    if (unbiased):
        autocorrelation /= (N - np.arange(N))

    # normalize and cut to lagged correlation coefficients
    autocorrelation_lags = autocorrelation[N // 2:] / autocorrelation[N // 2]

    return autocorrelation_lags