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

print("This script takes data.csv as default data")

alpha=float(input("Enter the value of alpha: "))
iterations=int(input("Enter number of iterations: "))
x_label=input("Enter x label: ")
y_label=input("Enter y label: ")

data=pd.read_csv("data.csv", header=None)

m=len(data)                                         # total data
x=np.hstack((data.iloc[:, 0])).reshape(m,1)         # creates a vector of (m,1) from 1st index
Y=np.hstack((data.iloc[:, 1])).reshape(m,1)         # creates a vector of (m,1) from 2nd index

ones= np.ones((m,1))                                # creates a vector of (m,1) of ones for x0
X=np.hstack((ones,x))                               # merge x and ones to X

theta= np.zeros((2,1))                              # theta vector of (2,1): theta0, theta1

def costfn(theta):                                  # calculates cost function
    temp=X.dot(theta)-Y
    return np.sum(np.power(temp,2))/(2*m)

def gradient_descent(theta):                                # calculates gradient descent
    for _ in range(iterations):
        temp=X.dot(theta)-Y
        temp2=X.transpose()
        temp=temp2.dot(temp)
        theta= theta - (alpha/m)*temp
    return theta

theta=gradient_descent(theta)
cost_value=costfn(theta)

print("Value of theta and minimum error")
print(theta)
print(cost_value)

plt.scatter(x, Y)                                   # scatter plot
plt.plot(x, X.dot(theta))                           # plot regression line
plt.xlabel(x_label)
plt.ylabel(y_label)
plt.show()

min_theta=int(np.amin(theta)-5)                     # creates a range for theta as input
max_theta=int(np.amax(theta)+5)

theta0=np.arange(min_theta,max_theta,0.1)           # creates theta0 from the range
theta1=np.arange(min_theta,max_theta,0.1)
j_vals= np.zeros((len(theta0),len(theta1)))         # to store the cost function value of theta0, theta1

t=np.ones((2,1))                                    # temporary theta

for i in range(len(theta0)):                        # storing the costfun values in j_vals
    for j in range(len(theta1)):
        t[0][0]=theta0[i]
        t[1][0]=theta1[j]
        j_vals[i][j]=costfn(t)

plt.contourf(theta0,theta1, j_vals)                 # plot contour
plt.show()


import numpy as np

def logit(x):
    return 1/(1. + np.exp(-x))

def identity(x):
    return x

def logistic(x):
    return np.log(1 + np.exp(x))


import numpy as np
import matplotlib.pyplot as pypl

'''
일반적인 미분. 기울기 = (f(x+h)-f(x-h))/2*h
'''
def numericalDiff(f, x) :
    h=1e-4
    return (f(x+h)-f(x-h))/(2*h)

def sample_func1(x) :
    return 0.01*x**2+0.1*x

'''
편미분 : 두개 이상의 독립변수가 존재하는 함수에서 하나의 독립변수에 대한 편미분은
나머지 독립변수들을 상수로 취급하여 미분하는 것. 두개 이상의 독립변수를 가진 함수의 기울기는
모든 독립변수에 대한 편미분을 벡터로 정리한 것을 말한다.
'''

def numericalGradient(f, x) :   # 입력 두개에 한정된 함수. 일반화가 필요함.
    h=1e-4
    grad=np.zeros(x.shape)
    for i in range(x.shape[0]):
        for j in range(x.shape[1]):
            x_copy=np.array(x)

            x_copy[i,j]=x[i,j]+h
            fh1=f(x_copy)

            x_copy[i,j]=x[i,j]-h
            fh2=f(x_copy)

            grad[i,j]=(fh1-fh2)/(2*h)

    return grad

def sample_func2(x) :
    return x[0]**2 + x[1]**2

# x=np.arange(0, 20, 0.1)
# y=sample_func1(x)
# pypl.xlabel('x')
# pypl.ylabel('f(x)')
# pypl.plot(x,y)
# pypl.show()
#
# print(numericalDiff(sample_func1,5))
# print(numericalDiff(sample_func1,10))

# print(numericalGradient(sample_func2,np.array([3.0, 4.0])))
# print(numericalGradient(sample_func2,np.array([0.0, 2.0])))
# print(numericalGradient(sample_func2,np.array([3.0, 0.0])))


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

def find_y_in_x(X,Y,x):
    m=  len(X)
    y = Y.copy()
    for k in range(1,m):
        y[0:m-k] = ((x-X[k:m])*y[0:m-k] + (X[0:m-k]-x)*y[1:m-k+1])/(X[0:m-k]-X[k:m])
    return y[0]

def main():
    X = np.array([0,math.pi/6,math.pi/4,math.pi/3,math.pi/2])
    Y = np.sin(X)**2
    x_in = math.pi/5
    y_true = np.sin(x_in)**2
    xnew = np.linspace(np.min(X),np.max(X),100)
    ynew = [find_y_in_x(X,Y,i) for i in xnew]
    plt.plot(X,Y,'o',xnew,ynew)
    plt.grid(True)
    y_in = find_y_in_x(X,Y,x_in)
    print(y_in-y_true)
    pylab.show()
main()


import unittest
from scipy.stats import ttest_ind, pearsonr, ks_2samp

from utils import prepare_data

class TestExercise2_04(unittest.TestCase):
    def setUp(self):
        self.data = prepare_data()
        self.data["Disease"] = self.data["Reason for absence"].apply(self.in_icd)

    def in_icd(self, val):
        return "Yes" if val >= 1 and val <= 21 else "No"

    def test_pearson(self):
        pearson_test = pearsonr(self.data["Age"], self.data["Absenteeism time in hours"])

        self.assertAlmostEqual(pearson_test[0], 0.065, places=2)
        self.assertAlmostEqual(pearson_test[1], 0.073, places=2)

    def test_means(self):
        means = self.data[["Disease", "Age"]].groupby("Disease").mean()

        self.assertAlmostEqual(means["Age"]["Yes"], 36.652, places=2)
        self.assertAlmostEqual(means["Age"]["No"], 36.338, places=2)

    def test_ks(self):
        disease_mask = self.data["Disease"] == "Yes"
        disease_ages = self.data["Age"][disease_mask]
        no_disease_ages = self.data["Age"][~disease_mask]

        test_res = ttest_ind(disease_ages, no_disease_ages)
        ks_res = ks_2samp(disease_ages, no_disease_ages)

        self.assertAlmostEqual(test_res[0], 0.629, places=2)
        self.assertAlmostEqual(test_res[1], 0.529, places=2)
        self.assertAlmostEqual(ks_res[0], 0.056, places=2)
        self.assertAlmostEqual(ks_res[1], 0.618, places=2)


import numpy as np
from sklearn.linear_model import LinearRegression

def get_signal_lr(f_window):
    lr = LinearRegression()
    x = np.array(list(range(len(f_window)))).reshape(-1, 1)
    lr.fit(x, f_window)
    return x, lr.coef_, lr.intercept_

# Buy = 2, Hold = 1, Sell = 0
def signal_code_to_str(signal, coef):
    if signal == 2:
        return f'Buy:{coef:.3f}'
    elif signal == 0:
        return f'Sell:{coef:.3f}'
    else:
        return f'Hold:{coef:.3f}'

def draw_signal_lr(b_window, f_window, signal, axis):
    x, coef, intercept = get_signal_lr(f_window)
    b_window_length = len(b_window)
    axis.scatter(x + b_window_length, f_window, marker='*', color='r')
    axis.plot(x + b_window_length, x * coef + intercept, color='r')
    ymin, ymax = axis.get_ylim()
    axis.text(b_window_length - .38,
              ymax - (ymax - ymin) * .12,
              signal_code_to_str(signal, coef[0]),
              fontsize='x-large',
              color='black')


import numpy as np

# Write a function that takes as input a list of numbers, and returns
# the list of values given by the softmax function.
def softmax(L):
    softmaxList = []
    for i in np.exp(L):
        softmaxList.append(i*1.0/sum(np.exp(L)))
    return softmaxList

Deep Learning/Neural Networks/Intro to Neural Networks/softmax.py


import numpy as np

def lr(z):
    a = 1 / (1 + np.exp(-z))
    return a

### Random values Generation
p = np.random.normal(0, 1, 500) / 10000  # y = 1
q = np.random.normal(0, 4, 500) / 10000  # y = -1
sample = [p, q]
sample_min = np.min(sample)
sample = np.array(sample)
w = 2
eta = 0.1
update_sum = 0

updateValueList = [w]
### Gradient descent implementation of Linear Regression
for i in range(2):
    for j in range(500):
        if i == 0:
            update_sum += (1 - sample[i, j] * w) * (-sample[i, j])
        if i == 1:
            update_sum += (-1 - sample[i, j] * w) * (-sample[i, j])
w = w - 2 * eta * update_sum
updateValueList.append(w)
while np.abs(update_sum) > 0.001:
    for i in range(2):
        for j in range(500):
            if i == 0:
                update_sum += (1 - sample[i, j] * w) * (-sample[i, j])
            if i == 1:
                update_sum += (-1 - sample[i, j] * w) * (-sample[i, j])
    w = w - 2 * eta * update_sum
    updateValueList.append(w)

# print(updateValueList)
import matplotlib.pyplot as plt
# lenofupdatevalues = len(updateValueList)
# print(lenofupdatevalues)
# xx = np.linspace(0,1,lenofupdatevalues)
# print(len(xx))
# plt.scatter(xx, updateValueList, label= "Decision Boundary",linestyle='solid',color = "k")
print('Global Minima by Linear Regression we got', update_sum)
# plt.show()

### Gradient Descent implementation of Logistic Regression
update_sum = 0
w = 2
updateValueList = [w]
for i in range(2):
    for j in range(500):
        if i == 0:
            update_sum += (1 - lr(sample[i, j] * w)) * (-sample[i, j]) * (lr(sample[i, j] * w)) ** 2
        if i == 1:
            update_sum += (-1 - lr(sample[i, j] * w)) * (-sample[i, j]) * (lr(sample[i, j] * w)) ** 2
w = w - 2 * eta * update_sum
updateValueList.append(w)

while update_sum > 0.001:
    for i in range(2):
        for j in range(500):
            if i == 0:
                update_sum += (1 - lr(sample[i, j] * w)) * (-sample[i, j]) * (lr(sample[i, j] * w)) ** 2
            if i == 1:
                update_sum += (-1 - lr(sample[i, j] * w)) * (-sample[i, j]) * (lr(sample[i, j] * w)) ** 2
    w = w - 2 * eta * update_sum
    updateValueList.append(w)

# lenofupdatevalues = len(updateValueList)
# print(lenofupdatevalues)
# xx = np.linspace(0,1,lenofupdatevalues)
# print(len(xx))
# plt.scatter(xx, updateValueList, label= "Decision Boundary",linestyle='solid',color = "k")
print('Global Minima by Logistic Regression we got', update_sum)
# plt.show()


from typing import List, Tuple

import numpy as np

from .quantifier import ProblemType, UncertaintyQuantifier
from .variation_ratio import VariationRatio

def entropy(data: np.ndarray, axis: int) -> np.ndarray:
    """
    A utility method to compute the entropy. May also be used by other quantifiers which internally rely on entropy.

    Following standard convention, the logarithm used in the entropy calculation is on base 2.

    :param data: The values on which the entropy should be computed.
    :param axis: Entropy will be taken along this axis.
    :return: An array containing the entropies. It is one dimension smaller than the passed data (the specified axis was removed).
    """
    # Remove zeros from nn_outputs (to allow to take logs)
    # Note that the actual increment (1e-20) does not matter, as it is multiplied by 0 below
    increments = np.zeros(shape=data.shape, dtype=np.float32)
    indexes_of_zeros = data == 0
    increments[indexes_of_zeros] = 1e-20
    nonzero_data = data + increments

    # These arrays can be quite large and are not used anymore - we free the space for the operations below
    del increments, indexes_of_zeros

    # Calculate and return the entropy
    return -np.sum(data * np.log2(nonzero_data), axis=axis)

class PredictiveEntropy(UncertaintyQuantifier):
    """
    A predictor & uncertainty quantifier, based on multiple samples (e.g. nn outputs) in a classification problem

    The prediction is made using a plurality vote, i.e., the class with the highest value in most samples is selected.
    In the case of a tie, the class with the lowest index is selected.

    The uncertainty is quantified using the predictive entropy;
    the entropy (base 2) of the per-class means of the sampled predictions.
    """

    # docstr-coverage:inherited
    @classmethod
    def aliases(cls) -> List[str]:
        return ["predictive_entropy", "pred_entropy"]

    # docstr-coverage:inherited
    @classmethod
    def takes_samples(cls) -> bool:
        return True

    # docstr-coverage:inherited
    @classmethod
    def problem_type(cls) -> ProblemType:
        return ProblemType.CLASSIFICATION

    # docstr-coverage:inherited
    @classmethod
    def calculate(cls, nn_outputs: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
        # For simplicity, we let the predictions be calculated by the Variation Ratio Code
        #    accepting a slight overhead from also calculating the actual variation ratio
        predictions, _ = VariationRatio.calculate(nn_outputs)

        # Take means over the samples
        means = np.mean(nn_outputs, axis=1)

        # The predictive entropy is the entropy of the means
        predictive_entropy = entropy(means, axis=1)

        return predictions, predictive_entropy


"""ЛР 3.5, Ларькин Владимир, М8О-303Б-18"""

import fire  # CLI
import numpy as np
from sympy import integrate

from utilities import str2fun

def get_points(x0, x, step):
    return [i for i in np.arange(x0, x + step, step)]

def get_values(points, f):
    return [f(x) for x in points]

def rectangle_method(x, h, f):
    return h * sum([f((x[i] + x[i + 1]) / 2) for i in range(len(x) - 1)])

def trapeze_method(y, h):
    n = len(y) - 1
    return h * (y[0] / 2 + sum([y[i] for i in range(1, n - 1)]) + y[n] / 2)

def simpson_method(y, h):
    n = len(y) - 1
    return h / 3 * (y[0] + sum([4 * y[i] for i in range(1, n, 2)]) +
                    sum([2 * y[i] for i in range(2, n - 1, 2)]) + y[n])

def runge_romberg_method(res, anal_val):
    k = res[0]['h'] / res[1]['h']
    err_rec = [abs(res[0]['Rectangle'] - res[1]['Rectangle']) / (k ** 2 - 1), abs(res[0]['Rectangle'] - anal_val) / (k ** 2 - 1)]
    err_trap = [abs(res[0]['Trapeze'] - res[1]['Trapeze']) / (k ** 2 - 1), abs(res[0]['Trapeze'] - anal_val) / (k ** 2 - 1)]
    err_sim = [abs(res[0]['Simpson'] - res[1]['Simpson']) / (k ** 4 - 1), abs(res[0]['Simpson'] - anal_val) / (k ** 4 - 1)]
    return {'Rectangle': err_rec, 'Trapeze': err_trap, 'Simpson': err_sim}

def main():
    """Численное интегрирование методами прямоугольников, трапеций и Симпсона"""

    init_dict = {
        "x": (-1, 1),
        "h": [0.5, 0.25],
        "f": "x / ((2 * x + 7) * (3 * x + 4))"
    }

    a, b = init_dict["x"]
    h_list = init_dict["h"]
    f_str = init_dict["f"]

    anal_val = float(integrate(f_str, ("x", a, b)))
    f = str2fun(f_str)

    save_res = []
    for h in h_list:
        points = get_points(a, b, h)
        values = get_values(points, f)

        res_rec = rectangle_method(points, h, f)
        res_trap = trapeze_method(values, h)
        res_sim = simpson_method(values, h)

        save_res.append({
            "h": h,
            "Rectangle": res_rec,
            "Trapeze": res_trap,
            "Simpson": res_sim
        })

    errors = runge_romberg_method(save_res, anal_val)

    print("Интеграл f(x) =", f_str, "от", a, "до", b)
    print("Аналитическое решение:", anal_val)
    print(f"-------------------------------------")
    print(f"|  h  | Прямоуг.|  Трап.  | Симпсон |")
    print(f"-------------------------------------")
    for res in save_res:
        h = res["h"]
        rec = res["Rectangle"]
        trap = res["Trapeze"]
        simp = res["Simpson"]
        print(f"|{h:5.2f}|{rec:9.6f}|{trap:9.6f}|{simp:9.6f}|")
    print(f"-------------------------------------")
    print(f"|   Погрешности (Рунге-Ромберг):    |")
    print(f"-------------------------------------")

    for i in range(len(errors["Rectangle"])):
        print(f"|{h_list[i]:5.2f}|{errors['Rectangle'][i]:9.6f}|{errors['Trapeze'][i]:9.6f}|{errors['Simpson'][i]:9.6f}|")
    print(f"-------------------------------------")

if __name__ == "__main__":
    fire.Fire(main)


import matplotlib.pyplot as plt # matplot lib is the premiere plotting lib for Python: https://matplotlib.org/
import numpy as np # numpy is the premiere signal handling library for Python: http://www.numpy.org/
import scipy as sp # for signal processing
from scipy import signal
from scipy.spatial import distance
import librosa
import random

def create_sine_wave(freq, sampling_rate, total_time_in_secs, return_time = False):
    '''Creates a sine wave with the given frequency, sampling rate, and length'''

    # Create an array from 0 to total_time_in_secs * sampling_rate (and then divide by sampling
    # rate to get each time_step)
    time = np.arange(total_time_in_secs * sampling_rate) / sampling_rate

    # Could also generate this signal by:
    # time = np.linspace(0, total_time_in_secs, int(total_time_in_secs * sampling_rate), endpoint=False)

    sine_wave = np.sin(2 * np.pi * freq * time)

    # or, once the sample is made:
    # time = np.linspace(0, len(s) / sampling_rate, num=len(s))

    if return_time is False:
        return sine_wave
    else:
        return (time, sine_wave)

def create_cos_wave(freq, sampling_rate, total_time_in_secs, return_time = False):
    '''Creates a cos wave with the given frequency, sampling rate, and length'''

    # Create an array from 0 to total_time_in_secs * sampling_rate (and then divide by sampling
    # rate to get each time_step)
    time = np.arange(total_time_in_secs * sampling_rate) / sampling_rate
    cos_wave = np.cos(2 * np.pi * freq * time)

    if return_time is False:
        return cos_wave
    else:
        return (time, cos_wave)

def get_random_xzoom(signal_length, fraction_of_length):
    '''Returns a tuple of (start, end) for a random xzoom amount'''
    zoom_length = int(signal_length * fraction_of_length)
    random_start = random.randint(0, signal_length - zoom_length)
    xlim_zoom = (random_start, random_start + zoom_length)
    return xlim_zoom

def map(val, start1, stop1, start2, stop2):
    '''Similar to Processing and Arduino's map function'''
    return ((val-start1)/(stop1-start1)) * (stop2 - start2) + start2;

### SIGNAL MANIPULATION FUNCTIONS ###

# While numpy provides a roll function, it does not appear to provide a shift
# https://stackoverflow.com/q/30399534
# So, lots of people have implemented their own, including some nice benchmarks here:
# https://stackoverflow.com/a/42642326
def shift_array(arr, shift_amount, fill_value = np.nan):
    '''Shifts the array either left or right by the shift_amount (which can be negative or positive)

       From: https://stackoverflow.com/a/42642326
    '''
    result = np.empty_like(arr)
    if shift_amount > 0:
        result[:shift_amount] = fill_value
        result[shift_amount:] = arr[:-shift_amount]
    elif shift_amount < 0:
        result[shift_amount:] = fill_value
        result[:shift_amount] = arr[-shift_amount:]
    else:
        result[:] = arr
    return result

### SIGNAL ANALYSIS FUNCTIONS ###

def calc_zero_crossings(s, min_gap = None):
    '''Returns the number of zero crossings in the signal s

    This method is based on https://stackoverflow.com/q/3843017

    Parameters:
    s: the signal
    min_gap: the minimum gap (in samples) between zero crossings
    TODO:
    - could have a mininum height after the zero crossing (within some window) to eliminate noise
    '''
    # I could not get the speedier Pythonista solutions to work reliably so here's a
    # custom non-Pythony solution
    cur_pt = s[0]
    zero_crossings = []
    last_zero_crossing_idx = None
    last_zero_cross_idx_saved = None
    for i in range(1, len(s)):
        next_pt = s[i]
        zero_crossing_idx = None

        # There are three cases to check for:
        #  1. If the cur_pt is gt zero and the next_pt is lt zero, obviously a zero crossing.
        #     Similarly, if the next_pt is gt zero and the cut_pt is lt zero, again a zero crossing
        #  2. If the cur_pt is zero and the next_pt gt zero, then we walk back to see when zero
        #     was first "entered"
        #  3. Finally, if the cut_pt is zero and the next_pt lt zero, we again walk back to see
        #     when zero was first "entered"
        if ((next_pt < 0 and cur_pt > 0) or (next_pt > 0 and cur_pt < 0)):
            # if we're here, a zero crossing occurred
            zero_crossing_idx = i

        elif cur_pt == 0 and next_pt > 0:
            # check for previous points less than 0
            # as soon as tmp_pt is not zero, we are done
            tmp_pt = cur_pt
            walk_back_idx = i
            while(tmp_pt == 0 and walk_back_idx > 0):
                walk_back_idx -= 1
                tmp_pt = s[walk_back_idx]

            if tmp_pt < 0:
                zero_crossing_idx = i

        elif cur_pt == 0 and next_pt < 0:
            # check for previous points greater than 0
            # as soon as tmp_pt is not zero, we are done
            tmp_pt = cur_pt
            walk_back_idx = i
            while(tmp_pt == 0 and walk_back_idx > 0):
                walk_back_idx -= 1
                tmp_pt = s[walk_back_idx]

            if tmp_pt > 0:
                zero_crossing_idx = i

        # now potentially add zero_crossing_idx to our list
        if zero_crossing_idx is not None:
            # potentially have a new zero crossing, check for other conditions
            if last_zero_cross_idx_saved is None or \
               last_zero_cross_idx_saved is not None and min_gap is None or \
               (min_gap is not None and (i - last_zero_cross_idx_saved) > min_gap):

                zero_crossings.append(zero_crossing_idx) # save the zero crossing point
                last_zero_cross_idx_saved = zero_crossing_idx

            last_zero_crossing_idx = zero_crossing_idx

        cur_pt = s[i]
    return zero_crossings

##### VISUALIZATION CODE ######
def plot_signal_to_axes(ax, s, sampling_rate, title=None, signal_label=None, marker=None):
    '''Plots a sine wave s with the given sampling rate

    Parameters:
    ax: matplot axis to do the plotting
    s: numpy array
    sampling_rate: sampling rate of s
    title: chart title
    signal_label: the label of the signal
    '''
    ax.plot(s, label=signal_label, marker=marker, alpha=0.9)
    ax.set(xlabel="samples")

    if signal_label is not None:
        ax.legend()

    # we use y=1.14 to make room for the secondary x-axis
    # see: https://stackoverflow.com/questions/12750355/python-matplotlib-figure-title-overlaps-axes-label-when-using-twiny
    if title is not None:
        ax.set_title(title, y=1.1)

    ax.grid()

    # add in a secondary x-axis to draw the x ticks as time (rather than samples)
    ax2 = ax.twiny()
    ax2.set_xlim(ax.get_xlim())

    ax_ticks = ax.get_xticks()[1:-1]
    ax2_tick_labels = ax.get_xticks()[1:-1] / sampling_rate

    num_samples_shown = ax.get_xlim()[1] - ax.get_xlim()[0]
    time_shown = num_samples_shown / sampling_rate
    if time_shown < 1:
        ax2.set_xlabel("time (ms)")
        # format with 'g' causes insignificant trailing zeroes to be removed
        # https://stackoverflow.com/a/2440708 but also uses scientific notation, oh well!
        ax2_tick_labels = [f"{x * 1000:.1f}" for x in ax2_tick_labels]
    else:
        ax2.set_xlabel("time (secs)")
        ax2_tick_labels = ['{:.2f}'.format(x) for x in ax2_tick_labels]

    ax2.set_xticks(ax_ticks)
    ax2.set_xticklabels(ax2_tick_labels)

def plot_signal(s, sampling_rate, quantization_bits = 16, title = None, xlim_zoom = None, highlight_zoom_area = True):
    '''Plots audio data with the given sampling_rate, quantization level, and xlim_zoom'''

    plot_title = title
    if plot_title is None:
        plot_title = f"{quantization_bits}-bit, {sampling_rate} Hz audio"

    if xlim_zoom == None:
        fig, axes = plt.subplots(1, 1, figsize=(15,6))

        plot_signal_to_axes(axes, s, sampling_rate, plot_title)
        return (fig, axes)
    else:
        fig, axes = plt.subplots(1, 2, figsize=(15,6), sharey=True, gridspec_kw={'width_ratios': [2, 1]})
        plot_signal_to_axes(axes[0], s, sampling_rate, plot_title)

        # if(xlim_zoom == None):
        #     xlim_zoom = get_random_xzoom(len(audio_data), 0.1)

        if highlight_zoom_area:
            # yellow highlight color: color='#FFFBCC'
            axes[0].axvspan(xlim_zoom[0], xlim_zoom[1], color='orange', alpha=0.3)

        axes[1].set_xlim(xlim_zoom)
        plot_signal_to_axes(axes[1], s, sampling_rate, plot_title + ' zoomed')
        fig.tight_layout()
        return (fig, axes)

def plot_sampling_demonstration(total_time_in_secs, real_world_freqs, real_world_continuous_speed = 10000, resample_factor = 200):
    '''Used to demonstrate digital sampling'''
    num_charts = len(real_world_freqs)
    fig_height = num_charts * 3.25
    fig, axes = plt.subplots(num_charts, 1, figsize=(15, fig_height))

    time = None

    i = 0
    sampling_rate = real_world_continuous_speed / resample_factor
    print(f"Sampling rate: {sampling_rate} Hz")
    for real_world_freq in real_world_freqs:
        time, real_world_signal = create_sine_wave(real_world_freq, real_world_continuous_speed,
                                               total_time_in_secs, return_time = True)
        sampled_time = time[::resample_factor]
        sampled_signal = real_world_signal[::resample_factor]

        axes[i].plot(time, real_world_signal)
        axes[i].axhline(0, color="gray", linestyle="-", linewidth=0.5)
        axes[i].plot(sampled_time, sampled_signal, linestyle='None', alpha=0.8, marker='s', color='black')
        axes[i].vlines(sampled_time, ymin=0, ymax=sampled_signal, linestyle='-.', alpha=0.8, color='black')
        axes[i].set_ylabel("Amplitude")
        axes[i].set_xlabel("Time (secs)")
        axes[i].set_title(f"{real_world_freq}Hz signal sampled at {sampling_rate}Hz")

        i += 1
    fig.tight_layout(pad = 3.0)

#### FREQUENCY VISUALIZATIONS ####
def plot_signal_and_magnitude_spectrum(t, s, sampling_rate, title = None, xlim_zoom_in_secs = None):
    # Plot the time domain
    ax_main_time = None
    ax_zoom_time = None
    ax_spectrum = None

    axes = []
    if xlim_zoom_in_secs is None:
        fig, axes = plt.subplots(2, 1, figsize=(15,8))
        ax_main_time = axes[0]
        ax_spectrum = axes[1]
    else:
        fig = plt.figure(figsize=(15, 9))

        # TODO: in future, ideally, we would have like a 70/30 split on top row
        ax_main_time = plt.subplot2grid((2, 2), (0, 0))
        ax_zoom_time = plt.subplot2grid((2, 2), (0, 1))
        ax_spectrum = plt.subplot2grid((2, 2), (1, 0), colspan=2)
        axes.append(ax_main_time)
        axes.append(ax_zoom_time)
        axes.append(ax_spectrum)

    # Plot main time domain
    ax_main_time.plot(t, s)

    if title is None:
        title = "Signal (time domain)"

    ax_main_time.set_title(title)
    ax_main_time.set_ylabel("Amplitude")
    ax_main_time.set_xlabel("Time (secs)")

    if ax_zoom_time is not None:
        # plot zoom
        ax_main_time.axvspan(xlim_zoom_in_secs[0], xlim_zoom_in_secs[1], color='orange', alpha=0.3)

        ax_zoom_time.set_xlim(xlim_zoom_in_secs)
        ax_zoom_time.plot(t, s)
        ax_zoom_time.set_title(title + " (Zoomed)")
        ax_zoom_time.set_ylabel("Amplitude")
        ax_zoom_time.set_xlabel("Time (secs)")

    # Plot the frequency transform
    ax_spectrum.magnitude_spectrum(s, Fs = sampling_rate, color='r')
    fig.tight_layout()

    return (fig, axes)

import matplotlib.ticker as ticker
def plot_spectrogram_to_axes(ax, s, sampling_rate, title=None, signal_label=None,
                             marker=None, custom_axes = True):
    '''Plots a spectrogram wave s with the given sampling rate

    Parameters:
    ax: matplot axis to do the plotting
    s: numpy array
    sampling_rate: sampling rate of s
    title: chart title
    signal_label: the label of the signal
    '''

    specgram_return_data = ax.specgram(s, Fs=sampling_rate)
    if signal_label is not None:
        ax.legend()

    # we use y=1.14 to make room for the secondary x-axis
    # see: https://stackoverflow.com/questions/12750355/python-matplotlib-figure-title-overlaps-axes-label-when-using-twiny
    if title is not None:
        ax.set_title(title, y=1.2)

    # add in a secondary x-axis to draw the x ticks as time (rather than samples)
    if custom_axes:
        ax.set(xlabel="samples")
        ax_xtick_labels = np.array(ax.get_xticks()) * sampling_rate
        ax_xtick_labels_strs = [f"{int(xtick_label)}" for xtick_label in ax_xtick_labels]
        ax.set_xticklabels(ax_xtick_labels_strs)

        ax2 = ax.twiny()
        ax2.set_xlim(ax.get_xlim())
        ax2.set_xlabel("time (secs)")
        ax2_tick_labels = ax_xtick_labels / sampling_rate
        ax2_tick_labels_strs = [f"{xtick_label:.1f}s" for xtick_label in ax2_tick_labels]
        ax2.set_xticks(ax.get_xticks())
        ax2.set_xticklabels(ax2_tick_labels_strs)
    return specgram_return_data

def plot_spectrogram(audio_data, sampling_rate, quantization_bits, xlim_zoom = None, highlight_zoom_area = True):
    '''Plots audio data with the given sampling_Rate, quantization level, and xlim_zoom'''
    fig, axes = plt.subplots(1, 2, figsize=(15,4), gridspec_kw={'width_ratios': [2, 1]})
    plot_title = f"{quantization_bits}-bit, {sampling_rate} Hz audio"
    specgram_return_data0 = plot_spectrogram_to_axes(axes[0], audio_data, sampling_rate, plot_title)

    if(xlim_zoom == None):
        max_length = len(audio_data)
        length = int(max_length * 0.1)
        random_start = random.randint(0, max_length - length)
        xlim_zoom = (random_start, random_start + length)

    axes[1].set_xlim(xlim_zoom)
    #axes[1].set_xlim(12000, 14000)
    specgram_return_data1 = plot_spectrogram_to_axes(axes[1], audio_data, sampling_rate, plot_title + ' zoomed', custom_axes = False)

    zoom_x1 = xlim_zoom[0] / sampling_rate
    zoom_x2 = xlim_zoom[1] / sampling_rate
    axes[1].set_xlim(zoom_x1, zoom_x2) # but this one seems to work

    ax2 = axes[1].twiny()
    ax2.set_xlim(axes[1].get_xlim())
    ax2.set_xticks(axes[1].get_xticks())
    ax2_tick_labels_strs = [f"{xtick_label:.1f}s" for xtick_label in axes[1].get_xticks()]
    ax2.set_xticklabels(ax2_tick_labels_strs)
    ax2.set_xlabel("time (secs)")

    ax_xtick_labels = np.array(axes[1].get_xticks()) * sampling_rate
    ax2_tick_labels_strs = [f"{int(xtick_label)}" for xtick_label in ax_xtick_labels]
    axes[1].set(xlabel="samples")
    axes[1].set_xticklabels(ax2_tick_labels_strs)

    if highlight_zoom_area:
        # yellow highlight color: color='#FFFBCC'
        axes[0].axvline(x = zoom_x1, linewidth=2, color='r', alpha=0.8, linestyle='-.')
        axes[0].axvline(x = zoom_x2, linewidth=2, color='r', alpha=0.8, linestyle='-.')

    fig.tight_layout()
    return (fig, axes)

def remap(val, start1, stop1, start2, stop2):
    '''Similar to Processing and Arduino's map function'''
    return ((val-start1)/(stop1-start1)) * (stop2 - start2) + start2;

def plot_signal_and_spectrogram(audio_data, sampling_rate, quantization_bits, xlim_zoom = None, highlight_zoom_area = True):
    '''Plot waveforms and spectrograms together'''
    fig = plt.figure(figsize=(15, 9))
    spec = fig.add_gridspec(ncols = 2, nrows = 2, width_ratios = [2, 1], height_ratios = [1, 1])
    plot_title = f"{quantization_bits}-bit, {sampling_rate} Hz audio"

    ax_waveform1 = plt.subplot(spec[0, 0])
    ax_waveform1.set_xlim(0, len(audio_data))
    ax_waveform2 = plt.subplot(spec[0, 1], sharey = ax_waveform1)

    ax_spectrogram1 = plt.subplot(spec[1, 0])
    ax_spectrogram2 = plt.subplot(spec[1, 1])

    plot_signal_to_axes(ax_waveform1, audio_data, sampling_rate, plot_title)
    specgram_return_data = plot_spectrogram_to_axes(ax_spectrogram1, audio_data, sampling_rate, plot_title)
    #print(len(specgram_return_data[2]))

    #print(ax_waveform1.get_xlim())
    #print(ax_spectrogram1.get_xlim())
    waveform_xrange = ax_waveform1.get_xlim()[1] - ax_waveform1.get_xlim()[0]

    ax_waveform2.set_xlim(xlim_zoom)
    plot_signal_to_axes(ax_waveform2, audio_data, sampling_rate, plot_title + ' zoomed')

    zoom_x1 = remap(xlim_zoom[0], ax_waveform1.get_xlim()[0], ax_waveform1.get_xlim()[1],
                    ax_spectrogram1.get_xlim()[0], ax_spectrogram1.get_xlim()[1])
    zoom_x2 = remap(xlim_zoom[1], ax_waveform1.get_xlim()[0], ax_waveform1.get_xlim()[1],
                    ax_spectrogram1.get_xlim()[0], ax_spectrogram1.get_xlim()[1])

    #print(ax_spectrogram2.get_xlim(), zoom_x1, zoom_x2)
    ax_spectrogram2.set_xlim(zoom_x1, zoom_x2) # this won't make a difference
    plot_spectrogram_to_axes(ax_spectrogram2, audio_data, sampling_rate, plot_title,
                             custom_axes = False)
    ax_spectrogram2.set_xlim(zoom_x1, zoom_x2) # but this one seems to work

    ax2 = ax_spectrogram2.twiny()
    ax2.set_xlim(ax_spectrogram2.get_xlim())
    ax2.set_xticks(ax_spectrogram2.get_xticks())
    ax2_tick_labels_strs = [f"{xtick_label:.2f}s" for xtick_label in ax_spectrogram2.get_xticks()]
    ax2.set_xticklabels(ax2_tick_labels_strs)
    ax2.set_xlabel("time (secs)")

    ax_xtick_labels = np.array(ax_spectrogram2.get_xticks()) * sampling_rate
    ax2_tick_labels_strs = [f"{int(xtick_label)}" for xtick_label in ax_xtick_labels]
    ax_spectrogram2.set(xlabel="samples")
    ax_spectrogram2.set_xticks(ax_spectrogram2.get_xticks())
    ax_spectrogram2.set_xticklabels(ax2_tick_labels_strs)

    if highlight_zoom_area:
        # yellow highlight color: color='#FFFBCC'
        ax_waveform1.axvspan(xlim_zoom[0], xlim_zoom[1], color='orange', alpha=0.3)
        ax_spectrogram1.axvline(x = zoom_x1, linewidth=2, color='r', alpha=0.8, linestyle='-.')
        ax_spectrogram1.axvline(x = zoom_x2, linewidth=2, color='r', alpha=0.8, linestyle='-.')

    fig.tight_layout()


# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: percent
#       format_version: '1.3'
#       jupytext_version: 1.4.2
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# %% jupyter={"outputs_hidden": false}
from sympy import *
init_printing(pretty_print=True,use_latex=True)
# %matplotlib inline
import matplotlib.pyplot as plt
from numpy import arange

# %% jupyter={"outputs_hidden": false}
f,t,T,G = symbols('f t T G')

# %% jupyter={"outputs_hidden": false}
f = G*t
print ('f =', f)

# %% jupyter={"outputs_hidden": false}
p = plot((f.subs(G,25),(t,0,1)),((f-25).subs(G,25),(t,1,2)),((f-50).subs(G,25),(t,2,3)), \
         ylabel = '$f = 25 t$ [V]', xlabel = '$t$ [sec]', xlim=(0,3), figsize=(10,8))

# %% jupyter={"outputs_hidden": false}
c0 = integrate(f,(t,0,T))*(1/T)
print(c0)
print (c0.subs([(G,25),(T,1)]))

# %% jupyter={"outputs_hidden": false}
a1 = (2/T)*integrate(f*sin(2*pi*t),(t,0,T))

# %% jupyter={"outputs_hidden": false}
print(a1)
print( a1.subs([(T,1),(pi, 3.14),(G,25)]))

# %% jupyter={"outputs_hidden": false}
a,b = [],[]
for n in range(10):
    a.append((2/T)*integrate(f*sin(n*pi*t),(t,0,T)))
    b.append((2/T)*integrate(f*cos(n*pi*t),(t,0,T)))

# %% jupyter={"outputs_hidden": false}
a[9], b[9]

# %% jupyter={"outputs_hidden": false}

c = []
for n in range(1,10):
    print( a[n])
    expr = sqrt(a[n]**2 + b[n]**2)
    expr = expr.subs([(T,1),(pi, 3.14),(G,25)])
    # print expr
    # val = lambdify(t,expr,'numpy')
    c.append(expr)

# %% jupyter={"outputs_hidden": false}
fig,ax = plt.subplots(figsize=(10,8))
ax.bar(-.5+arange(1,10),c,alpha=.5)
ax.set_xticks([1,2,3,4,5,6,7,8,9,10])
ax.set_xlabel('$n$',fontsize=16)
ax.set_ylabel('Fourier coefficients $a_n^2 + b_n^2$',fontsize=16)

# %% jupyter={"outputs_hidden": false}


###_______________________ FelixBaumgartner Jump ___________________________###
###_____________________ Ordinary Differential Eqs _________________________###
# EDO: (ecuación que gobierna la caída de Felix es:)
    # $$\displaystyle m \frac{d^2 y}{d t^2} = -m g + D$$ #
# With:
    # $$D = \frac{1}{2} \rho v^2 C_D A$$
# Where:
    # * $m$ es la masa de Félix y la tomaremos $m = 80~\text{kg}$,
    # * $\rho$ es la densidad del aire **y depende de la altura**,
    # * $v = |\dot{y}|$ es la velocidad,
    # * $C_D$ es el coeficiente de rozamiento, que tomaremos* $C_D = 0.4$, y
    # * $A$ es un área de referencia y tomaremos $A = 1~\text{m}^2$.
# Source: http://fisicadepelicula.blogspot.com.es/2012/10/la-fisica-del-salto-baumgartner.html
# Además, necesitaremos la altura inicial $h_0 = 39000 m$.
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
# from scipy.integrate import solve_ivp # Different solver
# from numpy.testing import assert_almost_equal

##_________________________ Temp ISA ___________________________##
# $$T(h) = \begin{cases} T_0 + \lambda h & 0 <= h <= 11000 \\ T(11000) & 11000 < h \end{cases}
# \\ ~\\ T_0 = 288.16 K \\
# \lambda = -6.5 \cdot 10^{-3}~\text{K/m}$$

# **¡Importante!** Si utilizas condicionales para comprobar las capas de la atmósfera,
# seguramente tus funciones fallarán si las quieres representar utilizando un `linspace`.
# Para estos casos es mejor utilizar la función `np.select`:
def T_ISA(h):
    """Temperature as a function of altitude using the ISA.

    Arguments
    ----------
    h : Altitude in metres.

    Returns
    --------
    T : Temperature in Kelvin.

    """
    # Con esta línea convertimos la entrada a un array
    h = np.asarray(h)
    # Initial values
    T0 = 288.16  # K
    ll = -6.5e-3 # K/m
    ## One way to do it (without h=np.asarray(h)) ##
    # if 0 <= h <= 11000:
    #     T = T0 + ll*h
    # elif 11000 < h:
    #     T = T0 + ll*11000
    ## Another way to do it with h as array ##
    # 0 <= h <= 110000 no funciona para arrays
    T1 = T0 + ll * h
    T2 = T0 + ll * 11000
    T = np.select([(0 <= h) & (h <= 11000), 11000 < h], [T1, T2])
    return T
# Si quieres comprobar que tus funciones hacen lo que deben, puedes ejecutar estos tests:
# print(assert_almost_equal(T_ISA(0), 288.16))
# print(assert_almost_equal(T_ISA(11000), 216.66))

##_________________________ Rho ISA ___________________________##
# $$ \rho(h) = \begin{cases} \rho_0 \left( \frac{T}{T_0} \right)^{-\frac{g}{\lambda R} - 1}
# & 0 <= h <= 11000 \\ \rho(11000)~e^{\frac{-g(z - 11000)}{R T}} & 11000 < h <= 20000
# \end{cases} $$
# $$\rho_0 = 1.225~\text{[SI]} \\
# R = 287~\text{[SI]}$$
def rho_ISA(h):
    """Density (rho) as a function of altitude using the ISA.

    Arguments
    ----------
    h : Altitude in metres.

    Returns
    --------
    rho : Density in [SI].

    """
    h = np.asarray(h)
    # Initial values
    T0 = 288.16  # K
    ll = -6.5e-3 # K/m
    rho0 = 1.225 # kg / m3
    g = 9.81     # m / s2
    R = 287      # [SI]
    rho1 = rho0 * (T_ISA(h) / T0) ** (-g / (ll * R) - 1)
    rho2 = rho0 * (T_ISA(11000) / T0) ** (-g / (ll * R) - 1) * np.exp(-g * (h - 11000) / (R * T_ISA(h)))
    rho = np.select([(0 <= h) & (h <= 11000), 11000 < h], [rho1, rho2])
    return rho

##_________________________ EDO ___________________________##
# System Equation
def f(y, t):
    g = 9.8  # m / s2
    C_D = 0.4
    A = 1.0  # m^2
    m = 80  # kg
    return np.array([
        y[1],
        -g + rho_ISA(y[0]) * y[1] ** 2 * C_D * A / (2 * m)
    ])
# Initial Conditions
y0 = np.array([39000, 0])
# Time vector
t = np.linspace(0, 250)
# Integrate the equation
sol = odeint(f, y0, t)
pos = sol[:, 0]  # Primera columna: posición
vel = sol[:, 1]  # Segunda columna: velocidad
# Representing the solution
with plt.style.context('seaborn-notebook'):
    fig, axes = plt.subplots(3, 1, sharex=True, figsize=(6, 6))
    line, = axes[0].plot(t, pos / 1e3, label="Position $y$")
    axes[0].set_ylabel("Position [km]")
    axes[1].plot(t, vel, '--', color=line.get_color(), label="Velocity $\dot{y}$")
    axes[1].set_ylabel("Velocity [m/s]")
    # axes[1].set_xlabel("Time (s)")
    axes[0].legend()
    axes[1].legend()
    axes[0].set_title("Felix Baumgartner free fall")
    axes[0].grid()
    axes[1].grid()
    fig.tight_layout()

##_________________________ Sound Barrier _________________________##
# La velocidad del sonido en el aire variará también, y lo hará de esta forma:
    # $$M = \frac{v}{c}$$
# where: $$c = \sqrt{\gamma R T}$$

# Como paso final, representa 𝑀 en función de 𝑡 y en la misma gráfica incluye una
# línea horizontal de trazo discontinuo donde 𝑀=1
gamma = 1.4
R = 287.0  # [SI]
c = np.sqrt(gamma * R * T_ISA(pos))

M = np.abs(vel) / c

with plt.style.context('seaborn-notebook'):
    plt.plot(t, M, 'r', label="Mach Number $\mathrm{M}$")
    plt.plot(t, np.ones_like(t), 'k--')
    plt.ylabel('Mach number')
    plt.xlabel('Time [s]')
    # plt.title("Mach number")
    plt.legend()
    plt.grid()


'''
If you have a story, you can simulate it!
100xp
Sometimes, the story describing our probability distribution does not have a named
distribution to go along with it. In these cases, fear not! You can always simulate
it. We'll do that in this and the next exercise.

In earlier exercises, we looked at the rare event of no-hitters in Major League Baseball.
Hitting the cycle is another rare baseball event. When a batter hits the cycle, he gets
all four kinds of hits, a single, double, triple, and home run, in a single game. Like
no-hitters, this can be modeled as a Poisson process, so the time between hits of the
cycle are also Exponentially distributed.

How long must we wait to see both a no-hitter and a batter hit the cycle? The idea is
that we have to wait some time for the no-hitter, and then after the no-hitter, we have
to wait for hitting the cycle. Stated another way, what is the total waiting time for
the arrival of two different Poisson processes? The total waiting time is the time waited
for the no-hitter, plus the time waited for the hitting the cycle.

Now, you will write a function to sample out of the distribution described by this story.

Instructions
-Define a function with call signature successive_poisson(tau1, tau2, size=1) that samples
the waiting time for a no-hitter and a hit of the cycle.
    -Draw waiting times tau1 (size number of samples) for the no-hitter out of an exponential
    distribution and assign to t1.
    -Draw waiting times tau2 (size number of samples) for hitting the cycle out of an exponential
    distribution and assign to t2.
    -The function returns the sum of the waiting times for the two events.
'''
import numpy as np

def successive_poisson(tau1, tau2, size=1):
    # Draw samples out of first exponential distribution: t1
    t1 = np.random.exponential(tau1, size)

    # Draw samples out of second exponential distribution: t2
    t2 = np.random.exponential(tau2, size)

    return t1 + t2


#!/usr/bin/env python
#
#----------------------------------------------------------------------
# Reference: https://epubs.siam.org/doi/pdf/10.1137/S0036144502417715

# In[1]:

import numpy as np
import matplotlib.pyplot as plt

from scipy.interpolate import lagrange

# mgena
#from pylab import *

print ("")
print ("01 ----------------------------")

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

# In[2]:

def f(t):
    return t ** 10 - 1 * t ** 9

ts = np.linspace(0, 1, 6)
fs = f(ts)
print(ts)

print ("02 ----------------------------")

# In[3]:

p4  = lagrange (ts[1:-1], fs[1:-1])
p51 = lagrange (ts[:-1],  fs[:-1])
p52 = lagrange (ts[1:],   fs[1:])
p6  = lagrange (ts, fs)
ts_cont = np.linspace(0, 1, 100)

# In[4]:

plt.plot (ts_cont, f(ts_cont), ts_cont, p6(ts_cont))

# In[5]:
#----------------------------------------------------------------------

class LagrangeBary:
    def __init__(self, ts, fs):
        self.ts = np.copy(ts)
        self.fs = np.copy(fs)
        self.compute_ws()

    def compute_ws_j(self, j):
        wsj = 1
        for k in range(len(self.ts)):
            if k == j:
                continue
            wsj /= self.ts[j] - self.ts[k]
        return wsj

    def compute_ws(self):
        n = len(self.ts)
        ws = np.ones(n)
        for j in range(n):
            ws[j] = self.compute_ws_j(j)
        self.ws = ws

    def remove_left(self):
        t = self.ts[0]
        for i in range(len(self.ws)):
            self.ws[i] *= self.ts[i] - t
        self.ts = np.delete(self.ts, 0)
        self.fs = np.delete(self.fs, 0)
        self.ws = np.delete(self.ws, 0)

    def add_right(self, ti, fi):
        self.ts = np.append(self.ts, ti)
        self.fs = np.append(self.fs, fi)

        for i in range(len(self.ws)):
            self.ws[i] /= self.ts[i] - ti

        w_new = self.compute_ws_j(len(self.ts) - 1)
        self.ws = np.append(self.ws, w_new)

    def __call__(self, t):
        for i in range(len(self.ts)):
            if self.ts[i] == t:
                return self.fs[i]
        n = len(self.ts)
        nom = sum(self.ws[j] * self.fs[j] / (t - self.ts[j]) for j in range(n))
        denom = sum(self.ws[j] / (t - self.ts[j]) for j in range(n))
        return nom / denom

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

# In[6]:

p_bary = LagrangeBary (ts[:-1], fs[:-1])

# In[7]:

plt.plot (ts_cont, p51(ts_cont), ts_cont, [p_bary(t) for t in ts_cont])

print ("03 ----------------------------")

# In[8]:

p_bary.remove_left()
plt.plot (ts_cont, p4(ts_cont), ts_cont, [p_bary(t) for t in ts_cont])

# In[9]:

p_bary.add_right(ts[-1], f(ts[-1]))
plt.plot (ts_cont, p52(ts_cont), ts_cont, [p_bary(t) for t in ts_cont])

print ("04 ----------------------------")

print ("")

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


"""
  Question 5: Poisson 2D with Conjugate Gradient
"""
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import pathlib
#%%
# Functions to use
p = lambda x, y: np.cos(x + y) * np.sin(x - y) # Analytic solution
f = lambda x, y: -4 * p(x, y) # RHS

# Conjugate gradient implementation
def ConjugateGradient(A, b, x, conv=1e-6):
  r = b - np.dot(A, x)
  p = r
  while np.linalg.norm(r) > conv: # Convergence criteria
    a = np.dot(p.T, r) / (np.dot(p.T, np.dot(A, r)))
    x = x + a * p
    r = r - a * np.dot(A, p)
    b = - np.dot(p.T, np.dot(A, r)) / np.dot(np.dot(A, p).T, p)
    p = r + b * p

  return x

# Create A and b
def createSystem(Nx, Ny, h, F, P):
  # Create A matrix
  A = np.zeros(((Nx-1)*(Ny-1), (Nx-1)*(Ny-1)))
  I = np.eye(Nx-1, Ny-1) # Identity matrix
  D = np.zeros((Nx-1, Ny-1)) # For 5 points stencil matrix
  np.fill_diagonal(D[1:], 1) # Lower diagonal
  D += D.T # Upper diagonal
  np.fill_diagonal(D, -4) # Main diagonal
  # Fill A matrix
  # Upper block
  A[:Nx-1,:Ny-1] = D
  A[:Nx-1,Ny-1:2*(Ny-1)] = I
  # Lower block
  A[-(Nx-1):,-(Ny-1):] = D
  A[-(Nx-1):,-2*(Ny-1):-(Ny-1)] = I
  # Inner blocks
  for i in range(1, Nx-2):
    A[i*(Nx-1):(i+1)*(Nx-1),i*(Ny-1):(i+1)*(Ny-1)] = D
    A[i*(Nx-1):(i+1)*(Nx-1),(i-1)*(Ny-1):i*(Ny-1)] = I
    A[i*(Nx-1):(i+1)*(Nx-1),(i+1)*(Ny-1):(i+2)*(Ny-1)] = I

  # Create b vector
  B = h**2 * F[1:-1,1:-1] # Inside
  B[0] += P[0,1:-1] # South boundary
  B[-1] += P[-1,1:-1] # North boundary
  B[:,0] += P[1:-1,0] # West boundary
  B[:,-1] += P[1:-1,-1] # East boundary

  b = B.flatten('F') # Flatten column-major order (vectorization)

  return A, b

# Experiment
def experiment(h):
  Nx, Ny = int(1/h), int(1/h)

  # Grid definition
  x = np.linspace(0, 1, Nx + 1)
  y = np.linspace(0, 1, Ny + 1)

  # Grid to evaluate
  X, Y = np.meshgrid(x, y)

  F = f(X, Y) # RHS evaluation
  P = p(X, Y) # For boundary conditions

  # Build A and b
  A, b = createSystem(Nx, Ny, h, F, P)
  x0 = np.zeros(len(b)) # Initial guess

  # Solve
  u = ConjugateGradient(A, b, x0)

  # Numerical solution
  U = np.copy(P) # Boundary
  U[1:-1,1:-1] = u.reshape((Nx-1), (Ny-1)) # Approximation of interior points

  return X, Y, U, P

# 2D plot
def plot2D(x, y, u):
  plt.contourf(x, y, u)
  plt.colorbar()
  plt.show()

#%% Experiments
X1, Y1, U1, P1 = experiment(0.1)
X2, Y2, U2, P2 = experiment(0.05)
X3, Y3, U3, P3 = experiment(0.025)
#%% Plots
print("h=0.1")
plot2D(X1, Y1, U1)
plot2D(X1, Y1, P1)
plot2D(X1, Y1, np.abs(U1-P1)) # "Error"

#%%
print("h=0.05")
plot2D(X2, Y2, U2)
plot2D(X2, Y2, P2)
plot2D(X2, Y2, np.abs(U2 - P2))

#%%
print("h=0.025")
plot2D(X3, Y3, U3)
plot2D(X3, Y3, P3)
plot2D(X3, Y3, np.abs(U3-P3))

#%% Error
e1 = np.linalg.norm((U1-P1).flatten(), np.inf)
e2 = np.linalg.norm((U2-P2).flatten(), np.inf)
e3 = np.linalg.norm((U3-P3).flatten(), np.inf)

print("Error for each h")
print(e1, e2, e3)

#%% Structures to save
M1, N1 = U1.shape
M2, N2 = U2.shape
M3, N3 = U3.shape

U1f = np.zeros((M1 * N1, 3)); U1f[:,0] = X1.flatten(); U1f[:,1] = Y1.flatten(); U1f[:,2] = U1.flatten()
U2f = np.zeros((M2 * N2, 3)); U2f[:,0] = X2.flatten(); U2f[:,1] = Y2.flatten(); U2f[:,2] = U2.flatten()
U3f = np.zeros((M3 * N3, 3)); U3f[:,0] = X3.flatten(); U3f[:,1] = Y3.flatten(); U3f[:,2] = U3.flatten()
E1f = np.zeros((M1 * N1, 3)); E1f[:,0] = X1.flatten(); E1f[:,1] = Y1.flatten(); E1f[:,2] = np.abs(U1-P1).flatten()
E2f = np.zeros((M2 * N2, 3)); E2f[:,0] = X2.flatten(); E2f[:,1] = Y2.flatten(); E2f[:,2] = np.abs(U2-P2).flatten()
E3f = np.zeros((M3 * N3, 3)); E3f[:,0] = X3.flatten(); E3f[:,1] = Y3.flatten(); E3f[:,2] = np.abs(U3-P3).flatten()

#%% Save data
DIR = 'data/5/b/'
pathlib.Path(DIR).mkdir(parents=True, exist_ok=True) # Create Folder
# Write files
np.savetxt(DIR + 'U1.csv', U1f, fmt='%.8f', delimiter=' ')
np.savetxt(DIR + 'U2.csv', U2f, fmt='%.8f', delimiter=' ')
np.savetxt(DIR + 'U3.csv', U3f, fmt='%.8f', delimiter=' ')
np.savetxt(DIR + 'E1.csv', E1f, fmt='%.8f', delimiter=' ')
np.savetxt(DIR + 'E2.csv', E2f, fmt='%.8f', delimiter=' ')
np.savetxt(DIR + 'E3.csv', E3f, fmt='%.8f', delimiter=' ')


"""
Computing pi with parallel quadrature formula
"""
import numpy
from mpi4py import MPI
import sys
import random

comm = MPI.COMM_WORLD
mynode = comm.Get_rank()
totalnodes = comm.Get_size()

truepi = 3.141592653589793238462643
dest = 0
pi = numpy.zeros(1)

# Initialize value of n only if this is rank 0
# we are not checking the input, if the user does something that
# has no meaning we are going to fail badly!
if mynode == 0:
    if len(sys.argv) == 1:
        n = numpy.full(1, 20, dtype=int) # default value
    else:
        n = numpy.full(1,int(sys.argv[1]),dtype=int)
else:
    n = numpy.zeros(1, dtype=int)

# Broadcast n to all processes
comm.Bcast(n, root=0)

# Compute local quantities
h  = 2.0 / totalnodes
x1 = -1.0 + mynode * h
x2 = x1 + h
y1 = -1.0
y2 = 1.0
my_SqPoints  = numpy.zeros(1, dtype=int)
my_CiPoints  = numpy.zeros(1, dtype=int)

for i in numpy.arange(1,n+1,totalnodes):
    x = random.random()
    x = x1 + x*(x2-x1)
    y = random.random()
    y = y1 + y*(y2-y1)
    my_SqPoints = my_SqPoints + 1
    if ( x**2 + y**2 <= 1.0 ):
        my_CiPoints = my_CiPoints + 1

SqPoints = numpy.zeros(1, dtype=int)
CiPoints = numpy.zeros(1, dtype=int)

# Send back to the root process the data
comm.Reduce(my_SqPoints, SqPoints, MPI.SUM, dest)
comm.Reduce(my_CiPoints, CiPoints, MPI.SUM, dest)

# Only print the result in process 0
if mynode == 0:
    pi = 4.0*float(CiPoints)/float(SqPoints)
    print('The Integral Sum =', pi," The Error is ",numpy.abs(pi-truepi))


# -*- coding: utf-8 -*-
"""K-Means Clustering.ipynb

Automatically generated by Colaboratory.

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

*Some contents of this notebook is from the [Python Data Science Handbook](http://shop.oreilly.com/product/0636920034919.do) by Jake VanderPlas*

# K-Means Clustering

Clustering algorithms seek to learn, from the properties of the data, an optimal division or discrete labeling of groups of points.

Many clustering algorithms are available in Scikit-Learn and elsewhere, but perhaps the simplest to understand is an algorithm known as *k-means clustering*, which is implemented in ``sklearn.cluster.KMeans``.
"""

# Commented out IPython magic to ensure Python compatibility.
# %matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()  # for plot styling
import numpy as np

"""## Understanding k-Means

The *k*-means algorithm searches for a pre-determined number of clusters within an unlabeled multidimensional dataset.
It accomplishes this using a simple conception of what the optimal clustering looks like:

- The "cluster center" is the arithmetic mean of all the points belonging to the cluster.
- Each point is closer to its own cluster center than to other cluster centers.

Those two assumptions are the basis of the *k*-means model.
We will soon dive into exactly *how* the algorithm reaches this solution, but for now let's take a look at a simple dataset and see the *k*-means result.

First, let's generate a two-dimensional dataset containing four distinct blobs.
To emphasize that this is an unsupervised algorithm, we will leave the labels out of the visualization
"""

from sklearn.datasets.samples_generator import make_blobs
X, y_true = make_blobs(n_samples=300, centers=4,
                       cluster_std=0.60, random_state=0)
plt.scatter(X[:, 0], X[:, 1], s=50);

X[:5]

"""Scalling the features"""

from sklearn.preprocessing import StandardScaler

data_scaler = StandardScaler()
X = data_scaler.fit_transform(X)
X[:5]

"""By eye, it is relatively easy to pick out the four clusters.
The *k*-means algorithm does this automatically, and in Scikit-Learn uses the typical estimator API:
"""

from sklearn.cluster import KMeans

kmeans = KMeans(n_clusters=4)
kmeans.fit(X)

y_kmeans = kmeans.predict(X)

# The lowest Sum Squared Error (SSE) value
print(kmeans.inertia_)

# The number of iterations required to converge
kmeans.n_iter_

"""Let's visualize the results by plotting the data colored by these labels.
We will also plot the cluster centers as determined by the *k*-means estimator:
"""

plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, s=50, cmap='viridis')

# plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, s=50, cmap='viridis')
centers = kmeans.cluster_centers_
plt.scatter(centers[:, 0], centers[:, 1], c='black', s=200, alpha=0.5);

plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, s=50, cmap='viridis')
centers = kmeans.cluster_centers_
plt.scatter(centers[:, 0], centers[:, 1], c='black', s=200, alpha=0.5);

"""## k-Means Algorithm: Expectation–Maximization

Expectation–Maximization (E–M) is a powerful algorithm that comes up in a variety of contexts within data science.
*k*-means is a particularly simple and easy-to-understand application of the algorithm, and we will walk through it briefly here.
In short, the expectation–maximization approach here consists of the following procedure:

1. Guess some cluster centers
2. Repeat until converged
   1. *E-Step*: assign points to the nearest cluster center
   2. *M-Step*: set the cluster centers to the mean

Here the "E-step" or "Expectation step" is so-named because it involves updating our expectation of which cluster each point belongs to.
The "M-step" or "Maximization step" is so-named because it involves maximizing some fitness function that defines the location of the cluster centers—in this case, that maximization is accomplished by taking a simple mean of the data in each cluster.

The literature about this algorithm is vast, but can be summarized as follows: under typical circumstances, each repetition of the E-step and M-step will always result in a better estimate of the cluster characteristics.

We can visualize the algorithm as shown in the following figure.
For the particular initialization shown here, the clusters converge in just three iterations.
For an interactive version of this figure, refer to the code in [the Appendix](06.00-Figure-Code.ipynb#Interactive-K-Means).

![(run code in Appendix to generate image)](https://github.com/jakevdp/PythonDataScienceHandbook/blob/master/notebooks/figures/05.11-expectation-maximization.png?raw=1)
[figure source in Appendix](06.00-Figure-Code.ipynb#Expectation-Maximization)

The *k*-Means algorithm is simple enough that we can write it in a few lines of code.
The following is a very basic implementation:
"""

from sklearn.metrics import pairwise_distances_argmin

def find_clusters(X, n_clusters, rseed=2):
    # 1. Randomly choose clusters
    rng = np.random.RandomState(rseed)
    i = rng.permutation(X.shape[0])[:n_clusters]
    centers = X[i]

    while True:
        # 2a. Assign labels based on closest center
        labels = pairwise_distances_argmin(X, centers)

        # 2b. Find new centers from means of points
        new_centers = np.array([X[labels == i].mean(0)
                                for i in range(n_clusters)])

        # 2c. Check for convergence
        if np.all(centers == new_centers):
            break
        centers = new_centers

    return centers, labels

centers, labels = find_clusters(X, 4)
plt.scatter(X[:, 0], X[:, 1], c=labels,
            s=50, cmap='viridis');

"""### Caveats of expectation–maximization

There are a few drawbacks to be aware of k-means algorithm.

#### The globally optimal result may not be achieved
First, although the E–M procedure is guaranteed to improve the result in each step, there is no assurance that it will lead to the *global* best solution.
For example, if we use a different random seed in our simple procedure, the particular starting guesses lead to poor results:
"""

centers, labels = find_clusters(X, 4, rseed=0)
plt.scatter(X[:, 0], X[:, 1], c=labels, s=50, cmap='viridis');
plt.scatter(centers[:, 0], centers[:, 1], c='black', s=200, alpha=0.5);

"""Here the E–M approach has converged, but has not converged to a globally optimal configuration. For this reason, it is common for the algorithm to be run for multiple starting guesses, as indeed Scikit-Learn does by default (set by the ``n_init`` parameter, which defaults to 10).

#### The number of clusters must be selected beforehand
Another common challenge with *k*-means is that you must tell it how many clusters you expect: it cannot learn the number of clusters from the data.
For example, if we ask the algorithm to identify six clusters, it will happily proceed and find the best six clusters:
"""

labels = KMeans(6, random_state=0).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=labels,
            s=50, cmap='viridis');

"""#### Choosing the Appropriate Number of Clusters
In this section, you’ll look at two methods that are commonly used to evaluate the appropriate number of clusters:

* The elbow method
* The silhouette coefficient

These are often used as complementary evaluation techniques rather than one being preferred over the other. To perform the elbow method, run several k-means, increment k with each iteration, and record the SSE:

**Elbow method**
"""

kmeans_kwargs = {
    "init": "random",
    "n_init": 10,
    "max_iter": 30,
    "random_state": 42,
}

# A list holds the SSE values for each k
sse = []
for k in range(1, 11):
    kmeans = KMeans(n_clusters=k, **kmeans_kwargs)
    kmeans.fit(X)
    sse.append(kmeans.inertia_)

plt.style.use("fivethirtyeight")
plt.plot(range(1, 11), sse)
plt.xticks(range(1, 11))
plt.xlabel("Number of Clusters")
plt.ylabel("SSE")
plt.show()

"""##### Silhouette Coefficient
The silhouette coefficient is a measure of cluster cohesion and separation. It quantifies how well a data point fits into its assigned cluster based on two factors:

* How close the data point is to other points in the cluster
* How far away the data point is from points in other clusters

Silhouette coefficient values range between -1 and 1. Larger numbers indicate that samples are closer to their clusters than they are to other clusters.
"""

from sklearn.metrics import silhouette_score

# A list holds the silhouette coefficients for each k
silhouette_coefficients = []

# Notice you start at 2 clusters for silhouette coefficient
for k in range(2, 11):
    kmeans = KMeans(n_clusters=k, **kmeans_kwargs)
    kmeans.fit(X)
    score = silhouette_score(X, kmeans.labels_)
    silhouette_coefficients.append(score)

plt.style.use("fivethirtyeight")
plt.plot(range(2, 11), silhouette_coefficients)
plt.xticks(range(2, 11))
plt.xlabel("Number of Clusters")
plt.ylabel("Silhouette Coefficient")
plt.show()

"""#### k-means is limited to linear cluster boundaries
The fundamental model assumptions of *k*-means (points will be closer to their own cluster center than to others) means that the algorithm will often be ineffective if the clusters have complicated geometries.

In particular, the boundaries between *k*-means clusters will always be linear, which means that it will fail for more complicated boundaries.
Consider the following data, along with the cluster labels found by the typical *k*-means approach:
"""

from sklearn.datasets import make_moons
X, y = make_moons(200, noise=.05, random_state=0)
plt.scatter(X[:, 0], X[:, 1], s=50);

labels = KMeans(2, random_state=0).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=labels,
            s=50, cmap='viridis');

"""#### Density-Based Spatial Clustering of Applications with Noise (DBSCAN)
DBSCAN works based on the idea that a cluster in data space is a contiguous region of high point density, separated from other such clusters by contiguous regions of low point density.

The DBSCAN algorithm uses two parameters:

* min_samples: The minimum number of points (a threshold) clustered together for a region to be considered dense.
* eps (ε): A distance measure that will be used to locate the points in the neighborhood of any point.
"""

from sklearn.cluster import DBSCAN

kmeans = KMeans(n_clusters=2)
dbscan = DBSCAN(eps=0.3, min_samples=3)

kmeans.fit(X)
dbscan.fit(X)

# Compute the silhouette scores for each algorithm
kmeans_silhouette = silhouette_score(
    X, kmeans.labels_
).round(2)

dbscan_silhouette = silhouette_score(
   X, dbscan.labels_
).round(2)

print(kmeans_silhouette, dbscan_silhouette)

# Plot the data and cluster silhouette comparison
fig, (ax1, ax2) = plt.subplots(
    1, 2, figsize=(8, 6), sharex=True, sharey=True
)
fig.suptitle(f"Clustering Algorithm Comparison: Crescents", fontsize=16)
fte_colors = {
    0: "#008fd5",
    1: "#fc4f30",
}
# The k-means plot
# km_colors = [fte_colors[label] for label in kmeans.labels_]
ax1.scatter(X[:, 0], X[:, 1], c=kmeans.labels_, s=50, cmap='viridis')
ax1.set_title(
    f"k-means\nSilhouette: {kmeans_silhouette}", fontdict={"fontsize": 12}
)

# The dbscan plot,
# db_colors = [fte_colors[label] for label in dbscan.labels_]
ax2.scatter(X[:, 0], X[:, 1], c=dbscan.labels_, s=50, cmap='viridis')
ax2.set_title(
    f"DBSCAN\nSilhouette: {dbscan_silhouette}", fontdict={"fontsize": 12}
)
plt.show()

"""##### Evaluating Clusters
Since the ground truth labels are known, it’s possible to use a clustering metric that considers labels in its evaluation. You can use the scikit-learn implementation of a common metric called the adjusted rand index (ARI). Unlike the silhouette coefficient, the ARI uses true cluster assignments to measure the similarity between true and predicted labels.
"""

from sklearn.metrics import adjusted_rand_score

ari_kmeans = adjusted_rand_score(y, kmeans.labels_)
ari_dbscan = adjusted_rand_score(y, dbscan.labels_)
print(ari_kmeans, ari_dbscan)

"""#### k-means can be slow for large numbers of samples
Because each iteration of *k*-means must access every point in the dataset, the algorithm can be relatively slow as the number of samples grows.

## Example

Being careful about these limitations of the algorithm, we can use *k*-means to our advantage in a wide variety of situations.
We'll now take a look at a couple examples.

### Example: k-means on digits

To start, let's take a look at applying *k*-means on the same simple digits data.
Here we will attempt to use *k*-means to try to identify similar digits *without using the original label information*.

We will start by loading the digits and then finding the ``KMeans`` clusters.
"digits" dataset consist of 1,797 samples with 64 features, where each of the 64 features is the brightness of one pixel in an 8×8 image:
"""

from sklearn.datasets import load_digits
digits = load_digits()
digits.data.shape

"""The clustering can be performed as we did before:"""

kmeans = KMeans(n_clusters=10, random_state=0)
clusters = kmeans.fit_predict(digits.data)
print(kmeans.cluster_centers_.shape)
kmeans.cluster_centers_[0]

"""The result is 10 clusters in 64 dimensions.
Notice that the cluster centers themselves are 64-dimensional points, and can themselves be interpreted as the "typical" digit within the cluster.
Let's see what these cluster centers look like:
"""

fig, ax = plt.subplots(2, 5, figsize=(8, 3))
centers = kmeans.cluster_centers_.reshape(10, 8, 8)
for axi, center in zip(ax.flat, centers):
    axi.set(xticks=[], yticks=[])
    axi.imshow(center, interpolation='nearest', cmap=plt.cm.binary)

"""We see that *even without the labels*, ``KMeans`` is able to find clusters whose centers are recognizable digits, with perhaps the exception of 1 and 8.

Because *k*-means knows nothing about the identity of the cluster, the 0–9 labels may be permuted.
We can fix this by matching each learned cluster label with the true labels found in them:
"""

from scipy.stats import mode

labels = np.zeros_like(clusters)
for i in range(10):
    mask = (clusters == i)
    labels[mask] = mode(digits.target[mask])[0]

"""Now we can check how accurate our unsupervised clustering was in finding similar digits within the data:"""

from sklearn.metrics import accuracy_score
accuracy_score(digits.target, labels)

"""With just a simple *k*-means algorithm, we discovered the correct grouping for 80% of the input digits!
Let's check the confusion matrix for this:
"""

from sklearn.metrics import confusion_matrix
mat = confusion_matrix(digits.target, labels)
sns.heatmap(mat.T, square=True, annot=True, fmt='d', cbar=False,
            xticklabels=digits.target_names,
            yticklabels=digits.target_names)
plt.xlabel('true label')
plt.ylabel('predicted label');

"""As we might expect from the cluster centers we visualized before, the main point of confusion is between the eights and ones.
But this still shows that using *k*-means, we can essentially build a digit classifier *without reference to any known labels*!

t-SNE is a nonlinear embedding algorithm that is particularly adept at preserving points within clusters.
Let's see how it does:
"""

from sklearn.manifold import TSNE

# Project the data: this step will take several seconds
tsne = TSNE(n_components=2, init='random', random_state=0)
digits_proj = tsne.fit_transform(digits.data)

# Compute the clusters
kmeans = KMeans(n_clusters=10, random_state=0)
clusters = kmeans.fit_predict(digits_proj)

# Permute the labels
labels = np.zeros_like(clusters)
for i in range(10):
    mask = (clusters == i)
    labels[mask] = mode(digits.target[mask])[0]

# Compute the accuracy
accuracy_score(digits.target, labels)

"""That's nearly 93+% classification accuracy *without using the labels*."""


## Speed Comparison ##

# This test is to compare how much faster numpy is compared to python lists, in terms of the dot product
# calculated the dot product using both methods 100,000 times, and then prints the ratio of time
import numpy as np
from datetime import datetime

# note: you can also use %timeit

a = np.random.randn(100)
b = np.random.randn(100)
T = 100000

def slow_dot_product(a, b):
  result = 0
  for e, f in zip(a, b):
    result += e*f
  return result

t0 = datetime.now()
for t in range(T):
  slow_dot_product(a, b)
dt1 = datetime.now() - t0

t0 = datetime.now()
for t in range(T):
  a.dot(b)
dt2 = datetime.now() - t0

print("Time for slow method:", dt1.total_seconds())
print("Time for fast method:", dt2.total_seconds())
print("(slow / fast) Factor:", dt1.total_seconds() / dt2.total_seconds())


import matplotlib
import matplotlib.pyplot as plt

import numpy as np

from skimage import io
import os

import math

image = io.imread(os.getcwd() + '/Ejercicio-4/Img/ruido04.jpg', as_gray=True)

print(image.shape)

transform = np.fft.rfft2(image)

transformM = np.abs(transform).astype('float64')

m = 1/(transformM.min() - transformM.max())
b = 1-m*transformM.min()

for i in range(0, transformM.shape[0]):
    for j in range(0, transformM.shape[1]):
        transformM[i,j] *= m
        transformM[i,j] += b
# transformP = np.angle(transform)

def lowPass2D(x, y, w0):
    return w0/(w0 + 1j*(x**2 + y**2)**0.5)

def highPass2D(x, y, w0):
    return -(1j*(x**2 + y**2)**0.5)/(w0 + 1j*(x**2 + y**2)**0.5)

shape = transform.shape

transform1 = transform.copy()
for i in range(0, shape[0]):
    for j in range(0, shape[1]):
        transform1[i,j] *= lowPass2D(i,j,20)

filterImg1 = np.fft.irfft2(transform1)

transform2 = transform.copy()
for i in range(0, shape[0]):
    for j in range(0, shape[1]):
        transform2[i,j] *= highPass2D(i,j,1)

filterImg2 = np.fft.irfft2(transform2)

transform3 = transform.copy()
for i in range(0, shape[0]):
    for j in range(0, shape[1]):
        transform3[i,j] *= lowPass2D(i,0,20)

filterImg3 = np.fft.irfft2(transform3)

transform4 = transform.copy()
for i in range(0, shape[0]):
    for j in range(0, shape[1]):
        transform4[i,j] *= highPass2D(0,j,1)

filterImg4 = np.fft.irfft2(transform4)

fig, ax = plt.subplots(1, 1)
ax.imshow(image, cmap=plt.cm.gray)
ax.set_title('Original')
ax.axis('off')

fig1, ax1 = plt.subplots(1, 1)
ax1.imshow(transformM, cmap=plt.cm.gray)
ax1.set_title('Transformada de Fourier')
plt.xlim(0,50)
plt.ylim(0,50)

fig2, ax2 = plt.subplots(1, 1)
ax2.imshow(filterImg1, cmap=plt.cm.gray)
ax2.set_title('Filtro Pasa Bajas')
ax2.axis('off')

fig3, ax3 = plt.subplots(1, 1)
ax3.imshow(filterImg2, cmap=plt.cm.gray)
ax3.set_title('Filtro Pasa Altas')
ax3.axis('off')

fig4, ax4 = plt.subplots(1, 1)
ax4.imshow(filterImg3, cmap=plt.cm.gray)
ax4.set_title('Filtro Pasa Bajas Vertical')
ax4.axis('off')

fig5, ax5 = plt.subplots(1, 1)
ax5.imshow(filterImg4, cmap=plt.cm.gray)
ax5.set_title('Filtro Pasa Altas Horizontal')
ax5.axis('off')

fig1, ax1 = plt.subplots(1, 1)
ax1.hist(image.ravel(), bins=256, histtype='step', color='black', density=True)
ax1.set_title('Histograma Original')

plt.show()


import numpy as np
import math
from timeit import default_timer as timer

#the function image
def f(x,y):
    return 100*(y-x**2)**2+(1-x)**2

#The gradient of the function
def gradf(x,y):
	gx=400*x**3+x*(2-400*y)-2
	gy=200*(y-x**2)
	return np.array([gx,gy])

#hessian of the function
def hessian(x,y):
	fxx=-400*(y-x**2)+800*x**2+2
	fyy=200
	fxy=-400*x
	H=np.array([[fxx,fxy],[fxy,fyy]])
	return H

#lambda times identity function
def landaI(l,dim):
	I=np.zeros((dim,dim))
	for i in range(dim):
		for j in range(dim):
			if i==j:
				I[i,j]=l
	return I

#inverse of a 2x2 matrix
def inverse(A):
	copy=np.zeros((2,2))
	posd=1
	negd=1
	for i in range(0,2):
		for j in range(0,2):
			if i!=j:
				copy[i,j]=-A[i,j]
				negd=negd*A[i,j]
			if i==j:
				copy[i,j]=A[i-1,j-1]
				posd=posd*A[i,j]
	detA=posd-negd
	return 1/(detA)*copy

#product of a matrix times a vector
def prod(A,v):
	result=np.zeros(2)
	for i in range(0,2):
		for j in range(0,2):
			result[i]=result[i]+(A[i,j]*v[j])
	return result

#step function of LM method
def s(x,y,la):
	H=hessian(x,y)
	lambdaI=landaI(la,2)
	grad=gradf(x,y)
	suma=H+lambdaI
	inv=inverse(suma)
	return -prod(inv,grad)

#main function or Levenberg-Marquardt algorithm
def LVMD(xin,yin,e,Lambda):
	#setting the initial conditions
	start = timer()
	finish=False
	maxiter=int(1e4)
	points=np.zeros((maxiter+2,2))
	posx=xin
	posy=yin
	i=0

	while finish==False:
		#saving points in a point array
		points[i,0]=posx
		points[i,1]=posy

		#step
		sx,sy=s(posx,posy,Lambda)
		xnew=posx+sx
		ynew=posy+sy

		#extra calculations for the termination condition
		newgrad=gradf(xnew,ynew)
		diff=np.sqrt((newgrad[0])**2+(newgrad[1])**2)
		fnew=f(xnew,ynew)
		fold=f(posx,posy)

		#landa updating
		if fnew<fold:
			Lambda=Lambda/2
		elif fold<fnew:
			Lambda=2*Lambda

		if diff<e or i>maxiter:
			finish=True

		#updating variables
		i=i+1
		posx=xnew
		posy=ynew

	#some performance calculations
	end = timer()
	t=end-start
	print("Algorithm finished with",i,"iterations and a time of ",t,"seconds", "\nthe final point is (",posx,posy,")")
	return i,t,points

a,ti,pointv=LVMD(-1.5,-1,1e-9,0.001)
#uncomment this last two lines to get the points and a csv with the points of the algorithm
print(pointv)
np.savetxt("pointsLVMD.csv",pointv,delimiter=",")


import math
from typing import Optional

import numpy as np

# modified from https://stackoverflow.com/questions/34372480/
def rotate_points(px, py, origin, angle):
    """
    Rotate points counterclockwise by a given angle around a given origin.

    The angle should be given in degrees.
    """
    angle = math.radians(angle)
    ox, oy = origin

    qx = ox + np.cos(angle) * (px - ox) - np.sin(angle) * (py - oy)
    qy = oy + np.sin(angle) * (px - ox) + np.cos(angle) * (py - oy)
    return qx, qy

def normalize(arr: np.ndarray,
              vmin: Optional[float] = None,
              vmax:  Optional[float] = None,
              ):
    if (vmin is None) & (vmax is None):
        return arr

    amin = np.amin(arr)
    amax = np.amax(arr)
    narr = (arr - amin) / (amax - amin)
    vmin = 0 if vmin is None else vmin
    vmax = 1 if vmax is None else vmax
    return narr * (vmax - vmin) + vmin


# variance
"""
Variance is another number that indicates how spread out the values are.
In fact, if you take the square root of the variance,
you get the standard deviation.
Or the other way around, if you multiply the standard deviation by itself, you get the variance.
To calculate the variance, you have to do as follows.
1. Find the mean.
2. For each value: find the difference from the mean.
3. For each difference: find the square value.
4. The variance is the average number of these squared differences.
"""
# but you can user var() of numpy to find the variance.

import numpy as np

speed = np.array([32,111,138,28,59,77,97])

x = np.var(speed)

print("The variance: ", x)


import scipy.constants as s_const
from math import pi
#In condensed matter physics, the Madelung constant gives the total electric potential felt by an atom in a solid.
#In this program, we will use the sodium chloride wich is arranged in a cubic lattice. The vertexes of the cube alternate
#positive to negative with the same charge e. If we give each vertex three coordinates, then the sodium atoms will fall
# where j+k+i is even. The chloride atoms will fall where i+j+k is odd.

#We also know that the Madelung constant is equal to the summation of of the potential energy of all the atoms in the
#lattice divided by  (4*pi*epsilon_0)*the spacing of the lattice.
#The potential enery of a charge is Q/4*pi*epsilon*r with r being the distance between the atom and the origin.
#The summation domain is from one end of the cube to the other excluding the origin.
e = s_const.elementary_charge #absolute value of electron charge
epsilon_0 = s_const.epsilon_0 # permittivity of vacuum
L = 600 #1/2 the width of the cube
a =1 #spacing of the atoms
V_tot = 0 #initial potential energy
# This works but the O^3 iteration is a bummer. I think if I let it sit at L= 1000 my computer will die
for i in range(-L,L+1):
    for j in range(-L,L+1):
        for k in range(-L,L+1):
            if (i == 0 or j==0 or k==0):
                V_tot +=0
            elif ((i+j+k)%2 == 0):
                V_tot += e/(4*pi*epsilon_0*a*((i**2)+(j**2)+(k**2))**0.5)
            else:
                V_tot -= e/(4 * pi * epsilon_0 * a * ((i ** 2) + (j ** 2) + (k ** 2))**0.5)
print((V_tot*(4 * pi * epsilon_0 * a ))/e)


from statistics import mean
import numpy as np

class LSR:

    def __init__(self):
        self.slope = 0 #This represents the slope of our regression
        self.intercept = 0 #This represents the intercept of our regression
        self.r_squared = 0 #This represents the r^2 squared of our regression

    def Model(self, x, y):
        temp_x = np.array(x, dtype=np.float64) #numpy array of our x values
        temp_y = np.array(y, dtype=np.float64) #numpy array of our y values
        if(temp_x.shape == temp_y.shape):
            self.slope = ( ((mean(temp_x) * mean(temp_y)) - mean(temp_x * temp_y))/((mean(temp_x)*mean(temp_x)) - mean(temp_x*temp_x)) )
            self.intercept = mean(temp_y) - (self.slope * mean(temp_x))
            temp_y_approx = self.slope*temp_x + self.intercept
            self.r_squared = 1 - ( (np.sum((temp_y - temp_y_approx)**2))/(np.sum((temp_y - mean(temp_y))**2)) )
            print("Slope: ", self.slope)
            print("Offset: ", self.intercept)
            print("R^2 Squared: ", self.r_squared)
            del temp_x, temp_y, temp_y_approx
        else:
            print("X and Y are not the same shape")


import numpy as np

# axis 0 = selecting elements in vertical direction
# axis 1 = selecting elements in horizontal direction

a = np.linspace(1, 5, 4)          # gives 4 values between 1 to 5 with equal distance
print(a)

b = np.empty(shape=(2, 4))        # gives empty 2 arrays with 4 elements in each with random numbers in it
print(b)

c = np.empty_like(a)             # copying shape of other array
print(c)

d = np.identity(3)                # create 3*3 shape array
print(d)

e = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(e.T)                    # transverse elements from row to column and column to row

f = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(f.flatten())                            # gives iterator for iteration of array

g = np.array([1, 2, 3, 4, 6, 7, 35, 2, 2, 45, 34, 2, 43, 46])
print(g.argmin())                            # to find index of minimum values from array
print(g.argmax())                            # to find index of maximum values from array
print(g.argsort())                           # find indexes to sort the array

h = np.array([1, 2, 3, 4, 5])
i = np.array([1, 4, 9, 16, 25])
print(h + i)                       # also can other arithmetic operations like divide, subtract, addition
print(np.square(h))                # to square elements of array
print(np.sqrt(i))                  # for square root of elements in array

Python/Numpy/numpy 44 - code with harray.py


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

# right hand side of linear sde model equation dX = aX dt + bX dW
# returns deterministic and stochastic part of right hand side
def linearSDE (X, t):

    # model parameters
    a = 5.0
    b = 1.0

    f_det   = np.array([a * X])
    f_stoch = np.array([b * X])

    return (f_det, f_stoch)

# returns analytic solution to linear sde dX = aX dt + bX dW
def X_analytic (t, Wt):

    # model parameters
    a  = 5.0
    b  = 1.0

    # initial state
    x0 = 1.0

    return (x0 * np.exp((a - np.power(b, 2) / 2.0) * t + b * Wt))

# returns time vector and numerical solution of sde
def numInt (x0, Ttrans, Teval, dt, sqrt_dt, Ito_dt, method):

    s       = solver.SDE_Solver()
    time, X = s.solveSDE(linearSDE, x0, Ttrans, Teval, dt, 1, method)
    X       = X[0, :]

    return (time, X)

# plots time series for a single realization
def plotSingle ():

    # initial state
    x0 = 1.0

    # parameters for numerical integration
    Ttrans  = 0.0
    Teval   = 1.0
    dt      = 1e-3
    sqrt_dt = np.sqrt(dt)                     # stdev for Wiener process
    Ito_dt  = np.sqrt(np.power(dt, 3) / 3.0)  # stdev for Itô integral
    method  = "explicitStrongOrder1"

    # generate data
    time, X = numInt(x0, Ttrans, Teval, dt, sqrt_dt, Ito_dt, method)

    # plot data
    plt.figure(figsize=(8, 6))
    plt.suptitle("linear sde: time series")
    plt.title(r"$dX_t = aX_t\,dt + bX_t\,dW_t$", fontsize=14)
    plt.plot(time, X)
    plt.xlabel(r"time $t$")
    plt.ylabel(r"$X(t)$")
    plt.grid(color="lightgray")
    plt.show()

# plots averaged time series and global error with respect to the analytic solution
def plotMulti ():

    # initial state
    x0 = 1.0

    # parameters for numerical integration
    Ttrans  = 0.0
    Teval   = 1.0
    dt      = 1e-3
    sqrt_dt = np.sqrt(dt)                     # stdev for Wiener process
    Ito_dt  = np.sqrt(np.power(dt, 3) / 3.0)  # stdev for Itô integral
    nSteps  = int((Ttrans + Teval) / dt)
    nSims   = 10

    # initialize solution arrays
    Wt      = np.zeros((nSteps, nSims))
    Ana     = np.zeros((nSteps, nSims))
    Euler   = np.zeros((nSteps, nSims))
    RuKu    = np.zeros((nSteps, nSims))
    SO1     = np.zeros((nSteps, nSims))
    SO15    = np.zeros((nSteps, nSims))

    # generate gaussian noise for analytic solution through integration
    # of Wiener increments dW
    for i in range(1, nSteps):
        Wt[i, :] = Wt[i-1, :] + np.random.normal(loc=0.0, scale=sqrt_dt, size=nSims)

    # generate data
    for i in range(nSims):

        print(i+1, " of ", nSims, " simulations")

        # generate data
        time, X_Eu   = numInt(x0, Ttrans, Teval, dt, sqrt_dt, Ito_dt, "explicitEulerMaruyama")
        time, X_RuKu = numInt(x0, Ttrans, Teval, dt, sqrt_dt, Ito_dt, "explicitRungeKutta")
        time, X_SO1  = numInt(x0, Ttrans, Teval, dt, sqrt_dt, Ito_dt, "explicitStrongOrder1")
        time, X_SO15 = numInt(x0, Ttrans, Teval, dt, sqrt_dt, Ito_dt, "explicitStrongOrder15")

        Ana[:, i]    = X_analytic(time, Wt[:, i])
        RuKu[:, i]   = X_RuKu
        Euler[:, i]  = X_Eu
        SO1[:, i]    = X_SO1
        SO15[:, i]   = X_SO15

    # calculation of averaged time series
    AnaMean   = np.mean(Ana, axis=1)
    EulerMean = np.mean(Euler, axis=1)
    RuKuMean  = np.mean(RuKu, axis=1)
    SO1Mean   = np.mean(SO1, axis=1)
    SO15Mean  = np.mean(SO15, axis=1)

    # calculation of global deviation from analytic solution
    errEuler  = np.sqrt(np.sum(np.square(AnaMean - EulerMean)))
    errRuKu   = np.sqrt(np.sum(np.square(AnaMean - RuKuMean)))
    errSO1    = np.sqrt(np.sum(np.square(AnaMean - SO1Mean)))
    errSO15   = np.sqrt(np.sum(np.square(AnaMean - SO15Mean)))

    # plot data
    plt.figure(figsize=(12, 9))
    plt.suptitle("linear sde: averaged time series for " + str(nSims) + " simulations, " + "dt = " + str(dt))
    plt.title(r"$dX_t = aX_t\,dt + bX_t\,dW_t$", fontsize=14)

    #~ for i in range(nSims):
        #~ plt.plot(time, Ana[:, i], color="blue", alpha=0.05)
        #~ plt.plot(time, Euler[:, i], color="orange", alpha=0.05)
        #~ plt.plot(time, SO1[:, i], color="green", alpha=0.05)
        #~ plt.plot(time, SO15[:, i], color="red", alpha=0.05)

    plt.plot(time, AnaMean, color="darkblue", label=r"analytic: $X_t = X_0\,\exp[(a - 0.5\,b^2)t + b\,W_t]$")
    plt.plot(time, EulerMean, color="darkorange", label="Euler-Maruyama, rms = " + str(errEuler))
    plt.plot(time, RuKuMean, color="purple", label="Runge-Kutta, rms = " + str(errRuKu))
    plt.plot(time, SO1Mean, color="darkgreen", label="strong order 1.0, rms = " + str(errSO1))
    plt.plot(time, SO15Mean, color="darkred", label="strong order 1.5, rms = " + str(errSO15))

    plt.xlabel(r"time $t$")
    plt.ylabel(r"$X(t)$")
    plt.legend(loc="upper left")
    plt.grid(color="lightgray")

    plt.show()

plotSingle()
plotMulti()


from unsupervised_learning.clustering.kernels import GaussianKernel
from sklearn.neighbors import NearestNeighbors
import numpy as np

'''
    Computes affinity matrix using an adjancy matrix with the nearest n_neighbors for each datapoint.
'''
class KnnAffinity():
    def __init__(self, n_neighbors=5):
        self.n_neighbors = n_neighbors;

    def compute(self, X):
        model = NearestNeighbors(n_neighbors=self.n_neighbors).fit(X);
        return model.kneighbors_graph(X).toarray();

'''
    Computes affinity matrix using a radial basis function kernel (such a gaussian kernel) to compute
    the similarity between points.
'''
class BasicAffinity():
    def __init__(self, kernel=GaussianKernel()):
        self.kernel = kernel;

    def compute(self, X):
        m = len(X)
        return np.array([self.kernel.dot(X[i], X[j])
                         for j in range(m) for i in range(m)]).reshape(m, m);

'''
    Computes affinity matrix using a gaussian kernel. The sigma1 and sigma2 are adaptative. They are being
    calculated with the closest neighbors for each point.
'''
class LocalScaling():
    def __init__(self):
        self.kernel = GaussianKernel();

    def compute(self, X):
        m = len(X)
        dists = np.array([np.linalg.norm(X[i] - X[j])
                          for j in range(m) for i in range(m)]).reshape(m, m);
        dists = np.sort(dists);
        sig = dists[:, :5].mean(axis=1);
        return np.array([self.kernel.dot(X[i], X[j], sig[i], sig[j])
                         for j in range(m) for i in range(m)]).reshape(m, m);


import numpy
import csv
import logging
import matplotlib.pyplot as plt
from matplotlib import style
import matplotlib.cm as cm
import random
import time
logging.basicConfig(filename="test.log", level=logging.DEBUG)
style.use('ggplot')

class kMeans:
    '''Initialize K-Means parameters @k - k,@r - number of iterations,@t - tolerance'''

    def __init__(self, k=3, r=10, t=0.0001):
        self.k = k
        self.r = r
        self.t = t
        self.rss = numpy.empty((r, 1))

    '''Cluster data into k clurster.@data - (n_rows,n_features)'''

    def clusterData(self, data):
        self.centroids = {}

        for c in range(self.k):
            randomPoint = random.randrange(1, len(data))
            self.centroids[c] = data[randomPoint]
        # end

        for r in range(self.r):
            self.clusters = {}

            for c in range(self.k):
                self.clusters[c] = []
            # end

            for d in data:
                distances = [numpy.linalg.norm(
                    d - self.centroids[clusterMean]) for clusterMean in self.centroids]
                assignment = distances.index(min(distances))
                self.clusters[assignment].append(d)
            # end
            oldCentroids = dict(self.centroids)
            for c in self.clusters:
                self.centroids[c] = numpy.average(self.clusters[c], axis=0)
            # end
                converged = True

            for centroid in self.centroids:
                old = oldCentroids[centroid]
                current = self.centroids[centroid]
                if numpy.sum((current-old)/old*100) > self.t:
                    converged = False
                # end
            if converged:
                break
            # end
            self.rss[r, 0] = sum(((x - self.centroids[c])**2).sum()
                                 for x, c in zip(data, self.clusters))
        # end
    # end

'''Starting point'''

def main():
    random.seed(time.time())
    print("Loading data set...")
    data = numpy.loadtxt('GMM_dataset.txt', dtype=float)
    km = kMeans(k=5, r=10, t=0.001)
    km.clusterData(data)
    print("K Means Centroids - ", km.centroids)
    print("K Means Sum Of Squared Error - ", km.rss)
    # Plotting starts here
    plt.subplot(121)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.title("K Means Clustering With K = "+str(km.k))
    colors = iter(cm.gist_rainbow(numpy.linspace(0, 1, len(km.clusters))))
    for centroid in km.centroids:
        plt.scatter(km.centroids[centroid][0],
                    km.centroids[centroid][1], color="k", s=100, marker="*")

    for classification in km.clusters:
        color = next(colors)
        for features in km.clusters[classification]:
            plt.scatter(features[0], features[1],
                        color=color, s=10, marker="o")
        # end
    # end
    plt.subplot(122)
    plt.plot(km.rss)
    plt.title("Sum Of Squared Error vs Iterations")
    plt.xlabel("Iterations")
    plt.ylabel("Sum Of Squared Error")
    plt.show()

if __name__ == "__main__":
    main()


import sys
import numpy as np
import math

default_precision = 0.5/100

def BER(M, gamma):
    L = np.sqrt(M)
    k = 2 * (L - 1) / (np.log2(M) * L)
    gamma = np.power(10, gamma / 10)
    arg = np.sqrt(3 * np.log2(M) * gamma / (2*M - 2))
    return k * math.erfc(arg)

def search_ber_qam(target: float, constellation_size: int, precision = default_precision):
    lb = 0
    rb = 100
    mb = lb + (rb - lb) / 2
    delta = 1
    n = 0;

    while(abs(delta) > precision):
        n += 1
        mb = lb + (rb - lb)/2
        B = BER(constellation_size, mb)
        delta = (target - B) / B if B != 0 else 1e6 # Avoid division by infinity
        delta = min(delta, 1e6)
        # print("[{}] T: {} C: {:1.2e} \t({}%) \t({:1.2f} {:1.2f} {:1.2f})".format(n, target, B, int(100*delta), lb, mb, rb))

        if(delta > 0):
            rb = mb
        else:
            lb = mb

    return mb

if __name__ == "__main__":
    if len(sys.argv) < 4:
        print("Usage:\n{} constellation_size target_ber_base target_ber_power [epsilon]".format(sys.argv[0]))
        print("\ni.e:\n{} 16 10 -6 returns the required Eb/No to achieve BER < 10^-6 on a 16 QAM system".format(sys.argv[0]))
        exit()

    M     = int( sys.argv[1] )
    base  = int( sys.argv[2] )
    power = int( sys.argv[3] )

    if( len(sys.argv) == 5 ):
        default_precision = float(sys.argv[4])

    assert( default_precision < 1.0 )
    assert( M > 1 )
    assert( pow(base, power) > 0 )
    target = pow(base, power)
    gamma = search_ber_qam(target, M)
    print("Found BER = {:1.2e} at Eb/No = {:.2f} dB".format(BER(M, gamma), gamma))


from sklearn.preprocessing import StandardScaler
from pandas import read_csv
from numpy import set_printoptions

print('\nStandardize using sklearn')
filename = 'pima-indians-diabetes.data.csv'
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
data_frame = read_csv(filename, names=names)
array = data_frame.values

# Separate array into input and output components
X = array[:, 0:8]
Y = array[:, 8]
scaler = StandardScaler().fit(X)
standardizedX = scaler.transform(X)

# Summarize transformed data
set_printoptions(precision=3)
print(standardizedX[0:5, :])

# -- Standardize from scratch -- #
print('\nStandardize from scratch')
# -- Standardize from scratch -- #
# Calculate data mean and standard deviation
X_mean = X.mean(axis=0)
X_std = X.std(axis=0)

# The values for each attribute now have a mean of 0 and standard deviation of 1
X_scaled = (X - X_mean) / X_std

print(X_scaled[0:5, :])


import numpy as np

def sum_of_squares(params):
    """ Implement Sum of Squared Parameters function.

    Function description: https://www.sfu.ca/~ssurjano/sumsqu.html.

    Args:
        params (pandas.DataFrame): Must have the column "value" containing
        input values for parameters. Accepts arbitrary numbers of input values.

    Returns:
        integer:  Sum of Squared Parameters function output.

    """
    params["multiplier"] = np.arange(1, len(params.index) + 1)
    return (params["multiplier"] * params["value"] ** 2).sum()

def trid(params):
    """ Implement Trid function.

    Function description: https://www.sfu.ca/~ssurjano/trid.html.

    Args:
        params (pandas.DataFrame): Must have the column "value" containing
        input values for parameters. Accepts arbitrary numbers of input values.

    Returns:
        integer:  Trid function output.

    """
    params_np = params["value"].to_numpy()
    return ((params["value"] - 1) ** 2).sum() - (
        params["value"][1:] * params_np[:-1]
    ).sum()

def rotated_hyper_ellipsoid(params):
    """ Implement Rotated Hyper Ellipsoid function.

    Function description: https://www.sfu.ca/~ssurjano/rothyp.html.

    Args:
        params (pandas.DataFrame): Must have the column "value" containing
        input values for parameters. Accepts arbitrary numbers of input values.

    Returns:
        integer: Rotated Hyper Ellipsoid function output.

    """
    val = 0
    for i in range(len(params["value"])):
        val += (params["value"][: i + 1] ** 2).sum()

    return val

def rosenbrock(params):
    """ Implement Rosenbrock function.

    Function description: https://www.sfu.ca/~ssurjano/rosen.html.

    Args:
        params (pandas.DataFrame): Must have the column "value" containing
        input values for parameters. Accepts arbitrary numbers of input values.

    Returns:
        integer:  Rosenbrock function output.

    """
    params_np = params["value"].to_numpy()
    r1 = ((params_np[1:] - params_np[:-1] ** 2) ** 2).sum() * 100
    r2 = ((params_np[:-1] - 1) ** 2).sum()
    return r1 + r2


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

# code starts here
df= pd.read_csv(path)
p_a = df[df['fico'].astype(float) >700].shape[0]/df.shape[0]
p_b = df[df['purpose'] == 'debt_consolidation'].shape[0]/df.shape[0]
df1 = df[df['purpose'] == 'debt_consolidation']
p_a_b = df1[df1['fico'].astype(float) >700].shape[0]/df1.shape[0]
result = p_a_b == p_a
print('The credit score greater than 700 and purpose equals to debt_consolidation are independent:', result)
# code ends here

# --------------
# code starts here
prob_lp = df[df['paid.back.loan'] == 'Yes'].shape[0]/df.shape[0]
prob_cs = df[df['credit.policy'] ==  'Yes'].shape[0]/df.shape[0]
new_df = df[df['paid.back.loan'] == 'Yes']
prob_pd_cs = new_df[new_df['credit.policy'] == 'Yes'].shape[0]/new_df.shape[0]
bayes = (prob_pd_cs * prob_lp) / prob_cs
print(bayes)

# code ends here

# --------------
# code starts here
df['purpose'].value_counts().plot('bar')
plt.xlabel('Purpose')
plt.ylabel('Count')
plt.title('Count of the diff purposes')
plt.show()

df1 = df[df['paid.back.loan'] == 'No']
df1['purpose'].value_counts().plot('bar')
plt.xlabel('Purpose where paid back loan is no')
plt.ylabel('Count')
plt.title('Count of the diff purposes')
plt.show()

# code ends here

# --------------
# code starts here
inst_median = df['installment'].median()
inst_mean = df['installment'].mean()
df.hist(column = 'installment')
plt.xlabel('Installments')
plt.title('Distribution of installment pattern')

df.hist(column = 'log.annual.inc')
plt.xlabel('Annual Income')
plt.title('Distribution of annual income pattern')

# code ends here


import numpy as np
import numpy.linalg as npla
import matplotlib.pyplot as plt

def lancoiz(A, max_iter=20):
    alphas = list()
    betas = list()
    ritz_vals = list()
    qk_1 = np.zeros(A.shape[1])
    qk = np.random.random(A.shape[1])
    qk = qk / np.linalg.norm(qk, ord=2)
    Q = list()
    Q.append(qk_1)
    Q.append(qk)
    beta = 0
    k = 1
    while True:
        qk = Q[k]
        qk_1 = Q[k-1]
        uk = np.dot(A, qk)
        ak = np.dot(qk, uk)
        alphas.append(ak)
        uk -= ((beta * qk_1) + (ak * qk))
        beta = npla.norm(uk, ord=2)
        if beta == 0:
            break
        betas.append(beta)
        qk_p1 = uk / beta

        T_i = np.diag(np.array(alphas))
        T_i = T_i + np.diag(np.array(betas[:len(alphas) - 1]), -1) + np.diag(np.array(betas[:len(alphas) - 1]), +1)
        ritzs = np.linalg.eigvals(T_i)

        ritz_vals.extend([[k, ritzs[j]] for j in range(len(ritzs))])

        k+=1
        if k >= max_iter:
            break
        Q.append(qk_p1)

    H = np.diag(np.array(alphas))
    H = H + np.diag(np.array(betas[:len(alphas) - 1]), -1) + np.diag(np.array(betas[:len(alphas) - 1]), +1)
    return np.array(Q[1:]).T, H, np.array(ritz_vals)

def main():

	B = np.random.random((100, 100))
	A = B + B.T
	Q, H, rvals = lancoiz(A, max_iter=20)

	part_1 = npla.norm(np.dot(Q, Q.T) - np.diag(np.ones(100)), ord = 2)

	part_2 = npla.norm(np.dot(np.dot(Q.T, A), Q) - H, ord=2) / npla.norm(A, ord=2)

	print("Answer for part 6(a) (i):", part_1)
	print("Answer for part 6(a) (ii):", part_2)

if __name__ == '__main__':
	main()


from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
from math import tan, cos, sin, pi
from scipy.integrate import odeint, simps, cumtrapz

##############
## y0 = yk
## y1 = theta
## y2 = px
## y3 = py
##############

def model(y, t):
    yk, theta, vx, vy = y

    # constants
    m = 0.206 # Mass of pendulum
    k = 10 # Stiffness of Spring
    b = 0.3 # Torsional Resistance
    R = 1.5 # Friction
    L = 0.61  # Length of Pendulum
    g = 9.81 # Gravitional acceleration
    Y = 0 # Equilibrium position

    # in between terms
    disp = (yk - Y)

    d_yk = vy + ((tan(theta) * vx))
    d_theta = vx / (L * cos(theta))
    d_vy = g + (( -R * d_yk - k * yk)/m)

    # the derivative causality is resolved here, so adding some in between
    # terms for easier debugging
    e_21 = tan(theta) * (d_vy - g) # comes from the left side of bg
    e_24 = d_theta * b  # torsional resistance
    e_22 = d_theta * tan(theta) * vx / (12 * (cos(theta)**2))
    factor = 1 / (1 + (1 / ( 12 * (cos(theta)**2))))

    d_vx = factor * (e_21 - e_22 - e_24)
    return [d_yk, d_theta, d_vx, d_vy]

time = np.linspace(0.0, 8.0, 10000)
# Initial condition parameters
# yinit = [Vertical spring displacement, pendulum angle relative to vertical, horizontal velocity, vertical]
yinit = [0, pi/4, 0, 0]
y = odeint(model, yinit, time)

# the state equations give us velocity
# integrate again to get displacement
# our variable of interest
ped_y = cumtrapz(y[:,3], time, initial=0)
ped_x = cumtrapz(y[:,2], time, initial=0)

plt.figure(1)

plt.subplot(311)
plt.plot(time, y[:,0])
plt.xlabel('t [s]')
plt.ylabel('Displacement [m]')
plt.title('Displacement of Spring in Y')
plt.grid()
plt.legend()

# plt.subplot(312)
# plt.plot(time, y[:,1])
# plt.xlabel('t [s]')
# plt.ylabel('Displacement [rad]')
# plt.title('Angle of rotation')
# plt.legend()

plt.subplot(312)
plt.plot(time, ped_x)
plt.xlabel('t [s]')
plt.ylabel('Displacement [m]')
plt.title('Displacement of Pendulum in X')
plt.grid()
plt.legend()

plt.subplot(313)
plt.plot(time, ped_y)
plt.xlabel('t [s]')
plt.ylabel('Displacement [m]')
plt.title('Displacement of Pendulum in Y')
plt.grid()
plt.legend()

plt.tight_layout()
plt.show()


import numpy as np
from sklearn.linear_model import LinearRegression

x = np.array([5, 15, 25, 35, 45, 55]).reshape((-1, 1))
print(x)
y = np.array([15, 11, 2, 8, 25, 32])

#create random matrix
#create the sample by init process in a json file
sample = np.random.normal(loc=[2., 20.], scale=[1., 3.5],size=(12,3, 2))
print(sample)

#axis refer to a single dimension of multidimension array
#provide multi array math operation
arr = np.array([[1, 2, 3],
               [20, 20, 20]])
print(arr.sum(axis=1))
print(arr.mean(axis=1))
mu=arr.mean(axis=1)
print('sample:', sample.shape, '| means:', mu.shape)
print(arr.std(axis=1))

#array operation
print(np.log(np.array([1,2,3])))

print(np.random.randn(1, 10))


import numpy as np
from numba import jit
from numba import float64
from numba import int64
"""
This module contains various implementations of ewma based on sample size
"""

@jit((float64[:], int64), nopython=False, nogil=True)
def ewma(arr_in, window):
    """Exponentialy weighted moving average specified by a decay ``window``
    to provide better adjustments for small windows via:
        y[t] = (x[t] + (1-a)*x[t-1] + (1-a)^2*x[t-2] + ... + (1-a)^n*x[t-n]) /
               (1 + (1-a) + (1-a)^2 + ... + (1-a)^n).

    :param arr_in : np.ndarray, float64. A single dimenisional numpy array
    :paran window : int64. The decay window, or 'span'
    :return: np.ndarray. The EWMA vector, same length / shape as ``arr_in``
    """
    n = arr_in.shape[0]
    ewma_arr = np.empty(n, dtype=float64)
    alpha = 2 / float(window + 1)
    w = 1
    ewma_old = arr_in[0]
    ewma_arr[0] = ewma_old
    for i in range(1, n):
        w += (1 - alpha)**i
        ewma_old = ewma_old * (1 - alpha) + arr_in[i]
        ewma_arr[i] = ewma_old / w

    return ewma_arr


import numpy as np

class LogCost():
    @staticmethod
    def get(A2, Y):
        m = Y.shape
        logProb = np.multiply(np.log(A2), Y) + np.multiply(np.log(1-A2), 1-Y)
        return - np.sum(logProb) / m

    @staticmethod
    def getDerivative(A2, Y):
        return - (Y / A2) + (1 - Y) / (1 - A2)


import numpy as np

def fact(n):
    if n<2:
        return 1
    else:
        return n*fact(n-1)

def f(N,k):
	return fact(N)/( fact(k) * fact(N-k) )

def b(t,k,N):
	return f(N,k) * (1-t)**(N-k) * t**k

def bezier(t,points):
	N = points.shape[1]-1 # colnum
	sum = np.zeros((3,1))
	for k in range(0,N+1):
		sum[:,0] += b(t,k,N)*points[:,k]
	return sum

def bezier1D(t,points):
	N = len(points)-1
	sum = 0
	for k in range(0,N+1):
		sum += b(t,k,N)*points[k]
	return sum

if __name__ == "__main__":
	points = np.array(
		[
			[ 20,  20, -20, -20],
			[ 10,   0,   0,  10],
			[  0,   0,   0,   0]
		]
	)
	print(bezier(0.783,points))