import numpy as np

class Softmax(object):

  def __init__(self, dims=[10, 3073]):
    self.init_weights(dims=dims)

  def init_weights(self, dims):
    """
    Initializes the weight matrix of the Softmax classifier.
    Note that it has shape (C, D) where C is the number of
    classes and D is the feature size.
    """
    self.W = np.random.normal(size=dims) * 0.0001

  def loss(self, X, y):
    """
    Calculates the softmax loss.

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

    Inputs:
    - 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.

    Returns a tuple of:
    - loss as single float
    """

    # Initialize the loss to zero.
    loss = 0.0

    # ================================================================ #
    # YOUR CODE HERE:
    #   Calculate the normalized softmax loss.  Store it as the variable loss.
    #   (That is, calculate the sum of the losses of all the training
    #   set margins, and then normalize the loss by the number of
    #   training examples.)
    # ================================================================ #
    N = X.shape[0]
    C = self.W.shape[0]
    WTX = self.W@X.T
    eWTX = np.exp(WTX)
    for i in range(N):
      loss = loss + np.log(np.ones((1,C))@eWTX[:,i]) - WTX[y[i],i]
    loss = loss/N
    # ================================================================ #
    # END YOUR CODE HERE
    # ================================================================ #

    return loss

  def loss_and_grad(self, X, y):
    """
    Same as self.loss(X, y), except that it also returns the gradient.

    Output: grad -- a matrix of the same dimensions as W containing
      the gradient of the loss with respect to W.
    """

    # Initialize the loss and gradient to zero.
    loss = 0.0
    grad = np.zeros_like(self.W)

    # ================================================================ #
    # YOUR CODE HERE:
    #   Calculate the softmax loss and the gradient. Store the gradient
    #   as the variable grad.
    # ================================================================ #
    N = X.shape[0]
    C = self.W.shape[0]
    WTX = self.W@X.T
    eWTX = np.exp(WTX)
    # Calculate Loss
    for i in range(N):
      loss = loss + np.log(np.ones((1,C))@eWTX[:,i]) - WTX[y[i],i]
    loss = loss/N
    # Calculate Gradient
    for j in range(C):
      for i in range(N):
        grad[j,:] = grad[j,:] + ( (1/(np.ones((1,C))@eWTX[:,i]))*(eWTX[j,i]) - (y[i]==j) )*X[i,:].T
    grad = grad/N

    # ================================================================ #
    # END YOUR CODE HERE
    # ================================================================ #

    return loss, grad

  def grad_check_sparse(self, X, y, your_grad, num_checks=10, h=1e-5):
    """
    sample a few random elements and only return numerical
    in these dimensions.
    """

    for i in np.arange(num_checks):
      ix = tuple([np.random.randint(m) for m in self.W.shape])

      oldval = self.W[ix]
      self.W[ix] = oldval + h # increment by h
      fxph = self.loss(X, y)
      self.W[ix] = oldval - h # decrement by h
      fxmh = self.loss(X,y) # evaluate f(x - h)
      self.W[ix] = oldval # reset

      grad_numerical = (fxph - fxmh) / (2 * h)
      grad_analytic = your_grad[ix]
      rel_error = abs(grad_numerical - grad_analytic) / (abs(grad_numerical) + abs(grad_analytic))
      print('numerical: %f analytic: %f, relative error: %e' % (grad_numerical, grad_analytic, rel_error))

  def fast_loss_and_grad(self, X, y):
    """
    A vectorized implementation of loss_and_grad. It shares the same
    inputs and ouptuts as loss_and_grad.
    """
    loss = 0.0
    grad = np.zeros(self.W.shape) # initialize the gradient as zero

    # ================================================================ #
    # YOUR CODE HERE:
    #   Calculate the softmax loss and gradient WITHOUT any for loops.
    # ================================================================ #
    N = X.shape[0]
    C = self.W.shape[0]
    WTX = self.W@X.T
    eWTX = np.exp(WTX)
    loss = np.ones((1,N))@(np.log(eWTX.T@np.ones((C,))) - WTX[y,np.arange(N)])/N
    scaling = eWTX/(eWTX.T@np.ones((C,)))
    scaling[y,np.arange(N)] -= 1
    grad = scaling@X/N
    # END YOUR CODE HERE
    # ================================================================ #

    return loss, grad

  def train(self, X, y, learning_rate=1e-3, num_iters=100,
            batch_size=200, verbose=False):
    """
    Train this linear classifier using stochastic gradient descent.

    Inputs:
    - X: A numpy array of shape (N, D) containing training data; there are N
      training samples each of dimension D.
    - y: A numpy array of shape (N,) containing training labels; y[i] = c
      means that X[i] has label 0 <= c < C for C classes.
    - learning_rate: (float) learning rate for optimization.
    - num_iters: (integer) number of steps to take when optimizing
    - batch_size: (integer) number of training examples to use at each step.
    - verbose: (boolean) If true, print progress during optimization.

    Outputs:
    A list containing the value of the loss function at each training iteration.
    """
    num_train, dim = X.shape
    num_classes = np.max(y) + 1 # assume y takes values 0...K-1 where K is number of classes

    self.init_weights(dims=[np.max(y) + 1, X.shape[1]])	# initializes the weights of self.W

    # Run stochastic gradient descent to optimize W
    loss_history = []

    for it in np.arange(num_iters):
      X_batch = None
      y_batch = None

      # ================================================================ #
      # YOUR CODE HERE:
      #   Sample batch_size elements from the training data for use in
      #     gradient descent.  After sampling,
      #     - X_batch should have shape: (dim, batch_size)
      #     - y_batch should have shape: (batch_size,)
      #   The indices should be randomly generated to reduce correlations
      #   in the dataset.  Use np.random.choice.  It's okay to sample with
      #   replacement.
      # ================================================================ #
      indicies = (num_train*np.random.rand(batch_size,1)).astype(int)
      X_batch = X[indicies].reshape(batch_size,dim)
      y_batch = y[indicies].reshape(batch_size,)

      # ================================================================ #
      # END YOUR CODE HERE
      # ================================================================ #

      # evaluate loss and gradient
      loss, grad = self.fast_loss_and_grad(X_batch, y_batch)
      loss_history.append(loss)

      # ================================================================ #
      # YOUR CODE HERE:
      #   Update the parameters, self.W, with a gradient step
      # ================================================================ #
      self.W = self.W -learning_rate*grad
      # ================================================================ #
      # END YOUR CODE HERE
      # ================================================================ #

      if verbose and it % 100 == 0:
        print('iteration {} / {}: loss {}'.format(it, num_iters, loss))

    return loss_history

  def predict(self, X):
    """
    Inputs:
    - X: N x D array of training data. Each row is a D-dimensional point.

    Returns:
    - y_pred: Predicted labels for the data in X. y_pred is a 1-dimensional
      array of length N, and each element is an integer giving the predicted
      class.
    """
    y_pred = np.zeros(X.shape[1])
    # ================================================================ #
    # YOUR CODE HERE:
    #   Predict the labels given the training data.
    # ================================================================ #
    y_pred = np.argmax(self.W@X.T,axis =0)
    # ================================================================ #
    # END YOUR CODE HERE
    # ================================================================ #

    return y_pred


import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
import math_models_animate as anim

class CompartmentModelBase:
    def __init__(self, initialConditions, labels, colors):
        self.numCompartments = len(initialConditions)
        self.initialConditions = initialConditions
        self.labels = labels
        self.colors = colors

    def hasLabel(self, label):
        return label in self.labels

    def hasColor(self, color):
        return color in self.colors

    def labelColor(self, label):
        return self.colors[self.labels.index(label)]

class SIRModel(CompartmentModelBase):
    def __init__(self, transmitRate=3.5, removeRate=0.5, sir0=(0.99, 0.01, 0.0)):
        super().__init__(sir0, ['Susceptible', 'Infected', 'Removed'], ['b', 'r', 'g'])
        self.transmitRate = transmitRate
        self.removeRate = removeRate

    def __str__(self):
        return 'SIR: Transmit={} Remove={}'.format(self.transmitRate, self.removeRate)

    def __repr__(self):
        return 'SIR({}, {})'.format(self.transmitRate, self.removeRate)

    def __call__(self, sir, t):
        # S'(t) = - transmitRate * S(t) * I(t)
        # I'(t) = transmitRate * S(t) * I(t) - removeRate * I(t)
        # R'(t) = removeRate * I(t)

        transmitted = self.transmitRate * sir[0] * sir[1]
        removed = self.removeRate * sir[1]
        dS = - transmitted
        dI = transmitted - removed
        dR = removed
        return dS, dI, dR

class SEIRModel(CompartmentModelBase):
    def __init__(self,
                 transmitRate=3.5,
                 reducedEIRate=0.0,
                 infectRate=1.0,
                 removeRate=0.5,
                 seir0=(0.99, 0.01, 0.0, 0.0)):
        super().__init__(seir0,
                         ['Susceptible', 'Exposed', 'Infected', 'Removed'],
                         ['b', 'c', 'r', 'g'])
        self.transmitRate = transmitRate
        self.reducedEIRate = reducedEIRate
        self.infectRate = infectRate
        self.removeRate = removeRate

    def __str__(self):
        return 'SEIR: Transmit={} ReduceEI={} Infect={} Remove={}'.format(
            self.transmitRate,
            self.reducedEIRate,
            self.infectRate,
            self.removeRate)

    def __repr__(self):
        return 'SIR({}, {}, {}, {})'.format(
            self.transmitRate,
            self.reducedEIRate,
            self.infectRate,
            self.removeRate)

    def __call__(self, seir, t):
        # S'(t) = - transmitRate * S(t) * (I(t) + reducedEIRate * E(t))
        # E'(t) = transmitRate * S(t) * (I(t) + reducedEIRate * E(t)) - infectRate * E(t)
        # I'(t) = infectRate * E(t) - removeRate * I(t)
        # R'(t) = removeRate * I(t)

        transmitted = self.transmitRate * seir[0] * (seir[2] + self.reducedEIRate * seir[1])
        infected = self.infectRate * seir[1]
        removed = self.removeRate * seir[2]
        dS = - transmitted
        dE = transmitted - infected
        dI = infected - removed
        dR = removed
        return dS, dE, dI, dR

def solve(model=SIRModel(), maxTime=10, timeSteps=100):
    t = np.linspace(0, maxTime, timeSteps)
    sir = odeint(model, model.initialConditions, t)
    return t, sir

def plotFinish_(title, legend=None):
    plt.xlabel('Time')
    plt.ylabel('Population')
    plt.title(title)
    if legend is not None:
        plt.legend(loc=legend)
    plt.grid()
    plt.show()

def plot(model, t, ys):
    for i in range(model.numCompartments):
        plt.plot(t, ys[:, i], color=model.colors[i], label=model.labels[i])

    plotFinish_('{}'.format(model), legend='best')

def animate(model, t, ys, legend=None):
    animation = anim.Animate(t,
                             [ys[:, i] for i in range(model.numCompartments)],
                             labels=model.labels,
                             colors=model.colors)
    animation.run(interval=25)
    plotFinish_('{}'.format(model), legend=legend)


import numpy as np
import time

def kmeans(x, k, max_it=20):
    '''
    KMEANS K-Means clustering algorithm

        Input:  x - data point features, n-by-p maxtirx.
                k - the number of clusters

        OUTPUT: idx  - cluster label
                ctrs - cluster centers, K-by-p matrix.
                iter_ctrs - cluster centers of each iteration, (iter, k, p)
                        3D matrix.
                err  - total square distance
    '''
    # YOUR CODE HERE

    # begin answer
    np.random.seed(int(time.time()))
    N = x.shape[0]
    p = x.shape[1]
    ctrs = x[np.random.randint(N, size=k)]
    iter_ctrs = np.zeros((max_it, k, p))
    idx = np.zeros(N, dtype=np.int64)
    dist = np.zeros((N, k))
    cnt = 0
    for i in range(max_it):
        # print(i)
        for j, ctr in enumerate(ctrs):
            dist[:,j] = np.linalg.norm(x-ctr, axis=1)
        # some dist may be NAN, so must use nanargmin to ignore these values.
        iidx = np.nanargmin(dist, axis=1)
        if((iidx == idx).all()):
            break
        idx = iidx
        for j in range(k):
            ctrs[j,:] = np.mean(x[idx == j], 0)
        iter_ctrs[i] = ctrs
        cnt += 1
    for j, ctr in enumerate(ctrs):
        dist[:, j] = np.linalg.norm(x - ctr, axis=1)
    err = np.sum(np.min(dist, axis=1))
    iter_ctrs = iter_ctrs[:cnt,:]
    # end answer
    return idx, ctrs, iter_ctrs, err


""""""
import numpy as np

def cartesian_to_polar(arr, axis=-1):
    """ Transform cartesian to polar coordinates in two dimensions.

    Parameters
    ----------
    arr : array_like
        Input array.
    axis : int, default -1
        Axis of input array representing x and y in cartesian coordinates.
        Must be of length 2.

    Returns
    -------
    arr_polar : array_like
        Output array.
    """
    if arr.shape[axis] != 2:
        raise ValueError(
            f"Expected length of axis {axis} to be 2, got {arr.shape[axis]} "
            f"instead."
        )

    r = np.linalg.norm(arr, axis=axis)
    phi = np.arctan2(np.take(arr, 1, axis=axis), np.take(arr, 0, axis=axis))
    return np.stack((r, phi), axis=axis)

def polar_to_cartesian(arr, axis=-1):
    """ Transform polar to cartesian coordinates in two dimensions.

    Parameters
    ----------
    arr : array_like
        Input array.
    axis : int, default -1
        Axis of input array representing r and phi in polar coordinates.
        Must be of length 2.

    Returns
    -------
    arr_cartesian : array_like
        Output array.
    """
    if arr.shape[axis] != 2:
        raise ValueError(
            f"Expected length of axis {axis} to be 2, got {arr.shape[axis]} "
            f"instead."
        )

    x = np.take(arr, 0, axis=axis) * np.cos(np.take(arr, 1, axis=axis))
    y = np.take(arr, 0, axis=axis) * np.sin(np.take(arr, 1, axis=axis))
    return np.stack((x, y), axis=axis)

def cartesian_to_spherical(arr, axis=-1):
    """ Transform cartesian to spherical coordinates in three dimensions.

    The spherical coordinate system is defined according to ISO 80000-2.

    Parameters
    ----------
    arr : array_like
        Input array.
    axis : int, default -1
        Axis of input array representing x, y and z in cartesian coordinates.
        Must be of length 3.

    Returns
    -------
    arr_spherical : array_like
        Output array.
    """
    if arr.shape[axis] != 3:
        raise ValueError(
            f"Expected length of axis {axis} to be 3, got {arr.shape[axis]} "
            f"instead."
        )

    r = np.linalg.norm(arr, axis=axis)
    theta = np.arccos(np.take(arr, 2, axis=axis) / r)
    phi = np.arctan2(np.take(arr, 1, axis=axis), np.take(arr, 0, axis=axis))
    return np.stack((r, theta, phi), axis=axis)

def spherical_to_cartesian(arr, axis=-1):
    """ Transform spherical to cartesian coordinates in three dimensions.

    The spherical coordinate system is defined according to ISO 80000-2.

    Parameters
    ----------
    arr : array_like
        Input array.
    axis : int, default -1
        Axis of input array representing r, theta and phi in spherical
        coordinates. Must be of length 3.

    Returns
    -------
    arr_cartesian : array_like
        Output array.
    """
    if arr.shape[axis] != 3:
        raise ValueError(
            f"Expected length of axis {axis} to be 3, got {arr.shape[axis]} "
            f"instead."
        )

    x = (
        np.take(arr, 0, axis=axis)
        * np.sin(np.take(arr, 1, axis=axis))
        * np.cos(np.take(arr, 2, axis=axis))
    )
    y = (
        np.take(arr, 0, axis=axis)
        * np.sin(np.take(arr, 1, axis=axis))
        * np.sin(np.take(arr, 2, axis=axis))
    )
    z = np.take(arr, 0, axis=axis) * np.cos(np.take(arr, 1, axis=axis))
    return np.stack((x, y, z), axis=axis)


import csv
import math
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
import numpy as np

# read the data
csvfile=open("linearX.csv", 'r')
x = list(csv.reader(csvfile))
csvfile=open("linearY.csv", 'r')
y = list(csv.reader(csvfile))

m=len(x)
n=1
x3=[]
y2=[]
for i in range(m):
    x3.append(float(x[i][0]))
    y2.append(float(y[i][0]))

# # a different dataset
# from sklearn import datasets, linear_model
#
# diabetes = datasets.load_diabetes()
# diabetes_X = diabetes.data[:, np.newaxis, 2]
# data = diabetes_X[:-20]
# y_data = diabetes.target[:-20]
#
# x3=data
# y2=y_data
# m=len(data)
# print(len(data))
# print(len(y_data))

# normalise the data
meanx=sum(x3)/m
v=0
for i in range(m):
    temp=x3[i]-meanx
    v+=temp*temp
v/=m
v=math.sqrt(v)
for i in range(m):
    x3[i]=(x3[i]-meanx)/v

x2=[]
for i in range(m):
    x2.append(np.array([1,x3[i]]))

X=np.array(x2)
Y=np.array(y2)

xvalues=np.arange(min(x3)-1,max(x3)+1,0.1)

plt.ion()
fig=plt.figure()
ax1 = fig.add_subplot(1,1,1)

# plots hypothesis funtion and training data
def pl(th):
    ax1.clear()
    ax1.scatter(x3, y2, label= "Training Data", color= "r",
                marker= ".", s=10)

    the=list(th)
    yvalues=the[1]*xvalues+the[0]

    ax1.plot(xvalues, yvalues, label="Hypothesis function learned",color ='b')

    plt.xlabel('Acidity')
    plt.ylabel('Density')
    plt.legend()
    plt.title('Q1 (b)')
    plt.show()
    plt.pause(0.001)

# return the value of J(theta)
def findcost(th):
    ans=0
    for i in range(m):
        temp=(Y[i]-np.sum(np.dot(th,X[i])))
        ans+=(temp*temp)
    ans=float(ans/2)
    return ans

def find_convergence(th1,th2):
    return abs(findcost(th1)-findcost(th2))

# Part (a)&(b)
epsilon=0.0000001
# epsilon=5
eta=0.001
theta=np.array([0,0])
t=0

pl(theta)

while(True):

    hthetas=[]
    for i in range(m):
        hthetas.append(np.sum(np.dot(theta,X[i])))

# calculate -ve of gradient
    gradient=np.zeros((n+1))
    for i in range(m):
        gradient+=(Y[i]-hthetas[i])*X[i]

# update theta
    thetaold=theta
    theta=theta+eta*gradient

    t+=1

    print("theta={}\n".format(theta))

    pl(theta)

# check if converged
    convergence=find_convergence(thetaold,theta)
    print("convergence={}".format(convergence))
    if(convergence<epsilon):
        break

print("Number of iterations=",t)
plt.ioff()
pl(theta)

# part (c)
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np

plt.ion()

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# plot J(theta)
xvalues = np.linspace(0, 2, 70)
yvalues = np.linspace(-1, 1, 70)
xvalues, yvalues = np.meshgrid(xvalues, yvalues)
Zs = np.array([findcost(np.array([x,y])) for x,y in zip(np.ravel(xvalues), np.ravel(yvalues))])
Z = Zs.reshape(xvalues.shape)

surf = ax.plot_surface(xvalues, yvalues, Z, cmap=cm.coolwarm,linewidth=0,alpha=0.7 ,antialiased=False,label='J(theta)')
plt.show()
plt.pause(0.001)

# plots point in 3d mesh
def plot_2(th):

    ax.scatter(th[0],th[1],findcost(th),c="black",depthshade=False,s=6)

    plt.xlabel('theta0')
    plt.ylabel('theta1')
    plt.title('Q1 (c)')
    plt.show()
    plt.pause(0.2)
    # plt.pause(0.001)

theta=np.array([0,0])
t=0
levels=[] # stores the values of J(theta) at each iteration
levels.append(findcost(theta))
thetas=[]
thetas.append(theta)
while(True):
    hthetas=[]
    for i in range(m):
        hthetas.append(np.sum(np.dot(theta,X[i])))

    gradient=np.zeros((n+1))
    for i in range(m):
        gradient+=(Y[i]-hthetas[i])*X[i]
    thetaold=theta
    theta=theta+eta*gradient

    levels.append(findcost(theta))
    thetas.append(theta)

    t+=1

    print("theta={}\n".format(theta))

    plot_2(theta)

    convergence=find_convergence(thetaold,theta)
    print("convergence=",convergence)
    if(convergence<epsilon):
        break

print("Number of iterations=",t)
plt.ioff()
plot_2(theta)

# part (d)&(e)
# plots contours at each iteration

plt.ion()
plt.figure()

plt.xlabel('theta0')
plt.ylabel('theta1')
plt.title('eta={}'.format(eta))
for i in range(len(levels)):
    print(i)
    plt.contour(xvalues, yvalues, Z,levels[i])
    plt.scatter(thetas[i][0],thetas[i][1])

    plt.show()
    plt.pause(0.2)

plt.ioff()
plt.show()


import numpy as np
from hilbert_tensor import make_hilbert_tensor
from tensor_operations import make_tensor_train_with_conventional_method, build_dense_tensor_from_tensor_train
import matplotlib.pyplot as plt

d = 5

# T_shape = [21,22,23,24,25]
# T_shape = [31,32,33,34,35]
T_shape = [41,42,43,44,45]
T = make_hilbert_tensor(T_shape)
rr = 2+np.arange(18)
errs = np.zeros(len(rr))
for k in range(len(rr)):
    r = rr[k]
    CC = make_tensor_train_with_conventional_method(T, tol=1e-20, max_rank=r)
    T2 = build_dense_tensor_from_tensor_train(CC)
    tt_err = np.linalg.norm(T2 - T) / np.linalg.norm(T)
    errs[k] = tt_err
    print('r=', r, ', tt_err=', tt_err,)

plt.figure()
plt.semilogy(rr.reshape(-1), errs.reshape(-1), color='k')
plt.legend(['TT-RSVD'])
plt.title('Hilbert tensor: approximation error vs. rank',fontsize=14)
plt.xlabel('Tensor train rank, $r$',fontsize=12)
plt.ylabel(r'$\frac{||T - \widetilde{T}||}{||T||}$', rotation=0, fontsize=16, labelpad=30)
plt.xlim([2,19])


from .. import Utils as utils
import statsmodels.api as sm

def plot_ols_forecast(df_train, df_test, col="Close", summary="True"):
    dates = df_train["Date"].append(df_test["Date"])
    del df_train["Date"]
    del df_test["Date"]
    ols_model = get_ols_model(df_train, col=col)
    df_train["model"] = ols_model.predict(sm.add_constant(df_train.loc[:, df_train.columns!="Close"]).to_numpy())
    df_test["forecast"] = ols_model.predict(sm.add_constant(df_test.loc[:, df_test.columns!="Close"]).to_numpy())
    df = df_train.append(df_test)
    df["Date"] = dates
    df["ts"] = df[col]
    utils.plot_forecast(df=df, title="Linear Regression Forecast", summary=summary)

def get_ols_model(train_df, col, with_y_int = True):
    values = train_df[col].to_numpy()
    X = train_df.loc[:, train_df.columns!=col]
    if with_y_int:
        X = sm.add_constant((X))
    X = X.to_numpy()
    return sm.OLS(values, X).fit()


import numpy as np

#Input array
# X=np.array([[1,0,1,0],[1,0,1,1],[0,1,0,1]])
X=np.array([[1,0,1,0]])
#Output
# y=np.array([[1,0],[1,0],[0,1]])
y=np.array([[1,0]])
#Sigmoid Function
def sigmoid (x):
    return 1/(1 + np.exp(-x))

#Derivative of Sigmoid Function
def derivatives_sigmoid(x):
    return x * (1 - x)

#Variable initialization
epoch=5000 #Setting training iterations
lr=0.2 #Setting learning rate
inputlayer_neurons = X.shape[1] #number of features in data set
hiddenlayer_neurons = 3 #number of hidden layers neurons
output_neurons = 2 #number of neurons at output layer

#weight and bias initialization
wh=np.random.uniform(size=(inputlayer_neurons,hiddenlayer_neurons))

bh=np.random.uniform(size=(1,hiddenlayer_neurons))

wout=np.random.uniform(size=(hiddenlayer_neurons,output_neurons))
bout=np.random.uniform(size=(1,output_neurons))

for i in range(10000):

    #Forward Propogation
    hidden_layer_input1=np.dot(X,wh)
    hidden_layer_input=hidden_layer_input1 + bh
    hiddenlayer_activations = sigmoid(hidden_layer_input)
    output_layer_input1=np.dot(hiddenlayer_activations,wout)
    output_layer_input= output_layer_input1+ bout
    output = sigmoid(output_layer_input)

    #Backpropagation
    E = y-output
    slope_output_layer = derivatives_sigmoid(output)
    slope_hidden_layer = derivatives_sigmoid(hiddenlayer_activations)
    d_output = E * slope_output_layer
    Error_at_hidden_layer = d_output.dot(wout.T)
    d_hiddenlayer = Error_at_hidden_layer * slope_hidden_layer
    wout += hiddenlayer_activations.T.dot(d_output) *lr
    bout += np.sum(d_output, axis=0,keepdims=True) *lr
    wh += X.T.dot(d_hiddenlayer) *lr
    bh += np.sum(d_hiddenlayer, axis=0,keepdims=True) *lr

print output


import numpy as np
import scipy.stats as sps
from scipy.spatial import distance
# from sklearn.metrics.pairwise import distance_metrics
import math

class PoloMath():

    @staticmethod
    def entropy(s1):
        return sps.entropy(s1, base=2)

    @staticmethod
    def cosine_sim(x, y):
        """Cosine similarity between two vectors"""
        return np.dot(x, y) / (np.sqrt(np.dot(x, x)) * np.sqrt(np.dot(y, y)))
        # return 1 - cosine(x, y)

    @staticmethod
    def cosine_dist(x, y):
        """Cosine distance between two vectors. 1 - cosine similarity."""
        return distance.cosine(x, y)

    @staticmethod
    def js_divergence(p1, p2):
        """Jennsen-Shannon Divergence."""
        p = sps.entropy(p1, p2, 2)
        q = sps.entropy(p2, p1, 2)
        jsd = (p + q) / 2
        return jsd

    @staticmethod
    def js_dist(x, y):
        """Jennsen-Shannon Distance. Square root of the convergence."""
        return distance.jensenshannon(x, y)

    @staticmethod
    def jaccard_dist(x, y):
        """Jaccard Distance. Square root of the convergence."""
        return distance.jaccard(x, y)

    @staticmethod
    def euclidean_dist(x, y):
        """Simple Euclidean distance"""
        # return math.sqrt(((s1 - s2)**2).sum())
        return distance.euclidean(x, y)

    @staticmethod
    def standard_euclidean_dist(x, y, V):
        return distance.seuclidean(x, y, V)

    @staticmethod
    def chebyshev_dist(x, y):
        return distance.chebyshev(x, y)

    @staticmethod
    def manhattan_dist(x, y):
        return distance.cityblock(x, y)

    @staticmethod
    def pwmi(p_a, p_b, p_ab, norm=.000001):
        """Computes the adjusted point-wise mutual information of two items (a and b)
        that appear in container vectors of some kind, e.g. items in a shopping
        basket."""
        # if p_ab == 0: p_ab = .000001  # To pr event craziness in prob calcs
        p_ab += norm
        i_ab = math.log2(p_ab / (p_a * p_b))  # Raw
        try:
            i_ab = i_ab / (math.log2(p_ab) * -1)  # Adjusted
        except ZeroDivisionError:
            i_ab = 0
        return i_ab

    @staticmethod
    def jscore(s1, s2, thresh = 0):
        """Computes the Jaccard score (aka distance) for two vectors (series). Series passed must
        share an index. This condition will be met for an unstacked matrix of weights or counts,
        where the two series belong to the matrix."""
        A = set(s1[s1 > thresh].index)
        B = set(s2[s2 > thresh].index)
        if len(A | B) > 0:
            return 1 - (len(A & B) / len(A | B))
        else:
            return -1  # Is this correct?

    @staticmethod
    def kl_distance(s1, s2):
        """Kullback-Leibler distance"""
        return sps.entropy(s1, s2, 2)

    @staticmethod
    def softmax(x):
        """Computes softmax values for each sets of scores in x."""
        e_x = np.exp(x - np.max(x))
        return e_x / e_x.sum(axis=0)


from sympy import *
x = symbols("x")  # 符号x，自变量
y = -pow(10,-11)*pow(x,6) + pow(10,-8)*pow(x,5) - 4*pow(10,-6)*pow(x,4) + 0.0006*pow(x,3) - 0.0428*pow(x,2) + 1.7561*x + 16.528 #公式

dify = diff(y,x) #求导
print(dify)  #打印导数

#给定x值，求对应导数的值

for i in range(0,305,5):
    print(dify.subs('x',i))

x2 = symbols("x2")  # 符号x2，自变量
y2 = pow(x2,2)

dify2 = diff(y2,x2) #求导
print(dify2)  #打印导数


import numpy as np

def volumeSphere(radius=1000):
    """
    Volume of a sphere

    Args:
        radius (float): Radius (Default: 1000)

    Returns:
        volume (float): Volume in [input units³]
    """
    assert radius > 0

    volume = 4 / 3 * np.pi * radius**3

    return volume

def massSphere(radius=1000, density=1e-21,
                verbose=False, inferDensity=True):
    """
    Calculates mass of a sphere

    Args:
        radius (float): Radius in [nm]. (Default: 1000 nm)
        density (float): Density, ϱ, in [g/nm³]. (Default: 1e-21 g/nm³)
        verbose (bool): Flag whether to show extra information. (Default: False)
        inferDensity (bool): If true inputs above 1e-5 are interpreted as g/cm³. (Default: True)

    Returns:
        mass (float):  Mass in [g]
    """
    assert radius > 0
    assert density > 0

    volume = volumeSphere(radius=radius)

    # check if density is provided in g/cm³.
    if inferDensity and density > 1e-5:
        print("Assuming that ϱ was provided in [g/cm³]. Converting to g/nm³")
        density /= 1e21
        print("ϱ is now: {} g/nm³".format(density))

    mass = volume * density

    if verbose:
        print("Input:")
        print("Radius of Sphere [nm]: {}".format(radius))
        print("Density of material [g/nm³]: {} \n".format(density))

        print("Output:")
        print("Mass of sphere [g]: {}\n".format(mass))

    return mass


import math
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from prettytable import PrettyTable, MARKDOWN
from . import parser
from . import Anova

class Processor(object):
    def __init__(self, dir):
        self.file_list = parser.getFiles(dir)
        self.dir = dir
        self.raw_data = [] # raw data directly obtained from the parser
        self.device = set() # types of device
        for file in self.file_list:
            file_data = parser.parseFile(file)
            if file_data == None or len(file_data)==0:
                print('warning: file ', file, ' cannot be read!')
                continue
            self.raw_data = self.raw_data + file_data
        # generate fitts data from raw data
        self.fitts_data = self._genFittsData(self.raw_data) #{name, device, ID, MT}

    def _genFittsData(self, raw_data):
        fitts_data = []
        for raw_d in raw_data:
            fitts_d = {}
            fitts_d['name'] = raw_d['name']
            fitts_d['device'] = raw_d['device']
            self.device.add(fitts_d['device'])
            # MT = a + b*ID
            # T = a + b*log2(A/W + 1)
            fitts_d['ID'] = math.log2(raw_d['distance']/raw_d['width'] + 1)
            fitts_d['MT'] = raw_d['time']
            fitts_data.append(fitts_d)
        return fitts_data

    def showScatterGraph(self):
        plt.clf()
        data_buf = {}
        # get device
        for d in self.fitts_data:
            data_buf[d['device']] = ([], [])
        # set data
        for d in self.fitts_data:
            data_buf[d['device']][0].append(d['ID']) #ID
            data_buf[d['device']][1].append(d['MT']) #MT
        # draw
        for device in data_buf:
            plt.scatter(data_buf[device][0], data_buf[device][1], marker = 'o', s = 40 ,label = device)
            plt.xlabel('ID = log2(A/W+1)')
            plt.ylabel('MT = time')
        plt.legend(loc = 'best')
        plt.show()

    def _regression(self, device, all_group):
        if device not in self.device:
            print(f"No device named: {device}, please check your input!")
            return
        # prepare data
        ID = []
        MT = []
        name = set()
        name.add('all')
        group = {}
        All = {} # [ID]: [MT]
        # get data from fitts data
        for d in self.fitts_data:
            if d['device'] == device:
                if(d['name']) not in name:
                    name.add(d['name'])
                    group[d['name']] = [[], []]
                group[d['name']][0].append(d['ID'])
                group[d['name']][1].append(d['MT'])
                if d['ID'] in All:
                    All[d['ID']].append(d['MT'])
                else:
                    All[d['ID']] = [d['MT']]
        # process total data
        group['**all**'] = [[], []] #[ID], [MT]
        for ID in All:
            group['**all**'][0].append(ID)
            group['**all**'][1].append(parser.avg(All[ID]))
        all_group[device] = group['**all**']
        # show data
        table = PrettyTable()
        table.field_names = ["user", "a", 'b', 'r^2']
        table.set_style(MARKDOWN)
        print(f" regression report on [{device}] ")
        print("(This table can be copied to markdown as a table directly)")
        for result in group:
            name = result
            ID = np.array(group[result][0]).reshape((-1,1))
            MT = np.array(group[result][1])
            # generate regression
            model = LinearRegression().fit(ID, MT)
            a = model.intercept_
            b = model.coef_[0]
            # print report
            table.add_row([name, a, b, model.score(ID, MT)])
            x = np.linspace(1.8,4.1)
            plt.scatter(ID,MT, marker='o')
            plt.plot(x, a+b*x, label=name)
            plt.xlabel('ID = log2(A/W+1)')
            plt.ylabel('MT = time')
        print(table)
        print(" ")
        plt.legend()
        plt_name = f"{device}_regress"
        plt.title(plt_name)
        plt.savefig("./" + plt_name + ".png")
        plt.clf()

    def _plt_total(self, all_group):
        for device in all_group:
            ID = np.array(all_group[device][0]).reshape((-1,1))
            MT = np.array(all_group[device][1])
            model = LinearRegression().fit(ID, MT)
            a = model.intercept_
            b = model.coef_[0]
            x = np.linspace(1.8,4.1)
            plt.scatter(ID,MT, marker='o')
            plt.plot(x, a+b*x, label=device)
        plt.xlabel('ID = log2(A/W+1)')
        plt.ylabel('MT = time')
        plt.legend()
        plt.title("Regression Result")
        plt.savefig("./total_regress.png")
        plt.clf()

    def regression(self):
        all_group = {}
        for device in self.device:
            all_group[device] = []
            self._regression(device, all_group)
        self._plt_total(all_group)

    def anova(self, params=['name', 'device']):
        Anova.multi_analyze(self.raw_data, params)

    def print_data(self):
        pd_data = pd.DataFrame(self.raw_data)
        print(pd_data)

    def getRawData(self):
        return self.raw_data

    def getFittsData(self):
        return self.fitts_data


"""
@author : Muhamad Irvan Dimetrio
NIM     : 18360018
Teknik Informatika
Institut Sains dan Teknologi Nasional
"""
from sklearn import datasets
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_samples, silhouette_score
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
from matplotlib import cm

iris = datasets.load_iris()

# Mengubah menjadi dataframe
iris = pd.DataFrame(data=np.c_[iris['data'], iris['target']],
                    columns=iris['feature_names'] + ['species'])

# Menghapus spasi dari kolom
iris.columns = iris.columns.str.replace(' ', '')
iris.head()

X = iris.iloc[:,:3] # variabel independe, dimana data mulai dari kolom 0 sampai 3
y = iris.species # variabel dependen , dimana adalah label kolom spesies
sc = StandardScaler()
sc.fit(X)
X = sc.transform(X)

score = []
for n_clusters in range(2, 10):
    kmeans = KMeans(n_clusters=n_clusters)
    kmeans.fit(X)
    labels = kmeans.labels_
    centroids = kmeans.cluster_centers_
    score.append(silhouette_score(X, labels, metric='euclidean'))

# Set the size of the plot
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.plot(score)
plt.grid(True)
plt.ylabel("Silhouette Score")
plt.xlabel("K")
plt.title("Silhouette for K-Means")

# Initialize the clusterer with n_clusters value and a random generator
model = KMeans(n_clusters=3, init='k-means++', n_init=10, random_state=0)
model.fit_predict(X)
cluster_labels = np.unique(model.labels_)
n_clusters = cluster_labels.shape[0]

# Compute the silhouette scores for each sample
silhouette_vals = silhouette_samples(X, model.labels_)

plt.subplot(1, 2, 2)
y_lower, y_upper = 0, 0
yticks = []
for i, c in enumerate(cluster_labels):
    c_silhouette_vals = silhouette_vals[cluster_labels ]
    c_silhouette_vals.sort()
    y_upper += len(c_silhouette_vals)
    cmap = cm.get_cmap("Spectral")
    color = cmap(float(i) / n_clusters)
    plt.barh(range(y_lower, y_upper), c_silhouette_vals,
             facecolor=color, edgecolor =color, alpha=0.7)
    yticks.append((y_lower + y_upper) / 2)
    y_lower += len(c_silhouette_vals)

silhouette_avg = np.mean(silhouette_vals)

plt.yticks(yticks, cluster_labels+1)

# The vertical line for average silhouette score of all the values
plt.axvline(x=silhouette_avg, color='red', linestyle='--')

plt.ylabel('Cluster')
plt.xlabel('Silhouette Coefficient')
plt.title('Silhouette for K-Means')
plt.show()


'''
cost_func
Collection of various cost functions and their gradients
used in Machine Learning
'''

import numpy as np

def least_squares(y_true, y_pred):
    return (y_true**2 - y_pred**2)**0.5

def binary_cross_entropy_loss(y_true, p):
    '''
    binary_cross_entropy_loss
    Returns total cross entropy loss for binary classes

    Inputs
        y_true : ground truth labels
        p      : probabilities

    Outputs
        loss : total loss over the training batch
    '''
    loss = -np.sum(y_true*np.log(p) + (1-y_true)*np.log(1-p))/y_true.shape[0]
    return loss

def grad_binary_cross_entropy_loss(y_true, p, X):
    '''
    grad_binary_cross_entropy_loss
    Returns total gradient of cross entropy loss for
    binary classes

    Inputs
        y_true : ground truth labels
        p      : probabilities
        X      : training data

    Outputs
        grad : total gradient over the training batch
    '''
    grad = np.sum(X*(p - y_true).reshape(p.shape[0],1))
    return grad


"""
Pozo de potencial (Problema 3)

Luis Eduardo Sánchez González

II Escuela de Verano de Física Computacional

lun 19 abr 2021 21:29:18 CDT

Repositorio: https://github.com/Luis2501/Ejercicios-IIEVFC
"""
import numpy as np
from scipy.constants import e, epsilon_0

class Potencial:

	def __init__(self, Z):

		self.Z1, self.Z2 = Z - 2, 2
		self.R = (2e-15)*((self.Z1)**(1/3))

	def __call__(self, r):

		Z1, Z2, R = self.Z1, self.Z2, self.R

		return np.array((self.Z1*self.Z2*(e**2))/(4*np.pi*epsilon_0*r))

	def Force(self, r):

		Z1, Z2 = self.Z1, self.Z2

		return np.array((self.Z1*self.Z2*(e**2))/(4*np.pi*epsilon_0*(r**2)))

if __name__ == "__main__":

	import sys
	sys.path.append("../")
	import matplotlib.pyplot as plt
	from PhysicsPy.Derivation import *

	Particula = Potencial(50)

	RR = np.linspace(Particula.R, 3*(Particula.R), 1001)

	Methods = [Forward, Central, Backward]
	Names = ["Forward", "Central", "Backward"]
	Solutions = []

	#Obtener soluciones
	for class_name in Methods:

		Solucion = class_name(Particula)
		Solucion.InitialConditions(RR, 1e-20)
		Fuerza = - Solucion.Solve()

		Solutions.append(Fuerza)

		del Fuerza, Solucion

	Solutions = np.array(Solutions)

	Force_Analytic = Particula.Force(RR)

	#Obtener los errores
	e_abs, e_r = [], []

	for Solution in Solutions:

		e_abs.append(abs(Force_Analytic - Solution))
		e_r.append(abs(Force_Analytic - Solution)/Force_Analytic)

	e_abs, e_r = np.array(e_abs), np.array(e_r)

	#Graficar la fuerza
	for Force, Name in zip(Solutions, Names):

		plt.plot(RR, Force, label = Name)

	plt.plot(RR, Force_Analytic, label = "Analytic Solution")

	plt.title("Fuerza que experimenta la partícula")
	plt.xlabel("Radio (r)") ; plt.ylabel("Fuerza (F)")
	plt.legend(fancybox=True) ; plt.grid()
	plt.show()

	#Grafica error absoluto
	for ea, Name in zip(e_abs, Names):

		plt.plot(RR, ea, label = Name)

	plt.title("Error absoluto")
	plt.xlabel("R") ; plt.ylabel(r"$e_{abs}$")
	plt.legend(fancybox=True) ; plt.grid()
	plt.show()

	#Grafica error relativo
	for er, Name in zip(e_r, Names):

		plt.plot(RR, er, label = Name)

	plt.title("Error relativo")
	plt.xlabel("R") ; plt.ylabel(r"$e_{r}$")
	plt.legend(fancybox=True) ; plt.grid()
	plt.show()


"""
Here we want to explore the changes in our outputs by incorporating a sinusoidal driver in our oscillator.
The only changes we want to make here compared to the last two parts are;
the addition of a sinusoidal driving term in our initial function for the van der Pol oscillator
and a new constant A (amplitude). Additionally we want to incorporate another omega term
for the sine function in the driver. We will hold mu constant at 1.0, and vary the driving omega term
for three sets of conditions.
"""
import numpy as np
import matplotlib.pyplot as plt
from math import sin
#Question 1c
w = 1.0
w2 = 4.0*w #defining new omega term with first desired condition
mu = 1.0
A = 8.53 #New amplitude constant
#We adjust the dvelocity function for our new driving term
def f(r,t):
    x = r[0]
    v = r[1]
    fx = v
    fv = A*sin(w2*t)+mu*(1-x**2)*v-(w**2)*x
    return np.array([fx,fv],float)

# everything from here on is taken from part a
a = 0.0
b = 60.0
N = 1000
h = (b-a)/N

time = np.arange(a,b,h)
xvals = []
vvals = []

r = np.array([1.0,0.0],float)
for t in time:
    xvals.append(r[0])
    vvals.append(r[1])
    k1 = h*f(r,t)
    k2 = h*f(r+0.5*k1,t+ 0.5*h)
    k3 = h*f(r+0.5*k2, t +0.5*h)
    k4 = h*f(r + k3, t + h)
    r += (k1+2*k2+2*k3+k4)/6

 #plotting
fig, graph = plt.subplots()
graph.plot(time, xvals)
graph.set(xlabel = 'time (s)', ylabel = 'position (m)', title = 'w2 = 4.0w, position vs time, van der Pol with sinusoidal driver')
plt.show()
fig, graph = plt.subplots()
plt.plot(xvals, vvals)
graph.set(ylabel = 'velocity (m/s)', xlabel = 'position (m)', title = 'w2 = 4.0w, phase space plot, van der Pol with sinusoidal driver')
plt.show()

"""
We repeat the exact code as that above two more times, with two different values of omega2
"""
w = 1.0
w2 = 0.5*w
mu = 1.0
A = 8.53
def f(r,t):
    x = r[0]
    v = r[1]
    fx = v
    fv = A*sin(w2*t)+mu*(1-x**2)*v-(w**2)*x
    return np.array([fx,fv],float)

a = 0.0
b = 60.0
N = 1000
h = (b-a)/N

time = np.arange(a,b,h)
xvals = []
vvals = []

r = np.array([1.0,0.0],float)
for t in time:
    xvals.append(r[0])
    vvals.append(r[1])
    k1 = h*f(r,t)
    k2 = h*f(r+0.5*k1,t+ 0.5*h)
    k3 = h*f(r+0.5*k2, t +0.5*h)
    k4 = h*f(r + k3, t + h)
    r += (k1+2*k2+2*k3+k4)/6

fig, graph = plt.subplots()
graph.plot(time, xvals)
graph.set(xlabel = 'time (s)', ylabel = 'position (m)', title = 'w2 = 0.5w, position vs time, van der Pol with sinusoidal driver')
plt.show()
fig, graph = plt.subplots()
plt.plot(xvals, vvals)
graph.set(ylabel = 'velocity (m/s)', xlabel = 'position (m)', title = 'w2 = 0.5w, phase space plot, van der Pol with sinusoidal driver')
plt.show()

w = 1.0
w2 = 1.0*w
mu = 1.0
A = 8.53
def f(r,t):
    x = r[0]
    v = r[1]
    fx = v
    fv = A*sin(w2*t)+mu*(1-x**2)*v-(w**2)*x
    return np.array([fx,fv],float)

a = 0.0
b = 60.0
N = 1000
h = (b-a)/N

time = np.arange(a,b,h)
xvals = []
vvals = []

r = np.array([1.0,0.0],float)
for t in time:
    xvals.append(r[0])
    vvals.append(r[1])
    k1 = h*f(r,t)
    k2 = h*f(r+0.5*k1,t+ 0.5*h)
    k3 = h*f(r+0.5*k2, t +0.5*h)
    k4 = h*f(r + k3, t + h)
    r += (k1+2*k2+2*k3+k4)/6

fig, graph = plt.subplots()
graph.plot(time, xvals)
graph.set(xlabel = 'time (s)', ylabel = 'position (m)', title = 'w2 = w, position vs time, van der Pol with sinusoidal driver')
plt.show()
fig, graph = plt.subplots()
plt.plot(xvals, vvals)
graph.set(ylabel = 'velocity (m/s)', xlabel = 'position (m)', title = 'w2 = w, phase space plot, van der Pol with sinusoidal driver')
plt.show()


from numpy import *
from matplotlib import *
from pylab import *
import matplotlib.lines as mlines

if __name__ == "__main__":
    rc('text', usetex=True)
    rc('font', family='serif')
    fs = 20
    ### Example 1
    x = arange(-5,5,0.1)

    # r > 0
    fig= figure(1)
    ax = fig.add_subplot(311)
    frame1 = plt.gca()
    hold
    r = 2
    xdot = r*x - x**2
    ax.plot(x,xdot,'b-')
    ylim([min(xdot),max(xdot)+3])
    xlim([min(x),max(x)])
    ax.plot(x,zeros_like(x),'k-')
    ax.plot(0,0,'bo',mfc='none',mec='b')
    ax.plot(r,0,'bo',fillstyle='full',mec='b')
    ax.set_title(r'$r > 0$')
    frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)

    ax.annotate('', xy=(-2, 0), xytext=(-1, 0),
             arrowprops=dict(facecolor='black', shrink=0.04, width=1),
             )
    ax.annotate('', xy=(r-1, 0), xytext=(0.5, 0),
             arrowprops=dict(facecolor='black', shrink=0.04, width=1),
             )
    ax.annotate('', xy=(r+1, 0), xytext=(r+2, 0),
             arrowprops=dict(facecolor='black', shrink=0.04, width=1),
             )

    # lft = mlines.Line2D.fillStyles
    # r = 0
    ax = fig.add_subplot(312)
    frame1 = plt.gca()
    r = 0
    xdot = r*x - x**2
    ax.plot(x,xdot,'b-')
    ax.plot(0,0,'bo',fillstyle='right',mec='b')
    ylim([min(xdot),max(xdot)+3])
    xlim([min(x),max(x)])
    ax.plot(x,zeros_like(x),'k-')
    ax.set_title(r'$r = 0$')
    frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)

    ax.annotate('', xy=(r-2, 0), xytext=(r-1, 0),
                arrowprops=dict(facecolor='black', shrink=0.04, width=1),
                )
    ax.annotate('', xy=(2, 0), xytext=(3, 0),
                arrowprops=dict(facecolor='black', shrink=0.04, width=1),
                )

    # r < 0
    ax = fig.add_subplot(313)
    frame1 = plt.gca()
    r = -2
    xdot = r*x - x**2
    ax.plot(x,xdot,'b-')
    ax.plot(0,0,'bo',fillstyle='full',mec='b')
    ax.plot(r,0,'bo', mfc='none',mec='b')
    ylim([min(xdot)-1,max(xdot)+3])
    xlim([min(x),max(x)])
    ax.plot(x,zeros_like(x),'k-')
    ax.set_title(r'$r < 0$')
    xlabel(r'$x$',fontsize=fs)
    ylabel(r'$\dot{x}$',fontsize=fs)
    frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)

    ax.annotate('', xy=(r - 2, 0), xytext=(r-1, 0),
                arrowprops=dict(facecolor='black', shrink=0.04, width=1),
                )
    ax.annotate('', xy=(-0.5, 0), xytext=(r+0.5, 0),
                arrowprops=dict(facecolor='black', shrink=0.04, width=1),
                )
    ax.annotate('', xy=(-r-1, 0), xytext=(-r, 0),
                arrowprops=dict(facecolor='black', shrink=0.04, width=1),
                )

    # bifurcation diagram
    x = arange(-5,5,0.1)
    fig= figure(2)
    ax = fig.add_subplot(111)
    frame1 = plt.gca()
    hold
    rp = arange(0,5,0.1)
    rn = arange(-5,0,0.1)
    rzp = zeros_like(arange(0,5,0.1))
    rzn = zeros_like(arange(-5,0,0.1))
    ax.plot(arange(-5,0,0.1),rzn,'b-')
    ax.plot(arange(0,5,0.1),rzp,'b--')
    ax.plot(arange(-5,0,0.1),rn,'b--')
    ax.plot(arange(0,5,0.1),rp,'b-')
    axvline(x=0,color='k')
    ax.set_title(r'$x^* = 0$')
    frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)

    ## log example

    x = arange(-0.999, 5, 0.02)
    fig = figure(3)
    i = 1
    my_xticks = ['' for j in x]
    zidx = nonzero(x == min(abs(x)))[0][0]
    my_xticks[zidx] = '0'
    for r in [-2,1,2]:
        ax = fig.add_subplot(310+i)
        plot(r*x - log(1+x))
        plot(zeros_like(x),'k-')
        a = ax.get_xticks().tolist()
        a[0:1] = ['',0]
        a[2:] = ['' for k in a[2:]]
        ax.set_xticklabels(a)
        frame1 = plt.gca()
        # frame1.axes.get_xaxis().set_visible(False)
        frame1.axes.get_yaxis().set_visible(False)
        i += 1

    fig = figure(4)
    rn = arange(-0.999,0.01,0.1)
    rp = arange(0.01,5,0.1)
    r = log(1+rp)/rp
    rr = log(1+rn)/rn
    ax = fig.add_subplot(111)
    plot(zeros(8),'k-')
    plot(r,rp,'b--')
    plot(rr,rn,'b-')

    a[0:1] = ['',1]
    a[2:] = ['' for k in a[2:]]
    ax.set_xticklabels(a)
    frame1 = plt.gca()
    # frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)
    xlabel(r'$r$',fontsize=fs)
    ylabel(r'$x^*$',fontsize=fs)
    ax.set_title(r'$x^* = 0$')

    # linear approximation
    fig = figure(5)
    ax = fig.add_subplot(111)
    rn = arange(0,1,0.01)
    rp = arange(1,2,0.1)
    plot(rn,2-2*rn,'b--')
    plot(rp,2-2*rp,'b')
    plot(zeros(4),'k-')
    plot(rn,zeros_like(rn),'b-')
    a[0:1] = ['',1]
    a[2:] = ['' for k in a[2:]]
    ax.set_xticklabels(a)
    frame1 = plt.gca()
    # frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)
    xlabel(r'$r$',fontsize=fs)
    ax.set_title(r'$x^* = 0$')

    # both
    fig = figure(6)
    ax = fig.add_subplot(111)
    rn = arange(0,1,0.1)
    rp = arange(1,2,0.1)
    plot(zeros(8),'k-')
    plot(rn,2-2*rn,'b--')
    plot(rp,2-2*rp,'b')
    rn = arange(-0.999,0.01,0.1)
    rp = arange(0.01,2,0.1)
    r = log(1+rp)/rp
    rr = log(1+rn)/rn
    plot(r,rp,'g--')
    plot(rr,rn,'g-')
    plot(rn,zeros_like(rn),'-')
    a[0:1] = ['',1]
    a[2:] = ['' for k in a[2:]]
    ax.set_xticklabels(a)
    frame1 = plt.gca()
    # frame1.axes.get_xaxis().set_visible(False)
    frame1.axes.get_yaxis().set_visible(False)
    xlabel(r'$r$',fontsize=fs)
    ax.set_title(r'$x^* = 0$')

    show()


"""
fit data to y = mx + b using
least sum of |y - mx - b|, or L1 norm instead of sum of sq's
"""
import math
import numpy as np
import matplotlib.pyplot as plt
from SciInf_utilities import *
import sys

""" main
"""
#
print("\n fit data to y = mx + b using")
print(" least sum of |y - mx - b|, or L1 norm instead of sum of sq's \n")
# get data
#
if(len(sys.argv)>1):
  input_file = sys.argv[1]
else:
  input_file = input("file with one x, y data pair per line> ")
#input_file = 'xy.dat'
print('input file: ',input_file)
x = []
y = []
ndata = read_xy(x,y,input_file)
#
# basic averages
#
av_x = average_x(x)
av_y = average_x(y)
av_xy = average_xy(x,y)
#
av_xx = average_xy(x,x)
av_yy = average_xy(y,y)
#
var_x = av_xx - av_x**2
var_y = av_yy - av_y**2
var_xy = av_xy - av_x*av_y
stdev_x = math.sqrt(var_x)
stdev_y = math.sqrt(var_y)
#Rpearson = (av_xy - av_x*av_y)/(stdev_x*stdev_y)
Rpearson = var_xy/(stdev_x*stdev_y)
print('\n===========================================================')
print('data summary')
print('===========================================================')
print('av x    %12.5f y   %12.5f xy %12.5f ' % (av_x,av_y,av_xy))
print('av x^2  %12.5f y^2 %12.5f  ' % (av_xx,av_yy))
print('var x   %12.5f y   %12.5f xy %12.5f ' % (var_x,var_y,var_xy))
print('stdev x %12.5f y   %12.5f  ' % (stdev_x,stdev_y))
print('Pearson R %12.5f R^2 %12.5f ' %(Rpearson, Rpearson**2))
print('===========================================================\n')
#
#
# best fit slope, intercept etc, using property of least. abs. dev
# that line goes through at least 2 of points- brute force search over all pairs
#
sum_ad_min = 1.e6
print('minimizing absolute Y-deviation...')
for i in range(ndata):
  for j in range(i+1,ndata):
    m = (y[j] - y[i])/(x[j] - x[i])
    b = y[j] - m * x[j]
    sum_ad = 0.
    for k in range(ndata):
      sum_ad += abs(y[k] - m*x[k] - b)
    if(sum_ad < sum_ad_min):
      sum_ad_min = sum_ad
      minpts = [(i,j)]
      #print(sum_ad,i,j)
    elif(sum_ad == sum_ad_min):
      minpts.append((i,j))
if(len(minpts) > 1):
  print('multiple fits for point pairs: ',minpts)
  print('choosing the first pair')
sum_ad_min /= ndata
i_min = minpts[0][0]
j_min = minpts[0][1]
print('mean abs deviation %12.5f by passing through points %d and %d' % (sum_ad_min,i_min,j_min))
m_min = (y[j_min] - y[i_min])/(x[j_min] - x[i_min])
b_min= y[j_min] - m_min * x[j_min]
print('mean absolute deviation %10.5f slope %10.5f intercept %10.5f  ' % (sum_ad_min,m_min,b_min))
#
file_out = open('ladline_plot.dat','w')
file_out.write('#  n       x         y        yfit       yresid    \n')
ycalc = []
for i in range(ndata):
    ytemp = x[i]*m_min + b_min
    ycalc.append(float(ytemp))
    resid = abs(y[i] - m_min*x[i] - b_min)
    #print('%4d %10.3f %10.3f %10.3f %10.3f %10.3f %10.3f ' % \
    #      (i,x[i],y[i],ycalc[i],resid[i],ycalc_plus_2s[i],ycalc_less_2s[i]))
    str_buf = '%4d %10.3f %10.3f %10.3f %10.3f \n' % \
          (i,x[i],y[i],ycalc[i],resid)
    file_out.write(str_buf)
file_out.close()
#
# plotting
#
if(MAKEPLOT):
  plt.figure(figsize=(8,7.75))
  plt.scatter(x,y,color='red',marker='o')
  plt.plot(x,ycalc,'b-')
  plt.xlabel('x')
  plt.ylabel('y')
  plt.title('Least abs. dev. fit (blue) ')
  plt.grid(True)
  plt.show()


import numpy as np
from scipy.linalg import svd

__all__ = ['orthomax']

def orthomax(Phi, gamma=1., maxiter=20, tol=1e-6):
    """
    Given n*k factor matrix Phi (k number of factors, n number of dimensions),
    find a rotated version of the factor loadings that fulfills optimization criteria,
    depending on gamma \in [0..1]

    If gamma=0 this is the "quartimax", for gamma=1 it is often called "varimax".

    It is not easy to find a good reference on this,
    one is
        Herve Abdi, "Factor Rotations in Factor Analyses."
        http://www.utd.edu/~herve/Abdi-rotations-pretty.pdf
    another which also has an algorithm listing and a nice application, but only for gamma = 0
        Justin Solomon et al., "Discovery of Intrinsic Primitives on Triangle Meshes", Eurographics 2011
        http://graphics.stanford.edu/projects/lgl/papers/sbbg-diptm-11/sbbg-diptm-11.pdf
    """
    if gamma < 0 or gamma > 1:
        raise ValueError("gamma must be between 0 and 1")
    p, k = Phi.shape
    R = np.eye(k)
    Lambda = Phi
    d_old = None
    for i in range(maxiter):
        if gamma > 0:
            Z = Lambda**3 - (gamma / p) * np.dot(Lambda, np.diag(np.diag(np.dot(Lambda.T, Lambda))))
        else:
            Z = Lambda**3
        U, s, Vt = svd(np.dot(Phi.T, Z), full_matrices=False)
        R = np.dot(U, Vt)
        Lambda = np.dot(Phi, R)
        d = np.sum(s)
        if d_old != None and d < d_old * (1 + tol):
            print("orthomax converged")
            break
        d_old = d
    return np.dot(Phi, R)

if __name__ == '__main__':
    import pylab as pl

    # generate randomly activated 2d gaussian blobs
    np.random.seed(2)
    n = 16
    n_components = 3
    n_obs = 200
    y, x = np.mgrid[:n, :n]
    xy = np.dstack((x, y)).astype(np.float)
    components = []
    for i in range(n_components):
        mean = np.random.uniform(0, n, 2)
        sigma = np.random.uniform(0, n/3, 2)
        p = np.exp( - ((xy - mean)**2 / (2*sigma)).sum(axis=-1))
        components.append(p.ravel())
    components = np.array(components)
    code = np.random.random((n_obs, n_components)) \
            + np.random.random(n_obs)[:,np.newaxis]
    obs = np.dot(code, components)
    obs += np.random.normal(scale=0.2, size=obs.shape)

    # pca
    U, s, Vt = svd(obs)
    pca_components = Vt[:n_components, :]
    # orthomaximalize the pca factors
    vmax = orthomax(pca_components.T, gamma=1., maxiter=100)

    # visualize
    pl.clf()
    for i, c in enumerate(pca_components):
        pl.subplot(3, n_components, i+1)
        pl.title("pca#%d" % i)
        pl.imshow(c.reshape(n,n))
    for i, c in enumerate(vmax.T):
        pl.subplot(3, n_components, i+4)
        pl.title("orthomax#%d" % i)
        pl.imshow(c.reshape(n,n))
    for i, c in enumerate(components[[2,0,1]]):
        pl.subplot(3, n_components, i+7)
        pl.title("original#%d" % i)
        pl.imshow(c.reshape(n,n))
    pl.show()


"""
  Name     : c9_22_LPSD.py
  Book     : Python for Finance (2nd ed.)
  Publisher: Packt Publishing Ltd.
  Author   : Yuxing Yan
  Date     : 6/6/2017
  email    : yany@canisius.edu
             paulyxy@hotmail.com
"""

import scipy as sp
import numpy as np

mean=0.15;
Rf=0.01
std=0.20
n=200
sp.random.seed(3412)
x=sp.random.normal(loc=mean,scale=std,size=n)

def LPSD_f(returns, Rf):
    y=returns[returns-Rf<0]
    m=len(y)
    total=0.0
    for i in sp.arange(m):
        total+=(y[i]-Rf)**2
    return total/(m-1)

answer=LPSD_f(x,Rf)
print("LPSD=",answer)


import math

import numpy

from . import util

class Exponential:
    def __init__(self, magnitude, rate):
        self.magnitude = magnitude
        self.rate = rate

    def __call__(self, x):
        return(self.magnitude*numpy.exp(-self.rate*numpy.array(x)))

    def __str__(self):
        return("{0:.2e}*exp(-{1:.2e}*t)".format(self.magnitude, self.rate))

    @property
    def area(self):
        return(self.magnitude/self.rate)

class MultiExponential:
    def __init__(self, params):
        self.exponentials = [Exponential(magnitude, rate) for magnitude, rate \
                             in zip(params[::2], params[1::2])]

    def __iter__(self):
        return(iter(self.exponentials))

    def __call__(self, x):
        return(sum(map(lambda f: f(x), self)))

    def __str__(self):
        return(" + ".join(map(str, self)))

    def __len__(self):
        return(len(self.exponentials))

    def __getitem__(self, index):
        return(self.exponentials[index])

    def __setitem__(self, index, value):
        self.exponentials[index] = value

    def sorted_by_area(self):
        return(list(sorted(self.exponentials, key=lambda x: x.area)))

    def sort_by_area(self):
        self.exponentials = self.sorted_by_area()

    def sorted_by_rate(self):
        return(list(sorted(self.exponentials, key=lambda x: x.rate)))

    def sort_by_rate(self):
        self.exponentials = self.sorted_by_rate()

    def areas(self):
        return(map(lambda x: x.area, self.exponentials))

    def rates(self):
        return(map(lambda x: x.rate, self.exponentials))

    def relative_areas(self, origin=None):
        """
        Report the relative areas of the two exponentials, optionally corrected
        by setting a starting time for integration.
        """
        if origin is None:
            return(util.normalize(self.areas))
        else:
            areas = list(map(lambda x: x.magnitude*math.exp(-x.rate*origin)\
                             /x.rate,
                             self))

            return(util.normalize(areas, key=sum))


#!/usr/bin/python3

'''
Interpolation tools
'''

try:
    import numpy as np
except ModuleNotFoundError:
    print("\"numpy\" not found. This module requires numpy")
try:
    import matplotlib.pyplot as plt
except ModuleNotFoundError:
    print("\"matplotlib\" not found. This module requires matplotlib")

from .Core import *

#######################################################################################################################################
#######################################################################################################################################
class MethodError(Exception):
    pass
########################################################################################################################################
########################################################################################################################################

def full_lagrange(xdata,ydata,points=100):
    '''
    Returns two arrays, x and y=f(x), where f is the Lagrange Polynomial Interpolation for the collection of points (xdata, ydata).
    Naturally, the x and y arrays have resolution of points given by the points argument.
    It is not recommended to interpolate a lot of points on xdata and ydata;
    the optimal value of points is maybe 15 of 20 (x,y) pairs, maybe more.
    '''
    if len(xdata)!=len(ydata):
        raise ValueError("xdata and ydata must be the same size, but have shapes %d and %d"%(len(xdata),len(ydata)))
    else:
        k=len(xdata)
    k=len(xdata)
    npx=np.array(xdata);npy=np.array(ydata)
    xglobal=np.linspace(npx[0],npx[-1],points)[:-1]
    yglobal=[]
    def L(q):
        rs=0
        for j in range(0,k):
            rp=1
            for i in exclude(j,k,0,1):
                    rp*=(q-npx[i])/(npx[j]-npx[i])
            rs+=npy[j]*rp
        return rs
    for w in xglobal:
        yglobal.append(L(w))
    return (xglobal,yglobal)

def reduced(xdata,ydata,points=100,reduction=1,method="random"):
    '''
    Reduce data before interpolation.
    '''
    if len(xdata)!=len(ydata):
        raise ValueError("xdata and ydata must be the same size, but have shapes %d and %d"%(len(xdata),len(ydata)))
    zipped=list(zip(xdata,ydata))
    zippedred=reduce_list(zipped,reduction,method)
    k_=len(zippedred)
    xunzip=np.zeros(k_)
    yunzip=np.zeros(k_)
    for i in range(k_):
        xunzip[i]+=zippedred[i][0]
        yunzip[i]+=zippedred[i][1]
    return full_lagrange(xunzip,yunzip,points)

def Interpolate_Data(x,y,n=3,p=50):
    '''
    Interpolate the data.
    It is not useful to do it with functions, but is sort of eqivalent to Newton-Cotes formulas, but slower.
    It is not a good idea use a large n. Usually 2 < n < 7
    '''
    shapes_comparation(x,y)
    res=len(x)%n
    xglobal=[]
    yglobal=[]
    for i in range(len(x)-res):
        if i%(n-1)==0:
            a=full_lagrange(x[i:i+n],y[i:i+n],p)
            xglobal+=list(a[0])
            yglobal+=list(a[1])
    if res>1:
        a=full_lagrange(x[len(x)-res+1:len(x)],y[len(x)-res+1:len(x)],100)
        xglobal+=list(a[0])
        yglobal+=list(a[1])
    return (xglobal,yglobal)


"""
Calculating the mean and the standard error of a randomly-generated sample.

CODE REVIEW CREDITS:
* IEatBagels: https://codereview.stackexchange.com/a/224039/20684
* dfhwze: https://codereview.stackexchange.com/a/224045/20684

TEST RESULTS CREDITS:
* https://www.miniwebtool.com/standard-error-calculator/

AUTHOR: Erel Segal-Halevi
SINCE:  2019-07-13
"""

import numpy as np

def mean_and_stderr(num_of_iterations:int, instance_generator) -> (float,float):
    """
    Calculate the mean and standard error of the given generator.

    :param instance_generator: a function that accepts no parameters,
             and returns either a float or a numpy array.
    :param num_of_iterations: number of times to run the instance_generator.

    :return (mean, standard_error)

    Test on a degenerate (constant) generator of numbers:
    >>> def five(): return 5
    >>> mean_and_stderr(100, five)
    (5.0, 0.0)

    Test on consecutive numbers
    >>> def iota(): iota.i+=1; return iota.i
    >>> iota.i = 0
    >>> mean_and_stderr(3, iota)   # 1,2,3
    (2.0, 0.57735026918962584)
    >>> mean_and_stderr(5, iota)   # 4,5,6,7,8
    (6.0, 0.70710678118654757)

    Test on a degenerate (constant) generator of vectors:
    >>> generator = lambda: np.array([1,2,3])
    >>> mean_and_stderr(100, generator)
    (array([ 1.,  2.,  3.]), array([ 0.,  0.,  0.]))
    """
    sum = sumSquares = None
    for i in range(num_of_iterations):
        x_i = instance_generator()
        if sum is None:
            sum = x_i
            sumSquares = (x_i*x_i)
        else:
            sum += x_i
            sumSquares += (x_i * x_i)
    mean = sum / num_of_iterations
    population_variance = sumSquares / num_of_iterations - (mean*mean)
    sample_variance = population_variance*num_of_iterations/(num_of_iterations-1)
    stderr = np.sqrt(sample_variance / num_of_iterations)
    return (mean,stderr)

if __name__=="__main__":
    generate_uniformly_random_number = np.random.random
    print(mean_and_stderr(10, generate_uniformly_random_number))
    # Typical output: (0.5863703739913031, 0.026898107452102943)
    print(mean_and_stderr(1000, generate_uniformly_random_number))
    # Typical output: (0.514204422858358, 0.0002934476865378269)

    generate_uniformly_random_vector = lambda: np.random.random(3)
    print(mean_and_stderr(10, generate_uniformly_random_vector))
    # Typical output: (array([ 0.53731682,  0.6284966 ,  0.48811251]), array([ 0.02897111,  0.0262977 ,  0.03192519]))
    print(mean_and_stderr(1000, generate_uniformly_random_vector))
    # Typical output: (array([ 0.50520085,  0.49944188,  0.50034895]), array([ 0.00028528,  0.00028707,  0.00029089]))


import os
os.environ['THEANO_FLAGS'] = 'device=cpu'

import numpy as np
import theano as th
import theano.tensor as tt
from theano import function
from theano import pp
from theano import shared
from theano.ifelse import ifelse
import time

th.config.floatX = 'float64'
th.config.mode = 'FAST_COMPILE'

# Baby Steps - Algebra
if False:
    print('--------------------')
    x = tt.dscalar('x') # declare a double scalar
    y = tt.dscalar('y')
    z = x + y
    f = function([x, y], z)
    print(f(2, 3))

if False:
    print('--------------------')
    x = tt.dmatrix('x')
    y = tt.dmatrix('y')
    z = x + y
    f = function([x, y], z)
    print(f(np.array([[1, 2], [3, 4]]), np.array([[10, 20], [30, 40]])))

# More Examples
if False:
    print('--------------------')
    a, b = tt.dmatrices('a', 'b')
    diff = a - b
    diff_abs = abs(diff)
    diff_squared = diff**2
    f = function([a, b], [diff, diff_abs, diff_squared])
    print(f([[1, 1], [1, 1]], [[0, 1], [2, 3]]))

if False:
    print('--------------------')
    state0 = shared(0)
    state1 = shared(0)
    inc = tt.iscalar('inc')
    #accumulator = function([inc], state0, updates={state0: state0+inc, state1: state1-inc})
    accumulator = function([inc], [state0, state1], updates=[(state0, state0+inc), (state1, state1-inc)])
    print(accumulator(1))
    state1.set_value(0)
    print(accumulator(300))
    print(state0.get_value(), state1.get_value())

if False:
    print('--------------------')
    state = shared(0)
    inc = tt.iscalar('inc')
    fn_of_state = state*2 + inc
    foo = tt.scalar(dtype=state.dtype)
    skip_shared = function([inc, foo], fn_of_state, givens=[(state, foo)], updates=[(state, state+1)])
    print('state: ', state.get_value())
    print(skip_shared(1, 3))
    print('state: ', state.get_value())
    print(skip_shared(1, 3))
    print('state: ', state.get_value())

# Derivatives in Theano
if False:
    print('--------------------')
    x = tt.dmatrix('x')
    y = tt.sum(1 / (1 + tt.exp(-x)))
    gy = tt.grad(y, x)
    f = th.function([x], gy)
    print(pp(gy))
    print(pp(f.maker.fgraph.outputs[0]))

if False:
    print('--------------------')
    x = tt.dvector('x')
    y = x**2
    j = th.gradient.jacobian(y, x)
    f = function([x], j)
    #print(pp(j))
    print(f([4, 4]))
    h = th.gradient.hessian(y.sum(), x)
    g = function([x], h)
    #print(pp(h))
    print(g([4, 4]))

if False:
    print('--------------------')
    x = tt.dvector('x')
    y = x**2
    J, updates = th.scan(
        lambda i,y,x: tt.grad(y[i], x),
        sequences=tt.arange(y.shape[0]),
        non_sequences=[y, x])
    f = function([x], J, updates=updates)
    print(f([4, 4]))

if False:
    print('--------------------')
    x = tt.dvector('x')
    y = (x**2).sum()
    gy = tt.grad(y, x)
    H, updates = th.scan(
        lambda i,gy,x: th.grad(gy[i], x),
        sequences=tt.arange(gy.shape[0]),
        non_sequences=[gy, x])
    f = function([x], H, updates=updates)
    print(f([4, 4]))

# Conditions
if False:
    print('--------------------')
    a, b = tt.scalars('a', 'b')
    x, y = tt.matrices('x', 'y')

    f_switch = function(
        [a, b, x, y],
        tt.switch(tt.lt(a, b), tt.mean(x), tt.mean(y)),
        mode=th.Mode(linker='vm'))
    f_ifelse = function(
        [a, b, x, y],
        ifelse(tt.lt(a, b), tt.mean(x), tt.mean(y)),
        mode=th.Mode(linker='vm'))

    val1 = 0.
    val2 = 1.
    big_mat1 = np.ones((10000, 1000))
    big_mat2 = np.ones((10000, 1000))

    n_times = 10

    tic = time.clock()
    for i in range(n_times):
        f_switch(val1, val2, big_mat1, big_mat2)
    print('time spent evaluating both values %f sec' % (time.clock() - tic))

    tic = time.clock()
    for i in range(n_times):
        f_ifelse(val1, val2, big_mat1, big_mat2)
    print('time spent evaluating both values %f sec' % (time.clock() - tic))

# Loop
if False:
    print('--------------------')
    X = tt.matrix('X')
    W = tt.matrix('W')
    B = tt.vector('B')

    results, updates = th.scan(lambda v: tt.tanh(tt.dot(v,W) + B), sequences=X)
    f = function(inputs=[X,W,B], outputs=results)

    x = np.eye(2, dtype=th.config.floatX)
    w = np.ones((2, 2), dtype=th.config.floatX)
    b = np.ones((2), dtype=th.config.floatX)
    b[1] = 2
    print('tanh(x(t)*W + b)\n', f(x, w, b))

if True:
    print('--------------------')
    coeffs = tt.vector('coeffs')
    X = tt.scalar('X')

    poly, _ = th.scan(
        lambda i, f, x: coeffs[i] + f*x,
        sequences=tt.arange(coeffs.size),
        outputs_info=tt.zeros_like(X),
        non_sequences=[X],
        go_backwards=True)
    f = function([coeffs, X], poly)
    test_coeffs = np.asarray([1, 0, 2], dtype=th.config.floatX)
    print(f(test_coeffs, 3))


import numpy as np
from scipy.optimize import minimize

def rosen(x):
    return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0)

x0 = np.array([1.3,0.7,0.8,1.9,1.2])

print('Testing the Rosenbrock function using scipy solvers')

print('\n1 - Nelder-Mead Simplex')
res_nms = minimize(rosen, x0, method='nelder-mead', options={'xtol': 1e-8, 'disp':True})
print(res_nms.x)

print('\n2 - BFGS')
def rosen_der(x):
    xm = x[1:-1]
    xm_ml = x[:-2]
    xm_pl = x[2:]
    der = np.zeros_like(x)
    der[1:-1] = 200*(xm-xm_ml**2) - 400*(xm_pl -xm**2)*xm - 2*(1-xm)
    der[0] = -400*x[0]*(x[1]-x[0]**2) - 2*(1-x[0])
    der[-1] = 200*(x[-1]-x[-2]**2)
    return der

res_bfgs = minimize(rosen, x0, method='BFGS', jac=rosen_der, options={'disp':True})
print(res_bfgs.x)

print('\n3- Newton-CG')
def rosen_hess(x):
    x = np.asarray(x)
    H = np.diag(-400*x[:-1],1) - np.diag(400*x[:-1],-1)
    diagonal = np.zeros_like(x)
    diagonal[0] = 1200 * x[0]**2 - 400*x[1]+2
    diagonal[-1] = 200
    diagonal[1:-1] = 202 + 1200*x[1:-1]**2 - 400*x[2:]
    H = H + np.diag(diagonal)
    return H
res_ncg = minimize(rosen,x0,method='Newton-CG',jac=rosen_der, hess=rosen_hess,options={'xtol':1e-8, 'disp':True})
print(res_ncg.x)


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

ny, nx = 5, 6

y = np.arange(0, ny)
x = np.arange(0, nx)

# x-component of covariance
Cx = np.zeros((nx, nx))
for i in range(nx):
    for j in range(nx):
        Cx[i, j] = np.exp(-0.5*((x[i] - x[j])/1.0)**2)
    Cx[i, i] += 1E-6

# y-component of covariance
Cy = np.zeros((ny, ny))
for i in range(ny):
    for j in range(ny):
        Cy[i, j] = np.exp(-0.5*((y[i] - y[j])/1.0)**2)
    Cy[i, i] += 1E-6

# Eigen decompositions
Ex, Vx = np.linalg.eig(Cx)
Ey, Vy = np.linalg.eig(Cy)

# Explicit full covariance matrix
n = nx*ny
C = np.zeros((n, n))
for i in range(n):
    for j in range(n):
        dx = x[i % nx] - x[j % nx]
        dy = y[i // nx] - y[j // nx]
        rsq = dx**2 + dy**2
        C[i, j] = np.exp(-0.5*rsq/1.0**2)
    C[i, i] += 1E-6
# C would equal np.kron(Cy, Cx) if it weren't for the extra diagonal bit.

# Some data
L = np.linalg.cholesky(C)
ns = rng.randn(n)
ys = C @ ns
img = ys.reshape((ny, nx))
plt.imshow(img)
plt.show()

# Explicit solve
logl0 = -n*0.5*np.log(2*np.pi) - 0.5*np.log(np.linalg.det(C)) \
                - 0.5*np.dot(ys, np.linalg.solve(C, ys))

# Cholesky solve
logl1 = -n*0.5*np.log(2*np.pi) - np.sum(np.log(np.diag(L))) \
                - 0.5*np.dot(ys, ns)

# Kronecker solve
E = np.kron(Ey, Ex) # All eigenvalues of C

# Dot product of the data against eigenvectors of C
# = the data represented in that basis
coeffs = np.zeros(n)
k = 0
for i in range(ny):
    for j in range(nx):
        V = np.kron(Vy[:,i], Vx[:,j])
        coeffs[k] = np.dot(ys, V)
        k += 1

logl2 = -n*0.5*np.log(2*np.pi) - 0.5*np.sum(np.log(E)) \
                - 0.5*np.dot(coeffs, coeffs/E)

# Eigendecomposition: C = V @ diag(E) @ V.T since C is symmetric V.T = Vinv

# First two should be equal, third should be close.
print(logl0, logl1, logl2)
plt.plot(coeffs)
plt.show()


""" Solution for Project Euler's problem #3 """

import os
import time
from datetime import timedelta

import numpy as np
import jax.numpy as jnp
from jax import jit

# ***************************************************************************************
# Critical for this problem (and for any 64-bit problems)
from jax.config import config
config.update("jax_enable_x64", True)
# ***************************************************************************************

from gante_project_euler.math.prime import get_all_primes, is_factor

NUMBER = 600851475143

@jit
def compute_solution(number, primes_list):
    """ Auxiliary function to compute the solution to the problem (largest prime factor of number).
    """
    return jnp.max(primes_list * is_factor(number=number, primes=primes_list))

def get_solution():
    """ Solves the problem and returns the answer.

    NOTE: At the time of writing, JAX does not enable 64 bit operations by default, required to
    solve this problem. Check the configuration at the top of this script.
    """
    max_prime = np.sqrt(NUMBER).astype(int) # No point looking after this one
    primes_list = jnp.asarray(get_all_primes(max_prime=max_prime), dtype=jnp.int32)
    return compute_solution(NUMBER, primes_list)

if __name__ == "__main__":
    os.environ["CUDA_VISIBLE_DEVICES"] = "0"
    start = time.time()
    solution = get_solution()
    end = time.time()
    print("Solution: {}".format(solution))
    print("Elapsed time (w/compile time):  {} (HH:MM:SS.us)".format(timedelta(seconds=end-start)))
    # The the code is compiled the first time it runs. This second run uses the cached compilation.
    start = time.time()
    _ = get_solution()
    end = time.time()
    print("Elapsed time (wo/compile time): {} (HH:MM:SS.us)".format(timedelta(seconds=end-start)))


# coding=utf-8
import numpy as np

# 随机数
print("random:\n{}\n".format(np.random.random(10)))  # 生成包含10个元素在[0.0, 1.0)之间的一维随机数组
print("random:\n{}\n".format(np.random.random((5, 4))))  # 生成5行4列，元素在[0.0, 1.0)之间的二维随机数组
print("rand:\n{}\n".format(np.random.rand(3, 4)))  # 根据指定的shape生成随机数
print("randint:\n{}\n".format(np.random.randint(0, 100, 20)))  # 生成指定范围内（[0, 100)）的指定数量（20）的随机整数
print("permutation:\n{}\n".format(np.random.permutation(np.arange(20))))  # 随机打乱已有的数据顺序

# 数学运算
base_data = np.random.randint(0, 100, 25).reshape(5, -1)  # 随机生成一个元素值在（[0, 100)）内的5行5列整数矩阵
print("base_data = \n{}\n".format(base_data))
print("np.amin：{} np.amax：{} np.average：{} np.sum：{} \n".format(
    np.amin(base_data),
    np.amax(base_data),
    np.average(base_data),
    np.sum(base_data)))

base_data2 = np.array([(-0.746, -0.2, -1.5, 2.0), (9.4, 7.447, 10, 11.555)])
print("base_data2 = \n{}\n".format(base_data2))
print("np.floor(base_data2)):\n", np.floor(base_data2))  # 返回不大于输入参数的最大整数，向下取整
print("np.ceil(base_data2)):\n", np.ceil(base_data2))  # 返回输入值的上限，向上取整
print("np.around(base_data2)):\n", np.around(base_data2, decimals=2))  # 返回四舍五入后的值，可指定精度
print("np.where(base_data2)):\n", np.where(base_data2 >= 3))  # 返回所有值大于等于3的元素的索引
print("np.diff(base_data2)):\n", np.diff(base_data2))  # 返回相邻元素的差（后一个元素值减去前一个元素值）
print("np.msort(base_data2)):\n", np.msort(base_data2))  # 数组排序

base_data3 = np.array([(3, 21, 10), (2, 9, 23), (11, 5, 17)])
print("\nbase_data3 = \n{}\n".format(base_data3))
print("tolist：{}\n".format(base_data3.tolist()))  # 返回python的list
print("clip：{}\n".format(base_data3.clip(2, 5)))  # 小于2的元素替换为2，大于5的元素替换为5
print("max：{} min：{} ptp：{} \n".format(base_data3.max(),
                                       base_data3.min(),
                                       base_data3.ptp()))  # 返回所有元素的最大值、最小值、最大值和最小值之差
print("var：{} std：{}\n".format(base_data3.var(),
                               base_data3.std()))  # 返回方差（元素与均值之差的平方的均值）、标准差（方差的算术平方根）
print("sum：{} prod：{} mean：{} \n".format(base_data3.sum(),
                                         base_data3.prod(),
                                         base_data3.mean()))  # 返回所有元素的和、乘积、算术平均值
print("argmin：{} argmax：{}\n".format(base_data3.argmin(),
                                     base_data3.argmax()))  # 返回最小值、最大值在扁平数组中的索引

base_data4 = np.array([3, 2, 4, 1, 5])
print("\nbase_data4 = \n{}\n".format(base_data4))
print("np.log(base_data4)): ", np.log(base_data4))  # 返回对数数组
print("np.exp(base_data4)): ", np.exp(base_data4))  # 返回指数数组
print("np.sqrt(base_data4)): ", np.sqrt(base_data4))  # 返回开方数组
print("np.power(base_data4, 3)): ", np.power(base_data4, 3))  # 返回3次方数组

# ### 随机数
# Docs：https://docs.scipy.org/doc/numpy/reference/routines.random.html
# 利用numpy.random包中的随机数算法可以生成多种随机数据；
#
# ### 数学运算
# Docs：https://docs.scipy.org/doc/numpy/reference/routines.math.html


import numpy as np

from ..base import Classifier, Regressor
from ..exceptions import MethodNotSupportedError
from ..metrics.classification import accuracy_score

class NaiveBayes(Classifier, Regressor):
    """Naive Bayes Classifier

    P(A|B) = P(B|A) * P(A) / P(B)

    Parameters:
    -----------
    eps : float, laplacian smoothing coefficient, optional

    """

    def __init__(self, eps=1e-18):
        self.eps = eps

        self._X = []
        self._y = []
        self._labels = []

    def fit(self, X, y):
        self._X, self._y = super().fit(X, y)
        self._labels = np.unique(self._y)
        return self

    def predict(self, X):
        return np.array([
            self._labels[np.argmax(proba)] for proba in self.predict_proba(X)
        ])

    def predict_proba(self, X):
        X = super().predict_proba(X)
        res = np.array([
            [
                self._calc_prior(label) * np.product(
                    [self._calc_likelihood(x, i, label) / self._calc_evidence(x, i) for i in range(len(x))]
                ) for label in self._labels
            ] for x in X
        ])

        return res / (np.sum(res, axis=1, keepdims=True) + self.eps)

    def _calc_likelihood(self, x, i, label):
        tmp = self._X[self._y == label, :]
        return np.count_nonzero(tmp[:, i] == x[i]) / tmp.shape[0]

    def _calc_prior(self, label):
        return np.count_nonzero(self._y == label) / self._y.size

    def _calc_evidence(self, x, i):
        val = np.count_nonzero(self._X[:, i] == x[i]) / self._X.shape[0]
        if val == 0:
            return self.eps
        else:
            return val

    def decision_function(self, X):
        raise MethodNotSupportedError("Decision function is not supported for Naive Bayes Classifier.")

    def evaluate(self, X, y):
        return accuracy_score(y, self.predict(X))


# -*- coding: utf-8 -*-
"""
  Name     : c10_43_EW_port.py
  Book     : Python for Finance (2nd ed.)
  Publisher: Packt Publishing Ltd.
  Author   : Yuxing Yan
  Date     : 6/6/2017
  email    : yany@canisius.edu
             paulyxy@hotmail.com
"""

import numpy as np

ret_A=np.array([0.102,-0.02, 0.213,0.12,0.13])
ret_B=np.array([0.1062,0.23, 0.045,0.234,0.113])

port_EW=(ret_A+ret_B)/2

round(np.mean(ret_A),3),round(np.mean(ret_B),3),round(np.mean(port_EW),3)

round(np.std(ret_A),3),round(np.std(ret_B),3),round(np.std(port_EW),3)


import numpy as np
from BasicML import visdata

class Regression:

    def __init__(self, x, y, w=[], d=1):
        self.y = y
        self.d = d
        self.w = w
        self.x = x
        self.m = x.shape[0]

    def poly_feat(self, x):
        px = []
        for i in range(2, self.d+1):
            px.append(x[:,1:]**i)
        return np.squeeze(np.array(px)).T

    def add_poly_feat(self, x):
        if self.d < 2:
            pass
        elif self.d == 2:
            zz = np.reshape(self.poly_feat(x), (self.poly_feat(x).shape[0], 1))
            x = np.append(x, zz, axis=1)
        else:
            x = np.append(x, self.poly_feat(x), axis=1)
        return x

    def initiate_weights(self,  process="zero"):
        if process == "zero":
            self.w = np.zeros((self.x.shape[1], 1))
        elif process == "random":
            self.w = np.random.randn(self.x.shape[1], 1)

    def cost_fn(self, reg):
        J = (np.sum((self.y - self.x@self.w)**2) + reg*np.sum(self.w[1:]@self.w[1:].T))/(2*self.m)
        return J

    def gradients(self, x, y, w, reg):
        dw = np.zeros(w.shape)
        m = x.shape[0]
        dw[0] = x[:,0].T@(x@w - y)/m
        dw[1:] = (x[:,1:].T@(x@w - y) + reg*w[1:])/m
        return dw

    def train(self, alpha=0.001, batch_size=1, n=1000, reg=0):
        cost = np.zeros((n,2))
        self.x = self.add_poly_feat(self.x)
        self.initiate_weights()
        ind = np.random.permutation(self.m)
        X = self.x[ind]
        Y = self.y[ind]
        for i in range(n):
            for j in range(self.m//batch_size):
                x = X[j*batch_size:(j+1)*batch_size, :]
                y = Y[j*batch_size:(j+1)*batch_size, :]
                self.w = self.w-alpha*self.gradients(x, y, self.w, reg)
            if self.m % batch_size != 0:
                x = X[self.m//batch_size*batch_size:self.m]
                y = Y[self.m//batch_size*batch_size:self.m]
            self.w = self.w - alpha*self.gradients(x, y, self.w, reg)
            print("Cost after", i+1, "Iterations : ", self.cost_fn(reg))
            cost[i,0] = i+1
            cost[i,1] = self.cost_fn(reg)
        print("\nFinal weights after training : ", self.w)
        return cost

    def predict(self, x):
        x = self.add_poly_feat(x)
        y_ = x@self.w
        return y_


# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: percent
#       format_version: '1.3'
#       jupytext_version: 1.4.2
#   kernelspec:
#     display_name: Python [conda env:mdd] *
#     language: python
#     name: conda-env-mdd-py
# ---

# %% [markdown]
# # Using FFT the right way to find the correct spectrum
#

# %% jupyter={"outputs_hidden": false}
from numpy import *
from numpy.fft import fft
import matplotlib.pyplot as plt
# %matplotlib inline

# redefine default figure size and fonts
import matplotlib as mpl
mpl.rc('font', size=16)
mpl.rc('figure',figsize=(12,10))
mpl.rc('lines', linewidth=1, color='lightblue',linestyle=':',marker='o')

# %%
import sys
sys.path.append('../../scripts')
from signal_processing import create_signal, spectrum

# %%
fs = 30 # sampling frequency, Hz
N = 256 # number of sampling points

t,y = create_signal(fs,N)

# %%
def plot_signal_with_fft(t,y,fs,N):
    """ plots a signal in time domain and its spectrum using
    sampling frequency fs and number of points N
    """

    T = N/fs # sampling period
    y -= y.mean() # remove DC
    frq,Y = spectrum(y,fs) # FFT(sampled signal)

    # Plot
    fig, ax = plt.subplots(2,1)
    ax[0].plot(t,y,'b.')
    ax[0].plot(t,y,':',color='lightgray')
    ax[0].set_xlabel('$t$ [s]')
    ax[0].set_ylabel('Y [V]')
    ax[0].plot(t[0],y[0],'ro')
    ax[0].plot(t[-1],y[-1],'ro')
    ax[0].grid()

    ax[1].plot(frq,abs(Y),'r') # plotting the spectrum
    ax[1].set_xlabel('$f$ (Hz)')
    ax[1].set_ylabel('$|Y(f)|$')
    lgnd = str(r'N = %d, f = %d Hz' % (N,fs))
    ax[1].legend([lgnd],loc='best')
    ax[1].grid()

# %%
### Note we remove DC right before the spectrum

# %%
plot_signal_with_fft(t,y,fs,N)

# %%
fs = 66 # sampling frequency, Hz
N = 256 # number of sampling points

t,y = create_signal(fs,N)
plot_signal_with_fft(t,y,fs,N)

# %%
fs = 100 # sampling frequency, Hz
N = 256 # number of sampling points

t,y = create_signal(fs,N)
plot_signal_with_fft(t,y,fs,N)

# %%
fs = 500 # sampling frequency, Hz
N = 256 # number of sampling points

t,y = create_signal(fs,N)
plot_signal_with_fft(t,y,fs,N)

# %% [markdown]
# * Very poor frequency resolution, $\Delta f = 1/T = fs/N = 500 / 256 = 1.95 Hz$ versus $\Delta f = 100 / 256 = 0.39 Hz$
# * peaks are at 9.76 Hz and 35.2 Hz
# * wasting a lot of frequency axis above 2 * 35.7

# %% [markdown]
# ## So the problem is still there:
# the peak is now shifted to 35.5 Hz, let's see: when we sampled at 30 we got aliased 35.5 - 30 = 5.5 Hz. Seems correct,
# when we sampled at 66 it was above 2/3*f but below 2*f, so 66 - 35.5 = 30.5 Hz, also seem to fit. So now we have explained (!)
# the previous results and we believe that hte signal has 10 Hz and 35.5 Hz (approximately) and 100 Hz is good enough
# but we could improve it by going slightly above Nyquist 2*35.5 = 71 Hz, and also try to fix the number of points such that
# we get integer number of periods. It's imposible since we have two frequencies, but at least we can try to get it close
# enough: 1/10 = 0.1 sec so we could do 256 * 0.1 = 25.6 Hz or X times that = 25.6 * 3 = 102.4 - could be too close
# let's try:

# %% jupyter={"outputs_hidden": false}
fs = 102.4 # sampling frequency, Hz
N = 256 # number of sampling points
t,y = create_signal(fs,N)
plot_signal_with_fft(t,y,fs,N)

# %% [markdown]
# Then the same principle to get better 35.5 Hz
# 1/35.5 * 256 = 7.21 * 15 = 108.16 Hz

# %% jupyter={"outputs_hidden": false}
fs = 108.16 # sampling frequency, Hz
N = 256 # number of sampling points
t,y = create_signal(fs,N)
plot_signal_with_fft(t,y,fs,N)

# %% jupyter={"outputs_hidden": false}
fs = 144.22 # sampling frequency, Hz
N = 512 # number of sampling points
t,y = create_signal(fs,N)
plot_signal_with_fft(t,y,fs,N)

# %% [markdown]
# ## Use windowing or low-pass filtering
#

# %% jupyter={"outputs_hidden": false}
from scipy.signal import hann  # Hanning window

# %% jupyter={"outputs_hidden": false}
fs = 150; N = 256;
t,y = create_signal(fs,N)

# %% jupyter={"outputs_hidden": false}
# we made a mistake with the DC

DC = y.mean()
y -= DC

yh = y*h

plt.plot(t,y,'b-',t,yh,'r')

# %% jupyter={"outputs_hidden": false}
frq,Y = spectrum(yh,fs)

Y = abs(Y)*sqrt(8./3.)# /(N/2)

plt.plot(frq,Y)

# %% [markdown]
# ### let's try to reconstruct

# %% jupyter={"outputs_hidden": false}
a1,f1 = Y.max(),frq[Y.argmax()]
print (a1,f1)
b = Y.copy()
b[:Y.argmax()+10] = 0 # remove the first peak
a2,f2 = b.max(),frq[b.argmax()]
print (a2,f2)

# %% jupyter={"outputs_hidden": false}
yhat = DC + a1*sin(2*pi*f1*t) + a2*sin(2*pi*f2*t)
plt.plot(t,y+DC,'b-',t,yhat,'r--');
plt.legend(('$y$','$\hat{y}$'),fontsize=16);


# 1. BinaryGap
# Find longest sequence of zeros in binary representation of an integer.

"""
A binary gap within a positive integer N is any maximal sequence of consecutive zeros that is surrounded by ones at both ends in the binary representation of N.
For example, number 9 has binary representation 1001 and contains a binary gap of length 2. The number 529 has binary representation 1000010001 and contains two binary gaps: one of length 4 and one of length 3. The number 20 has binary representation 10100 and contains one binary gap of length 1. The number 15 has binary representation 1111 and has no binary gaps. The number 32 has binary representation 100000 and has no binary gaps.
Write a function:

def solution(N)

that, given a positive integer N, returns the length of its longest binary gap. The function should return 0 if N doesn't contain a binary gap.
For example, given N = 1041 the function should return 5, because N has binary representation 10000010001 and so its longest binary gap is of length 5. Given N = 32 the function should return 0, because N has binary representation '100000' and thus no binary gaps.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..2,147,483,647].
"""

import numpy as np

def solution(N):
    # write your code in Python 3.6
    N_bin = bin(N).replace('0b', '')
    # print(N_bin)

    current_count = 0
    best_count = 0
    for i in range(len(N_bin)):
        checkpoint = N_bin[i]
        if checkpoint == '1':
            if current_count > best_count:
                best_count = current_count
            current_count = 0
        elif checkpoint == '0':
            current_count += 1
        # print(f'{i}: {current_count}')

    return best_count

if __name__ == '__main__':
    # 561892, 74901729, 1376796946
    np.random.seed(77)
    N = np.random.randint(1, 1376796946)
    N = 561892
    zero_count = solution(N)
    print(f'{N}: {bin(N)}: {zero_count}')


import numpy as np
import matplotlib.pyplot as plt

def sine_func(x_i):
	y = np.sin(2*np.pi*x_i)
	return y

def gen_toy_sine_curve_dataset(N, std, periods=1):
	"""
	:param N: Number of data points/samples
	:param std: Standard deviation for (white/Gaussian) noise input
	:return: 2-tuple (x_vector, y_train)
	"""
	y_vector = []
	x_vector = []
	for period_i in range(periods):
		for x_i in np.linspace(0, 1, N):
			x_i = x_i + period_i
			noise = np.random.normal(0, std)
			y_i = sine_func(x_i) + noise
			x_vector.append(x_i)
			y_vector.append(y_i)
	return x_vector, y_vector

N = 50
periods = 3
std_noise = 0

x_train, y_train = gen_toy_sine_curve_dataset(N, std_noise, periods)
# x_vector_test, y_hat_vector = gen_toy_sine_curve_dataset(10, 0.25)

fig_dims = (12, 12)
fig, ax = plt.subplots(figsize=fig_dims)
# fig, axes = plt.subplots(1, 3, figsize = fig_dims)
ax.plot(x_train, y_train, "g", label="Sine curve plot (x_train vs y_train) - num data points = {0} std = {1}".format(N, std_noise))
ax.grid(True)
ax.legend()
# plt.plot(x_train, y_train, "g")
# plt.plot(x_vector_test, y_hat_vector, "r")
plt.show()


#!/usr/bin/python
"""
author  : Bhekimpilo Ndhlela
author  : 18998712
module  : Applied Mathematics(Numerical Methods) TW324
task    : Computer Assignment 03 question 3 (a. to e.)
since   : Friday-09-03-2018
"""

def question_a(N=4, debug=True):
    x = zeros(N)
    x = [cos(((2 * k - 1) * pi)/(2 * N)) for k in xrange(1, N + 1)]
    # defining the chebyshev Vandermonde matrix where V = 4x4 Matrix
    V = C.chebvander(x, N - 1)
    if debug is True:
        print "DEBUG MODE: ON [Question 3 (a.)]:"
        print "vector x   = ", x
        print "\nchebyshev Vandermonde matrix where V:      \n", V
    return x, V

def question_b(x, V, debug=True):
    # finding the e^xi for the x elements
    exp_x = [exp(i) for i in x]
    V_inv = inv(V)
    c = matmul(V_inv, exp_x)
    if debug is True:
        print "\nDEBUG MODE: ON [Question 3 (b.)]:"
        print "vector e^x = ", exp_x
        print "\n(chebyshev Vandermonde matrix)^-I where V :\n", V_inv
        print "\nVc=exp(x)=> c=inv(V)exp(c) <=> inv(V)V=I  :\n", c

def question_c(b=3, a=0, N=0.0, debug=True):
    approx = lambda N : exp(N) * ((b-a)**N / (fact(N) * 2**(2*N-1)))
    while 10**-10 <= approx(N):
        N = N + 1.0
        print N
    if debug is True:
        print "\nDEBUG MODE: ON [Question 3 (c.)]:"
        print "Number of Chebyshev Points N = ", int(N)
        print "Approximated Value,      @ N = ", approx(N)
    return N

def question_d(N, debug=True):
    chebyshev_points = zeros(int(N))
    chebyshev_points = [3./2. + 3./2.*cos(((2 * k - 1) * pi)/(2 * N)) \
                        for k in xrange(1, int(N) + 1)]
    if debug is True:
        print "\nDEBUG MODE : ON [Question 3 d.)]"
        print "The n Chebyshev Point where n = ", int(N)
        print "i", "\t", "Chebyshev_Points"
        for i, value in enumerate(chebyshev_points):
            print i, "\t", value
    return chebyshev_points

def question_e(chebyshev_points, debug=True):
    exp_xk = [exp(vk) for vk in chebyshev_points]
    #use polyfit
    fit = polyfit(chebyshev_points, exp_xk, len(exp_xk) - 1)
    err_vals = [e - f for e, f in zip(exp_xk, fit)]
    warnings.simplefilter('ignore', RankWarning) #ignore warnings
    # plot the error function
    #plt.plot(linspace(0,3,num=19), exp_xk, label="exp(xk)")
    plt.plot(linspace(0,3,num=19), err_vals, label="err_vals")
    #plt.plot(linspace(0,3,num=19), fit, label="fit")
    plt.title('Error Functioin')
    plt.ylabel('Error')
    plt.xlabel('x')
    plt.legend(bbox_to_anchor=(1.0, 1), loc=0, borderaxespad=0.)
    plt.show()
    if debug is True:
        print "\nDEBUG MODE : ON  [Question 3 e.)]"
        print "k", "\t", "chebyshev_points(k)", "\t", "exp(k)\t\t\t",\
              "polyfit_points(k)"
        for k, (xk, e) in enumerate(zip(chebyshev_points, exp_xk)):
            print k, "\t", "{:.16f}".format(xk), "\t","{:.16f}".format(e), \
                  "\t", "{:.16f}".format(fit[k])
    else:
        print "\nDEBUG MODE : OFF [Question 3 e.)]"

if __name__ == "__main__":
    from math import (cos, pi, exp)
    from numpy import (array, matmul, zeros, RankWarning)
    from numpy import (linspace, shape, transpose, polyfit)
    from numpy.polynomial import chebyshev as C
    from numpy.linalg import inv
    from scipy.misc import factorial as fact
    import warnings
    import matplotlib.pyplot as plt

    x, V = question_a(debug=True)
    question_b(x, V, debug=True)
    N = question_c()
    chebyshev_points = question_d(N)
    question_e(chebyshev_points)
else:
    import sys
    sys.exit("Run the library as the client.")