import os
import numpy as np
from sklearn import preprocessing

##########################################################
def pca(data, normalize=False):
    """Perform Principal Component Analysis on @data. It expects the @data with
    rows as instances and features as columns.
    You may check the contribution of each component by calling
    get_pc_contribution()"""

    x = data.copy()
    if normalize:
        x = preprocessing.normalize(x, axis=0)

    x -= np.mean(x, axis=0) # just centralize
    cov = np.cov(x, rowvar = False)
    evals , evecs = np.linalg.eig(cov)

    idx = np.argsort(evals)[::-1]
    evecs = evecs[:,idx] # each column is a eigenvector
    evals = evals[idx]
    a = np.dot(x, evecs)

    return a, evecs, evals

##########################################################
def get_pc_contribution(evecs):
    """Get the id and calculate the relative contribution of the feature
    with major contribution to the first two components. Notice that the
    values are relative to each component and thus the sum may surpass 1."""
    pcs = []; contribs = []
    for i in range(2): # Just two major components
        evec = np.abs(evecs[:, i])
        contrib = evec / np.sum(evec)
        pcs.append(np.argsort(contrib)[-1])
        contribs.append(np.max(contrib))
    return pcs, contribs


# Import
import numpy as np
from scipy.integrate import odeint
from plotly.offline import plot
import plotly.graph_objects as go

# Population
N = 10000

# Nombre initial de sujets infectés et 'removed' (immunisés+décédés).
I0, R0 = 1, 0

# Individus sains au départ
S0 = N - I0 - R0

# beta l'infectiosité et gamma le taux de rétablissement moyen (en 1/jours).
beta, gamma = 0.6, 1.0/7.0

# échelle de temps (ici en jours)
t = np.linspace(0, 90, 90)

# Les équations différentielles du modèle SIR.
def deriv(y, t, N, beta, gamma):
    S, I, R = y
    dSdt = -beta * S * I / N
    dIdt = beta * S * I / N - gamma * I
    dRdt = gamma * I
    return dSdt, dIdt, dRdt

# vecteur initial
y0 = S0, I0, R0

# Intégration des équations différentielles
ret = odeint(deriv, y0, t, args=(N, beta, gamma))

S, I, R = ret.T

#on calcule le total des décès sur la base du taux de mortalité
D = np.cumsum(I*0.005)

# Plot de la figure avec plotly
fig = go.Figure()

fig.add_trace(
    go.Scatter(x=t, y=S, marker=dict(color='#636EFA', size=1), marker_line=dict(width=0.5),
               name="sains"))
fig.add_trace(
    go.Scatter(x=t, y=I, marker=dict(color='#EF553B',size=1), marker_line=dict(width=1),
               name="infectés" ))
fig.add_trace(
    go.Scatter(x=t, y=R, marker=dict(color='#000000', size=1), marker_line=dict(width=1),
               name="removed"))

fig.update_xaxes(title_text="jours")
fig.update_yaxes(title_text="population")
fig.update_layout(title_text="Modèle SIR")
plot(fig)


from itertools import combinations as comb
import numpy as np

# works up to 11x11 (as far as I can tell)

def solve_system(ads,des,dens):
    R = np.zeros(len(ads),dtype=np.longdouble)
    for i in range(0,len(dens)):
        R[i] = (des[i] / (ads[i]*dens[i])) + 1
    n = len(R)
    x = np.zeros(n)
    res = 0
    if n == 1:
        return np.array([1/float(R[0])])
    elif n == 2:
        denom = (R[0] * R[1] - 1)
        x1 = float(R[1] - 1) / denom
        x2 = float(R[0] - 1) / denom
        return np.array([x1,x2])
    else:
        denom = (n-2)*np.sum(R) + (-1)**n * reduce(lambda z, y: z*y, R) - (n-1)
        for k in range(2,n-1):
            c = list(comb(R,k))
            res = 0
            for tup in c:
                prod = reduce(lambda z, y: z*y, tup)
                res += prod
            denom += (-1)**(k+1) * (n - (k+1))*res
        for i in range(0,n):
            r = np.delete(np.array(R),i)
            numer = np.sum(r) - 1
            m = n-1
            for k in range(2,m+1):
                c = list(comb(r,k))
                res = 0
                for tup in c:
                    prod = reduce(lambda z, y: z*y, tup)
                    res += prod
                numer += (-1)**(k+1) * res
            x[i] = float(numer) / denom
    return x


import numpy as np
import matplotlib.pyplot as plt
import h5py
import scipy
from PIL import Image
from scipy import ndimage
from lr_utils import load_dataset

# Loading the data (cat/non-cat)

train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = load_dataset()

# Finding the values

m_train = train_set_y.shape[1]
m_test = test_set_y.shape[1]
num_px = train_set_x_orig.shape[1]

# Reshaping the training and test data sets

train_set_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T
test_set_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T

# Standardizing the dataset

train_set_x = train_set_x_flatten / 255
test_set_x = test_set_x_flatten / 255

# Activation Function (Sigmoid)

def sigmoid(z):

	s = 1 / (1 + np.exp(-z))

	return s

print(sigmoid(0))

# Initializing Parameters

def initializing(dim):

	w = np.zeros(shape=(dim, 1))
	b = 0

	return w, b

# Forward and Backward Propagation

def propagate(w, b, X, Y):

	m = X.shape[1]

	#Forward Propagation
	A = sigmoid(np.dot(w.T, X) + b)
	cost = (-1/m) * np.sum(Y * np.log(A) + (1 - Y) * (np.log(1 - A)))

	#Backward Propagation
	dw = (1/m) * np.dot(X, (A-Y).T)
	db = (1/m) * np.sum(A - Y)

	grads = {"dw":dw,
			"db":db}

	return grads, cost

w, b, X, Y = np.array([[1], [2]]), 2, np.array([[1,2], [3,4]]), np.array([[1, 0]])
grads, cost = propagate(w, b, X, Y)
print("dw: ", grads["dw"])
print("db: ", grads["db"])
print("cost: ", cost)

# Optimization function

def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost= False):

	costs = []

	for i in range(num_iterations):
		grads, cost = propagate(w, b, X, Y)

		dw = grads["dw"]
		db = grads["db"]

		w = w - learning_rate * dw
		b = b - learning_rate * db

		if i % 100 == 0:
			costs.append(cost)

		if i % 100 == 0 and print_cost:
			print("Cost after iteration %i: %f" % (i, cost))

	params = {"w": w,
			"b": b}

	grads = {"dw": dw,
			"db": db}

	return params, grads, costs

params, grads, costs = optimize(w, b, X, Y, num_iterations= 100, learning_rate = 0.009, print_cost = False)
print ("w = " + str(params["w"]))
print ("b = " + str(params["b"]))
print ("dw = " + str(grads["dw"]))
print ("db = " + str(grads["db"]))

# Computing predictions

def predict(w, b, X):

	m = X.shape[1]
	y_prediction = np.zeros((1, m))
	w = w.reshape(X.shape[0], 1)

	A = sigmoid(np.dot(w.T, X) + b)

	for i in range (A.shape[1]):

		y_prediction[0, i] = 1 if A[0, i] > 0.5 else 0

	return y_prediction

print("predictions = " + str(predict(w, b, X)))

# Overall model

def model(X_train, Y_train, X_test, Y_test, num_iterations=2000, learning_rate=0.5, print_cost=False):

	w, b = initializing(X_train.shape[0])

	parameters, grads, costs = optimize(w, b, X_train, Y_train, num_iterations, learning_rate, print_cost)

	w = parameters["w"]
	b = parameters["b"]

	y_prediction_test = predict(w, b, X_test)
	y_prediction_train = predict(w, b, X_train)

	print("train accuracy: {} %".format(100 - np.mean(np.abs(y_prediction_train - Y_train)) * 100))
	print("test accuracy: {} %".format(100 - np.mean(np.abs(y_prediction_test - Y_test)) * 100))

	d = {"costs": costs,
	         "Y_prediction_test": y_prediction_test,
	         "Y_prediction_train" : y_prediction_train,
	         "w" : w,
	         "b" : b,
	         "learning_rate" : learning_rate,
	         "num_iterations": num_iterations}

	return d

d = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations = 1000, learning_rate = 0.005, print_cost = True)

# Test

my_image = "3.jpg" #Your image here

fname = "images/" + my_image
image = np.array(ndimage.imread(fname, flatten=False))
my_image = scipy.misc.imresize(image, size=(num_px, num_px)).reshape((1, num_px * num_px * 3)).T
my_predicted_image = predict(d["w"], d["b"], my_image)

plt.imshow(image)
print("y = " + str(np.squeeze(my_predicted_image)) + ", your algorithm predicts a \"" + classes[int(np.squeeze(my_predicted_image)),].decode("utf-8") +  "\" picture.")

Neural Networks and Deep Learning/Logistic Regression with Neural Network Mindset.py


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

# Integration Simpson rule..
def simphson_integration(a, b, f, N=1000):
    ''' This present function is about simphson integration.'''
    inital_x = a  # inital boundary point
    final_x = b  # final boundary point
    dx = (final_x - inital_x) / N  # generating dx point
    sum = 0
    for i in range(N):
        # integration process

        if i == 0:
            sum += f(inital_x)
            inital_x += dx
        elif (i % 2) != 0:  # i is even
            sum += 4 * f(inital_x)
            inital_x += dx
        elif (i % 2) == 0:  # i is odd
            sum += 2 * f(inital_x)
            inital_x += dx
        if i == N - 1:
            sum += f(inital_x)

    return (dx / 3) * sum

# Planewave function
def wavefunc(k, x):
    value = math.e ** (1j * k * x)
    return float(value.real)

# 1st order Gradient of Function
def gradient1(k, func, r):
    h = 0.0001
    return (func(k, r + h) - func(k, r)) / h

# 2nd order Gradient of Function
def gradient2(k, func, r):
    h = 0.0001
    return ((gradient1(k, func, r + h)) - gradient1(k, func, r)) / h

# Sum of plane wave wavefunctions.
def sum_wavefunc(K, x):
    ''' k is an array in this problem'''
    wavesum = 0
    for i in range(len(K)):
        wavesum = wavesum + wavefunc(K[i], x)

    return wavesum

def gradient_sum_wave1(K, sum_func, r):
    h = 0.0001
    return (sum_func(K, r + h) - sum_func(K, r)) / h

def gradient_sum_wave2(K, sum_func, r):
    h = 0.0001
    return (gradient_sum_wave1(K, sum_func, r + h) - gradient_sum_wave1(K, sum_func, r)) / h

# Boundary energy potential
def V1(x):
    '''Simple box potential'''
    L = 10
    if x >= 0 and x <= L:
        V = -5
    else:
        V = 0
    return V

def E_known_energy(x):
    '''Simple box potential'''
    L = 10
    if x >= 0 and x <= L:
        E = -2
    else:
        E = 0
    return E

def E_integration_over_wave(x1, x2, K, V, sum_func):
    h = 1
    m = 1
    E_known_energy=0.314
    # simulation box
    r = [x1]
    small = 0.01
    while x1 < x2:
        x1 = x1 + small
        r.append(x1)

    gra2 = []
    func = []
    E_error_sum = 0
    for i in r:
        a = sum_func(K, i)
        func.append(a)
        b = gradient_sum_wave2(K, sum_func, float(i))
        gra2.append(b)
        k2 = b / a
        E_total_energy = -(h ** 2 * k2) / (2 * m) + V(i)
        E_error_sum = E_error_sum + abs(E_total_energy - E_known_energy)

    return E_error_sum

def generate_sample(x, sample_N=10):
    sample_set = []
    for k in range(sample_N):
        x_set = []
        for i in range(len(x)):
            random_x = random.uniform(-1, 1) * 0.01
            x_set.append(x[i] + random_x)
        sample_set.append(x_set)

    return sample_set

def search_algo():
    simul_bound_init = -5
    simul_bound_fnl = 15
    K = []
    for i in range(10):
        K.append(random.uniform(0.5, 0.6))

    while E_integration_over_wave(-0.5, 0.5, K, V1, sum_wavefunc) >= 0.1:
        #filehandle = open('wavefunc_param_new2.txt', 'a')

        mutated = generate_sample(K)
        COST = []
        for j in mutated:
            COST.append(E_integration_over_wave(-0.5, 0.5, j, V1, sum_wavefunc))

        min_cost = min(COST)
        print(min_cost)

        index_min_cost = COST.index(min_cost)
        final_K = mutated[index_min_cost]

        K = list(final_K)

        cost_line = 'cost: ' + str(min_cost) + '\n'
        #filehandle.write(cost_line)
        k_data = 'k_i=' + str(K) + '\n'
        #filehandle.write(k_data)
        #filehandle.close()
        print(K)

    return K

search_algo()

k_i1=[0.33974367709506353, 0.5015052550475873, 0.9019398014493342, 0.6788195610151461, 1.1295955061305067]
k_i=[0.7554899216729795, 0.7862935811161916, 0.806541360845643, 0.8022213214953788, 0.8107121544591318]
k_i11=[0.9913468628654323, 0.7623854149274232, 0.9264695806573522, 0.23776143936329017, 0.5885938062567493]
k_i00=[0.8145940062782712, 0.8079348577858096, 0.8119192949356293, 0.7194336670313155, 0.8073519739680358]

x_data=np.arange(-10,10,0.001)
y_data=[]
y2_data=[]
V_data=[]
for j in x_data:
    y_data.append(sum_wavefunc(k_i,j))
    y2_data.append(sum_wavefunc(k_i1,j))
    V_data.append(V1(j))

plt.plot(x_data,y_data)
plt.plot(x_data,y2_data)
#plt.plot(x_data,V_data)
plt.show()


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

from sklearn import datasets
from copy import deepcopy

iris = datasets.load_iris()

# Labels (0: Iris setosa, 1: Iris versicolor, 2: Iris virginica)
print(iris.target)

# Description
print(iris.DESCR)

# Store iris.datas
samples = iris.data

# Create x and y
x = samples[:, 0]
y = samples[:, 1]

sepal_length_width = np.array(list(zip(x, y)))

####################################
# Step 1: Place K random centroids #
####################################

# Number of clusters
k = 3

# Create x coordinates of k random centroids
centroids_x = np.random.uniform(min(x), max(x), size=k)

# Create y coordinates of k random centroids
centroids_y = np.random.uniform(min(y), max(y), size=k)

centroids = np.array(list(zip(centroids_x, centroids_y)))

##############################################
# Step 2: Assign samples to nearest centroid #
##############################################

# Distance formula
def distance(a, b):
  return ((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2) ** .5

# To store the value of centroids when it updates
centroids_old = np.zeros(centroids.shape)

# Cluster labels for each point (either 0, 1, or 2)
labels = np.zeros(len(samples))

# Distances to each centroid
distances = np.zeros(k)

# Initialize error:
error = np.zeros(k)

error[0] = distance(centroids[0], centroids_old[0])
error[1] = distance(centroids[1], centroids_old[1])
error[2] = distance(centroids[2], centroids_old[2])

while error.all() != 0:

    for i in range(len(samples)):
        distances[0] = distance(sepal_length_width[i], centroids[0])
        distances[1] = distance(sepal_length_width[i], centroids[1])
        distances[2] = distance(sepal_length_width[i], centroids[2])

        # Assign to the closest centroid
        cluster = np.argmin(distances)

        labels[i] = cluster

    # Print labels
    print (labels)

    ############################
    # Step 3: Update centroids #
    ############################

    centroids_old = deepcopy(centroids)

    for i in range(k):
        points = []
        for j in range(len(sepal_length_width)):
            if labels[j] == i:
                points.append(sepal_length_width[j])
        centroids[i] = np.mean(points, axis=0)

    error[0] = distance(centroids[0], centroids_old[0])
    error[1] = distance(centroids[1], centroids_old[1])
    error[2] = distance(centroids[2], centroids_old[2])

    print(centroids)
    print(centroids_old)

# Make a scatter plot of the centroids
colors = ['r', 'g', 'b']

for i in range(k):
  points = np.array([sepal_length_width[j] for j in range(len(samples)) if labels[j] == i])
  plt.scatter(points[:, 0], points[:, 1], c=colors[i], alpha=0.5)

plt.scatter(centroids[:, 0], centroids[:, 1], marker='D', s=150)

plt.xlabel('sepal length (cm)')
plt.ylabel('petal length (cm)')

# Display plot
plt.show()


import numpy as np

r = lambda x, y, z: np.sqrt(np.power(x, 2) + np.power(y, 2) + np.power(z, 2))

def s0(x, y, z): return 1
s0 = np.vectorize(s0)
f0 = r

s1 = lambda x, y, z: 1 - np.sin(r(x, y, z))
f1 = lambda x, y, z: np.cos(r(x, y, z)) + r(x, y, z) - 1;

s2 = r;
f2 = lambda x, y, z: (x**2 + y**2 + z**2)/2

A = np.array([
    [1,   1/4, 1/8],
    [1/4, 1,   1/4],
    [1/8, 1/4, 1]])
alpha = np.pi/5
C = lambda x, y, z: np.array([np.cos(alpha*x), np.cos(alpha*y), np.cos(alpha*z)])
S = lambda x, y, z: np.array([np.sin(alpha*x), np.sin(alpha*y), np.sin(alpha*z)])
s3 = lambda x, y, z: np.linalg.norm(alpha*np.diag(C(x, y, z))@(A + A.T)@S(x, y, z))
s3 = np.vectorize(s3)
f3 = lambda x, y, z: S(x, y, z)@A@S(x, y, z)
f3 = np.vectorize(f3)

Bsqrt = A
s4 = np.vectorize(lambda x, y, z: np.linalg.norm(Bsqrt@[x, y, z]))
f4 = np.vectorize(lambda x, y, z: [x, y, z]@Bsqrt@[x, y, z]/2)

_slowness_funcs = [s0, s1, s2, s3, s4]

_soln_funcs = [f0, f1, f2, s3, s4]

def get_field(g, X, Y, Z):
    assert(X.shape == Y.shape)
    assert(X.shape == Z.shape)
    return g(X, Y, Z)

def get_fields(u, s, X, Y, Z):
    return get_field(u, X, Y, Z), get_field(s, X, Y, Z)

def slowness_funcs():
    return _slowness_funcs

_slowness_func_names = {
    s0: 's0',
    s1: 's1',
    s2: 's2',
    s3: 's3',
    s4: 's4'
}

def slowness_func_names():
    return list(slowness_func_names.values())

def get_slowness_func_name(s):
    return _slowness_func_names[s]

_slowness_funcs_by_name = {
    _slowness_func_names[k]: k for k in _slowness_func_names.keys()}
def get_slowness_func_by_name(name):
    return _slowness_funcs_by_name[name]

for func in _slowness_funcs + _soln_funcs:
    func.dim = 3

_soln_func_map = {
    _slowness_funcs[i]: _soln_funcs[i] for i in range(len(_slowness_funcs))}

def get_soln_func(s):
    return _soln_func_map[s]


# -*- coding: utf-8 -*-
"""
Created on Mon Dec 3 2018
Updated on Sat Aug 10 2019

@authors: Lantian ZHANG <zhanglantian1992@163.com>

The codes below perform WOE transformation and IV calculation for features
The data format of features should be string or number.
"""
import pandas as pd
import numpy as np
from sklearn.base import BaseEstimator, TransformerMixin

def woe_vector(x, y, epslon=1e-10):
    """Calculate WOE and IV for 1 feature
    Parameters
    ----------
    x: numpy.array, shape (number of examples,)
            The column of data that need to woe-transformed.
            The data in col should be either string or number(integer/float)

    y: numpy.array, shape (number of examples,)
            The target column (or dependent variable).

    epslon: float, optional(default=1e-10)
            Replace 0 with a very small number during division
            or logrithm to avoid infinite value.

    Return
    ----------
    woe_dict: dict
            The dictionary that maps each unique value of x to woe values
    iv: float
            The information value for x with reference to y
    """

    # global goods/bads
    positive, total = y.sum(), len(y)
    negative = total - positive
    global_odds = positive / negative

    # goods, bads for each group
    x_unique, local_total = np.unique(x, return_counts=True)
    mask = (x.reshape(1,-1) == x_unique.reshape(1,-1).T) # identify groups
    local_pos = np.array([y[m].sum() for m in mask])
    local_neg = local_total - local_pos
    local_odds = local_pos/(local_neg+epslon)

    # woe and iv
    ratios = local_odds/(global_odds+epslon)
    woe_values = np.log(ratios+epslon)
    woe_dict = dict(zip(x_unique, woe_values))
    iv = np.sum((local_pos/positive - local_neg/negative) * woe_values)

    return woe_dict, iv

def map_np(array, dictionary):
    """map function for numpy array
    Parameters
    ----------
    array: numpy.array, shape (number of examples,)
            The array of data to map values to.

    distionary: dict
            The distionary object.

    Return
    ----------
    result: numpy.array, shape (number of examples,)
            The mapped result.
    """
    return [dictionary[e] for e in array]

class WOE_Encoder(BaseEstimator, TransformerMixin):
    """
    Perform WOE transformation for features and calculate the information
    value (IV) of features with reference to the target variable y.

    Parameters
    ----------
    epslon: float, optional(default=1e-10)
            Replace 0 with a very small number during division
            or logrithm to avoid infinite value.

    output_dataframe: boolean, optional(default=False)
            if output_dataframe is set to True. The transform() function will
            return pandas.DataFrame. If it is set to False, the output will
            be numpy ndarray.

    Attributes
    ----------
    iv_: a dictionary that contains feature names and their IV

    result_dict_: a dictionary that contains feature names and
        their WOE result tuple. Each WOE result tuple contains the
        woe value dictionary and the iv for the feature.

    Methods
    -------
    fit(X, y):
            fit the WOE transformation to the feature.

    transform(X):
            transform the feature using the WOE fitted.

    fit_transform(X, y):
            fit the WOE transformation to the feature and transform it.
    """
    def __init__(self, epslon=1e-10, output_dataframe=False):
        self.__epslon__ = epslon
        self.__output_dataframe__ = output_dataframe

    def fit(self, X, y):
        """
        Parameters
        ----------
        X: numpy.ndarray or pandas.DataFrame, shape (number of examples,
                                                     number of features)
            The data that need to be transformed.

        y: numpy.array or pandas.Series, shape (number of examples,)
            The target array (or dependent variable).
        """

        # if X is pandas.DataFrame, turn it into numpy.ndarray and
        # associate each column array with column names.
        # if X is numpy.ndarray,
        self.fit_sample_size_, self.num_of_x_ = X.shape
        if isinstance(X, pd.DataFrame):
            self.columns_ = X.columns.values # column names
            features = X.values.T
        elif isinstance(X, np.ndarray):
            self.columns_ = np.array(
                [''.join(('x',str(a))) for a in range(self.num_of_x_)]
                ) #  # column names (i.e. x0, x1, ...)
            features = X.T
        else:
            raise TypeError('X should be either numpy.ndarray or pandas.DataFrame')

        if isinstance(y, pd.Series):
            target = y.values
        elif isinstance(y, np.ndarray):
            target = y
        else:
            raise TypeError('y should be either numpy.array or pandas.Series')

        # Perform woe transformation to each feature
        self.result_dict_ = dict(zip(self.columns_,
                                    (woe_vector(x,y) for x in features)))
        # Extract iv from result
        self.iv_ = dict(zip(self.columns_,
                            (self.result_dict_[x][1] for x in self.columns_)))
        return self

    def transform(self, X):
        """
        Parameters
        ----------
        X: numpy.ndarray or pandas.DataFrame, shape (number of examples,
                                                     number of features)
            The data that need to be transformed.
        """
        # if X is pandas.DataFrame, turn it into numpy.ndarray and
        # associate each column array with column names.
        # if X is numpy.ndarray,
        self.transform_sample_size_ = X.shape[0]
        if isinstance(X, pd.DataFrame):
            features = X[self.columns_].values.T
        elif isinstance(X, np.ndarray):
            features = X.T
        else:
            raise TypeError('X should be either numpy.ndarray or pandas.DataFrame')

        # Apply fitted woe transformation to features
        result = np.array(
            [map_np(d, self.result_dict_[col][0]) for d,col in zip(features,
                                                                  self.columns_)])
        # Output
        if self.__output_dataframe__:
            return pd.DataFrame(result, index=self.columns_).T
        else:
            return result.T


import numpy as np

a = np.arange(12).reshape(3, 4)
print(a)

'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
'''

print(a.T) #転置

'''
[[ 0  4  8]
 [ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]]
'''

b = np.arange(24).reshape(2, 3, 4)
print(b) # 3 次元 array

'''
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
'''

print(b.transpose(0, 2, 1)) # 軸の入れ替え

'''
[[[ 0  4  8]
  [ 1  5  9]
  [ 2  6 10]
  [ 3  7 11]]

 [[12 16 20]
  [13 17 21]
  [14 18 22]
  [15 19 23]]]
'''


import numpy as np

def get_r_squared(yy, ff, n_params):

    n_data = len(yy)
    yy_mean = np.mean(yy)

    # Calculate residual and total sum of squares
    residual_sum_squares = 0
    total_sum_squares = 0
    for i in range(n_data):
        residual_sum_squares += (yy[i] - ff[i])**2
        total_sum_squares += (yy[i] - yy_mean)**2

    # R Squares
    r_squared = 1 - residual_sum_squares/total_sum_squares

    # Adjusted R squared
    adjusted_r_squared = 1 - (1-r_squared) * \
        (n_data-1) / (n_data - n_params - 1)

    return residual_sum_squares, total_sum_squares, r_squared, adjusted_r_squared


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime, date

sample_size = 500
sigma_e = 3.0             # true value of parameter error sigma
random_num_generator = np.random.RandomState(0)
x = 10.0 * random_num_generator.rand(sample_size)
e = random_num_generator.normal(0, sigma_e, sample_size)
y = 1.0 + 2.0 * x +  e          # a = 1.0; b = 2.0; y = a + b*x

sigma_e = 3.0

# initial value
theta_0_0 = np.array([[0.5], [0.5]])         # 2x1 array
W = np.array([[0.5, 0], [0, 0.5]])          # 2x2 array
P_0_0 = W

results = np.zeros([250, 2])
for k in range(250):          # 250 pairs
    print('step {}'.format(k))
    # A-Priori prediction
    # first step, let k = 1
    theta_1_0 = theta_0_0
    P_1_0 = P_0_0 + W

    # After observing two points (x1, y1) and (x2, y2)
    x1 = x[2*k+0]
    x2 = x[2*k+1]
    y1 = y[2*k+0]
    y2 = y[2*k+1]
    y_1 = np.array([y1, y2]).reshape(2,1)
    F_1 = np.array([[1, x1], [1, x2]])
    y_1_tilde = y_1 - np.dot(F_1, theta_1_0)

    # residual covariance
    V_1 = np.array([[sigma_e, 0], [0, sigma_e]])
    S_1 = np.dot(np.dot(F_1, P_1_0), np.transpose(F_1)) + V_1

    # Kalman Gain
    K_1 = np.dot(np.dot(P_1_0, np.transpose(F_1)), np.linalg.inv(S_1))

    # Posterior
    theta_1_1 = theta_1_0 + np.dot(K_1, y_1_tilde)
    P_1_1 = np.eye(2) - np.dot(np.dot(K_1, F_1), P_1_0)

    # assign for next iteration
    results[k, :] = theta_1_1.reshape(2,)
    theta_0_0 = theta_1_1
    P_0_0 = P_1_1

print(results.mean(axis=0))     # intercept: 0.6694;   slope: 1.9926

# present the results
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax1.plot(np.linspace(1, 250, num=250), results[:, 0])
ax1.title.set_text('Hidden State Evolution -- Intercept')
ax2 = fig.add_subplot(122)
plt.plot(np.linspace(1, 250, num=250), results[:, 1])
ax2.title.set_text('Hidden State Evolution -- Slope')
plt.show()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Nov 11 10:47:27 2019

Exercise 23

@author: Lauren King
"""
import math
import numpy as np

m=0.1
vy0=.55
vx0=.6
#db=0.05
#b=np.arange(-1,1,db)

def v(x,y):
    v=(x**2)*(y**2)*np.exp(-((x**2)+(y**2)))
    return v

def d2x(x,y,m):
    d2x=-(2/m)*(y**2)*x*(1-(x**2))*np.exp(-((x**2)+(y**2)))
    return d2x

def d2y(x,y,m):
    d2y=-(2/m)*(x**2)*y*(1-(y**2))*np.exp(-((y**2)+(x**2)))
    return d2y

t=np.arange(0,100.001,.01)
vx=np.arange(0,100.001,.01)
vx[0]=vx0
vy=np.arange(0,100.001,.01)
vy[0]=vy0
xpos=np.arange(0,100.001,.01)
ypos=np.arange(0,100.001,.01)
ang=np.arange(0,100.001,.01)

xpos[0]=.1

h=.01

i=1
while i<len(vx-1):
    vy[i]=vy[i-1]+d2y(xpos[i-1],ypos[i-1],m)*h
    vx[i]=vx[i-1]+d2x(xpos[i-1],ypos[i-1],m)*h
    xpos[i]=(vx[i]*h)+xpos[i-1]
    ypos[i]=(vy[i]*h)+ypos[i-1]
    ang[i]=math.atan2(vy[i],vx[i])
    i=i+1

#plt.plot(vy,vx)
#plt.show()
#plt.plot(t,vy)
#plt.plot(t,vx)
#plt.show()
#plt.plot(t,xpos)
#plt.plot(t,ypos)
#plt.show()
plt.plot(xpos,ypos)

x_v = np.arange(-10.0, 10.01, 0.01)
y_v = np.arange(-10.0, 10.01, 0.01)
X_v, Y_v = np.meshgrid(x_v, y_v)
Z_v = X_v**2 * Y_v**2 * np.exp(-(X_v**2 + Y_v**2))
fig, ax = plt.subplots(1, 1)#, figsize=(10, 8))

cb = ax.contourf(X_v, Y_v, Z_v, 10, cmap="Greens")
ax.plot(xpos, ypos, lw=1)

ax.set_xlim(-3.0, 3.0)
ax.set_xlabel("X Position")
ax.set_ylim(-3.0, 3.0)
ax.set_ylabel("Y Position")

cbar = fig.colorbar(cb)
cbar.ax.set_ylabel("Scattering Potential")

fig.tight_layout()
plt.show()


import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import seaborn as sb
import pandas as pd
from mpl_toolkits.mplot3d import Axes3D

def computeLoss(beta_0, beta_1, x, y):
	loss = 0

	# Loss = (y - beta_0 * x - beta_1)**2
	for i in range(len(x)):
		loss += (y[i] - beta_0*x[i] - beta_1)**2

	return loss/len(x)

def getLossSurface(x, y):
	loss = []
	for i in np.arange(-10, 10,0.5):
		for j in np.arange(-10, 10, 0.5):
			currentLoss = computeLoss(i, j, x, y)
			loss.append([i, j, currentLoss])

	loss = np.array(loss)
	return loss

def updateWeights(beta_0, beta_1, x, y, learningRate):
	db0, db1 = 0, 0
	N = len(x)

	# Compute gradients
	for i in range(len(x)):
		db0 += -2*(y[i] - beta_0*x[i] - beta_1)*(x[i])
		db1 += -2*(y[i] - beta_0*x[i] - beta_1)

	beta_0 -= (db0/N)*learningRate
	beta_1 -= (db1/N)*learningRate

	currentLoss = computeLoss(beta_0, beta_1, x, y)
	print("Weight: {}, bias: {}, loss: {}".format(beta_0, beta_1, currentLoss))

	return beta_0, beta_1, currentLoss

# Link: https://stackoverflow.com/questions/7941226/how-to-add-line-based-on-slope-and-intercept-in-matplotlib
def drawLine(slope, intercept):
    """Plot a line from slope and intercept"""
    axes = plt.gca()
    x_vals = np.array(axes.get_xlim())
    y_vals = intercept + slope * x_vals
    plt.plot(x_vals, y_vals, 'r-')

# Load the tips dataset
df = sb.load_dataset('tips')

# Convert to numpy
dataset = df.to_numpy()

amount = dataset[:,0]
tips = dataset[:,1]

# Compute loss at different values of parameters
lossValues = getLossSurface(amount, tips)

fig = plt.figure()
ax2 = fig.add_subplot(111, projection='3d')
ax2.scatter(lossValues[:,0], lossValues[:,1], lossValues[:,2])
ax2.set_xlabel('beta_0')
ax2.set_ylabel('beta_1')
ax2.set_zlabel('loss')

# Perform backprop and update weights
numIterations = 100
learningRate = 1e-4
beta_0, beta_1 = 10, 0
for i in range(numIterations):
	# Compute gradients and update weights
	beta_0, beta_1, loss = updateWeights(beta_0, beta_1, amount, tips, learningRate)
	ax2.scatter(beta_0, beta_1, loss, c='r')
	plt.pause(0.05)

fig = plt.figure()
plt.scatter(amount, tips, s=2)
plt.xlabel('Amount')
plt.ylabel('Tips')
drawLine(beta_0, beta_1)

plt.show()


from __future__ import division
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import object
import numpy as np

## Copyright (c) 2017, Amir H. Jabalameli . All rights reserved.

class PlaneModelND(object):
    def __init__(self):
        self.params = None

    def estimate(self, data):
        if data.shape[0] > 2:  # well determined
            origin = data.mean(axis=0)
            data_adjust = data - origin
            matrix = np.cov(data_adjust.T)
            eigenvalues, eigenvectors = np.linalg.eig(matrix)
            sort = eigenvalues.argsort()[::-1]
            self.eigenvectors = eigenvectors[:, sort]
            direction = self.eigenvectors[-1]
            self.params = (origin, direction)
            # print(self.params)
        else:  # under-determined
            # raise ValueError('At least 3 input points needed.')
            return False
        return True

    def residuals(self, data, params=None):
        if params is None:
            params = self.params
        assert params is not None
        if len(params) != 2:
            raise ValueError('Parameters are defined by 2 sets.')
        origin, direction = self.params
        res = np.dot(data-origin,direction)/np.linalg.norm(direction)[..., np.newaxis]
        return np.absolute(res)


# imports
import numpy as np
import tensorflow as tf
from numpy import random
import math
import time
import matplotlib.pyplot as plt

"""Part 1 - Forward Propagation"""

def initialize_parameters(layer_dims):
    """
    Description: This function initializes weights and biases

    :param layer_dims: an array of the dimensions of each layer in the /
    network (layer 0 is the size of the flattened input, layer L is the output softmax)
    :return: a dictionary containing the initialized W and b parameters of each layer (W1…WL, b1…bL).
    """
    parameters = {}
    for l in range(1, len(layer_dims)):
        parameters[f'W{l}'] = np.random.randn(layer_dims[l], layer_dims[l - 1]) * np.sqrt(2 / layer_dims[l - 1])
        parameters[f'b{l}'] = np.zeros(shape=(layer_dims[l], 1))
    return parameters

def linear_forward(A, W, b):
    """
    Description: Implement the linear part of a layer's forward propagation.

    :param A: the activations of the previous layer
    :param W: the weight matrix of the current layer (of shape [size of current layer, size of previous layer])
    :param b: the bias vector of the current layer (of shape [size of current layer, 1])
    :return: Z: the linear component of the activation function (i.e., the value before applying the non-linear function)
    :return: linear_cache: a dictionary containing A, W, b (stored for making the backpropagation easier to compute)
    """
    Z = np.dot(W, A) + b
    linear_cache = dict({'A': A, 'W': W, 'b': b})
    return Z, linear_cache

def softmax(Z):
    """
    Description: Implementation of softmax function

    :param Z: the linear component of the activation function
    :return: A: the activations of the layer
    :return: activation_cache: returns Z, which will be useful for the backpropagation
    """
    numerator = np.exp(Z)
    denominator = np.sum(numerator, axis=0, keepdims=True)
    A = numerator / denominator
    activation_cache = Z
    return A, activation_cache

def relu(Z):
    """
    Description: Implementation of relu function

    :param Z: the linear component of the activation function
    :return: A: the activations of the layer
    :return: activation_cache: returns Z, which will be useful for the backpropagation
    """
    A = np.maximum(0, Z)
    activation_cache = Z
    return A, activation_cache

def linear_activation_forward(A_prev, W, B, activation):
    """
    Description: Implement the forward propagation for the LINEAR->ACTIVATION layer

    :param A_prev: activations of the previous layer
    :param W: the weights matrix of the current layer
    :param B: the bias vector of the current layer
    :param activation: the activation function to be used (a string, either “softmax” or “relu”)
    :return: A: the activations of the current layer
    :return: cache: a joint dictionary containing both linear_cache and activation_cache

    """
    if activation in ['relu', 'softmax']:
        Z, linear_cache = linear_forward(A_prev, W, B)
        A, activation_cache = globals()[activation](Z)
        cache = dict({'linear_cache': linear_cache, 'activation_cache': activation_cache})
        return A, cache

    else:
        raise NotImplementedError(
            "The given actiavtion function was not implemented. please choose one between {relu} and {softmax}")

def l_model_forward(X, parameters, use_batchnorm):
    """
    Description: Implement forward propagation for the [LINEAR->RELU]*(L-1)->LINEAR->SOFTMAX computation

    :param X: the data, numpy array of shape (input size, number of examples)
    :param parameters: the initialized W and b parameters of each layer
    :param use_batchnorm: a boolean flag used to determine whether to apply batchnorm after the activation/
    :return:AL: the last post-activation value
    :return: caches: a list of all the cache objects generated by the linear_forward function
    """
    caches = list()
    A_prev = X
    num_layers = int(len(parameters.keys()) / 2)

    for l in range(1, num_layers):
        W = parameters[f'W{l}']
        B = parameters[f'b{l}']
        A_prev, cache = linear_activation_forward(A_prev, W, B, 'relu')

        if use_batchnorm:
            A_prev = apply_batchnorm(A_prev)

        caches.append(cache)

    W = parameters[f'W{num_layers}']
    B = parameters[f'b{num_layers}']
    AL, cache = linear_activation_forward(A_prev, W, B, 'softmax')
    caches.append(cache)

    return AL, caches

def compute_cost(AL, Y):
    """
    Description: Implement the cost function defined by equation. The requested cost function is categorical cross-entropy loss.

    :param AL: probability vector corresponding to your label predictions, shape (num_of_classes, number of examples)
    :param Y: the labels vector (i.e. the ground truth)
    :return: cost: the cross-entropy cost
    """
    inner_sum_classes = np.sum(Y * np.log(AL), axis=0, keepdims=True)
    outer_sum_samples = np.sum(inner_sum_classes, axis=1)
    m = AL.shape[1]
    cost = -1 / m * outer_sum_samples
    return cost

def apply_batchnorm(A):
    """
    Description: performs batchnorm on the received activation values of a given layer.

    :param A: the activation values of a given layer
    :return: NA: the normalized activation values, based on the formula learned in class
    """
    mu = np.mean(A, axis=0, keepdims=True)
    variance = np.var(A, axis=0, keepdims=True)
    epsilon = 0.01
    NA = (A - mu) / np.sqrt(variance + epsilon)
    return NA

"""Part 2 - Backward Propagation"""

def linear_backward(dZ, cache):
    """
    Description: Implements the linear part of the backward propagation process for a single layer

    :param dZ: the gradient of the cost with respect to the linear output of the current layer (layer l)
    :param cache: tuple of values (A_prev, W, b) coming from the forward propagation in the current layer
    :return:dA_prev: Gradient of the cost with respect to the activation (of the previous layer l-1), same shape as A_prev
    :return: dW: Gradient of the cost with respect to W (current layer l), same shape as W
    :return: db: Gradient of the cost with respect to b (current layer l), same shape as b
    """
    m = dZ.shape[1]
    dA_prev = np.dot(cache['W'].T, dZ)
    dW = (1 / m) * np.dot(dZ, cache['A'].T)
    db = (1 / m) * np.sum(dZ, axis=1, keepdims=True)
    return dA_prev, dW, db

def linear_activation_backward(dA, cache, activation):
    """
    Description: Implements the backward propagation for the LINEAR->ACTIVATION layer.
    The function first computes dZ and then applies the linear_backward function.

    :param dA: post activation gradient of the current layer
    :param cache: contains both the linear cache and the activations cache
    :param activation: the activation function name = ['relu' or 'softmax']
    :return: dA_prev: Gradient of the cost with respect to the activation (of the previous layer l-1), same shape as A_prev
    :return: dW: Gradient of the cost with respect to W (current layer l), same shape as W
    :return: db: Gradient of the cost with respect to b (current layer l), same shape as b
    """
    if activation == 'softmax':
        dZ = softmax_backward(dA, cache['activation_cache'])
    elif activation == 'relu':
        dZ = relu_backward(dA, cache['activation_cache'])
    dA_prev, dW, db = linear_backward(dZ, cache['linear_cache'])
    return dA_prev, dW, db

def relu_backward(dA, activation_cache):
    """
    Description: Implements backward propagation for a ReLU unit

    :param dA: the post-activation gradient
    :param activation_cache: contains Z (stored during the forward propagation)
    :return: dZ: gradient of the cost with respect to Z
    """
    derivative = activation_cache
    derivative[derivative >= 0] = 1
    derivative[derivative < 0] = 0
    dZ = dA * derivative
    return dZ

def softmax_backward(dA, activation_cache):
    """
    Description: Implements backward propagation for a softmax unit

    :param dA: the post-activation gradient
    :param activation_cache: contains Z (stored during the forward propagation)
    :return: dZ: gradient of the cost with respect to Z
    """
    AL = activation_cache['AL']
    Y = activation_cache['Y']
    dZ = AL - Y
    return dZ

def l_model_backward(AL, Y, caches):
    """
    Description: Implement the backward propagation process for the entire network.

    :param AL: the probabilities vector, the output of the forward propagation (L_model_forward)
    :param Y: the true labels vector (the "ground truth" - true classifications)
    :param caches: list of caches containing for each layer: a) the linear cache; b) the activation cache
    :return: Grads: a dictionary with the gradients
              grads["dA" + str(l)] = ...
              grads["dW" + str(l)] = ...
              grads["db" + str(l)] = ...
    """
    grads = dict()
    num_of_layers = len(caches)

    last_cache = caches[-1]
    last_cache['activation_cache'] = dict({'AL': AL, 'Y': Y, 'Z': last_cache['activation_cache']})

    dA_prev, dW, db = linear_activation_backward(None, last_cache, "softmax")   # dA = None cause not necessary
    grads["dA" + str(num_of_layers)] = dA_prev
    grads["dW" + str(num_of_layers)] = dW
    grads["db" + str(num_of_layers)] = db

    for l in range(num_of_layers - 1, 0, -1):
        dA_prev, dW, db = linear_activation_backward(dA_prev, caches[l - 1], "relu")
        grads["dA" + str(l)] = dA_prev
        grads["dW" + str(l)] = dW
        grads["db" + str(l)] = db

    return grads

def update_parameters(parameters, grads, learning_rate):
    """
    Description: Updates parameters using gradient descent

    :param parameters: a python dictionary containing the DNN architecture’s parameters
    :param grads: a python dictionary containing the gradients (generated by L_model_backward)
    :param learning_rate: the learning rate used to update the parameters (the “alpha”)
    :return: parameters: the updated values of the parameters object provided as input
    """
    num_of_layers = int(len(parameters.keys()) / 2)
    for l in range(1, num_of_layers + 1):
        parameters[f"W{l}"] = parameters[f"W{l}"] - learning_rate * grads[f"dW{l}"]
        parameters[f"b{l}"] = parameters[f"b{l}"] - learning_rate * grads[f"db{l}"]
    return parameters

"""Part 3 - Train and Predict"""

def train_validation_split(X, Y, train_size):
    """
    Description: (auxiliary function) split the train set into train and validation sets
    :param X: train set samples
    :param Y: train set labels
    :param train_size: percentage of the train set
    :return: tuples of (x_train, y_train), (x_val, y_val)
    """
    # create indices for train and validation sets
    indices = list(range(0, X.shape[1]))
    random.shuffle(indices)
    num_of_x_train_samples = math.ceil(X.shape[1] * train_size)

    # split train & validation
    x_train, y_train = X[:, indices[0:num_of_x_train_samples]], Y[:, indices[0:num_of_x_train_samples]]
    x_val, y_val = X[:, indices[num_of_x_train_samples:X.shape[1]]], Y[:, indices[num_of_x_train_samples:X.shape[1]]]

    return (x_train, y_train), (x_val, y_val)

def l_layer_model(X, Y, layers_dims, learning_rate, num_iterations, batch_size):
    """
    Description: Implements a L-layer neural network. All layers but the last should have the ReLU activation function,
    and the final layer will apply the softmax activation function. The size of the output layer should be equal to
    the number of labels in the data. Please select a batch size that enables your code to run well
    (i.e. no memory overflows while still running relatively fast).
    the function should use the earlier functions in the following order:
    initialize -> L_model_forward -> compute_cost -> L_model_backward -> update parameters

    :param X: the input data, a numpy array of shape (height*width , number_of_examples)
    :param Y: the “real” labels of the data, a vector of shape (num_of_classes, number of examples)
    :param layers_dims: a list containing the dimensions of each layer, including the input
    :param learning_rate: alpa parameter
    :param num_iterations: number of iterations - each iteration equals to one batch
    :param batch_size: the number of examples in a single training batch
    :return: parameters: the parameters learnt by the system during the training (the same parameters that were updated in the update_parameters function).
    :return: costs:  the values of the cost function (calculated by the compute_cost function). One value is to be saved after each 100 training iterations (e.g. 3000 iterations -> 30 values).

    """
    costs_val = []
    costs_train = []
    parameters = initialize_parameters(layers_dims)
    is_batchnorm = True  # change to True when batchnorm is needed
    epoch = 0
    val_accuracy = -1
    train_accuracy = -1
    log = []

    (x_train, y_train), (x_val, y_val) = train_validation_split(X, Y, 0.8)

    # split x and y train sets to batches
    num_of_batches = math.ceil(x_train.shape[1] / batch_size)
    batches_x = np.array_split(x_train, num_of_batches, axis=1)
    batches_y = np.array_split(y_train, num_of_batches, axis=1)

    for num_of_iteration in range(0, num_iterations):

        batch_num = num_of_iteration % num_of_batches  # current batch number
        current_batch_x, current_batch_y = batches_x[batch_num], batches_y[batch_num]  # get current batches

        AL, caches = l_model_forward(current_batch_x, parameters, is_batchnorm)
        grads = l_model_backward(AL, current_batch_y, caches)
        parameters = update_parameters(parameters, grads, learning_rate)

        # each hundred iterations compute costs for current batch and validation set, and accuracy for validation and
        # train sets
        if num_of_iteration % 100 == 0:
            AL_val, caches_val = l_model_forward(x_val, parameters, is_batchnorm)
            costs_val.append(compute_cost(AL_val, y_val))
            val_accuracy = predict(x_val, y_val, parameters)

            AL_batch, caches_train = l_model_forward(current_batch_x, parameters, is_batchnorm)
            costs_train.append(compute_cost(AL_batch, current_batch_y))
            log.append(f"Iteration: {num_of_iteration}, Cost: {costs_train[-1]}")
            train_accuracy = predict(x_train, y_train, parameters)

            print(
                f"Epoch: {epoch}, Iteration: {num_of_iteration}, batch_loss: {costs_train[-1]}, train_accuracy: {train_accuracy}, val_loss: {costs_val[-1]}, validation_accuracy: {val_accuracy}")

            # stopping criterion - no improvement on the validation set - threshold = 0.05
            if len(costs_val) > 2 and (costs_val[-1] - costs_val[-2] >= 0.005) and (costs_val[-2] - costs_val[-3] >= 0.005):
                print("Early stopping reached.")
                break

        # count epochs
        if num_of_iteration % num_of_batches == 0 and num_of_iteration > 0:
            epoch += 1

    print(f"val_accuracy {val_accuracy}")
    plot_model_history(costs_val, "Validation")

    print(f"train_accuracy {train_accuracy}")
    plot_model_history(costs_train, "Training")

    print(*log, sep="\n")  # for report

    return parameters, costs_train

def predict(X, Y, parameters):
    """
    Description: The function receives an input data and the true labels and calculates the accuracy of the trained neural network on the data.

    :param X: the input data, a numpy array of shape (height*width, number_of_examples)
    :param Y: the “real” labels of the data, a vector of shape (num_of_classes, number of examples)
    :param parameters: a python dictionary containing the DNN architecture’s parameters
    :return: accuracy – the accuracy measure of the neural net on the provided data
    (i.e. the percentage of the samples for which the correct label receives the highest confidence score).
     Use the softmax function to normalize the output values.
    """
    is_batchnorm = True    # change to True when batchnorm is needed
    AL, caches = l_model_forward(X, parameters, is_batchnorm)
    y_predict = (AL == np.amax(AL, axis=0)).astype(int)  # the class with the maximum prob is the predicted class
    accuracy = np.sum(y_predict * Y) / AL.shape[1]  # sum number of correct predictions
    return accuracy

def plot_model_history(costs_list, type):
    """
    Description: (auxiliary function) Plot graph of cost per 100 iterations
    :param costs_list:
    :param type: str - validation or training
    """
    x_index = range(0, len(costs_list)*100, 100)
    plt.plot(x_index, costs_list)
    plt.title(f'{type} Model Costs')
    plt.ylabel('Costs')
    plt.xlabel('Iterations')
    plt.show()

"""Part 4 - MNIST classification - W/out batchnorm"""

# load MNIST data
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data(path='mnist.npz')

# normalize train and test sets
x_train = x_train / 255
x_test = x_test / 255

# flatten matrices
x_train = x_train.reshape(x_train.shape[0], 784).T
x_test = x_test.reshape(x_test.shape[0], 784).T

# encode y vectors to one hot vector
num_of_classes = len(np.unique(y_train))
y_train_one_hot = np.zeros((num_of_classes, y_train.shape[0]))
y_train_one_hot[y_train, np.arange(y_train.shape[0])] = 1
y_test_one_hot = np.zeros((num_of_classes, y_test.shape[0]))
y_test_one_hot[y_test, np.arange(y_test.shape[0])] = 1

# run network
layers_dims = [x_train.shape[0], 20, 7, 5, 10]
learning_rate = 0.009
num_iterations = 50000
batch_size = 32

start = time.time()

parameters, costs = l_layer_model(x_train, y_train_one_hot, layers_dims, learning_rate, num_iterations, batch_size)
accuracy = predict(x_test, y_test_one_hot, parameters)

print(f"Total time: {(time.time() - start)} seconds.")
print(f"Test Accuracy: {accuracy}")


import numpy as np

if __name__ == '__main__':
    m,n = [int(i) for i in input().strip().split(' ')]
    X = []
    Y = []
    for i in range(n):
        data = input().strip().split(' ')
        X.append(data[:m])
        Y.append(data[m:])
    q = int(input().strip())
    X_new = []
    for x in range(q):
        X_new.append(input().strip().split(' '))
    X = np.array(X,float)
    Y = np.array(Y,float)
    X_new = np.array(X_new,float)

    #center
    X_R = X-np.mean(X,axis=0)
    Y_R = Y-np.mean(Y)

    #calculate beta
    beta = np.dot(np.linalg.inv(np.dot(X_R.T,X_R)),np.dot(X_R.T,Y_R))

    #predict
    X_new_R = X_new-np.mean(X,axis=0)
    Y_new_R = np.dot(X_new_R,beta)
    Y_new = Y_new_R + np.mean(Y)

    #print
    for i in Y_new:
        print(round(float(i),2))


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

from sympy import *
x, t, z, nu = symbols('x t z nu')
init_printing(use_unicode=True)
print(diff(sin(x)*exp(x), x))
print(integrate(exp(x)*sin(x) + exp(x)*cos(x), x))
print(integrate(sin(x**2), (x, -oo, oo)))
print(limit(sin(x)/x, x, 0))
print(solve(x**2 - 2, x))
y = Function('y')
print(dsolve(Eq(y(t).diff(t, t) - y(t), exp(t)), y(t)))
print(Matrix([[1, 2], [2, 2]]).eigenvals())
print(besselj(nu, z).rewrite(jn))
print(latex(Integral(cos(x)**2, (x, 0, pi))))


import numpy as np

grades = [88, 82, 85, 84, 90]
mean = np.mean(grades)

#When calculating these variables, square the difference.
difference_one = (88 - mean) ** 2
difference_two = (82 - mean) ** 2
difference_three = (85 - mean) ** 2
difference_four = (84 - mean) ** 2
difference_five = (90 - mean) ** 2

difference_sum = difference_one + difference_two + difference_three + difference_four + difference_five

variance = difference_sum / 5

print("The sum of the squared differences is " + str(difference_sum))
print("The variance is " + str(variance))

Data Scientist Career Path/7. Summary Statistics/3. Variance n Standard Deviation/1. Variance/4. square.py


import numpy as np
import math as m

def coswin(a,n):
    t = np.linspace(0,1,n)
    # Section 1
    i = 0
    res = []
    while t[i] >= 0.0 and t[i] <= a:
        c1 = (1-m.cos(m.pi/a*t[i]))/2
        res.append(c1)
        i = i + 1

    # Section 2
    j = 0
    while t[j] <= a:
        j = j + 1
        while t[j] >= a and t[j] <= (1-a):
            c2 = 1.0
            res.append(c2)
            j = j + 1

    # Section 3
    k = 0
    while t[k] <= (1-a):
        k = k + 1
    kk = k+1
    while kk <= n:
        c3 = (1-m.cos(m.pi/a*(1-t[kk-1])))/2
        res.append(c3)
        kk = kk + 1
    return res


import numpy as np
import matplotlib.pyplot as plt

def mandelbrot (c):
    p = 0
    z = 0
    while (p < 50 and abs(z) <= 2):
        z = z**2 + c
        p+=1
    if (p<50):
        return p
    else:
        return -1

def show_mandelbrot (lng):
    x = np.linspace(-2,2,lng)
    y = np.linspace(-2,2,lng)
    iteration = np.zeros((lng, lng))
    for i in range(len(x)):
        for j in range(len(y)):
            iteration[i,j]=mandelbrot(complex(x[i],y[j]))
    plt.imshow(iteration)
    plt.show()

#show_mandelbrot(1000)

def julia (c, z):
    p = 0
    while (p < 50 and abs(z) <= 2):
        z = z**2 + c
        p+=1
    if (p<50):
        return p
    else:
        return -1

def show_julia (c, lng, save):
    x = np.linspace(-2,2,lng)
    y = np.linspace(-2,2,lng)
    iteration = np.zeros((lng, lng))
    for i in range(len(x)):
        for j in range(len(y)):
            iteration[i,j]=julia(c, complex(x[i],y[j]))
    fig=plt.imshow(iteration)
    if (save):
        plt.axis('off')
        plt.savefig('julia_' + str(c.real) + '+i(' + str(c.imag) + ').png', figsize=(lng, lng), bbox_inches='tight', pad_inches=0, dpi=lng)
    else:
        plt.show()

#show_julia(complex(0.28,0.53),15000, False)
#show_julia(complex(0.28,0.53),1000 False)
#show_julia(complex(-0.63,0.67),1000, False)
show_julia(complex(-0.85,0.2),1000, True)


import numpy as np

"""
# Equation
	3x - 2y = 7
	2x - 2y = 2
--------------
We know, Ax = b, where A => co-efficient matrix
		       b => constant-vector
		       x => unknowns
"""
A = np.array([[3, -2], [2, -2]])
b = np.array([7, 2])

solution_vector = np.linalg.solve(A, b)
print(solution_vector) # [5, 4]


import numpy as np
import pandas as pd

def calc_mse(y_pred, y_true):
    return np.mean(np.square(y_true - y_pred))

def calc_mae(y_pred, y_true):
    return np.mean(np.abs(y_true - y_pred))

def calc_mape(y_pred, y_true):
    y_true[y_true == 0] = 1
    return np.mean(np.abs(y_true - y_pred) / np.abs(y_true))

def calc_corr_error(y_pred, y_true):
    return np.corrcoef(y_pred, y_true)[0, 1]

def calc_min_max_error(y_pred, y_true):
    mins = np.amin(np.hstack([y_pred[:, None],
                              y_true[:, None]]), axis=1)
    maxs = np.amax(np.hstack([y_pred[:, None],
                              y_true[:, None]]), axis=1)

    return 1 - np.mean(mins / maxs)

def measure_error(preds, test_df, target_col):
    cols = ['date', 'actual', 'forecast']
    test_df = pd.DataFrame(test_df[target_col]).reset_index()

    y_pred = preds
    y_true = test_df[target_col].values

    mse = calc_mse(y_pred, y_true)
    mae = calc_mae(y_pred, y_true)
    mape = calc_mape(y_pred, y_true)
    corr = calc_corr_error(y_pred, y_true)
    minmax = calc_min_max_error(y_pred, y_true)

    result_df = test_df.copy(deep=True)
    result_df['pred'] = y_pred
    result_df.columns = cols

    error = {'Mean Squared Error': mse,
             'Mean Absolute Error': mae,
             'Mean Absolute Percentage Error': mape,
             'Correlation between forecast and actual values': corr,
             'Min-Max Error': minmax}

    return result_df, error


import numpy as np
from math import cos, sin, pi, radians, pow
from pyquaternion import Quaternion

def rot_matrix_z(theta):
    return np.array([[cos(theta), -sin(theta), 0],
                      [sin(theta), cos(theta), 0],
                      [0, 0, 1]])

def rot_matrix_y(beta):
    return np.array([[cos(beta), 0, sin(beta)],
                      [0, 1, 0],
                      [-sin(beta), 0, cos(beta)]])

def rot_matrix_x(gamma):
    return np.array([[1, 0, 0],
                      [0, cos(gamma), -sin(gamma)],
                      [0, sin(gamma), cos(gamma)]])

def rot_matrix_aggregate(roll, pitch, yaw):
    #return (rot_matrix_z(yaw) * (rot_matrix_y(pitch) * rot_matrix_x(roll)))
    return rot_matrix_z(yaw).dot(rot_matrix_y(pitch).dot(rot_matrix_x(roll)))

def rot_matrix(roll, pitch, yaw):
    # gamma is roll
    # beta is pitch
    # alpha is yaw
    ca = cos(yaw)
    cb = cos(pitch)
    sa = sin(yaw)
    sb = sin(pitch)
    sg = sin(roll)
    cg = cos(roll)

    return np.array([[ca*cb, ca*sb*sg - sa*cg, ca*sb*cg + sa*sg],
                      [sa*cb, sa*sb*sg + ca*cg, sa*sb*cg - ca*sg],
                      [-sb, cb*sg, cb*cg]])

def T(roll, pitch, yaw, translate):
    m = np.identity(4, dtype=float)
    m[:3,:3] = rot_matrix(0, 0, 0)
    m[:3,3] = translate
    return m

def skew_sym(w):
    return np.array([[  0,   -w[2], +w[1]],
                     [+w[2],   0,   -w[0]],
                     [-w[1], +w[0],    0]])

def exp_so3(theta, w):
    return np.identity(3) + sin(theta)/theta * skew_sym(w) \
        + (1-cos(theta))/skew_sym(pow(theta,2))

def main():
    roll = radians(10)
    pitch = radians(-20)
    yaw = radians(180)

    R_agg = rot_matrix_aggregate(roll, pitch, yaw)
    print(R_agg)

    R = rot_matrix(roll, pitch, yaw)
    print(R)

    diff = R_agg - R
    print(diff)

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

    my_T = T(roll, pitch, yaw, translate)
    print(my_T)

    Q_rot = Quaternion(axis=[0, 0, 1], angle=yaw) * Quaternion(axis=[0, 1, 0], angle=pitch) * Quaternion(axis=[1, 0, 0], angle=roll)
    print(Q_rot.rotation_matrix)
    print(Q_rot.rotation_matrix - R)

    Q_rot_unit = Q_rot.unit
    print(Q_rot_unit)

if __name__ == '__main__':
    main()


#!/usr/bin/env python
import scipy
import numpy as np
import scipy.stats

def cdf( d ):
    '''
    Input:  (d)    iterable, a data set
    Output: (f)    NumPy array with (bins) rows and two columns
                   the first column are values in the range of (d)
                   the second column are CDF values
                   alternatively, think of the columns as the
                   domain and range of the CDF function
            (finv) inverse of (f)
    ---------------------------------------------------------
    Calculate the cumulative distribution function
    and its inverse for a given data set
    '''
    # the number of data points
    N = float( len( d ) )
    # sorted array of data points
    xs = np.sort( d )
    # array of unique data points
    xu = np.unique( xs )
    # number of unique data points
    U = len( xu )
    # initialize an array of U zeros
    cdf = np.zeros((U))
    # for each unique data point..
    for i in range( U ):
        # count the number of points less than
        # this point, and then divide by the
        # total number of data points
    	cdf[i] = len( xs[ xs < xu[i] ] ) / N
    # f : input value --> output percentage describing
    # the number of points less than the input scalar
    # in the modeled distribution; if 5 is 20% into
    # the distribution, then f[5] = 0.20
    f = np.vstack((xu,cdf)).T
    # inverse of f
    # finv : input percentage --> output value that
    # represents the input percentage point of the
    # distribution; if 5 is 20% into the distribution,
    # then finv[0.20] = 5
    finv = np.fliplr(f)
    return f, finv

def fit( d ):
    '''
    Input:  (d) NumPy array with two columns,
                a domain and range of a mapping
    Output: (f) function that interpolates the mapping d
    ----------------------------------------------------
    This takes a mapping and returns a function that
    interpolates values that are missing in the original
    mapping, and maps values outside the range* of the
    domain (d) to the maximum or minimum values of the
    range** of (d), respectively.
    ----------------------------------------------------
    *range - here, I mean "maximum minus minimum"
    **range - here I mean the output of a mapping
    '''
    x, y = d[:,0], d[:,1]
    def f(t):
        # return the minimum of the range
        if t <= x.min():
            return y[ np.argmin(x) ]
        # return the maximum of the range
        elif t >= x.max():
            return y[ np.argmax(x) ]
        # otherwise, interpolate linearly
        else:
            intr = scipy.interpolate.interp1d( x, y )
            return intr(t)
    return f

def to_norm( data ):
    '''
    Input  (data) 1D NumPy array of observational data
    Output (z)    1D NumPy array of z-score transformed data
           (inv)  inverse mapping to retrieve original distribution
    '''
    # look at the dimensions of the data
    dims = data.shape
    # if there is more than one dimension..
    if len( dims ) > 1:
        # take the third column of the second dimension
        z = data[:,2]
    # otherwise just use data as is
    else:
        z = data
    # grab the number of data points
    N = len( z )
    # grab the cumulative distribution function
    f, inv = cdf( z )
    # h will return the cdf of z
    # by interpolating the mapping f
    h = fit( f )
    # ppf will return the inverse cdf
    # of the standard normal distribution
    ppf = scipy.stats.norm(0,1).ppf
    # for each data point..
    for i in range( N ):
        # h takes z to a value in [0,1]
        p = h( z[i] )
        # ppf takes p (in [0,1]) to a z-score
        z[i] = ppf( p )
    # convert positive infinite values
    posinf = np.isposinf( z )
    z = np.where( posinf, np.nan, z )
    z = np.where( np.isnan( z ), np.nanmax( z ), z )
    # convert negative infinite values
    neginf = np.isneginf( z )
    z = np.where( neginf, np.nan, z )
    z = np.where( np.isnan( z ), np.nanmin( z ), z )
    # if the whole data set was passed, then add the
    # transformed variable and recombine with data
    if len( dims ) > 1:
        z = np.vstack(( data[:,:2].T, z )).T
    return z, inv

def from_norm( data, inv ):
    '''
    Input:  (data) NumPy array of zscore data
            (inv)  mapping that takes zscore data back
                   to the original distribution
    Output: (z)    Data that should conform to the
                   distribution of the original data
    '''
    # convert to a column vector
    d = data.ravel()
    # create an interpolating function
    # for the inverse cdf, mapping zscores
    # back to the original data distribution
    h = fit( inv )
    # convert z-score data to cdf values in [0,1]
    f = scipy.stats.norm(0,1).cdf( d )
    # use inverse cdf to map [0,1] values to the
    # original distribution, then add the mu and sd
    z = np.array( [ h(i) for i in f ] )
    # reshape the data
    z = np.reshape( z, data.shape )
    return z


from numpy import zeros

# Define euler function
def euler(f,t0,tf,y0,n):
    h = (tf - t0)/n
    t = zeros(n+1)
    y = zeros(n+1)
    t[0] = t0
    y[0] = y0
    for i in range(n):
        y[i+1] = y[i] + h * f(t[i],y[i])
        t[i+1] = t[i] + h
    return t,y

# Define functions
def f(t,y):
    return  t - y

# Set initial conditions
t0 = 0.0
tf = 1.0
y0 = 1.0
n = 5

# Execute the function and print
t, yel = euler(f,t0,tf,y0,n)

print('%9s %9s' % ('t','y'))
for i in range(n+1):
    print('%9.4f %9.4f' % (t[i],yel[i]))


from mpl_toolkits import mplot3d
import numpy as np
import matplotlib.pyplot as plt

cm = plt.cm.RdBu

def get_Z(X, Y):
    Z = 0.8*np.sinc(np.sqrt(np.square(X) + np.square(Y))) + .8*np.sin(1.5*X + np.pi/4) +\
        0.5*np.sinc(np.sqrt((X-2) ** 2 + (Y-1) ** 2)) + \
        0.6*np.sinc(np.sqrt((X+1.5) ** 2 + (Y-1.5) ** 2)) +\
        0.3*X + 5.0 + 0.2*Y +\
        2*np.asarray(X > 0, dtype=float)* np.sin(0.5*X) +\
        (np.sqrt(X**2+Y**2)-np.sqrt(50)) * (np.sqrt(X**2 + Y**2) > np.sqrt(50))
    return Z

init = (np.asarray(3.8), np.asarray(2.5))

def get_path(init, SGD=False):
    iters = 10
    lr = 4
    c = init
    l = [c]
    decay = 0.98
    for step in range(iters):
        alpha = lr*decay**step
        y, x = c
        z = get_Z(*np.meshgrid(np.linspace(x-1, x+1, 11), np.linspace(y-1, y+1, 11)))
        g_y, g_x = np.gradient(z)
        g_y, g_x = g_y[5,5], g_x[5,5]
        if SGD:
            g_y += np.random.randn()*0.05
            g_x += np.random.randn()*0.05
        c = y-alpha*g_y, x-alpha*g_x
        l.append(c)
    l_y, l_x = tuple(zip(*l))
    return np.asarray(l_y), np.asarray(l_x)

fig = plt.figure()
ax = plt.axes(projection='3d')

# BGD
bgd_y_path, bgd_x_path = get_path(init)

ax.plot(xs=bgd_x_path, ys=bgd_y_path, zs=get_Z(bgd_x_path, bgd_y_path), c='#234a28', lw=1, zorder=100, label='BGD')
# SGD
sgd_y_path, sgd_x_path = get_path(init, SGD=True)
ax.plot(xs=sgd_x_path, ys=sgd_y_path, zs=get_Z(sgd_x_path, sgd_y_path), c='#aaff00', lw=1, zorder=100, label='SGD')

lim = 5.0
x = np.linspace(-0.1 + min(bgd_x_path.min(), sgd_x_path.min()),
                .1+max(bgd_x_path.max(), sgd_x_path.max()), 256)
y = np.linspace(-.1 + min(bgd_y_path.min(), sgd_y_path.min()),
                .1+max(bgd_y_path.max(), sgd_y_path.max()), 256)
XX, YY = np.meshgrid(x, y)
Z = get_Z(XX, YY)
ax.plot_surface(XX, YY, Z, cmap=cm)

ax.set_zticks([])
plt.xticks([])
plt.yticks([])
plt.legend()
plt.show()


import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import math
import sys
import os

data_dir = sys.argv[1]
out_dir = sys.argv[2]
dataX = os.path.join(sys.argv[1], 'logisticX.csv')
dataY = os.path.join(sys.argv[1], 'logisticY.csv')

# 3. Logistic Regression

trainX = np.loadtxt(dataX, delimiter=',')
trainY = np.loadtxt(dataY)

def normalize(X):
	mu = np.mean(X)
	sigma = np.std(X)
	return (X - mu)/sigma

X1 = normalize(trainX[:,0])
X2 = normalize(trainX[:,1])
X = np.column_stack((X1, X2))
X = np.column_stack((np.ones(X.shape[0]), X))
Y = trainY.reshape(-1,1)
m = len(trainY)

# (a) Logistic Regression

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

def hw(theta, x):
	return sigmoid(np.dot(x, theta))

def LLw(y, h):
	return -1*np.sum(y*np.log(h) + (1-y)*np.log(1-h))

def dJw(x, y, h):
	return np.dot(x.T, (h - y))

def Hessian(x, h):
	A = np.diag((h*(1-h)).reshape(-1,))
	return np.dot(np.dot(x.T, A), x)

def LogisticRegression(x, y):
	theta = np.zeros((x.shape[1], 1))
	h = hw(theta, x)
	prevCost = LLw(y, h)
	converged = False
	itr = 0

	while not converged:
		H = Hessian(x, h)
		theta = theta - np.dot(np.linalg.pinv(H), dJw(x, y, h))
		h = hw(theta, x)
		cost = LLw(y, h)
		error = abs(cost - prevCost)
		prevCost = cost
		itr += 1
		if error < 1e-10 or itr > 10:
			converged = True
	return theta

theta = LogisticRegression(X, Y)

def computeY(theta, x):
	return -(theta[0] + (theta[1] * x)) / theta[2]

def plotDecisionBoundary():
	x1 = np.array([X[i,1:3] for i in np.where(Y == 0)[0]])
	x2 = np.array([X[i,1:3] for i in np.where(Y == 1)[0]])

	plt.plot(x1[:,0], x1[:,1], 'ro', marker = '.', label = 'Negative')
	plt.plot(x2[:,0], x2[:,1], 'bo', marker = '+', label = 'Positive')

	axes = plt.gca()
	xv = np.array(axes.get_xlim())
	yv = computeY(theta, xv)
	plt.plot(xv, yv, color = 'green')
	plt.xlabel(r'$X_1$')
	plt.ylabel(r'$X_2$')
	plt.title('Decision Boundary')
	plt.legend()
	decision_boundary = os.path.join(sys.argv[2], "Q3bDecisionBoundary.png")
	plt.savefig(decision_boundary)
	plt.close()

plotDecisionBoundary()


from scipy.integrate import odeint, simps
import numpy as np
import matplotlib.pyplot as plt

def pend(y, t, b, c):
    theta, omega = y
    dydt = [omega, -b*omega - c*np.sin(theta)]
    return dydt

b = 0.025
c = 5.0
y0 = [np.pi - 0.1, 0.0]
t = np.linspace(0, 100, 1001)
sol = odeint(pend, y0, t, args=(b, c))

x, p = sol.T[0], sol.T[1]
plt.plot(x, p, ".", markersize=4)
plt.pause(3)
plt.savefig('plot_xp.png', dpi=60)
plt.close()

plt.plot(t, sol[:, 0], 'b', label='theta(t)')
plt.xlabel('t')
plt.grid()
plt.legend(loc='best')
plt.pause(3)
plt.plot(t, sol[:, 1], 'g', label='omega(t)')
plt.legend(loc='best')
plt.pause(3)
plt.savefig('plot_thomegavst.png', dpi=60)
plt.close()

def dualPendulum(y, t, L1, L2,g,m1,m2):
    """
    (𝑚1 +𝑚2)𝑙1^2𝜃1̈  = -(+𝑚2𝑙1𝑙2(𝜃2̈ cos(𝜃1 −𝜃2)+𝜃2̇ ^2 sin(𝜃1 −𝜃2)) +(𝑚1 +𝑚2)𝑔𝑙1 sin𝜃1)
    𝑚2𝑙2^2𝜃2̈  = -(+𝑚2𝑙1𝑙2(𝜃1̈ cos(𝜃1 −𝜃2)−𝜃1̇ 2 sin(𝜃1 −𝜃2)) +𝑚2𝑔𝑙2 sin𝜃2)
    𝜃1'' = - (a*(𝜃2''*cos(𝜃1-𝜃2)+𝜃2'^2*sint(𝜃1-𝜃2)) + b*sint𝜃1)
    𝜃2'' = -(c*(𝜃1''*cos(𝜃1-𝜃2)-𝜃1'^2*sin(𝜃1-𝜃2))+d*sin𝜃1)

    𝜃1'(t) = ω1(t)
    𝜃2'(t) = ω2(t)
    ω1'(t) = - (a*(ω2'*cos(𝜃1-𝜃2)+ω2^2*sin(𝜃1-𝜃2)) + b*sin𝜃1)
    ω2'(t) = - (c*(ω1'*cos(𝜃1-𝜃2)-ω1^2*sin(𝜃1-𝜃2)) + d*sin𝜃1)
    ω1'(t) = (-g(2m1+m2)sin𝜃1-m2gsin(θ1−2θ2)-2sin(θ12)m2(ω2^2L2+ω1^2L1cos(θ12)))/(L1(2m1+m2 - m2cos(2𝜃12))
    ω2'(t) = (2sin𝜃12(ω1^2L1(m1+m2)+g(m1+m2)cos(θ1)+ω2^2L2m2cos𝜃12))/(L2(2m1+m2 - m2cos(2𝜃12))

    ω1'(t) = -b*omega1(t) - c*sin(theta1(t)) - k*theta21
    ω2'(t) = -b*omega2(t) - c*sin(theta2(t)) + k*theta21

    theta''(t) + b*theta'(t) + c*sin(theta(t)) = 0
    theta'(t) = omega(t)
    omega'(t) = -b*omega(t) - c*sin(theta(t))
    """
    theta1, omega1,theta2, omega2 = y
    #theta21=theta2-theta1
    dydt = [omega1, (-g*(2*m1+m2)*np.sin(theta1)-m2*g*np.sin(theta1-theta2)-2*np.sin(theta1-theta2)*m2*(omega2*omega2*L2+omega1*omega1*L1*np.cos(theta1-theta2)))/(L1*(2*m1+m2-m2*np.cos(2*(theta1-theta2)))), omega2, (2*np.sin(theta1-theta2)*(omega1*omega1*L1*(m1+m2)+g*(m1+m2)*np.cos(theta1)+omega2*omega2*L2*m2*np.cos(theta1-theta2)))/(L2*(2*m1+m2 - m2*np.cos(2*(theta1-theta2))))]
    return dydt

L1=500
L2=497.1
g=9.8
m1=10000
m2=1750
#b = 0.001  #0.025
#c = 5.0
y01=0.99990
y0 = [y01, 0.0,0, 0.0]
t = np.linspace(0, 10000, 4001)
sol = odeint(dualPendulum, y0, t, args=(L1, L2,g,m1,m2))

x1, p1,x2,p2 = sol.T[0], sol.T[1], sol.T[2], sol.T[3]
plt.plot(x1, p1, ".", markersize=4)
plt.pause(3)
plt.savefig('plot_xp1omega_L1{}L2{}m1{}m2{}y01{}n.png'.format(L1,L2,m1,m2,y01), dpi=180)
plt.close()
plt.plot(x2, p2, ".", markersize=4)
plt.pause(3)
plt.savefig('plot_xp2omega_L1{}L2{}m1{}m2{}y01{}n.png'.format(L1,L2,m1,m2,y01),dpi=180)
plt.close()

plt.plot(t, sol[:, 0], 'b', label='theta1(t)')
plt.xlabel('t')
plt.xlim(0,10000)
#plt.ylim(-0.5,0.5)
plt.grid()
plt.legend(loc='best')
plt.pause(3)
plt.plot(t, sol[:, 2], 'g', label='theta2(t)')
plt.legend(loc='best')
plt.pause(3)
plt.savefig('plot_theta2vst010000_L1{}L2{}m1{}m2{}y01{}n.png'.format(L1,L2,m1,m2,y01), dpi=180)
plt.close()

plt.plot(t, sol[:, 1], 'b', label='omega1(t)')
plt.xlabel('t')
plt.xlim(0,10000)
#plt.ylim(-1,1)
plt.grid()
plt.legend(loc='best')
plt.pause(3)
plt.plot(t, sol[:, 3], 'g', label='omega2(t)')
plt.legend(loc='best')
plt.pause(3)
plt.savefig('plot_omega2vst010000_L1{}L2{}m1{}m2{}y01{}n.png'.format(L1,L2,m1,m2,y01), dpi=180)
plt.close()


# Linear regression example
# including confidence intervals for params
from scipy import linspace, polyval, polyfit, sqrt, stats, randn
from pylab import figure, plot, title, show , legend, xlabel, ylabel, grid
from numpy import arange, linspace, mean, std, zeros, ones
from numpy import loadtxt, array
import scipy.interpolate

## definition
def mylinearregression(x,y,confidence_level):
    """
    function to calculate simple linear regression
    inputs: x,y-data pairs and a confidence level (in percent)
    outputs: slope = b1, intercept = b0 its confidence intervals
    and R (+squared)
    """
    show_plots = 'on'        # 'on' to show data, fit and conf interval
    x_average = mean(x)
    x_stdev = std(x)
    y_average = mean(y)
    y_stdev = std(y)
    n = len(x)
    # calculate linear regression coefficients
    b1 = sum((x-x_average)*(y-y_average))/sum((x-x_average)**2)
    b0 = y_average - b1 * x_average
    #sample_correlation = b1*x_stdev/y_stdev
    # calculate residuals (observed - predicted)
    TotSS = sum((y-y_average)**2)   # Total Sum of Squares
    y_hat = b1 * x + b0             # fitted values
    ResSS = sum((y-y_hat)**2)       # Residual Sum of Squares
    # calculate standard deviations of fit params
    b1_stdev = sqrt((ResSS/(n-2))/sum((x-x_average)**2))
    b0_stdev = b1_stdev*sqrt(sum(x**2)/n)
    # compute the mean square error (variance) and standard error (root of var), R2 and R
    mserr = ResSS/n-2
    sterr = sqrt(mserr)
    R2 = 1 - ResSS/TotSS
    R = sqrt(R2)
    # Pearson's r (this is the same as sample_correlation)
    #pearsonsr = (sum(x*y)-(sum(x)*sum(y))/n)/sqrt((sum(x**2)-sum(x)**2/n)*(sum(y**2)-sum(y)**2/n))
    #print 'Pearsons r = %.3f ' %(pearsonsr)

    ## calculate confidence interval
    # alpha
    alpha = 1.-(confidence_level*1./100.)
    # degrees of freedom (2 lost by estimates of slope and intercept)
    DF = n-2
    # critical value (look up in t table)
    cv = 2.01
    # Margin of error = Critical value x Standard error of the statistic
    moe_b1 = cv * b1_stdev
    moe_b0 = cv * b0_stdev
    lower_b1 = b1-moe_b1
    upper_b1 = b1+moe_b1
    lower_b0 = b0-moe_b0
    upper_b0 = b0+moe_b0
    print ' Report of linear regression:'
    print ' Slope = %.4f +/- %.4f, Intercept = %.4f +/- %.4f' %(b1, moe_b1, b0, moe_b0)
    print ' %g percent confidence interval for slope: %.4f to %.4f' %(confidence_level, lower_b1, upper_b1)
    print ' %g percent confidence interval for intercept: %.4f to %.4f' %(confidence_level, lower_b0, upper_b0)
    # compute confidence lines for plot
    lower = upper_b1 * x + lower_b0
    upper = lower_b1 * x + upper_b0

    if show_plots == 'on':
        figure(1000)
        title('My Linear Regression')
        xlabel('x')
        ylabel('y')
        grid()
        plot(x,y,'bo', label='data')
        plot(x,y_hat,'r.-', label='linear fit')
        plot(x,lower,'c-')
        plot(x,upper,'c-')
        legend(loc='best',numpoints=3)
        # are the residuals normally distributed?
        figure(1001)
        title('Residuals of fit')
        xlabel('x')
        ylabel('Residuals')
        grid()
        plot(x,y-y_hat,'mo')
    return b1,b0,lower_b1,upper_b1,lower_b0,upper_b0,R2,R

### program start: choose wiki data or random data
## WIKIPEDIA DATA
## http://en.wikipedia.org/wiki/Simple_linear_regression
x = [1.47,1.50,1.52,1.55,1.57,1.60,1.63,1.65,1.68,1.70,1.73,1.75,1.78,1.80,1.83]
y = [52.21,53.12,54.48,55.84,57.20,58.57,59.93,61.29,63.11,64.47,66.28,68.10,69.92,72.19,74.46]
x = array(x)
y = array(y)
## Random Sample data creation
n=50
x=linspace(-5,5,n)
#parameters
a=0.7; b=-4
y=polyval([a,b],x)
#add some noise
y=y+randn(n)
print ' Run simple linear regression:'
b1,b0,lower_b1,upper_b1,lower_b0,upper_b0,R2,R = mylinearregression(x, y, 95)
show()


import numpy as np
import matplotlib.pyplot as plt

def Combination(n, i):
    numerator = np.math.factorial(n)
    denomenator = np.math.factorial(i) * np.math.factorial(n - i)
    return numerator / denomenator

def BernsteinBasis(n, i, t):
    return Combination(n, i) * np.math.pow(t, i) * np.math.pow(1.0 - t, n - i)

def BezierCurve(T, Points):
    countPoints = np.size(Points, 0)
    n = countPoints - 1
    dim = np.size(Points, 1)
    rVal = []
    for t in T:
        point = np.zeros(dim)
        for i in range(0, countPoints):
            point += Points[i] * BernsteinBasis(n, i, t)
        rVal.append(point)
    return np.array(rVal)

if __name__ == "__main__":
    #Points = np.array([[0., -1.], [1., 1.], [2., -1.], [3., 1.]]) #Sawtooth Pattern
    #Points = np.array([[0., 0.], [2., 1.], [3., 1.], [5., 0.]]) #arc
    Points = np.array([[0., 0.], [3., 0.], [2., 2.], [1., 1.]]) #hook
    T = np.arange(0, 1, 0.01)

    Curve = BezierCurve(T, Points)

    plt.plot(Points[:, 0], Points[:, 1])
    plt.plot(Curve[:, 0], Curve[:, 1])
    plt.show()


import numpy as np
import matplotlib.pyplot as plt

def perlin_generator(x_min, x_max, y_min, y_max, wavelength, amplitude):
	""" return random values with the same shapes as x and y """
	node_x = np.arange(x_min - wavelength/2, x_max + wavelength, wavelength)
	node_y = np.arange(y_min - wavelength/2, y_max + wavelength, wavelength)
	grad_θ = np.random.uniform(0, 2*np.pi, (len(node_x), len(node_y)))
	grad_x, grad_y = np.cos(grad_θ), np.sin(grad_θ)
	def weight(z):
		return np.sin(z*(np.pi/2))**2

	def aplai(x, y):
		i_part = np.interp(x, node_x, np.arange(len(node_x)))
		i_part = np.clip(i_part, 0, grad_x.shape[0]-1.001)
		j_part = np.interp(y, node_y, np.arange(len(node_y)))
		j_part = np.clip(j_part, 0, grad_y.shape[1]-1.001)
		i, j = np.floor(i_part).astype(int), np.floor(j_part).astype(int)
		a, b = weight(i_part - i), weight(j_part - j)
		unnormed = (grad_x[i,j]*(x - node_x[i]) + grad_y[i,j]*(y - node_y[j])) * (1 - a)*(1 - b) +\
			       (grad_x[i,j+1]*(x - node_x[i]) + grad_y[i,j+1]*(y - node_y[j+1])) * (1 - a)*b +\
			       (grad_x[i+1,j]*(x - node_x[i+1]) + grad_y[i+1,j]*(y - node_y[j])) * a*(1 - b) +\
			       (grad_x[i+1,j+1]*(x - node_x[i+1]) + grad_y[i+1,j+1]*(y - node_y[j+1])) * a*b
		return unnormed*amplitude/wavelength

	return aplai

def perlin(x, y, wavelength, amplitude):
	""" return random values with the same shapes as x and y """
	pg = perlin_generator(x.min(), x.max()+1e-15, y.min(), y.max()+1e-15, wavelength, amplitude)
	return pg(x, y)

def wave_generator(x_min, x_max, y_min, y_max, wavelength, amplitude, dimensions=1):
	θ_0 = np.random.uniform(0, 2*np.pi)
	ɸ_0 = np.random.uniform(0, 2*np.pi)
	z_0 = np.random.normal((x_min + x_max)/2*np.cos(θ_0) + (y_min + y_max)/2*np.sin(θ_0), wavelength/(2*np.pi))

	def aplai(x, y):
		z = x*np.cos(θ_0) + y*np.sin(θ_0)
		return amplitude*np.sin(2*np.pi*z/wavelength + ɸ_0)/(1 + (np.pi*(z - z_0)/wavelength)**2)

	if dimensions == 1:
		return aplai
	elif dimensions == 2:
		return lambda x,y: aplai(x,y)*np.cos(θ_0), lambda x,y: aplai(x,y)*np.sin(θ_0)

if __name__ == '__main__':
	X, Y = np.meshgrid(np.linspace(-5, 5, 216), np.linspace(-5, 5, 216))
	Z = perlin(X, Y, np.pi/2, 1)
	plt.contourf(X, Y, Z)
	plt.colorbar()
	plt.show()


import numpy as np
from sklearn.metrics import mean_squared_error

def APE(actual, forecast):
    return np.abs((actual - forecast) / (actual))

def APE_inv(actual, forecast):
    return np.abs(actual / (actual - forecast))

def sAPE(actual, forecast):
    return np.abs(actual - forecast) / ((actual + forecast) / 2)

def sAPE2(actual, forecast):
    return np.abs((actual - forecast) * ((actual + forecast) / 2) ** 0.5)

def AAPE(actual, forecast):
    return np.arctan(APE(actual, forecast))

def AAPE_inv(actual, forecast):
    return np.arctan(APE_inv(actual, forecast))

def MAPE(actual, forecast):
    return np.mean(APE(actual, forecast))

def MdAPE(actual, forecast):
    return np.median(APE(actual, forecast))

def sMAPE(actual, forecast):
    return np.mean(sAPE(actual, forecast))

def sMAPE2(actual, forecast):
    return np.mean(sAPE2(actual, forecast))

def MAAPE(actual, forecast):
    return np.mean(AAPE(actual, forecast))

def MAAPE_inv(actual, forecast):
    return np.mean(AAPE_inv(actual, forecast))

def RMSE(actual, forecast):
    return np.sqrt(mean_squared_error(actual, forecast))

def median_within(a):
    '''
    Adjusted median to keep the value in the array
    :param a:
    :return:
    '''
    a_ = np.array(a).copy()
    a_.sort()

    return a_[len(a_) // 2]


import numpy as np
import matplotlib.pyplot as plt

nx = 256
ny = 256

x     = np.linspace(0,2*np.pi,nx)
y     = np.linspace(0,2*np.pi,ny)
xx,yy = np.meshgrid(x,y)
x_hat = np.fft.fftfreq(nx)*nx
y_hat = np.fft.fftfreq(ny)*ny
xx_hat,yy_hat  = np.meshgrid(x_hat,y_hat)

x0         = x_hat[32]
y0         = y_hat[16]
sigma      = float(nx)/128.
four_samp  = 1000
kx_samp    = np.random.normal(x0,sigma,four_samp)
ky_samp    = np.random.normal(y0,sigma,four_samp)
signal     = np.zeros([nx,ny])
for i in range(four_samp):
    signal += np.cos(kx_samp[i]*xx) + 0.3*np.cos(ky_samp[i]*yy)
signal /= four_samp

print( x0 , y0 , sigma )
signal_hat = np.fft.ifft2(signal)

plt.figure()
plt.subplot(121); plt.contourf(xx_hat,yy_hat,signal_hat); plt.title('Frequency domain')
plt.subplot(122); plt.contourf(xx,yy,signal); plt.title('Physical domain')
plt.show()

np.save('../data/signal_gaussian_2d.npy',signal)


# Comparing ICA and PCA on data from a 2d uniform distribution
# Author : Aleyna Kara
# This file is based on https://github.com/probml/pmtk3/blob/master/demos/icaDemoUniform.m

import superimport

from sklearn.decomposition import PCA, FastICA
import numpy as np
import matplotlib.pyplot as plt
import pyprobml_utils as pml

def plot_samples(S, title, file_name):
  min_x, max_x = -4, 4
  min_y, max_y = -3, 3
  plt.scatter(S[:, 0], S[:, 1], marker='o',s=16)
  plt.hlines(0, min_x, max_x, linewidth=2)
  plt.vlines(0, min_y, max_y, linewidth=2)
  plt.xlim(min_x, max_x)
  plt.ylim(min_y, max_y)
  plt.title(title)
  pml.savefig(f'{file_name}.pdf')
  plt.show()

np.random.seed(2)
N = 100
A = np.array([[2,3],[2,1]])* 0.3 # Mixing matrix

S_uni = (np.random.rand(N, 2)* 2 - 1)* np.sqrt(3)
X_uni = S_uni @ A.T

pca = PCA(whiten=True)
S_pca = pca.fit(X_uni).transform(X_uni)

ica = FastICA()
S_ica = ica.fit_transform(X_uni)
S_ica /= S_ica.std(axis=0)

plot_samples(S_uni, 'Uniform Data', 'ica-uniform-source')

plot_samples(X_uni, 'Uniform Data after Linear Mixing', 'ica-uniform-mixed')

plot_samples(S_pca, 'PCA Applied to Mixed Data from Uniform Source', 'ica-uniform-PCA')

plot_samples(S_ica, 'ICA Applied to Mixed Data from Uniform Source', 'ica-uniform-ICA')


# -*- coding: utf-8 -*-
import numpy as np

#python
# 1D hampel filter
#
# purpose
#  Outlier detection and remove

def hampel(x,k,method="center",thr=3):
    #Input
    # x       input data
    # k       half window size (full 2*k+1)
    # mode    about both ends
    #         str {‘center’, 'same','ignore',‘nan’}, optional
    #
    #           center  set center of window at target value
    #           same    always same window size
    #           ignore  set original data
    #           nan     set non
    #
    # thr     threshold (defaut 3), optional
    #Output
    # newX    filtered data
    # omadIdx indices of outliers
    arraySize=len(x)
    idx=np.arange(arraySize)
    newX=x.copy()
    omadIdx=np.zeros_like(x)
    for i in range(arraySize):
        mask1=np.where( idx>= (idx[i]-k) ,True, False)
        mask2=np.where( idx<= (idx[i]+k) ,True, False)
        kernel= np.logical_and(mask1,mask2)
        if method=="same":
            if i<(k):
                kernel=np.zeros_like(x).astype(bool)
                kernel[:(2*k+1)]=True
            elif i>= (len(x)-k):
                kernel=np.zeros_like(x).astype(bool)
                kernel[-(2*k+1):]=True
        #print (kernel.astype(int))
        #print (x[kernel])
        med0=np.median(x[kernel])
        #print (med0)
        s0=1.4826*np.median(np.abs(x[kernel]-med0))
        if np.abs(x[i]-med0)>thr*s0:
             omadIdx[i]=1
             newX[i]=med0

    if method=="nan":
        newX[:k]=np.nan
        newX[-k:]=np.nan
        omadIdx[:k]=0
        omadIdx[-k:]=0
    elif method=="ignore":
        newX[:k]=x[:k]
        newX[-k:]=x[-k:]
        omadIdx[:k]=0
        omadIdx[-k:]=0

    return newX,omadIdx.astype(bool)

if __name__ == "__main__":
    np.random.seed(2)
    t=np.arange(1024)
    x=np.arange(1024)
    z=np.random.normal(0,1,1024)
    x[0]=z[0]
    for i in range(1,1024,1):
        x[i] = 0.4*x[i-1] + 0.8*x[i-1]*z[i-1]+z[i]

    #ret=hampel(x,20,"same")
    ret=hampel(x,20,"center")
    #ret=hampel(x,20)
    print (ret[0])#filtered data
    print (ret[1])#indices of outliers


#!/usr/bin/env python

"""
Produce the posterior on the parameters of a line (assuming uniform priors) and plot this with the
marginal likelihood for each parameter
"""

import matplotlib.pyplot as pl
import numpy as np

# set plot to render labels using latex
pl.rc('text', usetex=True)
pl.rc('font', family='serif')
pl.rc('font', size=14)

# x values
x = np.linspace(-5, 5, 6)

# gradient
m = 0.75

# y intercept
c = 1.

# line
y = m*x + c

# noise with sigma = 1
sigma = 1.;
n = np.random.randn(len(x))

d = y + n # the x "data"

# get the least squares fit values for m and c
mfit, cfit = np.linalg.lstsq(np.vstack([x, np.ones(len(x))]).T, d, rcond=None)[0]
yfit = mfit*x + cfit

fig = pl.figure(figsize=(12,10), dpi=100)

pl.subplot(2,2,2) # plot the data in the upper right corner

# plot data points line + noise
pl.plot(x, d, 'bx', markersize=10, mew=1, label='$x$ data')
pl.plot(x, y, 'k-', label='True line')
pl.plot(x, yfit, 'r-', label='Best fit line')

pl.grid(True)
pl.legend(loc='upper left')
ax = pl.gca()
ax.set_xlabel('$x$')
ax.set_ylabel('$y$')

# m and c grid
ms = np.linspace(-3., 3., 200)
cs = np.linspace(-3., 3., 200)

logpost = np.zeros((200,200))

for i in range(200):
  for j in range(200):
    logpost[i,j] = -np.sum(0.5*(d-(ms[i]*x + cs[j]))**2/sigma**2)

# convert log posterior into posterior
post = np.exp(logpost-np.max(logpost))

pl.subplot(2,2,3)
pl.contour(ms, cs, post.T)
pl.plot(m, c, 'kx', markersize=10, mew=1, label='True value')
pl.legend(loc='lower left')
pl.grid(True)
ax = pl.gca()
ax.set_xlabel('$m$')
ax.set_ylabel('$c$')
ax.set_xlim([ms[0], ms[-1]])
ax.set_ylim([cs[0], cs[-1]])

# marginalise over c
postm = np.apply_along_axis(np.trapz, 1, post, cs)
postm = postm/np.trapz(postm, ms) # normalise

# marginalise over m
postc = np.apply_along_axis(np.trapz, 0, post, ms)
postc = postc/np.trapz(postc, cs) # normalise

# get maximum posterior position
mi = np.argmax(postm)
ci = np.argmax(postc)

pl.subplot(2,2,1)
pl.plot(ms, postm, 'b')
pl.axvline(m, color='k', ls='--', label='True value')
pl.plot(ms[mi], np.max(postm), 'o', markersize=10)
pl.legend(loc='lower left')
ax = pl.gca()
ax.set_xlabel('$m$')
ax.set_ylabel('$p(m|d,I)$')
ax.set_xlim([ms[0], ms[-1]])
ax.set_ylim([0., 1.05*np.max(postm)])
ax.text(-2.8, 0.95*np.max(postm), 'max. posterior $m = %.2f$' % ms[mi], fontsize=16)
ax.text(-2.8, 0.85*np.max(postm), 'max. likelihood $\hat{m} = %.2f$' % mfit, fontsize=16)

pl.subplot(2,2,4)
pl.plot(cs, postc, 'b')
pl.axvline(c, color='k', ls='--', label='True value')
pl.plot(cs[ci], np.max(postc), 'o', markersize=10)
pl.legend(loc='lower left')
ax = pl.gca()
ax.set_xlabel('$c$')
ax.set_ylabel('$p(c|d,I)$')
ax.set_xlim([cs[0], cs[-1]])
ax.set_ylim([0., 1.05*np.max(postc)])
ax.text(-2.8, 0.95*np.max(postc), 'max. posterior $c = %.2f$' % cs[ci], fontsize=16)
ax.text(-2.8, 0.85*np.max(postc), 'max. likelihood $\hat{c} = %.2f$' % cfit, fontsize=16)

#fig.subplots_adjust(bottom=0.12)
pl.tight_layout()
pl.show()
fig.savefig('../bayesian_line_fitting.pdf')

# do the same but using the Student's t posterior
fig.clf()
pl.close(fig)

logpost1 = np.zeros((200,200)) # using uniform prior on sigma
logpost2 = np.zeros((200,200)) # using Jeffreys prior on sigma

for i in range(200):
  for j in range(200):
    logpost1[i,j] = -0.5*(len(d)-1.)*np.log(np.sum((d-(ms[i]*x + cs[j]))**2))
    logpost2[i,j] = -0.5*(len(d))*np.log(np.sum((d-(ms[i]*x + cs[j]))**2))

# convert log posterior into posterior
post1 = np.exp(logpost1-np.max(logpost1))
post2 = np.exp(logpost2-np.max(logpost2))

# marginalise over c
post1m = np.apply_along_axis(np.trapz, 1, post1, cs)
post1m = post1m/np.trapz(post1m, ms) # normalise

# marginalise over m
post1c = np.apply_along_axis(np.trapz, 0, post1, ms)
post1c = post1c/np.trapz(post1c, cs) # normalise

# marginalise over c
post2m = np.apply_along_axis(np.trapz, 1, post2, cs)
post2m = post2m/np.trapz(post2m, ms) # normalise

# marginalise over m
post2c = np.apply_along_axis(np.trapz, 0, post2, ms)
post2c = post2c/np.trapz(post2c, cs) # normalise

fig = pl.figure(figsize=(10,5), dpi=100)

pl.subplot(1,2,1)
pl.plot(ms, postm, 'r--', label='Known $\sigma$')
pl.plot(ms, post1m, 'b-', label='Unknown $\sigma$, $p(\sigma|I) = C$')
pl.plot(ms, post2m, 'b--', label='Unknown $\sigma$, $p(\sigma|I) \propto 1/\sigma$')
pl.axvline(m, color='k', ls='--', label='True value')
pl.legend(loc='upper left', fancybox=True, framealpha=0.3, prop={'size': 14})
ax = pl.gca()
ax.set_xlim([ms[0], ms[-1]])
ax.set_ylim([0, 1.05 * np.max([postm.max(), post1m.max(), post2m.max()])])
ax.set_xlabel('$m$')
ax.set_ylabel('$p(m|d,I)$')

pl.subplot(1,2,2)
pl.plot(cs, postc, 'r--', label='Known $\sigma$')
pl.plot(cs, post1c, 'b-', label='Unknown $\sigma$, $p(\sigma|I) = C$')
pl.plot(cs, post2c, 'b--', label='Unknown $\sigma$, $p(\sigma|I) \propto 1/\sigma$')
pl.axvline(c, color='k', ls='--', label='True value')
ax = pl.gca()
ax.set_xlabel('$c$')
ax.set_ylabel('$p(c|d,I)$')
ax.set_xlim([cs[0], cs[-1]])
ax.set_ylim([0, 1.05 * np.max([postc.max(), post1c.max(), post2c.max()])])

pl.tight_layout()
pl.show()
fig.savefig('../bayesian_line_fitting_2.pdf')


#taken from https://machinelearningmastery.com/statistical-hypothesis-tests-in-python-cheat-sheet/

#This section lists statistical tests that you can use to check if your data has a Gaussian distribution

from scipy.stats import shapiro
def ShapiroWilk(data):
    """Tests whether a data sample has a Gaussian distribution.
    Assumptions
    -----------
    Observations in each sample are independent and identically distributed (iid).
    Interpretation
    --------------
    H0: the sample has a Gaussian distribution.
    H1: the sample does not have a Gaussian distribution.

    Parameters
    ----------
    data: array of sample data to test.

    Returns
    -------
    stat:float: The test statistics
    p:float: The p-value for the hypothesis test.
    """
    stat, p = shapiro(data)
    return stat, p

from scipy.stats import normaltest
def DAgostinosK2(data):
    """Tests whether a data sample has a Gaussian distribution.
    Assumptions
    -----------
    * Observations in each sample are independent and identically distributed (iid).
    Interpretation
    --------------
    * H0: the sample has a Gaussian distribution.
    * H1: the sample does not have a Gaussian distribution.

    Parameters
    ----------
    data: array of sample data to test.

    Returns
    -------
    stat : float or array
        `s^2 + k^2`, where `s` is the z-score returned by `skewtest` and `k` is the z-score returned by `kurtosistest`.
    p : float or array
        A 2-sided chi squared probability for the hypothesis test.
    """
    stat, p = normaltest(data)
    return stat, p

from scipy.stats import anderson
def AndersonDarling(data):
    """Tests whether a data sample has a Gaussian distribution.
    Assumptions
    -----------
    * Observations in each sample are independent and identically distributed (iid).
    Interpretation
    --------------
    * H0: the sample has a Gaussian distribution.
    * H1: the sample does not have a Gaussian distribution.

    Parameters
    ----------
    data: array of sample data to test.

    Returns
    -------
    stat:float: the test statistics.
    critical:list: critical values.
    sig:list: the significance values for the criticals in percents.
    """
    stat, critical, sig = anderson(data)
    return stat, critical, sig


#/usr/bin/env python3
# ------------------------------------------
# Creator: Shekhar Singh
# Date: 20/07/2021
# Project: Corigine Technical Assignment
# Description: This program will find the sum of the digits of the factorial of the input number.
# ------------------------------------------

import numpy as np
import sys

# Function to seperate and add the digits of the factorial:
def separate_sum_func(input_fact):
    separate_array = []
    # 1. Separating digits:
    while input_fact !=0:
        remainder = np.mod(input_fact, 10)      # Dividing by 10, the mod is separating the value
        input_fact = input_fact//10             # Updating input_fact with the quotient o dividing by 10
        separate_array.insert(0,remainder)      # adding the remainder value for each loop until input_fact reaches zero

    # 2. Summing values:
    fact_sum = np.sum(separate_array)
    return fact_sum

def main(user_input):
    # 1. Calculate factorial of input number
    input_fact = np.math.factorial(user_input)

    # 2. Separate digits and sum them:
    answer = separate_sum_func(input_fact)

    # 3. Print output value:
    print(answer)

if __name__ == "__main__":
    try:
        user_input = int(sys.argv[1])
        if user_input < 0:                      # Factorials of negative integers are invalid
            print("Invalid! Please enter a positive integer.")
        elif isinstance(user_input,float):
            print("Invalid! Please enter a positive integer")
        else:
            main(user_input)
    except ValueError:
        print("Error! Please enter a positive value of int type")


# %% [markdown]
# #### init

# %%
import numpy as np
import scipy.signal as sp
import matplotlib.pyplot as plt

# %%
# helper function for basic plotting
def plot(x, y, title="", xlabel="", ylabel="", legend=None):
    if legend is None:
        plt.figure(figsize=(8, 5))
    plt.title(title)
    plt.xlabel(xlabel)
    plt.ylabel(ylabel)
    plt.plot(x, y)
    if legend is not None:
        plt.legend(legend)
    plt.grid(True)

# %% [markdown]
# #### Time Response of a Spring

# %%
# f(t) = cos(freq*t) exp(-decay*t) u(t)
# d2x/dt2 + freq^2 * x = f(t)
def time_response_spring(decay):
    den = np.polymul([1, 0, 1.5 ** 2], [1, 2 * decay, decay ** 2 + 1.5 ** 2])
    return sp.lti([1, decay], den)

# %%
t, x = sp.impulse(time_response_spring(0.5), T=np.linspace(0, 50, 501))
plot(t, x, "Damped Oscillator with 0.5/s Decay", "$t$", "$x$")

# %% [markdown]
# #### Response with Smaller Decay

# %%
_, x = sp.impulse(time_response_spring(0.05), T=t)
plot(t, x, "Damped Oscillator with 0.05/s Decay", "$t$", "$x$")

# %% [markdown]
# #### Response at Varying Frequencies

# %%
plt.figure(figsize=(12, 16)).subplots_adjust(hspace=0.25)
ax = plt.subplot(3, 2, 6)

H = sp.lti([1], [1, 0, 1.5 ** 2])

for i, freq in enumerate(np.linspace(1.4, 1.6, 5)):
    # f(t) = cos(freq*t) exp(-decay*t) u(t)
    f = np.cos(freq * t) * np.exp(-0.05 * t) * (t >= 0)
    x = sp.lsim(H, f, t)[1]

    ax.plot(t, x, label=freq)
    plt.subplot(3, 2, i + 1)
    plt.title(f"Damped Oscillator with {freq} Hz Frequency")
    plt.xlabel("$t$")
    plt.ylabel("$x$")
    plt.plot(t, x)
    plt.ylim(-7, 7)
    plt.grid()

ax.set_title("Damped Oscillator with Varying Frequencies")
ax.set_xlabel("$t$")
ax.set_ylabel("$x$")
ax.set_ylim(-7, 7)
ax.legend(title="Frequency")
ax.grid()

# %% [markdown]
# #### Coupled Spring Problem

# %%
# d2x/dt2 + (x - y) = 0
# d2y/dt2 + 2*(y - x) = 0
t, x = sp.impulse(sp.lti([1, 0, 2], [1, 0, 3, 0]), T=np.linspace(0, 20, 201))
_, y = sp.impulse(sp.lti([2], [1, 0, 3, 0]), T=t)

plot(t, x)
plot(t, y, "Coupled Springs", "t", "$x(t)$   &   $y(t)$", ["$x(t)$", "$y(t)$"])

# %% [markdown]
# #### Magnitude and Phase Responses

# %%
# H(s) = 1 / (LCs^2 + RCs + 1)
H = sp.lti([1], [1e-6 * 1e-6, 100 * 1e-6, 1])

w, S, phi = H.bode()
plt.figure(figsize=(6, 10)).subplots_adjust(hspace=0.3)
plt.subplot(2, 1, 1)
plt.title("Magnitude Response")
plt.xlabel("$\omega$")
plt.ylabel("$|H(\omega)|$   (in dB)")
plt.semilogx(w, S)
plt.grid()
plt.subplot(2, 1, 2)
plt.title("Phase Response")
plt.xlabel("$\omega$")
plt.ylabel("$\phi$   (in degrees)")
plt.semilogx(w, phi)
plt.grid()

# %% [markdown]
# #### Output Signal Analysis

# %%
def v_o(t, H):
    v_i = np.cos(1e3 * t) * (t >= 0) - np.cos(1e6 * t) * (t >= 0)
    return sp.lsim(H, v_i, t)[1]

y = v_o(np.linspace(0, 30e-6, 10000), H)
plot(np.linspace(0, 30, 10000), y, "Output Voltage for $0<t<30\mu$s (short term)", "$t$ (in $\mu$s)", "$V_o(t)$")

y = v_o(np.linspace(0, 15e-3, 10000), H)
plot(np.linspace(0, 15, 10000), y, "Output Voltage for $0<t<15m$s (long term)", "$t$ (in ms)", "$V_o(t)$")


#!/usr/bin/env python3

import numpy as np

def projectData(X, U, K):
    #PROJECTDATA Computes the reduced data representation when projecting only
    #on to the top k eigenvectors
    #   Z = projectData(X, U, K) computes the projection of
    #   the normalized inputs X into the reduced dimensional space spanned by
    #   the first K columns of U. It returns the projected examples in Z.
    #

    # You need to return the following variables correctly.
    #Z = zeros(size(X, 1), K)

    # ====================== YOUR CODE HERE ======================
    # Instructions: Compute the projection of the data using only the top K
    #               eigenvectors in U (first K columns).
    #               For the i-th example X(i,:), the projection on to the k-th
    #               eigenvector is given as follows:
    #                    x = X(i, :)'
    #                    projection_k = x' * U(:, k)
    #

    Z = np.dot(X, U[:, :K])

    # =============================================================

    return Z
    #end


import numpy as np
from numpy.random import normal, uniform
from numpy.linalg import inv

import matplotlib.pyplot as plt
from scipy.stats import norm, multivariate_normal

def polynomial(x, n):
    """
    Returns a numpy.array of powers of x of length n.
    x: polynomial variable
    n: degree of the polynomial
    """

    if hasattr(x, "__len__"):
        return np.array([[e**(i) for i in range(n+1)] for e in x])
    return np.array([x**(i) for i in range(n+1)]).reshape(1, -1)

def generateData(w, n, noise_stddev=0):
    """
    Returns a dataset of observations [x, t] uniformly sampled from the curve t = X.w + noise.
    w: parameters of the curve from which to take the observations
    n: number of observations to take
    noise_stddev: gaussian noise added to the targets
    """

    x = uniform(0.95, 5.05, n)
    x.sort()
    X = polynomial(x, len(list(w))-1)
    if noise_stddev != 0:
        t = X.dot(w) + normal(0, noise_stddev, n)
    else:
        t = X.dot(w)
    return np.array([x, t])

def getTarget(w, x):
    """
    Returns the target corresponding to x by performing t = X.w.
    w: parameters of the curve we are predicting
    x: attributes to get corresponding targets
    """

    X = polynomial(x, len(list(w))-1)
    return X.dot(w)

def getOptimalParams(x, t, n):
    """
    Returns the optimal parameters using the least squares fit.
    x, t: data to fit
    n: degree of the polynomial to fit
    """

    X = polynomial(x, n)
    XT = X.transpose()

    return inv(XT.dot(X)).dot(XT).dot(t)

def MSEloss(x, t, w):
    """
    Returns the Mean Squared Error calculated on the parameters.
    """

    X = polynomial(x, len(list(w))-1)
    tmp = t - X.dot(w)

    if len(tmp) > 1:
        return tmp.dot(tmp) / x.shape[0]
    return tmp**2

def std_dev(x, t, w):
    return np.sqrt(variance(x, t, w))

def variance(x, t, w):
    return MSEloss(x, t, w)

def get_likelihood(x, t, w):
    likelihood = 1
    standard_deviation = std_dev(x, t, w)
    for i in range(len(list(t))):
        X_i = np.array([x[i]**n for n in range(len(w))])
        likelihood *= norm.pdf(t[i], X_i.dot(w), standard_deviation)
    return likelihood

def LOOCV(x, t, d):

    loss = []
    for i in range(len(x)):
        mask = np.ones(len(x), dtype=bool)
        mask[i] = False

        w = getOptimalParams(x[mask], t[mask], d)
        X = polynomial(x[i], d)
        loss.append((t[i] - X.dot(w))**2)

    return np.average(loss)

def predict(X_new, x, t, w):
    t_new = w.T.dot(X_new)
    X = polynomial(x, len(list(w))-1)
    var_new = variance(x, t, w) * X_new.T.dot(inv(X.T.dot(X))).dot(X_new)
    return [t_new, np.sqrt(var_new)]

def set_plot(ax, xlim, ylim, xticks, yticks, xlabel, ylabel):
    ax.set_xlim(xlim)
    ax.set_ylim(ylim)
    ax.set_xticks(xticks)
    ax.set_yticks(yticks)
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel, rotation=0)

def plt_contourf(multivar_normal, w, ax, size=5):
    x, y = np.mgrid[w[0]-size:w[0]+size:.005, w[1]-size:w[1]+size:.005]
    pos = np.empty(x.shape + (2,))
    pos[:, :, 0] = x; pos[:, :, 1] = y
    ax.contourf(x, y, multivar_normal.pdf(pos), cmap=plt.get_cmap('gist_heat'))#matplotlib.cm.winter)