# Description: Functions to fit statistical models to data series.
# Author:      André Palóczy
# E-mail:      paloczy@gmail.com
# Description: Functions to fit statistical models to data series.

__all__ = ['sinfitn',
           'fourfilt']

import numpy as np
import matplotlib.pyplot as plt
from numpy.fft import fft, ifft

def sinfitn(x, t, periods, constant=True, line=True, return_misfit=False, return_params=False):
	"""
	USAGE
	-----
	xm = sinfitn(d, t, periods, constant=True, line=True, return_misfit=False, return_params=False)

	Returns a statistical model 'xm(t)' with M periodic components. The period of each sinusoid
	is specified in the array 'period'. The model parameters are obtained by solving the
	overdetermined least-squares problem that minimizes the model misfit as measured by
	the Euclidean norm L2 = ||Gm - d||^2:

	m = (G^{T}*G)^{-1} * G^{T}*d,

	where 'd(t)'' is the data vector (N x 1) specified at the coordinates 't', m is the model
	parameter vector and G is the data kernel matrix.

	If 'constant'=True (default), a constant term is added to the model. If 'line'=True (default),
	a linear term is added to the model.

	If return_misfit=True (defaults to False), the model misfit L2 is also returned.

	If 'return_params'=True (defaults to False), the model parameter vector 'm' is returned
	instead of the statistical model 'xm'.

	REFERENCES
	----------
	Strang, G.: Introduction to Linear Algebra. 4th edition (2009).

	EXAMPLE
	-------
	>>> import numpy as np
	>>> import matplotlib.pyplot as plt
	>>> from ap_tools.fit import sinfitn
	>>> t = np.linspace(0., 200., 300.)
	>>> periods = [25., 50., 100.]
	>>> f1, f2, f3 = 2*np.pi/np.array(periods)
	>>> x = 50. + 0.8*t + 12.5*sin(f1*t) + 10*sin(f2*t) + 30*sin(f3*t) + 5.0*np.random.randn(t.size)
	>>> xm = sinfitn(x, t, periods)
	>>> fig, ax = plt.subplots()
	>>> ax.plot(t, x, 'g', label='Data')
	>>> ax.plot(t, xm, 'm', label='Sinusoidal model')
	>>> ax.grid(True)
	>>> ax.legend(loc='upper left')
	>>> ax.set_xlabel('Time [s]', fontsize=20)
	>>> ax.set_ylabel('Signal [arbitrary units]', fontsize=20)
	>>> plt.show()
	"""
	d = np.matrix(x)
	periods = list(periods)
	N = d.size       # Number of data points.
	M = len(periods) # Number of model parameters.

	## The data must be a row vector.
	if d.shape==(1,N):
		d = d.T

	## Setting up the data kernel matrix G.
	## Contains model functions evaluated at data points.
	G = np.matrix(np.zeros((N, 0)))
	if constant:
		x0 = np.expand_dims(np.repeat(1., N), 1)
		G = np.concatenate((G,x0), axis=1)
		M = M + 1
	if line:
		x1 = np.expand_dims(t, 1)
		G = np.concatenate((G,x1), axis=1)
		M = M + 1

	for period in periods:
		fn = 2*np.pi/period
		xn = np.matrix([np.sin(fn*t), np.cos(fn*t)]).T
		G = np.concatenate((G,xn), axis=1)

	## Solution to the overdetermined least-squares problem
	## to obtain the model parameters that minimize the
	## L2 norm of the model misfit vector, ||Gm - d||^2.
	## e.g., Strang (2009), pg. 218.
	m = (G.T*G).I*G.T*d

	## Assemble the statistical model using the parameters in the vector m.
	xm = G*m

	## Compute the L2 norm, ||Gm - d||^2.
	err = xm - d
	L2 = np.sqrt(err.T*err)
	L2 = np.float(L2)
	print("")
	print("Model-data misfit: %.1f"%L2)

	if return_params:
		if return_misfit:
			return m, L2
		else:
			return m
	else:
		xm = np.array(xm).squeeze()
		if return_misfit:
			return xm, L2
		else:
			return xm

def fourfilt(x, dts, Tmax, Tmin):
    # See the docstring of the original MATLAB function.
    # The usage is the same, see the docstring for
    # low-pass, high-pass and band-pass filter examples.
    #
    # In the Python version, the variable names
    # have been changed as follows:
    #
    # MATLAB      Python
    #  delt   ->   dts
    #  tmax   ->   Tmax
    #  tmin   ->   Tmin
    # filtdat ->   xfilt
    #
    # Translated from the MATLAB function fourfilt.m
    # by André Palóczy (github.com/apaloczy).
    #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    # function [filtdat]=fourfilt(x,delt,tmax,tmin)
    #  FOURFILT  Fourier low, high, or bandpass filter.
    #
    #     [filtdat]=fourfilt(x,delt,tmax,tmin)
    #
    #     where:   x:      data series to be filtered
    #              delt:   sampling interval
    #              tmax:   maximum period filter cutoff
    #              tmin:   minimum period filter cutoff
    #
    #     usage:  lowpassdata=fourfilt(data,0.5,2000,20)
    #
    #               gives lowpass filter with cutoff at 20.0 sec
    #               tmax set > (length(x)*delt) for no cutoff at low freq end
    #
    #     usage:  highpassdata=fourfilt(x,0.5,20,0.9)
    #
    #               gives highpass filter with cutoff at 20.0 sec
    #               tmin set < (2*delt) for no cutoff at high freq end
    #
    #     usage:  bandpassdata=fourfilt(x,0.5,20,10)
    #
    #               gives bandpass filter passing 10-20 sec. band
    #
    # Reference:
    # Walters, R. A.  and Heston, C., 1982. Removing the tidal-period variations from time-series
    # data using low-pass digital filters. Journal of Physical Oeanography, 12 112-115 .
    #
    #############################
    # Version 1.0  (12/4/96)  Jeff List (jlist@usgs.gov)
    # Version 1.1  (1/8/97)  Rich Signell (rsignell@usgs.gov)
    #     removed argument for number of points and add error trapping for matrices
    # Version 1.1b (12/1/2005) Rich Signell (rsignell@usgs.gov)
    #     added reference
    # (3/18/2019)
    # Translated to Python by André Palóczy.
    #############################
    npts = x.size
    # if npts%2==0: # N is even.
    nby2 = npts//2
    # else:
        # nby2 = (npts-1)//2

    tfund = npts*dts
    ffund = 1.0/tfund

    xmean = x.mean()
    x -= xmean # Remove the mean from data.
    coeffs = np.fft.fft(x) # Fourier-transform data.

    # Filter coefficients.
    f = ffund
    for i in range(1, nby2+2):
        t = 1.0/f
        if np.logical_or(t>Tmax, t<Tmin):
            coeffs[i] = coeffs[i]*0
        f += ffund

    # Calculate the remaining coefficients.
    for i in range(1, nby2+1):
        coeffs[npts-i] = coeffs[i].conj()

    # Back-transform data and take real part.
    xfilt = np.fft.ifft(coeffs).real
    xfilt += xmean # Add back the mean.

    return xfilt


# -*- coding: utf-8 -*-
"""10_locally_weighted_regression.ipynb

Automatically generated by Colaboratory.

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

**10. Implement the non-parametric Locally Weighted Regression algorithm in order to fit data
points. Select appropriate data set for your experiment and draw graphs.**
"""

from math import ceil
import numpy as np
from scipy import linalg

def lowess(x, y, f, iterations):
    n = len(x)
    r = int(ceil(f * n))
    h = [np.sort(np.abs(x - x[i]))[r] for i in range(n)]
    w = np.clip(np.abs((x[:, None] - x[None, :]) / h), 0.0, 1.0)
    w = (1 - w ** 3) ** 3
    yest = np.zeros(n)
    delta = np.ones(n)
    for iteration in range(iterations):
        for i in range(n):
            weights = delta * w[:, i]
            b = np.array([np.sum(weights * y), np.sum(weights * y * x)])
            A = np.array([[np.sum(weights), np.sum(weights * x)],[np.sum(weights * x), np.sum(weights * x * x)]])
            beta = linalg.solve(A, b)
            yest[i] = beta[0] + beta[1] * x[i]

        residuals = y - yest
        s = np.median(np.abs(residuals))
        delta = np.clip(residuals / (6.0 * s), -1, 1)
        delta = (1 - delta ** 2) ** 2

    return yest

import math
n = 100
x = np.linspace(0, 2 * math.pi, n)
y = np.sin(x) + 0.3 * np.random.randn(n)
f =0.25
iterations=3
yest = lowess(x, y, f, iterations)

import matplotlib.pyplot as plt
plt.plot(x,y,"r.")
plt.plot(x,yest,"b-")

10.Locally Weighted Regression Algorithm/10_locally_weighted_regression.py


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 25 10:28:55 2019

@author: alankar
"""

import numpy as np

def RK4(f,x0,t,*args): #f must be a matrix of order (dim,1)
    if isinstance(t,list):
        t = np.array(t)
    elif not(isinstance(t,np.ndarray) or isinstance(t,list)):
        t = np.array([0,t])

    if isinstance(x0,list):
        x0 = np.array(x0)
    elif not(isinstance(x0,np.ndarray) or isinstance(x0,list)):
        x0 = np.array([x0])

    x = np.zeros((x0.shape[0],t.shape[0],),dtype=np.float64)
    h = t[1] - t[0]
    x[:,0] = x0 #Initial Condition
    dim = x0.shape[0]

    for i in range(1,t.shape[0]):
        k1, k2, k3, k4 = None, None, None, None

        if (dim==1):
            k1 = f(t[i-1],x[:,i-1],*args)*h
            k2 = f(t[i-1]+h/2,x[:,i-1]+k1/2,*args)*h
            k3 = f(t[i-1]+h/2,x[:,i-1]+k2/2,*args)*h
            k4 = f(t[i-1]+h,x[:,i-1]+k3,*args)*h

            x[:,i] = x[:,i-1] + (k1+2*(k2+k3)+k4)/6
        else:
            k1 = f(t[i-1],x[:,i-1],*args)*h
            k2 = f(t[i-1]+h/2,x[:,i-1]+k1[:,0]/2,*args)*h
            k3 = f(t[i-1]+h/2,x[:,i-1]+k2[:,0]/2,*args)*h
            k4 = f(t[i-1]+h,x[:,i-1]+k3[:,0],*args)*h

            x[:,i] = x[:,i-1] + (k1[:,0]+2*(k2[:,0]+k3[:,0])+k4[:,0])/6

    if (x.shape[0]==1): return x[0]
    return x


# Author: Sylvain Lapeyrade (sylla801)
# File: TSKS11-Lab2: Task 4

# ***************************** TASK 4 *****************************
# Calculate the Google PageRank score of each article in your network
# with parameter alpha = 0.85. List the top five articles and their
# PageRank score. Use the version of PageRank explained in the lecture
# notes. Also try some other values of alpha and comment on the result.

import numpy as np

# The calculations being too expensive, only one file
#  will be dealt with at the same time

network_number = 1  # Number of the file wanted

title_file = open(
    '/courses/TSKS11/ht2019/data_and_fcns/session2/titles/{}.txt'
    .format(network_number), 'r')
link_file = open(
    '/courses/TSKS11/ht2019/data_and_fcns/session2/links/{}.txt'
    .format(network_number), 'r')

title_list = []
titles = title_file.read().splitlines()  # Array of the titles
for title in titles:
    title_list.append(title)

degree = np.loadtxt(link_file, dtype=int)  # Loads all links
n = max(map(max, degree))  # Number of nodes

m = np.zeros((n, n), dtype=float)  # Matrix M initialized with 0
for j in range(len(degree)):  # Put 1 for every links
    m[degree[j][1] - 1][degree[j][0] - 1] = 1

totals_colums = np.sum(m, axis=0)  # totals of the colums
for i in range(n):
    if totals_colums[i] == 0:  # If a column total is 0
        totals_colums[i] = 1/n  # it is replaced by 1/n

for j in range(n):
    for i in range(n):
        m[j][i] /= totals_colums[i]  # Normalisation to obtain B

# Vector with only ones (3000, 1)
vector_I = np.ones((n, 1), dtype=int)

identity_matrix = np.identity(n)  # Identity Matrix 3000x3000

alpha = 0.85  # 0.85 by default

# Close formed PageRank formula
page_rank_score = (1 / n) * \
    np.matmul(np.linalg.inv(identity_matrix - (alpha * m)), vector_I)

# Sum of all page rank scores
total_page_rank = float(np.sum(page_rank_score, axis=0))

for i in range(n):
    page_rank_score[i] /= total_page_rank  # Normalisation

# Arguments of the fives largest PageRank score
five_argmax_pagerank = page_rank_score.argsort(axis=None)[-5:][::-1]

print("\n\nNetwork {}: \n".format(network_number))
print("Alpha = {}: \n".format(alpha))
print("Nodes with the highest PageRank Score:")
for i in range(5):
    print(str(i + 1) + '.', "PageRank Score: {0:.6f}"
          .format(round(float(page_rank_score[five_argmax_pagerank[i]]), 6)),
          "| Title:", title_list[five_argmax_pagerank[i]])

# Exact solution for Task 5
for i in range(5):
    print("Exact values", i+1, ":",
          float(page_rank_score[five_argmax_pagerank[i]]))


# -*- coding: utf-8 -*-
"""KFMO.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1NNjtUdUx-mh3swT5tVs9i0_GmOfzaD0z

#**Kalman Filter For Moving Object**
"""

! pip install pykalman

import numpy as np
import pylab as pl
from pykalman import KalmanFilter

"""**Let’s assume an object moves up and down over time, and the censor detects it with a small error. I postulate a perfect sin wave with randomness for the movement over time. When the location is plotted over time, it looks like the following**"""

rnd = np.random.RandomState(0)
n_timesteps = 100
x = np.linspace(0, 3 * np.pi, n_timesteps)
y = 20 * (np.sin(x) + 0.5 * rnd.randn(n_timesteps))
pl.figure(figsize=(40, 10))
pl.scatter(x,y, marker='x', color='b', label='observations')
pl.xlabel('time')
pl.ylabel('Position')
pl.show()

"""**Construction of Kalman Filter with transition_covariance**"""

kf = KalmanFilter(transition_matrices=np.array([[1, 1], [0, 1]]),
                  transition_covariance=0.01 * np.eye(2))
states_pred = kf.em(y).smooth(y)[0]

"""**Here,the state vector Xt can have two elements: position and velocity, and both are unobservable and hence the transition matrix would also consist of the same ,when passing the same through the kalman filter the output would be a perfect sine curve**"""

pl.figure(figsize=(40, 10))
obs_scatter = pl.scatter(x, y, marker='x', color='b',
                         label='observations')
position_line = pl.plot(x, states_pred[:, 0],markersize=2,
                        linestyle='-', marker='o', color='r',
                        label='position est.')
velocity_line = pl.plot(x, states_pred[:, 1],markersize=2,
                        linestyle='-', marker='o', color='g',
                        label='velocity est.')
pl.legend(loc='lower left',fontsize=14)
pl.xlim(xmin=0, xmax=x.max())
pl.xlabel('time')
pl.show()

"""**If in case there is only a single element in the  transition matrix , then this would be the result for the same , it would not be a perfect sinecurve but would resemble the same**"""

kf = KalmanFilter(transition_matrices=[1],
                  transition_covariance=0.01)
states_pred = kf.em(y).smooth(y)[0]
pl.figure(figsize=(40, 10))
obs_scatter = pl.scatter(x, y, marker='x', color='b',
                         label='observations')
position_line = pl.plot(x, states_pred,markersize=2,
                        linestyle='-', marker='o', color='r',
                        label='position est.')
pl.legend(loc='lower left',fontsize=14)
pl.xlim(xmin=0, xmax=x.max())
pl.xlabel('time')
pl.show()


def bgd(w, X_train, y_train, learning_rate=1e-3, num_iters=1):
    """Return weights and errors after given iterations of batch GD.

    Args:
        w -- M x 1 -- float: Weights.
        X_train -- N -- float: Inputs for training.
        y_train -- N -- float: Labels for training.
        learning_rate -- 1 -- float: Learning rate.
        num_iters -- 1 -- int: # of iterations.

    Returns:
        w -- M -- float: Updated weights.
        errors -- num_iters -- float: Errors after each iteration.
    """
    from numpy import concatenate, ones, newaxis, sum

    # Convert X_train to X to use it in GD,
    # i.e. concatenate [1, ... , 1] to its first row.
    N = len(y_train) # # of data points
    X = concatenate((ones((1, N)), X_train[newaxis, :]), axis=0)
    errors = []

    for iter in range(num_iters):
        w = w - learning_rate * X @ (w.T @ X - y_train[newaxis, :]).T / N
        MSE = sum((w.T @ X - y_train[newaxis, :]) ** 2) / N
        errors.append(MSE)

    return w, errors

def sgd(w, X_train, y_train, learning_rate=1e-3, num_iters=1):
    """Return weights and errors after given iterations of stochastic GD.

    One iteration uses all the data points.

    Args:
        w -- M x 1 -- float: Weights.
        X_train -- N -- float: Inputs for training.
        y_train -- N -- float: Labels for training.
        learning_rate -- 1 -- float: Learning rate.
        num_iters -- 1 -- int: # of iterations.

    Returns:
        w -- M -- float: Updated weights.
        errors -- num_iters -- float: Errors after each iteration.
    """
    from numpy import concatenate, ones, newaxis, sum

    # Convert X_train to X to use it in GD,
    # i.e. concatenate [1, ... , 1] to its first row.
    N = len(y_train) # # of data points
    X = concatenate((ones((1, N)), X_train[newaxis, :]), axis=0)
    errors = []

    for iter in range(num_iters):
        for idx in range(N):
            Xcur = X[:, idx, newaxis] # Data to use now.
            w = w - learning_rate * (w.T @ Xcur - y_train[idx]) * Xcur
        MSE = sum((w.T @ X - y_train[newaxis, :]) ** 2) / N
        errors.append(MSE)

    return w, errors

def main_a():
    """ Find the coefficients of a first degree polynomial using BGD and SGD.
    """
    from numpy import load, ones
    from matplotlib.pyplot import subplots, savefig, show

    # Load training data.
    X_train = load("data/q1xTrain.npy")
    y_train = load("data/q1yTrain.npy")

    # Set parameters.
    M = 2 # Define M, the # of features.
    w = ones((M, 1)) # Initialize the weights.
    num_iters = 100

    # Run BGD and SGD.
    wB, errB = bgd(w, X_train, y_train, learning_rate=1.5, num_iters=num_iters)
    wS, errS = sgd(w, X_train, y_train, learning_rate=0.1, num_iters=num_iters)

    # Find convergence iteration of BGD and SGD.
    # Define convergence if error <= 0.2
    # or decrease of error <= 0.0001.
    for idx in range(len(errB) - 1):
        if errB[idx] > 0.2 and errB[idx + 1] <= 0.2:
            thB = idx + 1
            break
        elif errB[idx] - errB[idx + 1] < 0.0001:
            thB = idx + 1
            break
    for idx in range(len(errS) - 1):
        if errS[idx] > 0.2 and errS[idx + 1] <= 0.2:
            thS = idx + 1
            break
        elif errS[idx] - errS[idx + 1] < 0.0001:
            thS = idx + 1
            break

    # Print weights and plot errors of BGD and SGD.
    print("Problem 1-(a)")
    print("Weight of BGD after {} iterations: {}".format(num_iters, wB.T))
    print("Weight of SGD after {} iterations: {}".format(num_iters, wS.T))
    fig, ax = subplots()
    ax.plot(errB, label="BGD Error")
    ax.title.set_text("MSE of Batch and Stochastic Gradient Descent\nBGD Weights: {}\nSGD Weights: {}".format(wB.T, wS.T))
    ax.set_xlabel("Iterations")
    ax.set_ylabel("Mean Squared Error")
    ax.scatter(thB, errB[thB], label="BGD Convergence: After {}th iteration".format(thB))
    ax.plot(errS, label="SGD Error")
    ax.scatter(thS, errS[thS], label="SGD Convergence: After {}th iteration".format(thS))
    ax.legend()
    savefig("q1-a-ii.png")
    show()

def make_design_matrix(X, M):
    """ Return a design matrix.

    Args:
        X -- N -- float: Inputs for training or testing.
        M -- 1 -- int: # of features to use.

    Returns:
        Phi -- N x M -- float: Design matrix.
    """
    assert M > 0 and type(M) == int, "M should be a positive integer."

    from numpy import zeros

    N = len(X)
    Phi = zeros((N, M))
    for col in range(M):
        Phi[:, col] = X ** col

    return Phi

def CFS(Phi, y_train):
    """ Return weights of linear regression using closed form solution.

    Args:
        Phi -- N x M -- float: Design matrix.
        y_train -- N -- float: Labels for training.

    Returns:
        w -- M -- float: Updated weights.
    """
    from numpy.linalg import pinv

    # Calculate closed form solution.
    w = pinv(Phi.T @ Phi) @ (Phi.T @ y_train)

    return w

def main_b():
    """ Find the coefficients of an M degree polynomial
    and check if overfitting happens.
    """
    from numpy import load, sqrt
    from matplotlib.pyplot import subplots, savefig, show

    # Load training and test data.
    X_train = load("data/q1xTrain.npy")
    y_train = load("data/q1yTrain.npy")
    X_test = load("data/q1xTest.npy")
    y_test = load("data/q1yTest.npy")

    RMSE_train = []
    RMSE_test = []
    for degree in range(10): # Iterate over polynomial degrees
        # Find closed form solutions with different # of features.
        Phi_train = make_design_matrix(X_train, M=degree+1)
        w = CFS(Phi_train, y_train)

        # Get "sum of squared error" of training data.
        SSE_train = (w.T @ Phi_train.T - y_train.T) @ (Phi_train @ w - y_train) / 2

        # Get RMSE of training data.
        N_train = len(y_train)
        RMSE_train.append(sqrt(2 * SSE_train / N_train))

        # Get "sum of squared error" and RMSE of testing data.
        Phi_test = make_design_matrix(X_test, M=degree+1)
        SSE_test = (w.T @ Phi_test.T - y_test.T) @ (Phi_test @ w - y_test) / 2
        N_test = len(y_test)
        RMSE_test.append(sqrt(2 * SSE_test / N_test))

    _, best_idx = min((val, idx) for (idx, val) in enumerate(RMSE_test))

    # Plot RMSE of training and testing data.
    print("Problem 1-(b)")
    fig, ax = subplots()
    ax.title.set_text("RMSE Plot for Under- and Over-fitting Check")
    ax.set_xlabel("M")
    ax.set_ylabel("RMSE")
    ax.plot(RMSE_train, label="Training Data")
    ax.plot(RMSE_test, label="Testing Data")
    ax.scatter(best_idx, RMSE_test[best_idx], label="{}th degree is the best".format(best_idx), color="orange")
    ax.legend()
    print("{}th degree is the best".format(best_idx))
    savefig("q1-b-i.png")
    show()

def CFS_ridge(Phi, reg, y_train):
    """ Return weights of ridge regression using closed form solution.

    Args:
        Phi -- N x M -- float: Design matrix.
        reg -- 1 -- float: Regularization coefficient.
        y_train -- N -- float: Labels for training.

    Returns:
        w -- M -- float: Updated weights.
    """
    from numpy import identity
    from numpy.linalg import pinv

    # Calculate closed form solution.
    w = pinv(Phi.T @ Phi + reg * identity(len(Phi.T))) @ (Phi.T @ y_train)

    return w

def main_c():
    """ Apply regularization.
    """
    from numpy import load, arange, sqrt
    from matplotlib.pyplot import subplots, savefig, show

    # Load training and test data.
    X_train = load("data/q1xTrain.npy")
    y_train = load("data/q1yTrain.npy")
    X_test = load("data/q1xTest.npy")
    y_test = load("data/q1yTest.npy")

    RMSE_train = []
    RMSE_test = []
    reg_list = [0] + [10 ** exp for exp in range(-8, 1)]
    for reg in reg_list:
        # Find closed form solutions of ridge regression.
        Phi_train = make_design_matrix(X_train, M=10)
        w = CFS_ridge(Phi_train, reg, y_train)

        # Get "sum of squared error" of training data.
        SSE_train = (w.T @ Phi_train.T - y_train.T) @ (Phi_train @ w - y_train) / 2

        # Get RMSE of training data.
        N_train = len(y_train)
        RMSE_train.append(sqrt(2 * SSE_train / N_train))

        # Get "sum of squared error" and RMSE of testing data.
        Phi_test = make_design_matrix(X_test, M=10)
        SSE_test = (w.T @ Phi_test.T - y_test.T) @ (Phi_test @ w - y_test) / 2
        N_test = len(y_test)
        RMSE_test.append(sqrt(2 * SSE_test / N_test))

    _, best_idx = min((val, idx) for (idx, val) in enumerate(RMSE_test))

    # Plot RMSE of training and testing data.
    reg_list = [str(elem) for elem in reg_list]
    print("Problem 1-(c)")
    fig, ax = subplots()
    ax.title.set_text("RMSE Plot to Check Regularization Effect")
    ax.set_xlabel("Regularization Coefficient")
    ax.set_ylabel("RMSE")
    ax.plot(reg_list, RMSE_train, label="Training Data")
    ax.plot(reg_list, RMSE_test, label="Testing Data")
    ax.scatter(best_idx, RMSE_test[best_idx], label="Reg. coeff. {} is the best".format(reg_list[best_idx]), color="orange")
    ax.legend()
    print("Regularization coefficient {} is the best".format(reg_list[best_idx]))
    savefig("q1-c-i.png")
    show()

if __name__ == "__main__":
    main_a()
    main_b()
    main_c()


"""Test a uniform permutation algorithm against a non-uniform one."""
import typing as t

import matplotlib.pyplot as plt
import numpy as np

def uniform_permutation(num_elements: int,
                        random_state: t.Optional[int] = None) -> np.ndarray:
    r"""Uniformly distributed permutation algorithm.

    A permutation algorithm being uniformily distributed means that every
    permutation of ``n`` elements has exactly $\frac{1}{n!}$ probability to
    happen.
    """
    if random_state is not None:
        np.random.seed(random_state)

    vals = np.arange(num_elements)

    for i in np.arange(num_elements):
        j = np.random.randint(i, num_elements)
        vals[i], vals[j] = vals[j], vals[i]

    return vals

def non_uniform_permutation(
        num_elements: int, random_state: t.Optional[int] = None) -> np.ndarray:
    """Produces an non-uniform permutation."""
    if random_state is not None:
        np.random.seed(random_state)

    vals = np.arange(num_elements)

    for i in np.arange(num_elements):
        j = np.random.randint(num_elements)
        vals[i], vals[j] = vals[j], vals[i]

    return vals

def _uniformity_test(num_elements: int,
                     permutation_func: t.Callable[[int, int], t.Sequence[int]],
                     num_samples: int = int(1e+6),
                     random_state: int = 16) -> np.ndarray:
    """Count the frequencies of each permutation of ``num_elements`` distinct elements."""
    # This test quality is inversely proportional to num_elements!
    hash_counter = {}  # type: t.Dict[t.Tuple[int, ...], int]

    for i in np.arange(num_samples):
        config = tuple(
            permutation_func(num_elements, int(random_state * (1 + i))))

        if config not in hash_counter:
            hash_counter[config] = 0

        hash_counter[config] += 1

    print(hash_counter)

    return np.array(list(hash_counter.values()), dtype=int)

def _test():
    """Compare a non-uniform permutation algorithm against a uniform one."""

    def fac(n: int):
        fac = 1
        while n:
            fac *= n
            n -= 1

        return fac

    num_elements = 3
    n_fac = fac(num_elements)

    plt.subplot(1, 2, 1)
    vals = _uniformity_test(
        num_elements=num_elements, permutation_func=non_uniform_permutation)
    plt.plot(vals / vals.sum(), label="Relative frequency")
    plt.hlines(y=1 / n_fac, xmin=0, xmax=n_fac - 1, linestyle='--')
    plt.ylim(0, 1)
    plt.title("Non-uniform permutation")
    plt.legend()

    plt.subplot(1, 2, 2)
    vals = _uniformity_test(
        num_elements=num_elements, permutation_func=uniform_permutation)
    plt.plot(vals / vals.sum(), label="Relative frequency")
    plt.hlines(y=1 / n_fac, xmin=0, xmax=n_fac - 1, linestyle='--')
    plt.ylim(0, 1)
    plt.title("Uniform permutation")
    plt.legend()

    plt.show()

if __name__ == "__main__":
    _test()


import numpy as np
from random import shuffle
import scipy as sc

def softmax_loss_naive(W, X, y, reg):
  """
  Softmax loss function, naive implementation (with loops)

  Inputs have dimension D, there are C classes, and we operate on minibatches
  of N examples.

  Inputs:
  - W: A numpy array of shape (D, C) containing weights.
  - X: A numpy array of shape (N, D) containing a minibatch of data.
  - y: A numpy array of shape (N,) containing training labels; y[i] = c means
    that X[i] has label c, where 0 <= c < C.
  - reg: (float) regularization strength

  Returns a tuple of:
  - loss as single float
  - gradient with respect to weights W; an array of same shape as W
  """
  # Initialize the loss and gradient to zero.
  loss = 0.0
  dW = np.zeros_like(W)
  num_train = X.shape[0]
  num_classes = dW.shape[1]

  for i in range(num_train):
    scores_i = W.T.dot(X[i, :])

    maximum = np.max(scores_i) # trick to deal with numerical instability
    scores_i -= maximum

    # compute the denominator in the log part
    suma = 0
    for el in scores_i:
      suma += np.exp(el)

    nominator = np.exp(scores_i[y[i]]) # compute the nominator in the log part
    loss -= np.log(nominator/suma)

    # compute the graient
    for j in range(num_classes):
      p = np.exp(scores_i[j])/suma
      dW[:, j] += (p-(j == y[i])) * X[i, :]

  # divide the loss/gradient with the number of examples and add the regularization term
  loss /= num_train
  loss += 0.5 * reg * np.sum(W * W)
  dW /= num_train
  dW += reg * W

  return loss, dW

def softmax_loss_vectorized(W, X, y, reg):
  """
  Softmax loss function, vectorized version.

  Inputs and outputs are the same as softmax_loss_naive.
  """
  # Initialize the loss and gradient to zero.
  loss = 0.0
  dW = np.zeros_like(W)
  num_train = X.shape[0]

  scores = W.T.dot(X.T)
  scores -= np.max(scores)
  correct_scores = scores[y, range(num_train)]

  nominator = np.exp(correct_scores)
  denominator = np.exp(scores)
  denominator = np.sum(denominator, axis = 0)

  loss -= np.log(nominator/denominator)
  loss = np.mean(loss)

  p = np.exp(scores)/np.sum(np.exp(scores), axis=0)
  ind = np.zeros(p.shape)
  ind[y, range(num_train)] = 1
  dW = np.dot((p-ind), X)
  dW /= num_train
  dW = dW.T

  loss += 0.5 * reg * np.sum(W * W)
  dW += reg * W
  return loss, dW


import torch
import numpy as np

'''initializing a tensor'''
# Directly from data
data = [[1, 2], [3, 4]]
x_data = torch.tensor(data)
print(x_data)

# from a numpy data
np_array = np.array(data)
x_np = torch.from_numpy(np_array)
print(x_np)

# from another tensors
# The new tensor retains the properties (shape, datatype) of the argument tensor, unless explicitly overridden.
x_ones = torch.ones_like(x_data)  # retains the properties of x_data
print(f"Ones Tensor: \n {x_ones} \n")

x_rand = torch.rand_like(x_data, dtype=torch.float)  # overrides the datatype of x_data
print(f"Random Tensor: \n {x_rand} \n")

# With random or constant values:
# shape is a tuple of tensor dimensions. In the functions below, it determines the dimensionality of the output tensor.
shape = (2, 3,)
rand_tensor = torch.rand(shape)
ones_tensor = torch.ones(shape)
zeros_tensor = torch.zeros(shape)

print(f"Random Tensor: \n {rand_tensor} \n")
print(f"Ones Tensor: \n {ones_tensor} \n")
print(f"Zeros Tensor: \n {zeros_tensor}")

'''Attributes of a Tensor'''
# Tensor attributes describe their shape, datatype, and the device on which they are stored.
tensor = torch.rand(3, 4)

print(f"Shape of tensor: \n {tensor}")
print(f"Shape of tensor: {tensor.shape}")
print(f"Datatype of tensor: {tensor.dtype}")
print(f"Device tensor is stored on: {tensor.device}")

'''Operations on Tensors'''
# if tensors are created on the CPU, We need to explicitly move tensors to the GPU using .to method (after checking for GPU availability).
# We move our tensor to the GPU if available
if torch.cuda.is_available():
  print(f'cuda: {torch.cuda.is_available()}')
  tensor = tensor.to("cuda")

# Standard numpy-like indexing and slicing:
tensor = torch.ones(4, 4)
print(f"First row: {tensor[0]}")
print(f"First column: {tensor[:, 0]}")
print(f"Last column: {tensor[..., -1]}")
tensor[:, 1] = 0
print(tensor)

# Joining tensors You can use torch.cat to concatenate a sequence of tensors along a given dimension
t1 = torch.cat([tensor, tensor, tensor], dim=1)
print(t1)

# Arithmetic operation
# This computes the matrix multiplication between two tensors. y1, y2, y3 will have the same value
y1 = tensor @ tensor.T
print(f'y1: {y1}')

y2 = tensor.matmul(tensor.T)
print(f'y2: {y2}')

y3 = torch.rand_like(tensor)
print(f'y3: {y3}')

y4 = torch.matmul(tensor, tensor.T, out=y3)
print(f'y4: {y4}')

# This computes the element-wise product. z1, z2, z3 will have the same value
z1 = tensor * tensor
print(f'z1: {z1}')

z2 = tensor.mul(tensor)
print(f'z2: {z2}')

z3 = torch.rand_like(tensor)
print(f'z3: {z3}')

z4 = torch.mul(tensor, tensor, out=z3)
print(f'z4 {z4}')


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time           : 17-9-7 下午3:15
# @Author         : Tom.Lee
# @CopyRight      : 2016-2017 OpenBridge by yihecloud
# @File           : np_mgrid_ogrid.py
# @Product        : PyCharm
# @Docs           :
# @Source         :

# #创建网格索引
"""
>>> import numpy as np

# 密集网格np.mgrid
>>> mgrid = np.lib.index_tricks.nd_grid()
>>> mgrid[0:5,0:5]
array([[[0, 0, 0, 0, 0],
        [1, 1, 1, 1, 1],
        [2, 2, 2, 2, 2],
        [3, 3, 3, 3, 3],
        [4, 4, 4, 4, 4]],
       [[0, 1, 2, 3, 4],
        [0, 1, 2, 3, 4],
        [0, 1, 2, 3, 4],
        [0, 1, 2, 3, 4],
        [0, 1, 2, 3, 4]]])
>>> mgrid[-1:1:5j]
array([-1. , -0.5,  0. ,  0.5,  1. ])

# 稀疏网格np.ogrid
>>> ogrid = np.lib.index_tricks.nd_grid(sparse=True)
>>> ogrid[0:5,0:5]
[array([[0],
        [1],
        [2],
        [3],
        [4]]), array([[0, 1, 2, 3, 4]])]

"""


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

df = pd.read_csv('data1.csv', header = None)

plt.scatter(df[0], df[1])
plt.xticks(np.arange(0, 30, 5))
plt.yticks(np.arange(0, 30, 5))
plt.title("Food truck and their profit")
plt.show()

def computeCost(X, y, theta):

    m, n = X.shape

    X = np.hstack((np.ones((m,1)), X))

    predictions = X@theta
    error = sum((predictions-y)**2)
    J = (1/(2*m))*error

    grad = (1/m) * (X.T @ (predictions-y))

    return J, grad

X = df.iloc[:,0:1].values
y = df.iloc[:,1:2].values
theta = np.zeros((X.shape[1]+1, 1))

J, grad = computeCost(X, y, theta);
print('Cost J: ',J)
print('grad value: ', grad)

def gradientDescent(X, y, alpha, number_iterations):

    m, n = X.shape
    j_history = []
    theta = np.zeros((n+1, 1))
    for i in range(number_iterations):

        J, grad = computeCost(X, y, theta)

        theta = theta - (alpha * grad)
        j_history.append(J)

    return j_history, theta
j_history, theta_final = gradientDescent(X, y, alpha = 0.01, number_iterations=1500)
print('Cost function j_history size: ', np.size(j_history))
print('Final value of Theta size: ', theta_final)

plt.plot(j_history)
plt.xlabel('Number of iterations')
plt.ylabel('Cost values J')
plt.title('Cost Vs Iterations')
plt.show()

X_values = [X for X in range(25)]
y_values = [y*theta_final[1]+theta_final[0] for y in X_values]
plt.plot(X_values, y_values)
plt.xlabel('Goods vslues')
plt.ylabel('Profit')
plt.title('Fitting prediction line on Data')
plt.show()


import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import quad
from scipy.interpolate import UnivariateSpline
from scipy.optimize import minimize_scalar
import scipy.stats as ss
from randomvars._continuous import Cont, _detect_finite_supp, _combine_grids
from randomvars.options import config

N_GRID_PLOT = 1001

def cdf_grid(rv, n_grid):
    x_left, x_right = _detect_finite_supp(rv, supp=None, small_prob=1e-6)

    # Construct equidistant grid
    x_equi = np.linspace(x_left, x_right, n_grid)

    # Construct quantile grid
    prob_left, prob_right = rv.cdf([x_left, x_right])
    prob_equi = np.linspace(prob_left, prob_right, n_grid)
    x_quan = rv.ppf(prob_equi)

    # Combine equidistant and quantile grids into one sorted array
    return _combine_grids(x_equi, x_quan)

def create_cdf_spline(rv, n_grid, **kwargs):
    x_grid = cdf_grid(rv, n_grid)
    return UnivariateSpline(x=x_grid, y=rv.cdf(x_grid), **kwargs)

def cont_from_cdf_spline(rv, n_grid, **kwargs):
    cdf_spline = create_cdf_spline(rv, n_grid, **kwargs)
    x_grid_spline = cdf_spline.get_knots()
    y_grid_spline = cdf_spline.derivative(n=1)(x_grid_spline)
    return Cont(x=x_grid_spline, y=np.clip(y_grid_spline, a_min=0, a_max=None))

def plot_spline(spline, **kwargs):
    knots = spline.get_knots()
    x_grid = np.linspace(knots[0], knots[-1], N_GRID_PLOT)
    plt.plot(x_grid, spline(x_grid), **kwargs)

def plot_spline_deriv(spline, **kwargs):
    knots = spline.get_knots()
    x_grid = np.linspace(knots[0], knots[-1], N_GRID_PLOT)
    plt.plot(x_grid, spline.derivative(n=1)(x_grid), **kwargs)

def plot_rv(rv, fun_name="cdf", *args, **kwargs):
    f = getattr(rv, fun_name)
    p_grid = np.linspace(1e-6, 1 - 1e-6, N_GRID_PLOT)
    x_grid = rv.ppf(p_grid)
    plt.plot(x_grid, f(x_grid), *args, **kwargs)

def fun_diff(f, g, method="L2"):
    if method == "L1":
        integrand = lambda x: np.abs(f(x) - g(x))
    elif method == "L2":
        integrand = lambda x: (f(x) - g(x)) ** 2

    res = quad(integrand, -np.inf, np.inf, limit=100)[0]
    res = np.sqrt(res) if method == "L2" else res
    return res

rv = ss.norm()
# rv = ss.gamma(a=10)

# rv = ss.beta(a=0.5, b=0.5)
# rv = ss.chi2(df=1)
# rv = ss.chi2(df=2)
# rv = ss.weibull_max(c=0.5)

# rv = ss.cauchy()

n_grid = 1001
s = 1e-8
k = 2
cdf_spline = create_cdf_spline(rv, n_grid, s=s, k=k)
x_grid_spline = cdf_spline.get_knots()
y_grid_spline = cdf_spline.derivative(n=1)(x_grid_spline)
cump_grid_spline = cdf_spline(x_grid_spline)

plot_spline(cdf_spline, label="spline")
plot_rv(rv, label="original")
plt.plot(x_grid_spline, cump_grid_spline, "ok")
plt.legend()
plt.show()

plot_spline_deriv(cdf_spline, label="spline")
plot_rv(rv, fun_name="pdf", label="original")
plt.plot(x_grid_spline, y_grid_spline, "ok")
plt.legend()
plt.show()

# Comparing with current `Cont`
with config.context({"n_grid": n_grid}):
    rv_cont = Cont.from_rv(rv)
rv_spline = cont_from_cdf_spline(rv, n_grid, s=s, k=k)

print(rv_cont)
print(rv_spline)

plot_rv(rv, "pdf", color="black", label="original")
plot_rv(rv_cont, "pdf", color="blue", label="Cont")
plt.plot(rv_cont.x, rv_cont.y, color="blue", marker="o")
plot_rv(rv_spline, "pdf", color="red", label="spline")
plt.plot(rv_spline.x, rv_spline.y, color="red", marker="o")
plt.legend()
plt.show()

fun_diff(rv.pdf, rv_cont.pdf)
fun_diff(rv.pdf, rv_spline.pdf)
fun_diff(rv_cont.pdf, rv_spline.pdf)

fun_diff(rv.cdf, rv_cont.cdf)
fun_diff(rv.cdf, rv_spline.cdf)
fun_diff(rv_cont.cdf, rv_spline.cdf)

# Timings
# with config.context({"n_grid": n_grid}):
#     %timeit Cont.from_rv(rv)

# %timeit cont_from_cdf_spline(rv, n_grid, s=s, k=k)

# CURRENT CONCLUSION: using splines to find xy-grid (by approximating CDF with
# quadratic spline) with `s=1e-8` gives:
# - Pro++: around 8 to 10 times fewer grid elements.
# - Pro: approximates CDF on par with current method.
# - Con: not so well approximates density (L2 distance is around 1e-4 against 1e-5).
# - Con: takes about 8 to 10 times more computation time (around 10 ms vs around 1 ms).
# - Cont: it doesn't scale with `n_grid` very well in terms of execution time.


"""

A perfect square binomial is a quadratic function that can be factored into the following

a*x^2 + b*x + c = (u*x + v)^2

If we are less strict we can allow

a*x^2 + b*x + c = w*(u*x + v)^2

The first condition can be satisfied when the discriminant is 0 and the gcd of a, b, c is 1
d = b*b - 4*a*c = 0
gcd(a, gcd(a, b)) = 1

If we want the second form, we can get rid of the requirement of the gcd

"""

from sympy.abc import x
import sympy
import numpy as np
import sys

def str2bool(s):
    return s.lower() in ['true', '1', 't', 'y']

def is_perfect_square_binomial(a, b, c, strict):
    d = b*b - 4*a*c
    if d != 0:
        return False

    if strict and np.gcd(a, np.gcd(b, c)) != 1:
        return False

    return True

def find(n, strict):
    for a in range(1, n+1):
        for b in range(1, n+1):
            for c in range(1, n+1):
                if is_perfect_square_binomial(a, b, c, strict):
                    s = a*x*x + b*x + c
                    print("{} | {} | ({},{},{})".format(sympy.factor(s), s, a, b, c))

if len(sys.argv) < 3:
    print("usage: <n> <strict>")
    sys.exit(2)

find(int(sys.argv[1]), str2bool(sys.argv[2]))


from pprint import pprint
import numpy as np

## the data
row_names = np.array(["A2M", "FOS", "BRCA2","CPOX"])
column_names = np.array(["4h","12h","24h","48h"])
values0  = np.array([[0.12,0.08,0.06,0.02]])
values1  = np.array([[0.01,0.07,0.11,0.09]])
values2  = np.array([[0.03,0.04,0.04,0.02]])
values3  = np.array([[0.05,0.09,0.11,0.14]])

#############################################
## create an array for the data
#############################################
print("\nQuestion 1")
X = np.vstack([values0,values1,values2,values3])
print(X)
print(X.shape)

#############################################
## find the mean expression value per gene
#############################################
print("\nQuestion 2")
gene_means = X.mean(axis=1)
print("Gene means check: ", X[0,:].mean()==gene_means[0])
print(["%s = %s"%(gene,gene_means[g]) for g, gene in enumerate(row_names)])

#############################################
## find the mean expression per time point
#############################################
print("\nQuestion 3")
time_means = X.mean(axis=0)
print("Time means check: ", X[:,0].mean()==time_means[0])
print(["%s = %s"%(tp,time_means[t]) for t, tp in enumerate(column_names)])

########################################################
## which gene has the maximum mean expression value?
########################################################

print("\nQuestion 4")
gene_means = X.mean(axis=1)
gene_mean_ind = np.argmax(gene_means)
print("gene with max mean expression value: %s (%s)"%(row_names[gene_mean_ind],gene_means[gene_mean_ind]))

########################################################
## sort the gene names by the max expression value
########################################################

gene_names = row_names
print("sorted gene names: %s"%(gene_names[np.argsort(np.max(X,axis=1))]))


#
# Author : Francesco Seccamonte
# Copyright (c) 2020 Francesco Seccamonte. All rights reserved.
# Licensed under the MIT License. See LICENSE file in the project root for full license information.
#

#
# Internal implementation of the Theta method (including Backward Euler) for ODEs numerical solution.
#

import numpy as np

def _Theta_step(f, df, xi, ti, h, theta, TOL, MAXITER):
	"""Internal function implementing one step of the theta (including Backward Euler) method.

	The ODE to be solved is of the form: x' = f(t,x), x being a vector in n-dimensions

	- **parameters**, **types**, **return** and **return types**::
		:param f: function in x' = f(t,x)
		:param df: Jacobian of f
		:param xi: initial condition at time ti
		:param ti: current time
		:param h: step size
		:param theta: value between 0 and 1
		:param TOL: Numerical tolerance for convergence
		:param MAXITER: Maximum number of Newton iterations to be performed
		:type f: Callable
		:type df: Callable
		:type xi: np.array[float]
		:type ti: np.float
		:type h: np.float
		:type theta: np.float
		:type TOL: np.float
		:type NEWTITER: (unsigned) int
		:return: Vector x containing solution of component j at next time ti+h (x[j])
		:rtype: np.array[float]

	"""

	# xinu represents the \nu step of the Newton iteration algorithm
	# xinu's first guess initialized as previous solution
	xinu = np.copy(xi);

	# Newton iteration
	for i in range(MAXITER):
		A = (np.identity(xi.size) - (1-theta)*h*df(ti+h,xinu));
		b = -(xinu - xi -theta*h*f(ti,xi) -(1-theta)*h*f(ti+h,xinu));

		# delta = xinu+1 - xinu
		# Solving the linear system of equations A delta = b, that is,
		# (I - (1-theta)*h*df)*delta = -(xinu - xi -theta*h*f(ti,xi) -(1-theta)*h*f(ti+h,xinu))
		delta = np.linalg.solve(A, b);

		xinu += delta;

		# check for convergence
		if np.linalg.norm(delta) <= TOL:
			return xinu;

	raise ArithmeticError('Newton iteration has not converged')


from aSurnameFilters import *
import numpy as  np
import matplotlib.pyplot as plt
#Plot of all graphs
#There will be a total of 6 plots
def plotlab3b(code, date):
    n = np.arange(-10, 10 + 1)
    x = 1*(n==0)
    y = [s1(x), s2(x), s2(s1(x)), s1(s2(x))]
    # we are using object oriented programming
    # in using the figure plots in
    # matplot matplotlib
    title = 'Figure 3312a\n'
    title += 'Impulse response of s1(n)\n'
    title += code + ' ' + date
    f, axarr = plt.subplots(2)
    f.suptitle(title)
    axarr[0].stem(n, x)
    axarr[1].stem(n, y[0])
    axarr[0].grid()
    axarr[1].grid()
    axarr[1].set_xlabel('n')
    axarr[0].set_ylabel('x(n)')
    axarr[1].set_ylabel('s1(n)')
    title = title.replace('3312a', '3312b', 1)
    title = title.replace('s1(n)', 's2(n)', 1)
    f, axarr = plt.subplots(2)
    f.suptitle(title)
    axarr[0].stem(n, x)
    axarr[1].stem(n, y[1])
    axarr[0].grid()
    axarr[1].grid()
    axarr[1].set_xlabel('n')
    axarr[0].set_ylabel('xa(n)')
    axarr[1].set_ylabel('inte(xa(n))')
    title = title.replace('3312b', '3312c', 1)
    title = title.replace('s2(n)', 's2(s1(n))')
    f, axarr = plt.subplots(2)
    f.suptitle(title)
    axarr[0].stem(n, x)
    axarr[1].stem(n, y[2])
    axarr[0].grid()
    axarr[1].grid()
    axarr[1].set_xlabel('n')
    axarr[0].set_ylabel('xb(n)')
    axarr[1].set_ylabel('diff(xb(n))')
    title = title.replace('3312c', '3312d', 1)
    title = title.replace('s2(s1(n))', 's1(s2(n))')
    f, axarr = plt.subplots(2)
    f.suptitle(title)
    axarr[0].stem(n, x)
    axarr[1].stem(n, y[3])
    axarr[0].grid()
    axarr[1].grid()
    axarr[1].set_xlabel('n')
    axarr[0].set_ylabel('xb(n)')
    axarr[1].set_ylabel('inte(xb(n))')
    n = np.arange(0, 128 + 1)
    x = 1*(n==0)
    title = title.replace('3312d', '351', 1)
    title = title.replace('s1(s2(n))', '\ny(n) + 0.8y(n − 2) = 0.2x(n) + 0.4x(n − 1) + 0.2x(n − 2)')
    f, axarr = plt.subplots(2)
    f.suptitle(title)
    axarr[0].stem(n, x)
    axarr[1].stem(n, fil351(x))
    axarr[0].grid()
    axarr[1].grid()
    axarr[1].set_xlabel('n')
    axarr[0].set_ylabel('x(n)')
    axarr[1].set_ylabel('y(n)')
    n = np.arange(-10, 100 + 1)
    x = 1*(n==0)
    title = title.replace('351', '352', 1)
    title = title.replace('y(n) − 1.8 cos(π/16)y(n − 1) + 0.81y(n − 2) = x(n) + 1/2x(n − 1)',
        'y(n) + 0.8y(n − 2) = 0.2x(n) + 0.4x(n − 1) + 0.2x(n − 2)')
    f, axarr = plt.subplots(2)
    f.suptitle(title)
    axarr[0].stem(n, x)
    axarr[1].stem(n, fil352(x))
    axarr[0].grid()
    axarr[1].grid()
    axarr[1].set_xlabel('n')
    axarr[0].set_ylabel('x(n)')
    axarr[1].set_ylabel('y(n)')
    plt.show()

if __name__ == '__main__':
# edit your code and date here
    code = 'RJTRAMOS'
    date = '1/16/2018'
    plotlab3b(code, date)
    path = 'music.wav'
    musicFilter(path)


import numpy as np

def read_data(filename='./set1.dat'):
    dataset = []
    with open(filename, 'r') as f:
        for line in f:
            line = (line.strip()).split('\t')
            line = [float(t) for t in line]
            dataset.append(line)

    dataset = np.array(dataset, dtype=np.float32)
    np.random.shuffle(dataset)
    X = dataset[:, :-1]
    X = scale_data(np.array(X))
    Y = dataset[:, -1]

    N = X.shape[0]
    tr = int(N * 0.8)

    X_train = X[:tr, :]
    X_test = X[tr:, :]
    Y_train = Y[:tr]
    Y_test = Y[tr:]

    return X_train, Y_train, X_test, Y_test

def scale_data(X):
    ############################################################################
    #                            START OF YOUR CODE                            #
    ############################################################################
    min_values = np.amin(X, axis=0)
    max_values = np.amax(X, axis=0)
    return (X - min_values) / (max_values - min_values)
    ############################################################################
    #                             END OF YOUR CODE                             #
    ############################################################################


def find_rigid_transform(a, b, visualize=False):
    """
    Args:
        a: a 3xN array of vertex locations
        b: a 3xN array of vertex locations

    Returns: (R,T) such that R.dot(a)+T ~= b
    Based on Arun et al, "Least-squares fitting of two 3-D point sets," 1987.
    See also Eggert et al, "Estimating 3-D rigid body transformations: a
    comparison of four major algorithms," 1997.
    """
    import numpy as np
    import scipy.linalg
    from blmath.numerics.matlab import col

    if a.shape[0] != 3:
        if a.shape[1] == 3:
            a = a.T
    if b.shape[0] != 3:
        if b.shape[1] == 3:
            b = b.T
    assert a.shape[0] == 3
    assert b.shape[0] == 3

    a_mean = np.mean(a, axis=1)
    b_mean = np.mean(b, axis=1)
    a_centered = a - col(a_mean)
    b_centered = b - col(b_mean)

    c = a_centered.dot(b_centered.T)
    u, s, v = np.linalg.svd(c, full_matrices=False)
    v = v.T
    R = v.dot(u.T)

    if scipy.linalg.det(R) < 0:
        if np.any(s == 0): # This is only valid in the noiseless case; see the paper
            v[:, 2] = -v[:, 2]
            R = v.dot(u.T)
        else:
            raise ValueError("find_rigid_transform found a reflection that it cannot recover from. Try RANSAC or something...")

    T = col(b_mean - R.dot(a_mean))

    if visualize != False:
        from lace.mesh import Mesh
        from lace.meshviewer import MeshViewer
        mv = MeshViewer() if visualize is True else visualize
        a_T = R.dot(a) + T
        mv.set_dynamic_meshes([
            Mesh(v=a.T, f=[]).set_vertex_colors('red'),
            Mesh(v=b.T, f=[]).set_vertex_colors('green'),
            Mesh(v=a_T.T, f=[]).set_vertex_colors('orange'),
        ])

    return R, T

def find_rigid_rotation(a, b, allow_scaling=False):
    """
    Args:
        a: a 3xN array of vertex locations
        b: a 3xN array of vertex locations

    Returns: R such that R.dot(a) ~= b

    See link: http://en.wikipedia.org/wiki/Orthogonal_Procrustes_problem
    """
    import numpy as np
    import scipy.linalg
    from blmath.numerics.matlab import col

    assert a.shape[0] == 3
    assert b.shape[0] == 3

    if a.size == 3:
        cx = np.cross(a.ravel(), b.ravel())
        a = np.hstack((col(a), col(cx)))
        b = np.hstack((col(b), col(cx)))

    c = a.dot(b.T)
    u, _, v = np.linalg.svd(c, full_matrices=False)
    v = v.T
    R = v.dot(u.T)

    if scipy.linalg.det(R) < 0:
        v[:, 2] = -v[:, 2]
        R = v.dot(u.T)

    if allow_scaling:
        scalefactor = scipy.linalg.norm(b) / scipy.linalg.norm(a)
        R = R * scalefactor

    return R


#
#	Solved Problems in Geostatistics
#
# ------------------------------------------------
#	Script for lesson 4.3
#	"Transfer of Uncertainty"
# ------------------------------------------------

import sys
sys.path.append(r'../shared')

from numpy import *
from geo import *
from statistics import *
from matplotlib import *
from pylab import *
from scipy import *
from scipy.interpolate import *

# ---------------------------------------------------
#	Problem:
#
#	Evaluate the uncertainty in NVP for the first 5 years of a proposed project given the following parameter distributions provided by a finance model: Annual revenue, R, may be modeled by a normal distribution with mean and variance of $10 million and 2 million, respectively. Annual costs, C, are also assumed to follow a normal distribution with mean and variance of $8 million and 2 million. Choose a constant discount factor, r, say 10%. Calculate the P10, P50, and P90 of NPV. What is the probability of negative NPV?
#
# ----------------------------------------------------

# Mean and variance of annual revenue, R.
mean_R = 10
var_R = 2

# Mean and variance of annual costs, C.
mean_C = 8
var_C = 2

# Constant discount factor, r.
r = 0.1

# Number of years.
n = 5

# Number of realizations.
l = 1000

# Function for calculating NPV:
def npv_calculate(R, C, r, n):
	npv = 0.0
	for i in xrange(n):
		npv = npv + ((R[i] - C[i]) / (1 + r)**i)
	return npv

npv_array = []

# Repeat l times to assemble the distribution for NPV.
for i in xrange(l):
	#Simulate random R
	R = random.normal(mean_R, sqrt(var_R), n)

	#Simulate random C
	C = random.normal(mean_C, sqrt(var_C), n)

	npv_array.append(npv_calculate(R, C, r, n))
print "NPV", npv_array

[array_bins, array_hist] = histogram(npv_array, l)

for i in xrange(l-1):
	array_bins[i+1] = array_bins[i+1] + array_bins[i]

array_bin = zeros( (l), order = 'F', dtype = float)

for i in xrange(l):
	array_bin[i] =  float(array_bins[i]) / l

array_hist = delete(array_hist, [0])
z = []

# Interpolation
int_obj = interp1d(array_bin, array_hist, kind = 'linear')
z.append(int_obj(0.1))
z.append(int_obj(0.5))
z.append(int_obj(0.9))
print "P10 = ", z[0]
print "P50 = ", z[1]
print "P90 = ", z[2]

# Calculate the probability of a negative NPV.

negative_npv = 0.0
for i in xrange(l):
	if (npv_array[i] < 0):
		negative_npv = negative_npv + 1.0

prob_npv = negative_npv / l
print "Probability of negative NPV = ", prob_npv

# Histogram (1) and cumulative histogram (2) of simulated NPV assuming independence between the input variables.

figure()
hist(npv_array, 50, normed = True)
xlabel("NPV")
ylabel("Frequency")
title("Histogram of simulated NPV")

figure()
plot(array_hist, array_bin)
xlabel("NPV")
ylabel("Cumulative Frequency")
title("Cumulative histogram of simulated NPV")
show()

src/sample-scripts/solved_problems/4.3. Transfer of Uncertainty/1_npv.py


"""
measure.py
Analyzing and Visualizing Molecules (MOLSSI)

Handles the primary functions
"""

import numpy as np

def calculate_distance(Atom_A, Atom_B):

    """
    Distance Between Two Atoms.

    Parameters
    __________

    Atom_A, Atom_B : np.ndarray
        The Coordinates for Atom_A and Atom_B.

    Returns
    _______

    distance : float
        The Distance from Atom_A to Atom_B.

    Examples
    ________

    >>> r1 = np.array([0.0, 0.0, 0.0])
    >>> r2 = np.array([1.0, 0.0, 0.0])
    >>> calculate_distance(r1, r2)
    1.0
    """

    difference = (Atom_A - Atom_B)
    distance = np.linalg.norm(difference)
    return distance

def calculate_angle(rA, rB, rC, degrees=False):
    # Calculate the angle between three points. Answer is given in radians by default, but can be given in degrees
    # by setting degrees=True
    AB = rB - rA
    BC = rB - rC
    theta=np.arccos(np.dot(AB, BC)/(np.linalg.norm(AB)*np.linalg.norm(BC)))

    if degrees:
        return np.degrees(theta)
    else:
        return theta


import numpy as np
import pandas as pd
import scipy.optimize as opt
import seaborn as sns
import matplotlib.pyplot as plt

from helper import general as general
sns.set(context="notebook", style="ticks", font_scale=1.5)

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

def cost(theta, X, y):
    ''' cost fn is -l(theta) for you to minimize'''
    return np.mean(-y * np.log(sigmoid(X @ theta)) - (1 - y) * np.log(1 - sigmoid(X @ theta)))

def gradient(theta, X, y):
    '''just 1 batch gradient'''
    return (1 / len(X)) * X.T @ (sigmoid(X @ theta) - y)

def predict(x, theta):
    prob = sigmoid(x @ theta)
    return (prob >= 0.5).astype(int)

# for i in 0..i
#   for p in 0..i:
#     output x^(i-p) * y^p

def feature_mapping(x, y, power, as_ndarray=False):
    """return mapped features as ndarray or dataframe"""
    # data = {}
    # # inclusive
    # for i in np.arange(power + 1):
    #     for p in np.arange(i + 1):
    #         data["f{}{}".format(i - p, p)] = np.power(x, i - p) * np.power(y, p)

    data = {"f{}{}".format(i - p, p): np.power(x, i - p) * np.power(y, p)
                for i in np.arange(power + 1)
                for p in np.arange(i + 1)
            }

    if as_ndarray:
        return pd.DataFrame(data).as_matrix()
    else:
        return pd.DataFrame(data)

def regularized_cost(theta, X, y, l=1):
    '''you don't penalize theta_0'''
    theta_j1_to_n = theta[1:]
    regularized_term = (l / (2 * len(X))) * np.power(theta_j1_to_n, 2).sum()

    return cost(theta, X, y) + regularized_term

def regularized_gradient(theta, X, y, l=1):
    '''still, leave theta_0 alone'''
    theta_j1_to_n = theta[1:]
    regularized_theta = (l / len(X)) * theta_j1_to_n

    # by doing this, no offset is on theta_0
    regularized_term = np.concatenate([np.array([0]), regularized_theta])

    return gradient(theta, X, y) + regularized_term

def feature_mapped_logistic_regression(power, l):
    """for drawing purpose only.. not a well generealize logistic regression
    power: int
        raise x1, x2 to polynomial power
    l: int
        lambda constant for regularization term
    """
    df = pd.read_csv('ex2data2.txt', names=['test1', 'test2', 'accepted'])
    x1 = np.array(df.test1)
    x2 = np.array(df.test2)
    y = general.get_y(df)

    X = feature_mapping(x1, x2, power, as_ndarray=True)
    theta = np.zeros(X.shape[1])

    res = opt.minimize(fun=regularized_cost,
                       x0=theta,
                       args=(X, y, l),
                       method='TNC',
                       jac=regularized_gradient)
    final_theta = res.x

    return final_theta

def find_decision_boundary(density, power, theta, threshhold):
    t1 = np.linspace(-1, 1.5, density)
    t2 = np.linspace(-1, 1.5, density)

    cordinates = [(x, y) for x in t1 for y in t2]
    x_cord, y_cord = zip(*cordinates)
    mapped_cord = feature_mapping(x_cord, y_cord, power)  # this is a dataframe

    inner_product = mapped_cord.as_matrix() @ theta

    decision = mapped_cord[np.abs(inner_product) < threshhold]

    return decision.f10, decision.f01

def draw_boundary(power, l):
    """
    power: polynomial power for mapped feature
    l: lambda constant
    """
    density = 1000
    threshhold = 2 * 10**-3

    final_theta = feature_mapped_logistic_regression(power, l)
    x, y = find_decision_boundary(density, power, final_theta, threshhold)

    df = pd.read_csv('ex2data2.txt', names=['test1', 'test2', 'accepted'])
    sns.lmplot('test1', 'test2', hue='accepted', data=df, size=6, fit_reg=False, scatter_kws={"s": 100})

    plt.scatter(x, y, c='R', s=10)
    plt.title('Decision boundary')

def logistic_regression(X, y, l=1):
    """generalized logistic regression
    args:
        X: feature matrix, (m, n+1) # with incercept x0=1
        y: target vector, (m, )
        l: lambda constant for regularization

    return: trained parameters
    """
    # init theta
    theta = np.zeros(X.shape[1])

    # train it
    res = opt.minimize(fun=regularized_cost,
                       x0=theta,
                       args=(X, y, l),
                       method='TNC',
                       jac=regularized_gradient,
                       options={'disp': True})
    # get trained parameters
    final_theta = res.x

    return final_theta


import numpy as np

class KMeans():
    """Implementation of the KMeans Algorithm"""

    def __init__(self, n_cluster, max_iter=100, e=0.0001):
        """constructor

        Args
        ----
            - n_cluster(int): "k" in K-Means
            - max_iter(int): Maximum number of iterations to consider before returning
            - e(double): tolerance. Difference between successive distortions to define "converged"

        """
        self.n_cluster = n_cluster
        self.max_iter = max_iter
        self.e = e

    def fit(self, x):
        '''Finds n_cluster clusters in the data x

        We need to determine the optimal cluster memberships and centroids.

        Args
        ----
            - x (numpy array):  N X D input matrix

        Returns
        -------
            - mu(numpy.ndarray): centroids or means
            - r(numpy.array): cluster membership
            - iter(int): number of iterations taken to converge

        Algorithm
        ---------
            - Initialize means by picking self.n_cluster from N data points
            - Update means and membership until convergence

        '''
        assert len(x.shape) == 2, "fit function takes 2-D numpy arrays as input"
        np.random.seed(42)
        N, D = x.shape

        K = self.n_cluster

        # Initialize muk as random datapoints in x.

        point_idx = np.arange(N)
        np.random.shuffle(point_idx)
        cluster_centers = point_idx[:K]  # K x 1
        mu = x[cluster_centers, :]

        # Initializa cost
        J = np.inf

        for i in range(self.max_iter):

            # Compute r
            r = np.zeros(N)
            dist = np.zeros((N, K))

            for n in range(N):
                for k in range(K):
                    dist[n, k] = np.inner(mu[k,:]-x[n,:], mu[k,:]-x[n,:])

            r = np.argmin(dist, axis=1)

            J_new = 0
            for n in range(N):
                J_new += dist[n,r[n]]

            J_new /= N # Just computed the "average" distortion to speed up process

            #print("Iteration [",i,"]: J = ", J ," ; Diff = ", np.absolute(J - J_new))
            print("Iteration [",i,"]: J = ", J)

            if np.absolute(J - J_new) <= self.e:
                return (mu, r, i)

            J = J_new

            for k in range(K):
                k_idx_samples, = np.where(r == k)
                mu[k] = np.sum(x[k_idx_samples, :], axis=0) / len(k_idx_samples)

        print("Did not converge!")
        return (mu, r, self.max_iter)


import numpy as np

np.random.seed(1234)

# 1. Data Preprocess and declare
x = np.array([
    [1,0,0],
    [1,1,0],
    [1,1,1]
])

y = np.array([
    [1],
    [2],
    [3]
])

# 1.3 Starting Weights - however -
# the best set of weights would be wx = 1 and wrec = 1
wx = [0.2]
wrec = [1.5]

# Hyper Par
number_or_epoch = 30000
number_of_training_data = 3
learning_rate_x = 0.02
learning_rate_rec = 0.0006

# np array
states = np.zeros((3,4))
grad_over_time = np.zeros((3,4))

# 2. Start the Training
for iter in range(number_or_epoch):

    # 2.3 Feed Forward of the network
    layer_1 = x[:,0] * wx + states[:,0] * wrec
    states[:,1] = layer_1

    layer_2 = x[:,1] * wx + states[:,1] * wrec
    states[:,2] = layer_2

    layer_3 = x[:,2] * wx + states[:,2] * wrec
    states[:,3] = layer_3

    cost = np.square(states[:,3] - y).sum() / number_of_training_data

    grad_out = (states[:,3] - np.squeeze(y)) * 2 / number_of_training_data
    grad_over_time[:,3] = grad_out
    grad_over_time[:,2] = grad_over_time[:,3] * wrec
    grad_over_time[:,1] = grad_over_time[:,2] * wrec

    # NOTE: Do Not really need grad_over_time[:,0]
    grad_over_time[:,0] = grad_over_time[:,1] * wrec

    #
    grad_wx = np.sum(grad_over_time[:,3] * x[:,2] +
                     grad_over_time[:,2] * x[:,1]  +
                     grad_over_time[:,1] * x[:,0])

    grad_rec = np.sum(grad_over_time[:,3] * states[:,2] +
                      grad_over_time[:,2] * states[:,1]  +
                      grad_over_time[:,1] * states[:,0])

    wx = wx - learning_rate_x * grad_wx
    wrec = wrec - learning_rate_rec * grad_rec

    if iter%1000 == 0:
        print('Current Epoch: ',iter, '  current predition :' ,layer_3)

# 3. Final Output and rounded resutls
layer_1 = x[:,0] * wx + states[:,0] * wrec
states[:,1] = layer_1

layer_2 = x[:,1] * wx + states[:,1] * wrec
states[:,2] = layer_2

layer_3 = x[:,2] * wx + states[:,2] * wrec
states[:,3] = layer_3

print('Ground Truth: ',layer_3)
print('Rounded Truth: ',np.round(layer_3))
print("Final weight X : ",wx)
print("Final weight Rec : ",wrec)

# ---- end code ---


import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate

f = lambda x: np.sin(x*x)

def pA():
    n = 20
    x_knots = np.linspace(1, 5, n+1)
    y_knots = f(x_knots)

    xs = []
    ys_lin = []

    for i, left_x in enumerate(x_knots[0:-1]):
        right_x = x_knots[i+1]
        dx = right_x - left_x
        for x in np.linspace(0,1,100):
            xs.append(left_x + x*dx)
            ys_lin.append(y_knots[i]*(1-x) + y_knots[i+1]*x)

    xs = np.array(xs)

    tck = interpolate.splrep(x_knots, y_knots, s=0)
    ys_cubic = interpolate.splev(xs, tck, der=0)

    plt.figure()
    plt.plot(xs, ys_lin, label="Linear")
    plt.plot(xs, ys_cubic, label="Cubic")
    plt.plot(xs, f(xs), label="f")
    plt.ylabel("f(x)")
    plt.xlabel("x")
    plt.legend()
    plt.title('Spline interpolation')
    plt.show()

def pB():
    n = 20
    x_knots = np.linspace(1, 5, n+1)
    y_knots = f(x_knots)

    xs = []
    ys_lin = []

    for i, left_x in enumerate(x_knots[0:-1]):
        right_x = x_knots[i+1]
        dx = right_x - left_x
        for x in np.linspace(0,1,1000, endpoint=False):
            xs.append(left_x + x*dx)
            ys_lin.append(y_knots[i]*(1-x) + y_knots[i+1]*x)

    xs = np.array(xs)

    tck = interpolate.splrep(x_knots, y_knots, s=0)
    ys_cubic = interpolate.splev(xs, tck, der=0)

    fxs = f(xs)
    plt.figure()
    plt.plot(xs, abs(f(xs) - ys_lin), label="Linear Error")
    plt.plot(xs, abs(f(xs) - ys_cubic), label="Cubic Error")
    plt.ylabel("$$|f(x) - s(x)|$$")
    plt.xlabel("x")
    plt.legend()
    plt.title('Spline interpolation error')
    plt.show()

def pCD():
    def inorm(n):
        x_knots = np.linspace(1, 5, n+1)
        y_knots = f(x_knots)

        xs = []
        ys_lin = []

        for i, left_x in enumerate(x_knots[0:-1]):
            right_x = x_knots[i+1]
            dx = right_x - left_x
            for x in np.linspace(0,1,round(10000.0/n), endpoint=False):
                xs.append(left_x + x*dx)
                ys_lin.append(y_knots[i]*(1-x) + y_knots[i+1]*x)

        xs = np.array(xs)

        tck = interpolate.splrep(x_knots, y_knots, s=0)
        ys_cubic = interpolate.splev(xs, tck, der=0)

        fxs = f(xs)

        return (max(abs(fxs - ys_lin)), max(abs(fxs - ys_cubic)))

    xs = np.arange(20,1000)
    ys_cub = np.empty_like(xs, dtype=float)
    ys_lin = np.empty_like(xs, dtype=float)
    for i,n in enumerate(xs):
        (ys_lin[i], ys_cub[i]) = inorm(n)

    plt.figure()
    plt.yscale("log")
    plt.plot(xs, ys_lin)
    plt.ylabel(r'$|f - s_L|_\infty$')
    plt.xlabel("n")
    plt.title('Linear Error per precision')
    plt.show()

    plt.figure()
    plt.yscale("log")
    plt.plot(xs, ys_cub)
    plt.ylabel(r'$|f - s_C|_\infty$')
    plt.xlabel("n")
    plt.title('Cubic Error per precision')
    plt.show()


import math
import numpy as np

# Generate Hadamhard matrix of atleast a given size using Sylvester's method
def generated_hadamhard_matrix(lower_bound):

    dim = 1
    h = np.array([[1.0]], dtype=float)

    while dim < lower_bound:
        h = np.block([[h, h], [h, -h]])
        dim = 2 * dim

    # Trim the columns of the matrix to match the lower bound
    return h[:, :lower_bound]

# Size of the smallest Hadamhard matrix which is greater than lower bound, as generated by Sylvester's method.
def get_sylvester_hadamhard_matrix_dim(lower_bound):
    return int(math.pow(2, math.ceil(math.log(lower_bound, 2))))


# Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.

import numpy as np
import matplotlib.pyplot as plt

def target_function2(a,y):
    p1 = y * np.log(a)
    p2 = (1-y) * np.log(1-a)
    y = -p1 - p2
    return y

if __name__ == '__main__':
    err = 1e-2  # avoid invalid math caculation
    a = np.linspace(0+err,1-err)
    y = 0
    z1 = target_function2(a,y)
    y = 1
    z2 = target_function2(a,y)
    p1, = plt.plot(a,z1)
    p2, = plt.plot(a,z2)
    plt.grid()
    plt.legend([p1,p2],["y=0","y=1"])
    plt.xlabel("a")
    plt.ylabel("Loss")
    plt.show()


import numpy as np

def linear_interpolation_at_t(p0, p1, t):
    return (1-t)*p0 + t*p1

def linear_interpolation_of_points(control_points):
    interpolated_points = list()
    time_array = np.linspace(0.0, 1.0, 101)
    if (control_points.shape[0] < 2): # need atleast two points to interpolate
        return interpolated_points
    for p0, p1 in zip(control_points[:-1], control_points[1:]):
        points = [linear_interpolation_at_t(p0, p1, t) for t in time_array]
        interpolated_points += points

    return np.array(interpolated_points)

def bezier_interpolation_at_t(p0, p1, p2, p3, t):
  """All the points are given as np.array. t is a floating number that represents time."""
  Mb = np.array([[-1, 3, -3, 1],[3, -6, 3, 0], [-3, 3, 0, 0], [1, 0, 0, 0]])
  Gb = np.vstack((p0, p1, p2, p3))
  T = np.array([t**3, t**2, t, 1])
  return T @ Mb @ Gb

def bezier_interpolation_of_points(control_points):
  """control_points is a list of points (np.array)."""
  interpolated_points = list()  # The container for interpolated points
  time_array = np.linspace(0.0, 1.0, 101)  # time[0] = 0.0, time[1] = 0.01, ... time[100] = 1.0

  # For each segment of control points
  for i in range(0, control_points.shape[0], 3):
    if i + 3 >= control_points.shape[0]: # if out of range
      break
    p0, p1, p2, p3 = [control_points[idx] for idx in (i, i+1, i+2, i+3)]
    # Compute the interpolated points and append to the list
    points = [bezier_interpolation_at_t(p0, p1, p2, p3, t) for t in time_array]
    interpolated_points += points

  return np.array(interpolated_points)

def bspline_interpolation_at_t(p0, p1, p2, p3, t):
  """All the points are given as np.array. t is a floating number that represents time."""
  Mbs = np.array([[-1, 3, -3, 1],[3, -6, 3, 0], [-3, 0, 3, 0], [1, 4, 1, 0]]) / 6
  Gbs = np.vstack((p0, p1, p2, p3))
  T = np.array([t**3, t**2, t, 1])
  return T @ Mbs @ Gbs

def bspline_interpolation_of_points(control_points):
  """control_points is a list of points (np.array)."""
  interpolated_points = list()  # The container for interpolated points
  time_array = np.linspace(0.0, 1.0, 101)  # time[0] = 0.0, time[1] = 0.01, ... time[100] = 1.0

  # For each segment of control points (De Boor points)
  for i in range(control_points.shape[0]-3):
    p0, p1, p2, p3 = [control_points[idx] for idx in (i, i+1, i+2, i+3)]
    # Compute the interpolated points and append to the list
    points = [bspline_interpolation_at_t(p0, p1, p2, p3, t) for t in time_array]
    interpolated_points += points

  return np.array(interpolated_points)

def bspline_interpolation_of_points_v2(control_points):
  # ghost points (interpolating first and last)
  if control_points.shape[0] < 2:
      return []
  gp1 = 2*control_points[0,:] - control_points[1,:]
  gp2 = 2*control_points[-1,:] - control_points[-2,:]
  cps = np.vstack((gp1, control_points, gp2))
  return bspline_interpolation_of_points(cps) # reuse v1 implementation

def catmullrom_interpolation_at_t(p0, p1, p2, p3, t):
  """All the points are given as np.array. t is a floating number that represents time."""
  Mc = np.array([[-1, 3, -3, 1],[2, -5, 4, -1], [-1, 0, 1, 0], [0, 2, 0, 0]]) / 2
  Gc = np.vstack((p0, p1, p2, p3))
  T = np.array([t**3, t**2, t, 1])
  return T @ Mc @ Gc

def catmullrom_interpolation_of_points(control_points):
  """control_points is a list of points (np.array)."""
  interpolated_points = list()  # The container for interpolated points
  time_array = np.linspace(0.0, 1.0, 101)  # time[0] = 0.0, time[1] = 0.01, ... time[100] = 1.0

  # For each segment of control points
  for i in range(control_points.shape[0]-3):
    p0, p1, p2, p3 = [control_points[idx] for idx in (i, i+1, i+2, i+3)]
    # Compute the interpolated points and append to the list
    points = [catmullrom_interpolation_at_t(p0, p1, p2, p3, t) for t in time_array]
    interpolated_points += points

  return np.array(interpolated_points)

def c2_interpolation_of_points(control_points):
  # hard
  # big linear system and solve (invert lin-system server from numpy lib)
  if control_points.shape[0] < 2:
      return []
  N = control_points.shape[0]
  dim = control_points.shape[1]
  A = np.zeros((N, N))
  A[0,:2] = np.array([2, 1])
  for i in range(1,N-1):
    A[i,i-1:i+2] = np.array([1, 4, 1])
  A[-1,-2:] = np.array([1, 2])
  b = np.vstack((3*(control_points[1,:] - control_points[0,:]),    # boundary start
                 3*(control_points[2:,:] - control_points[:-2,:]), # middle derivatives
                 3*(control_points[-1,:] - control_points[-2,:]))) # boundary end
  D = np.linalg.inv(A) @ b
  cps = np.empty((3*N - 2, dim), dtype=control_points.dtype) # N points ( 2(N-1) + N = 3N - 2)
  # C0, D0', D1', C1, D1', D2', C2
  cps[0::3] = control_points
  cps[1::3] = control_points[:-1,:] + D[:-1,:]/3  # D1 = 3 ( C2 - C1) --> C2 = C1 + D1/3
  cps[2::3] = control_points[1:,:] - D[1:,:]/3 # D4 = 3 ( C4 - C3) --> C3 = C4 - D4/3
  return bezier_interpolation_of_points(cps)


import numpy as np
import pandas as pd

#load MNIST data
data = pd.read_csv('./sample_data/mnist_test.csv')
data = data.drop('7',axis=1) #dropping the label column
data = np.array(data)[0:1000].T
print (data.shape)

#PCA by eigenvector decomposition
#mean normalization of dataset features
data = (data - np.mean(data,axis=1).reshape(-1,1))
covar = np.cov(data)  #covar = np.matmul(data,data.T)/data.shape[1]
eig_value,eig_vector = np.linalg.eig(covar)

#rotated dataset (dataset in a new linear basis)
new_dataset = np.matmul(eig_vector.T,data)
print (np.cov(new_dataset))  #should be a diagonal matrix

#Calculating the number of principal components to keep such that more than 95% variance is retained
sum_eigs = np.sum(eig_value)
run_sum = 0
for i in range(len(eig_value)):
  run_sum += eig_value[i]
  if run_sum/sum_eigs > 0.95:
    print (i)
    break

#retained dataset
PC = eig_vector.T[:i+1,:]
rot_dataset = np.matmul(PC,data)
print (rot_dataset.shape)

#PCA by SVD

#load mnist data
data = pd.read_csv('./sample_data/mnist_test.csv')
data = data.drop('7',axis=1) #dropping the label column
data = np.array(data)[0:1000].T
print (data.shape)

#svd of covariance matrix of data
u,s,vt = np.linalg.svd(np.cov(data))
print (u.shape,s.shape,vt.shape)

#rotated dataset (dataset in a new linear basis)
new_dataset = np.matmul(u.T,data)
print (np.cov(new_dataset))

#Calculating the number of principal components to keep such that more than 95% variance is retained
sum_eigs = np.sum(s)
run_sum = 0
for i in range(len(s)):
  run_sum += s[i]
  if run_sum/sum_eigs > 0.95:
    print (i)
    break

#retained dataset
PC = u.T[:i+1,:]
rot_dataset = np.matmul(PC,data)
print (rot_dataset.shape)

eps = 1e-5
#PCA Whitening
PCAwhite = new_dataset / np.sqrt(s.reshape(-1,1)  + eps)
#XCA Whitening
ZCAWhite = np.matmul(u,PCAwhite)


'''
basic euler approximation. this is an explicit numerical solution, meaning all unknown variables
    from the known ones.

want to approximate y = ln(x) by using numerical approximation. will take dy/dx = 1/x and
    y0=-2.3 @ x0 = 0.1

in order to solve, need :
    * differential equation dy/dx = fn
    * boundary / initial conditions y0 = integral(fn)(x0)
    * step size dx
    * some final desired state, either a number of iterations or estimated Y value

RECALL THAT THIS IS HOW YOU SOLVED EQ 10.9 ON PG 473 OF MECH. AND THERMO OF PROPULSION IN PROPS
    CLASS.
'''

import matplotlib.pyplot as plt
import numpy as np

# initial conditions
x = [0.1]
y= [-2.302]
fn = lambda _x:1/_x

dx = 0.005
while(y[-1]<0.1): # define some
    y.append( dx*fn(x[-1])+y[-1] )
    x.append(x[-1] + dx)

x_vals = np.array(x)
y_approx = np.array(y)
y_true = np.log(x_vals)

print('initial error: {}'.format( y_approx[0]-y_true[0] ))
print('final error: {}'.format( y_approx[-1]-y_true[-1] ))

plt.plot(x_vals,y_true,label = 'true')
plt.plot(x_vals,y_approx,label = 'approx')
plt.show()


# K-means clustering
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs

X,y=make_blobs(n_samples=500,n_features=2,centers=5,random_state=3)

k=5
color  = ["green","red","blue","yellow","orange"]

clusters={}
for i in range(k):
    center=10*(2*(np.random.random(X.shape[1],))-1)
    points=[]

    cluster={
        'center':center,
        'points':points,
        'color':color[i]
    }
    clusters[i]=cluster

def distance(v1,v2):
    return np.sqrt(np.sum((v1-v2)**2))
def assignPointToCluster(clusters):
    for ix in range(X.shape[0]):
        dist=[]
        curr_x=X[ix]

        for kx in range(k):
            d=distance(curr_x,clusters[kx]['center'])
            dist.append(d)

        current_cluster=np.argmin(dist)
        clusters[current_cluster]['points'].append(curr_x)

def updateClusters(clusters):
    for kx in range(k):
        pts=np.array(clusters[kx]['points'])

        if pts.shape[0]>0:
            new_u = pts.mean(axis=0)
            clusters[kx]['center'] = new_u
            clusters[kx]['points'] = []

def plotClusters(clusters):

    for kx in range(k):
        #print(len(clusters[kx]['points']))

        pts = np.array(clusters[kx]['points'])
        #print(pts.shape)

        #Plot the points
        try:
            plt.scatter(pts[:,0],pts[:,1],color=clusters[kx]['color'])
        except:
            pass

        #Plot the cluster center
        uk = clusters[kx]['center']
        plt.scatter(uk[0],uk[1],color="black",marker="*")

assignPointToCluster(clusters)
plotClusters(clusters)
updateClusters(clusters)


import fem.frame2d as f2d
import sympy
from sympy import symbols, Symbol, simplify
from sympy import diff, integrate
from sympy import zeros

# --------------------------------------------------------------------------------}
# --- General
# --------------------------------------------------------------------------------{
def stiffnessMatrixFromPot(Epot,u_dof):
    """ Return stiffness matrices from an experssion of potential energy and a list of DOF"""
    n=len(u_dof)
    Ke= zeros(n,n)
    for i in range(n):
        for j in range(n):
            Ke[i,j] = Epot.diff(u_dof[j]).diff(u_dof[i])
    return Ke

def stiffnessMatrixFromShapeFunctions(NN, x, L, EI):
    """
    For beam bending:
         ke = EI \int_0^L B^T B dx  where B = d^2N/dx^2 (curvature, or strain-displacement)
    TODO other
    """
    # --- "Slope"
    SS = NN.diff(x)
    # --- "Curvature" - Strain-displacement vector
    BB = NN.diff(x).diff(x)

    Ke = EI* integrate(BB.T * BB, (x, 0, L))

    return Ke

def massMatrixFromShapeFunctions(NN, x, L, m):
    """ Mass matrix for a Beam """
    Me = m/L*integrate(NN.T * NN, (x, 0, L))
    return Me

# --------------------------------------------------------------------------------}
# --- Frame 2d
# --------------------------------------------------------------------------------{
def frame2d_U_B(h,x,L, EI, u2=Symbol('u_2'), u3=Symbol('u_3'), u5=Symbol('u_5'), u6=Symbol('u_6')):
    """ Bending strain energy"""
    hpp=h(x,u2,u3, u5, u6, L).diff(x).diff(x)
    return EI/2*integrate( hpp * hpp, (x,0,L))

def frame2d_U_A(u, x, L, EA, u1=Symbol('u_1'), u4=Symbol('u_4')):
    """ Longitudinal strain energy TODO TODO TODO VERIFY ME"""
    up = u(x,u1,u4,L).diff(x)
    return EA/2*integrate( up * up, (x,0,L))

def frame2d_U_G(h,x,L,T, u2=Symbol('u_2'), u3=Symbol('u_3'), u5=Symbol('u_5'), u6=Symbol('u_6')):
    """ Potential energy due to axial loads """
    hp = h(x,u2,u3, u5, u6,L).diff(x)
    return T/2*integrate( hp*hp , (x,0,L))

# --------------------------------------------------------------------------------}
# --- Misc sympy utils
# --------------------------------------------------------------------------------{
def cleantex(s):
    """ clean a latex expression

    Example:
        print( cleantex( vlatex(MM, symbol_names={Jxx:'J_{xx}'})))
    """
    D_rep={
        '\\operatorname{sin}':'\\sin',
        '\\operatorname{cos}':'\\cos',
        '\\left(\\theta\\right)':'\\theta',
        '\\left[\\begin{matrix}':'\\begin{bmatrix}\n',
        '\\end{matrix}\\right]':'\n\\end{bmatrix}\n' ,
        '\\\\':'\\\\ \n'
        }
    for k in D_rep.keys():
        s=s.replace(k,D_rep[k])
    return s


import numpy as np

def lu_decomp(a,swap):
    (row,col)=a.shape
    for j in range(row):
        #search pivot
        maxind=j+np.argmax(abs(a[j:,j]))
        swap[j]=maxind
        #swap!
        a[[j,maxind],j:]=a[[maxind,j],j:]
        pivot=a[j,j]
        for i in range(j+1,row):
            p= -a[i,j]/pivot
            a[i,j:]+=p*a[j,j:]
            #memorize value p at [i,j] of a
            a[i,j]=p

def push_forward(a,swap,b):
    (row,col)=a.shape
    for j in range(row):
        #swap!
        b[[swap[j],j]]=b[[j,swap[j]]]
        for i in range(j+1,row):
            b[i]+= a[i,j] * b[j]

def back_forward(a,b,x):
    row=len(x)
    for i in range(row)[::-1]:
        x[i]=(b[i]-np.dot(a[i,i+1:row],x[i+1:row]))/a[i,i]

def main():
    a=np.matrix([[2,4,6],
                 [1,-1,5],
                 [4,1,-2]],dtype='float64')
    b=np.matrix([28,7,21],dtype='float64').T
    x=np.array([[None]*len(b)],dtype='float64').T
    swap=np.zeros(len(b),dtype='i').T

    lu_decomp(a,swap)
    push_forward(a,swap,b)
    back_forward(a,b,x)
    print("sol of ax=b with respect to x is =\n{}".format(x))

if __name__ == '__main__':
    main()


import numpy as np

def standardize(X, axis=0):
    mean_ = np.mean(X, axis=axis, keepdims=True)
    std_ = np.std(X, axis=axis, keepdims=True)
    return (X - mean_) / (std_ + 1e-15)


import numpy as np
from . import compute_max_angle

def gensk97(N):
    # See http://dx.doi.org/10.1016/j.jsb.2006.06.002 and references therein
    N = int(N)
    h = -1.0 + (2.0/(N-1))*np.arange(0,N)
    theta = np.arccos(h)
    phi_base = np.zeros_like(theta)
    phi_base[1:(N-1)] = ((3.6/np.sqrt(N))/np.sqrt(1 - h[1:(N-1)]**2))
    phi = np.cumsum(phi_base)
    phi[0] = 0
    phi[N-1] = 0

    stheta = np.sin(theta)
    dirs = np.vstack([np.cos(phi)*stheta, np.sin(phi)*stheta, np.cos(theta)]).T

    return dirs

class SK97Quadrature:
    @staticmethod
    def compute_degree(N,rad,usFactor):
        ang = compute_max_angle(N,rad,usFactor)
        return SK97Quadrature.get_degree(ang)

    @staticmethod
    def get_degree(maxAngle):
        degree = np.ceil((3.6/maxAngle)**2)
        cmaxAng = 3.6/np.sqrt(degree)

        return degree, cmaxAng

    @staticmethod
    def get_quad_points(degree,sym = None):
        verts = gensk97(degree)
        p = np.array(verts)
        w = (4.0*np.pi/len(verts)) * np.ones(len(verts))

        if sym is None:
            return p, w
        else:
            validPs = sym.in_asymunit(p)
            return p[validPs], w[validPs] * (np.sum(w) / np.sum(w[validPs]))


# rotational and orbital  motion of Hyperion, in the dumbbell model introduced
# in the Giordano-Nakanishi textbook
#
# solves
#
#      d^2r/dt^2 = - G*M r / r^3         for the CM motion
#
#      domega/dt = -3 GM / r^5 * [x cos(theta) + y sin(theta)] * [x sin(theta) - y cos(theta)]
#
# the orbital plane and the plane of rotation re both the x-y plane (assumption)
#
# Hyperion units (circular orbit has radius 1 HU, period 1 Hyr)
#
#
# by Denes Molnar for PHYS 580, Fall 2020

from math import sqrt, sin, cos
from math import pi as PI
import numpy as np

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

# compute evolution from given initconds
def computeMotion(initconds, dt, nsteps):
   (x0, y0, vx0, vy0, th0, om0) = initconds

   # allocate storage - only store position, angle, angular velocity
   x = np.zeros(nsteps + 1)
   y = np.zeros(nsteps + 1)
   theta = np.zeros(nsteps + 1)
   omega = np.zeros(nsteps + 1)
   # load initconds
   x[0], y[0] = x0, y0
   theta[0], omega[0] = th0, om0

   vx, vy = vx0, vy0    # only track instantaneous velocity

   # Euler-Cromer integrator
   GM = 4. * PI**2    # G * M_Saturn in HU-Hyr units
   for i in range(nsteps):
      # update CM velocity
      r = sqrt(x[i]**2 + y[i]**2)
      vx = vx - GM * x[i] * dt / r**3
      vy = vy - GM * y[i] * dt / r**3
      # then CM position
      x[i + 1] = x[i] + dt * vx
      y[i + 1] = y[i] + dt * vy
      # update axis rotational velocity, then angle
      angularTerm  = x[i] * sin(theta[i]) - y[i] * cos(theta[i])
      angularTerm *= x[i] * cos(theta[i]) + y[i] * sin(theta[i])
      omega[i + 1] = omega[i] - dt * 3. * GM / r**5 * angularTerm
      theta[i + 1] = theta[i] + dt * omega[i + 1]
      # map angle to [-pi, pi)
      if theta[i + 1] >= PI:   theta[i + 1] -= 2. * PI
      if theta[i + 1] < -PI:   theta[i + 1] += 2. * PI

   # return results
   return x, y, theta, omega

# get parameters
#

# initial conditions
x0  = float( input('Hyperion CM position x_0 [HU]: ') )
y0  = float( input('                     y_0 [HU]: ') )
vx0 = float( input('    CM velocity vx_0 [HU/Hyr]: ') )
vy0 = float( input('                vy_0 [HU/Hyr]: ') )
th0 = float( input('Axis angle [rad]:' ) )
om0 = float( input('Axis angular velocity [rad/Hyr]:' ) )

# computational parameters
t_end  = float( input('t_end [Hyr]: ') )
dt     = float( input('dt [Hyr]: ') )

nsteps = int(t_end / dt + 0.5)

# first compute entire evolution
#

initconds = (x0, y0, vx0, vy0, th0, om0)

xvals, yvals, thvals, omvals = computeMotion(initconds, dt, nsteps)
# construct time values
timevals = [ dt * i  for i in range(nsteps + 1) ]

# plots
#

#fontsize = 30   # fontsize, need to be tuned to screen resolution
fontsize = 15    # fontsize, for 1920x1080
#linewidth = 1.5
linewidth = 0.7
#pointarea = 2.
pointarea = 0.5

# make 2x2 plot
fig, axArray = plt.subplots(2, 2)
((ax0, ax1), (ax2, ax3)) = axArray

# TOP LEFT: x-y
#
ax0.tick_params(labelsize = fontsize)
#ax0.legend(fontsize = fontsize)
ax0.set_xlabel("x [HU]", fontsize = fontsize)
ax0.set_ylabel("y [HU]", fontsize = fontsize)
ax0.set_xlim((-1.5, 1.5))
ax0.set_ylim((-1.5, 1.5))
ax0.set_title("CM position")

# depict Saturn at origin
ax0.add_artist( plt.Circle((0, 0), 0.2, color = "purple") )

ax0.plot(xvals, yvals, linewidth = linewidth, color = "blue")

# TOP RIGHT: theta-omega
#
ax1.tick_params(labelsize = fontsize)
#ax1.legend(fontsize = fontsize)
ax1.set_xlabel("theta [rad]", fontsize = fontsize)
ax1.set_ylabel("omega [rad/Hyr]", fontsize = fontsize)
ax1.set_title("Axis phase portrait")

#ax1.plot(thvals, omvals, linewidth = linewidth, color = "blue")
ax1.scatter(thvals, omvals, s = pointarea, color = "blue", marker = ".")

# BOTTOM LEFT:  theta vs t
#
ax2.tick_params(labelsize = fontsize)
#ax2.legend(fontsize = fontsize)
ax2.set_xlabel("time [Hyr]", fontsize = fontsize)
ax2.set_ylabel("theta [rad]", fontsize = fontsize)
ax2.set_title("Axis orientation")

ax2.plot(timevals, thvals, linewidth = linewidth, color = "blue")

# BOTTOM RIGHT:  omega vs t
#
ax3.tick_params(labelsize = fontsize)
#ax3.legend(fontsize = fontsize)
ax3.set_xlabel("time [Hyr]", fontsize = fontsize)
ax3.set_ylabel("omega [rad/Hyr]", fontsize = fontsize)
ax3.set_title("Angular velocity")

ax3.plot(timevals, omvals, linewidth = linewidth, color = "blue")

# add some spacing between plots
plt.subplots_adjust(wspace = 0.3, hspace = 0.5)
# create plot window and show plot
plt.show()

#EOF


import numpy as np

def split_matrix(x):
    m = np.split(x, 2, axis=1)
    ac = np.split(m[0], 2)
    bd = np.split(m[1], 2)
    return ac[0], bd[0], ac[1], bd[1]

def strassen(x, y):
    assert x.shape == y.shape, 'X and Y must have same dimensions'
    assert x.ndim == 2, 'X and Y must be 2-dimensional'
    assert x.shape[0] == x.shape[1], 'X and Y must be a quadratic matrices'
    n = x.shape[0]
    if n == 2:
        a, b, c, d = split_matrix(x)
        e, f, g, h = split_matrix(y)
        p1 = int(a * (f - h))
        p2 = int((a + b) * h)
        p3 = int((c + d) * e)
        p4 = int(d * (g - e))
        p5 = int((a + d) * (e + h))
        p6 = int((b - d) * (g + h))
        p7 = int((a - c) * (e + f))
        return np.vstack((
            np.hstack((p5 + p4 - p2 + p6, p1 + p2)),
            np.hstack((p3 + p4, p1 + p5 - p3 - p7))
        ))

    a, b, c, d = split_matrix(x)
    e, f, g, h = split_matrix(y)
    row1 = np.hstack((strassen(a, e) + strassen(b, g), strassen(a, f) + strassen(b, h)))
    row2 = np.hstack((strassen(c, e) + strassen(d, g), strassen(c, f) + strassen(d, h)))
    return np.vstack((row1, row2))

if __name__ == '__main__':
    x = np.random.randint(128, size=(8, 8))
    y = np.random.randint(128, size=(8, 8))
    z = strassen(x, y)
    print('result of multiplying X * Y', z)
    print('result is correct:', np.array_equal(z, np.dot(x, y)))


from adaline_sgd import *
from plot_decision_regions import *
import matplotlib.pyplot as plt
import numpy as np

# ### Reading-in the Iris data
import pandas as pd

df = pd.read_csv('https://archive.ics.uci.edu/ml/'
        'machine-learning-databases/iris/iris.data', header=None)
df.tail()

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

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

### 正規化してから勾配法つかう
# standardize features
X_std = np.copy(X)
X_std[:, 0] = (X[:, 0] - X[:, 0].mean()) / X[:, 0].std()
X_std[:, 1] = (X[:, 1] - X[:, 1].mean()) / X[:, 1].std()

### 確率的勾配法
ada = AdalineSGD(n_iter=15, eta=0.01, random_state=1)
ada.fit(X_std, y)

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

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

plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Average Cost')

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


# Libraries
import numpy as np
import numpy.ma as ma
from scipy import linalg
np.set_printoptions(precision=2)

nel    = 2
nnos   = nel + 1
L      = 1
alldof = np.linspace(1, 1,2*nnos) # all degrees of freedom
kf = np.zeros((2*nnos,2*nnos))    # global stiffness matrix pre-allocation
kg = np.zeros((2*nnos,2*nnos))    # global stiffness matrix pre-allocation
coord = np.zeros((nnos, 2))       # coordinate matrix pre-allocation
inci = np.zeros((nel, 5))         # incidence matrix pre-allocation

for i in range(0, nnos):
    coord[i,0] = i + 1           # node number
    coord[i,1] = i*L/(nnos-1)    # node position

for i in range(0, nel):
    inci[i,0] = i + 1          # element number
    inci[i,1] = i + 1          # first node
    inci[i,2] = i + 2          # second node
    inci[i,3] = coord[i,1]     # first node coordinate
    inci[i,4] = coord[i+1,1]   # second node coordinate

# Material properties
E = 200e9

# Geometry properties
# first element
D1 = 20e-3
d1 = 18e-3
# second element
D2 = 20e-3
d2 = 16e-3

l = L/nel

geo = np.array([[D1, d1],[D2, d2]])

# Boundary conditions
#   bc=[node | degree of freedom | value]
#
#   Degree of freedom 1 --> y
#   Degree of freedom 2 --> oz

bc = np.array([[1,1,0],[1,2,0]])

mask = np.zeros((2*nnos,2*nnos))
for i in range(0, np.size(bc,0)):
    if bc[i,1] == 1:
        mask[2*(bc[i,0] - 1),2*(bc[i,0] - 1)] = 1
    elif bc[i,1] == 2:
        mask[2*(bc[i,0] - 1)+1,2*(bc[i,0] - 1) + 1] = 1
mask = ma.masked_equal(mask, 1)
mask = ma.mask_rowcols(mask)
mask = (mask==False)

for i in range(nel):
    node1 = inci[i,1] # first node element
    node2 = inci[i,2] # second node element
    D = geo[i,0]
    d = geo[i,1]
    inertia = np.pi/64*(D**4 - d**4)

    # local stiffness matrix
    kf_e = E*inertia/l**3*np.array([[  12, 6*l, -12, 6*l],
                                    [ 6*l,  4*l**2, -6*l,  2*l**2],
                                    [-12,-6*l,  12,-6*l],
                                    [ 6*l,  2*l**2, -6*l,  4*l**2]])

    # local geometric matrix
    kg_e = 1/30/l*np.array([[ 36, 3*l, -36, 3*l],
                            [ 3*l,4*l**2, -3*l, -l**2],
                            [-36,-3*l,  36,-3*l],
                            [ 3*l,-l**2, -3*l, 4*l**2]])

    # localization vector
    loc = [2*node1-2,2*node1-1,2*node2-2,2*node2-1]

    # global stiffness matrix
    kf[[[int(loc[0])],[int(loc[1])],[int(loc[2])], [int(loc[3])]], [int(loc[0]),int(loc[1]),int(loc[2]),int(loc[3])]] = kf[[[int(loc[0])],[int(loc[1])],[int(loc[2])], [int(loc[3])]], [int(loc[0]),int(loc[1]),int(loc[2]),int(loc[3])]] +  kf_e
    kg[[[int(loc[0])],[int(loc[1])],[int(loc[2])], [int(loc[3])]], [int(loc[0]),int(loc[1]),int(loc[2]),int(loc[3])]] = kg[[[int(loc[0])],[int(loc[1])],[int(loc[2])], [int(loc[3])]], [int(loc[0]),int(loc[1]),int(loc[2]),int(loc[3])]] +  kg_e

kg_ = kg[mask.data]
kg_ = np.reshape(kg_, (2*nnos-np.size(bc,0), 2*nnos-np.size(bc,0)))

kf_ = kf[mask.data]
kf_ = np.reshape(kf_, (2*nnos-np.size(bc,0), 2*nnos-np.size(bc,0)))

w, v = linalg.eig(kf_, kg_)
Pcr = np.min(np.real(w))

print('Pcr = ' + str(format(Pcr, '.2f')) + ' N')


import numpy as np

# Vectorized cross and dot product functions
def cross(x1,y1,z1,x2,y2,z2):
    xc = y1 * z2 - z1 * y2
    yc = z1 * x2 - x1 * z2
    zc = x1 * y2 - y1 * x2
    return xc, yc, zc

def dot(x1,y1,z1,x2,y2,z2):
    return x1*x2+y1*y2+z1*z2

def nr(M, ecc, epsilon_target=1.0e-5):
    """
    Newton-Raphson Iteration.
    Computes Eccentric/Hyperbolic Anomaly from Mean Anomaly.
    Cf. Slide 13/26
    http://mmae.iit.edu/~mpeet/Classes/MMAE441/Spacecraft/441Lecture17.pdf
    """

    Ei = M; ii = 1
    # print "Running Newton-Raphson for M=%.2e, e=%.2f" % ( M, ecc )
    while True:
        # Eccentric Anomaly
        if ecc < 1.0:
            Ei1 = Ei - \
                ( Ei - ecc * np.sin(Ei) - M ) / (  1.0 - ecc * np.cos(Ei)  )
        # Hyperbolic Anomaly
        elif ecc > 1.0:
            Ei1 = Ei + \
                ( M - ecc * np.sinh(Ei) + Ei ) / ( ecc * np.cosh(Ei) - 1.0 )
        epsilon = np.abs(Ei1 - Ei)
        Ei = Ei1
        # print "Iteration %i, Residual %.2e" % ( ii, epsilon )
        if epsilon < epsilon_target:
            break
        if ii > 100:
            raise Exception("NR Iteration Failed To Converge.")
        ii += 1
    # print "Found E=%.2f" % Ei1
    return Ei1

def PQW(Omega, omega, inc):
    """
    Rotation Matrix Components (Orbit Frame => Inertial Frame)
    http://biomathman.com/pair/KeplerElements.pdf (End)
    http://astro.geo.tu-dresden.de/~klioner/celmech.pdf (Eqn. 2.30)
    NB: Shapiro Notation Tricky; Multiplies x = R.T * X, Dresden x = R * X
    """

    Px = np.cos(omega) * np.cos(Omega) - \
         np.sin(omega) * np.cos(inc) * np.sin(Omega)
    Py = np.cos(omega) * np.sin(Omega) + \
         np.sin(omega) * np.cos(inc) * np.cos(Omega)
    Pz = np.sin(omega) * np.sin(inc)

    Qx = - np.sin(omega) * np.cos(Omega) - \
           np.cos(omega) * np.cos(inc) * np.sin(Omega)
    Qy = - np.sin(omega) * np.sin(Omega) + \
           np.cos(omega) * np.cos(inc) * np.cos(Omega)
    Qz =   np.sin(inc) * np.cos(omega)

    return Px, Py, Pz, Qx, Qy, Qz


#Pascal's triangle

def PascalNumber(n,k):
    from math import factorial as mmfac
    from sympy import Float as mmmfloat
    from sympy import Integer as mmmint

    def _autoFloat(f):
        from math import log10 as mloggg
        digits = (mloggg(f))+1
        if(digits>15):
            return mmmfloat(f)
        else:
            return mmmint(f)

    return _autoFloat(mmfac(n)/(mmfac(k)*mmfac(n-k)))

def PascalSequence(countt=10,returni=False):
    if(returni):
        s = set()
    for n in range(countt):
        for k in range(n+1):
            if(not returni):
                print(PascalNumber(n,k),end=", ")
            else:
                s.add(PascalNumber(n,k))
    if(returni):
        return s

def PascalTriangle(countt=10):
    colk = [k for k in range(0,countt)]
    s=[['' for j in colk] for i in colk]
    for k in range(0,countt):
        for n in range(k,countt+1):
            s[n-1][k] = PascalNumber(n,k)
            pass
    from pandas import DataFrame as mmpd
    df = mmpd(s, columns=colk, index=colk)
    df =df.rename_axis(columns="n/k")
    return df

#PascalNumber(6,3)
#PascalSequence(100)
#PascalTriangle(200)


import numpy as np

def get_phaselc(t, p, data, v_num):
	return 1.+p.amp1[v_num]*np.cos(2.*np.pi*(t-p.theta1[v_num])/p.per[v_num]) + p.amp2[v_num]*np.cos(4.*np.pi*(t-p.theta2[v_num])/p.per[v_num])


import numpy as np

def mesh_exp(r_min, r_max, a, N):
    """Creates an exponential radial mesh.

    """
    mesh = np.zeros(N+1)
    beta = np.log(a) / (N-1)
    alpha = (r_max - r_min) / (np.exp(beta*N) - 1)
    for i in range(0, N+1):
        mesh[i] = alpha * (np.exp(beta*(i)) - 1) + r_min
    return mesh


from math import sqrt, e, pi
import numpy as np, scipy.odr.odrpack as odrpack, matplotlib.pyplot as plt, matplotlib as mpl
from scipy import interpolate
from os import environ

def flin(B, x):
    return B[0] * x + B[1]

def fpow(B, x):
    return B[1] * x ** B[0] + B[2]

def gaussian(B, x):
    return 1.0 / (B[0] * sqrt(2 * pi)) * e ** (-(x - B[1]) ** 2 / (2 * B[0] ** 2))

def ftwo_gaussian(B, x):
    return 1.0 / (2 * B[0] * sqrt(2 * pi)) * e ** (-(x - B[1]) ** 2 / (2 * B[0] ** 2)) + 1.0 / (2 * B[2] * sqrt(2 * pi)) * e ** (-(x - B[3]) ** 2 / (2 * B[2] ** 2))

def fpoly(B, x):
    return np.sum([b * x ** m for m, b in enumerate(B)])

def fexp(B, x, base=e):
    return B[1] * base ** (B[0] * x) + B[2]

def fnexp(B, x, base=e):
    return B[0] + np.sum([B[i] * base ** (x * B[i + 1]) for i in range(1, len(B) - 1)])

def fsexp(B, x):
    return B[0] * B[1] ** (x ** B[2]) + B[3]

def do_odr(f, x, xe, y, ye, estimates):
    model = odrpack.Model(f)
    data = odrpack.RealData(x, y, sx=xe, sy=ye)
    odr = odrpack.ODR(data, model, estimates)
    output = odr.run()
    return output

def chi2_calc(f, betas, x, y):
    chi2 = 0
    for xval, yval in zip(x, y):
        chi2 += (yval - f(betas, xval)) ** 2

    return chi2

def do_fit(func, beta_est, x_list, y_list, xerr=None, yerr=None):
    xerr = [1] * len(x_list) if xerr is None else xerr
    yerr = [1] * len(y_list) if yerr is None else yerr
    fit = do_odr(func, x_list, xerr, y_list, yerr, beta_est)
    chi2 = chi2_calc(func, fit.beta, x_list, y_list)
    return fit.beta, fit.sd_beta, chi2

def plot_f_fits(func, beta_est, x_list, y_list, ax, label, color, xerr=None, yerr=None, kwargs={}):
    xerr = [1e-07] * len(x_list) if xerr is None else xerr
    yerr = [1e-07] * len(y_list) if yerr is None else yerr
    fit_beta, chi2 = do_fit(func, beta_est, x_list, y_list, xerr=xerr, yerr=yerr)
    xs = np.linspace(min(x_list), max(x_list), 100)
    ax.plot(x_list, y_list, 'o', label='tmax = ' + str(label), color=color)
    ax.legend(loc='lower right')
    ax.set_yscale('log', basey=2)