import numpy as np
import matplotlib.pyplot as plt
from tdma import tdma

# Solve for COUETTE FLOW (Laplace equation)

################## FINITE DIFFERENCE FORMULATION ##################
L = 1      # length of the domain
N =  64   #  number of nodes
Tl = -0.5; # Left Dir BC
Tr = +0.5; # Right Dir BC
h = L/(N-1);   # spacing
x = np.linspace(0,L,N) # grid

# Create a tridiagonal matrix
def tridiag(a, b, c, k1, k2, k3): # ki is the ith diagonal relative to principal diagonal
    return np.diag(a, k1) + np.diag(b, k2) + np.diag(c, k3)

# Coefficent matrix
a = np.ones(N-3);    # upper and lower diagonal
b = -2*np.ones(N-2); # principal diagonal
A = tridiag(a, b, a, -1, 0, 1)

# Constant matrix
X = np.zeros((N-2,1));X[0] = -Tl; X[-1] = -Tr;

# Solution
T_actual = x-0.5;
T_num = tdma(A,X); # TDMA
T_fdm = np.append(np.append(Tl,T_num),Tr) # Append BCs

################### FINITE VOLUME FORMULATION ##################
dy = L/(N-1);   # spacing (dyn = dys = dy)
dys = dy;
dyn = dy;

# Coefficent matrix
a = np.ones(N-3)/dyn;    # upper diagonal
b = -np.ones(N-2)*(1/dys+1/dyn); # principal diagonal
a = np.ones(N-3)/dys;    # lower diagonal
A = tridiag(a, b, a, -1, 0, 1)

# Constant matrix
X = np.zeros((N-2,1));X[0] = -Tl; X[-1] = -Tr; X = X/dy;

# Solution
T_actual = x-0.5;
T_num = tdma(A,X); # TDMA
T_fvm = np.append(np.append(Tl,T_num),Tr) # Append BCs

# Plot
plt.plot(x,T_fdm,'r-')
plt.plot(x,T_fvm,'g^')
plt.plot(x,T_actual,'bo',markersize = 3)
plt.xlabel('position');plt.ylabel('velocity'); plt.axis([0,1,-0.5,0.5])
plt.legend(('finite difference solution','finite volume solution','exact solution','')); #plt.title('Solution to Couette flow')
m = 10; counter = np.linspace(0,m,m+1);counter = counter.astype(int)# number of labels in Y
y_values = np.linspace(Tl,Tr,m+1); y_values = [round(i,2) for i in y_values]
new_ticks = np.append(np.append("$V_{lower}$", list(y_values[1:m])),"$V_{upper}$")
plt.yticks(y_values,new_ticks)
plt.grid()
plt.show()


import numpy as np
from sklearn.neighbors import NearestNeighbors

def best_fit_transform(A, B):
    '''
    Calculates the least-squares best-fit transform that maps corresponding points A to B in m spatial dimensions
    Input:
      A: Nxm numpy array of corresponding points
      B: Nxm numpy array of corresponding points
    Returns:
      T: (m+1)x(m+1) homogeneous transformation matrix that maps A on to B
      R: mxm rotation matrix
      t: mx1 translation vector
    '''

    assert A.shape == B.shape

    # get number of dimensions
    m = A.shape[1]

    # translate points to their centroids
    centroid_A = np.mean(A, axis=0)
    centroid_B = np.mean(B, axis=0)
    AA = A - centroid_A
    BB = B - centroid_B

    # rotation matrix
    H = np.dot(AA.T, BB)
    U, S, Vt = np.linalg.svd(H)
    R = np.dot(Vt.T, U.T)

    # special reflection case
    if np.linalg.det(R) < 0:
       Vt[m-1,:] *= -1
       R = np.dot(Vt.T, U.T)

    # translation
    t = centroid_B.T - np.dot(R,centroid_A.T)

    # homogeneous transformation
    T = np.identity(m+1)
    T[:m, :m] = R
    T[:m, m] = t

    return T, R, t

def nearest_neighbor(src, dst):
    '''
    Find the nearest (Euclidean) neighbor in dst for each point in src
    Input:
        src: Nxm array of points
        dst: Nxm array of points
    Output:
        distances: Euclidean distances of the nearest neighbor
        indices: dst indices of the nearest neighbor
    '''

    assert src.shape == dst.shape

    neigh = NearestNeighbors(n_neighbors=1)
    neigh.fit(dst)
    distances, indices = neigh.kneighbors(src, return_distance=True)
    return distances.ravel(), indices.ravel()

def icp(A, B, init_pose=None, max_iterations=20, tolerance=0.001):
    '''
    The Iterative Closest Point method: finds best-fit transform that maps points A on to points B
    Input:
        A: Nxm numpy array of source mD points
        B: Nxm numpy array of destination mD point
        init_pose: (m+1)x(m+1) homogeneous transformation
        max_iterations: exit algorithm after max_iterations
        tolerance: convergence criteria
    Output:
        T: final homogeneous transformation that maps A on to B
        distances: Euclidean distances (errors) of the nearest neighbor
        i: number of iterations to converge
    '''

    assert A.shape == B.shape

    # get number of dimensions
    m = A.shape[1]

    # make points homogeneous, copy them to maintain the originals
    src = np.ones((m+1,A.shape[0]))
    dst = np.ones((m+1,B.shape[0]))
    src[:m,:] = np.copy(A.T)
    dst[:m,:] = np.copy(B.T)

    # apply the initial pose estimation
    if init_pose is not None:
        src = np.dot(init_pose, src)

    prev_error = 0

    for i in range(max_iterations):
        # find the nearest neighbors between the current source and destination points
        distances, indices = nearest_neighbor(src[:m,:].T, dst[:m,:].T)

        # compute the transformation between the current source and nearest destination points
        T,_,_ = best_fit_transform(src[:m,:].T, dst[:m,indices].T)

        # update the current source
        src = np.dot(T, src)

        # check error
        mean_error = np.mean(distances)
        if np.abs(prev_error - mean_error) < tolerance:
            break
        prev_error = mean_error

    # calculate final transformation
    T,_,_ = best_fit_transform(A, src[:m,:].T)

    return T, distances, i

def rotation_matrix(axis, theta):
    axis = axis/np.sqrt(np.dot(axis, axis))
    a = np.cos(theta/2.)
    b, c, d = -axis*np.sin(theta/2.)

    return np.array([[a*a+b*b-c*c-d*d, 2*(b*c-a*d), 2*(b*d+a*c)],
                  [2*(b*c+a*d), a*a+c*c-b*b-d*d, 2*(c*d-a*b)],
                  [2*(b*d-a*c), 2*(c*d+a*b), a*a+d*d-b*b-c*c]])


import numpy as np

def chirp1d_1():
    h = np.zeros(128)
    for t in range(64):
        h[t] = np.cos(2.0 * np.pi * t * 6.0 / 128.0)
    for t in range(64, 128):
        h[t] = np.cos(2.0 * np.pi * t * 25.0 / 128.0)
    for t in range(20, 30):
        h[t] += 0.5 * np.cos(2.0 * np.pi * t * 52.0 / 128.0)
    return h

def chirp1d_2():
    h = np.zeros(256)
    for t in range(256):
        h[t] = np.cos(2.0 * np.pi * (10.0 + t / 7.0) * t / 256.0) + np.cos(
            2.0 * np.pi * (256.0 / 2.8 - t / 6.0) * t / 256.0
        )
    for t in range(114, 122):
        h[t] += np.cos(2.0 * np.pi * t * 0.42)
    for t in range(134, 142):
        h[t] += np.cos(2.0 * np.pi * t * 0.42)
    return h

def chirp2d():
    h = np.zeros((64, 16))
    for x in range(64):
        h[x, :] = 10.0 * np.cos(2.0 * np.pi * 4.0 * x / 64.0)
    for x in range(33):
        h[x, :] += 10.0 * np.cos(2.0 * np.pi * 24.0 * x / 64.0)
    for x in range(33, 64):
        h[x, :] += 10.0 * np.cos(2.0 * np.pi * 10.0 * x / 64.0)
    return h

if __name__ == "__main__":
    import sys

    assert len(sys.argv) == 2, "missing signal identifier"
    h = {"1d-1": chirp1d_1, "1d-2": chirp1d_2, "2d": chirp2d}[sys.argv[1]]()
    np.savetxt(sys.stdout.buffer, h, fmt="%11.6f")


import numpy as np

def euclidean_norm(vectorList, listP, listQ):
    """Calculates the euclidean norm (distance) of two array-like objects, in this case vectors
    Args:
        listP (integer list): List of indices of the reference vector of the\
        array.
        list_comp (integer list): list of indices of vectors to compare to\
        data (numpy array): Data object with vectors to be analyzed.
    Returns:
        numpy array: The L2 norm (euclidean distance) between the P vectors and\
        Q vectors.
    """
    distanceArray = np.zeros(len(listP))
    for i in range(0, len(listP)):
        distanceArray[i] = np.linalg.norm(vectorList[listQ[i]] - vectorList[listP[i]])
    return distanceArray


import numpy as np
import cv2
import random
from time import time
from numba import jit

@jit(nopython=True)
def line_draw(startXY, endXY):
    xy = []
    if (endXY[0] - startXY[0]) is not 0:
        slope = (endXY[1] - startXY[1]) / (endXY[0] - startXY[0])
        if slope >= 0:
            # Case in which starting x and y are smaller than end x and y
            if endXY[0] > startXY[0]:
                # In this case we try to estimate to get increment X and find Y or vice versa
                if abs(endXY[0] - startXY[0]) >= abs(endXY[1] - startXY[1]):  # Add X
                    for i in range(startXY[0], endXY[0]):
                        y = startXY[1] + slope * (i - startXY[0])
                        xy.append(tuple((int(round(i)), int(round(y)))))
                        # cv2.circle(canvas, tuple((int(round(i)), int(round(y)))), 1, (128, 255, 255), -1)
                else:
                    for i in range(startXY[1], endXY[1]):
                        x = startXY[0] + (1 / slope) * (i - startXY[1])
                        xy.append(tuple((int(round(x)), int(round(i)))))
                        # cv2.circle(canvas, tuple((int(round(x)), int(round(i)))), 1, (128, 255, 255), -1)
            else:
                if abs(endXY[0] - startXY[0]) >= abs(endXY[1] - startXY[1]):  # Add X
                    for i in range(endXY[0], startXY[0]):
                        y = startXY[1] + slope * (i - startXY[0])
                        xy.append(tuple((int(round(i)), int(round(y)))))
                        # cv2.circle(canvas, tuple((int(round(i)), int(round(y)))), 1, (128, 255, 255), -1)
                else:
                    for i in range(endXY[1], startXY[1]):
                        x = startXY[0] + (1 / slope) * (i - startXY[1])
                        xy.append(tuple((int(round(x)), int(round(i)))))
                        # cv2.circle(canvas, tuple((int(round(x)), int(round(i)))), 1, (128, 255, 255), -1)
        else:
            if endXY[0] < startXY[0]:
                if abs(endXY[0] - startXY[0]) >= abs(endXY[1] - startXY[1]):  # Add X
                    for i in range(endXY[0], startXY[0]):
                        y = startXY[1] + slope * (i - startXY[0])
                        xy.append(tuple((int(round(i)), int(round(y)))))
                        # cv2.circle(canvas, tuple((int(round(i)), int(round(y)))), 1, (128, 255, 255), -1)
                else:
                    for i in range(startXY[1], endXY[1]):
                        x = startXY[0] + (1 / slope) * (i - startXY[1])
                        xy.append(tuple((int(round(x)), int(round(i)))))
                        # cv2.circle(canvas, tuple((int(round(x)), int(round(i)))), 1, (128, 255, 255), -1)
            else:
                if abs(endXY[0] - startXY[0]) >= abs(endXY[1] - startXY[1]):  # Add X
                    for i in range(startXY[0], endXY[0]):
                        y = startXY[1] + slope * (i - startXY[0])
                        xy.append(tuple((int(round(i)), int(round(y)))))
                        # cv2.circle(canvas, tuple((int(round(i)), int(round(y)))), 1, (128, 255, 255), -1)
                else:
                    for i in range(endXY[1], startXY[1]):
                        x = startXY[0] + (1 / slope) * (i - startXY[1])
                        xy.append(tuple((int(round(x)), int(round(i)))))
                        # cv2.circle(canvas, tuple((int(round(x)), int(round(i)))), 1, (128, 255, 255), -1)
    elif endXY[0] - startXY[0] is 0:
        if endXY[1] > startXY[1]:
            for i in range(startXY[1], endXY[1]):
                xy.append(tuple((int(round(startXY[0])), int(round(i)))))
                # cv2.circle(canvas, tuple((int(round(startXY[0])), int(round(i)))), 1, (128, 255, 255), -1)
        else:
            for i in range(endXY[1], startXY[1]):
                xy.append(tuple((int(round(startXY[0])), int(round(i)))))
                # cv2.circle(canvas, tuple((int(round(startXY[0])), int(round(i)))), 1, (128, 255, 255), -1)
    return xy

if __name__ == "__main__":
    for i in range(0, 100):
        canvas = np.zeros((800, 800, 3), dtype=np.uint8)
        start_coordinates = (random.randint(0, 800), random.randint(0, 800))
        end_coordinates = (random.randint(0, 800), random.randint(0, 800))
        # list_of_start_coordinates = [(116, 641)]
        # list_of_end_coordinates = [(299, 639)]
        tic = time()
        coordinates = line_draw(start_coordinates, end_coordinates)
        print(time()-tic)
        cv2.circle(canvas, tuple(start_coordinates), 1, (0, 0, 255), 10)
        cv2.circle(canvas, tuple(end_coordinates), 1, (0, 0, 255), 10)
        for items in coordinates:
            cv2.circle(canvas, tuple(items), 1, (128, 255, 255), -1)
        #     OpenCV draw line
        tic = time()
        cv2.line(canvas, start_coordinates, end_coordinates, (255, 0, 255), 1)
        print(time()-tic)
        cv2.imshow("WINDOW_NAME_PARTICLES", canvas)
        cv2.waitKey(1000)


# -*- coding: utf-8 -*-
"""Intergral-atv2.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1caFaNxwvShBNHFVQvbFLeNqzJvhV-No-
"""

import numpy as np
import matplotlib.pyplot as plt

# Integral pelo traapézio

def int_trap(func, a, b, n):
  '''Calcula a integral de uma função entre os limites a e b pela área de n
  trapézios.
  func: função analítica
  a, b: limites inferior e superior
  n: número de secções da área sob a função
  '''
  dx = (b - a)/n
  sdx = (func(a) + func(b))/2
  for i in range(1, n):
    sdx += func(a + i*dx)
  return sdx*dx

# Método de Simpson

def int_simpson(fx, a, b, n):
  '''Integração pelo Método de Simpson.
  fx: função a ser integrada
  a, b: limites inferior e superior para a integração
  n: número de secções da área integrada
  return: o valor da integral definida de fx
  '''
  if n % 2 != 0:
    n += 1
  h = (b-a)/n
  x = list(a+(j*h) for j in range(n+1))
  si = 4*sum(map(fx, x[1:n:2]))
  sp = 2*sum(map(fx, x[2:n-1:2]))
  return (h/3)*(fx(a) + fx(b) + si + sp)

fx = lambda x: x**5 + 3*x + 5
print(int_simpson(fx, 0, 1, 1000))
print(int_trap(fx, 0, 1, 1000))

"""#Atividade 2"""

def int_simpson(fx, a, b, n):
  '''Integração pelo Método de Simpson.
  fx: função a ser integrada
  a, b: limites inferior e superior para a integração
  n: número de secções da área integrada
  return: o valor da integral definida de fx
  '''
  if n % 2 != 0:
    n += 1
  h = (b-a)/n
  x = list(a+(j*h) for j in range(n+1))
  si = 4*sum(map(fx, x[1:n:2]))
  sp = 2*sum(map(fx, x[2:n-1:2]))
  return (h/3)*(fx(a) + fx(b) + si + sp)

def bessel(m, x):
  pi = np.pi
  fx = lambda th: np.cos(m*th - x*np.sin(th))
  return (1/pi)*int_simpson(fx, 0, pi, 1000)

xi = np.linspace(0, 20, 100)
y0 = bessel(0, xi)
y1 = bessel(1, xi)
y2 = bessel(2, xi)

plt.plot(xi, y0, 'k', label=r'$J_{0}(x)$')
plt.plot(xi, y1, 'b', label=r'$J_{1}(x)$')
plt.plot(xi, y2, 'g', label=r'$J_{2}(x)$')
plt.legend()
plt.grid()
plt.xlim(0, 20)
plt.show()

def intdif(l, r):
  pi = np.pi
  k = (2*pi)/l
  return (bessel(1, k*r)/(k*r))**2

r = np.linspace(-1e-6, 1e-6, 1000)
yi = intdif(450e-9, r)

plt.plot(r, yi, 'g', label='I(r)')
plt.legend()
plt.xlim(-1e-6, 1e-6)
plt.grid()
plt.show()

x = np.linspace(-1e-6, 1e-6, 100)
y = np.linspace(-1e-6, 1e-6, 100)
xx, yy = np.meshgrid(x, y)
mr = lambda i, j: ((i**2) + (j**2))**(1/2)

plt.imshow(intdif(450e-9, mr(xx, yy)), cmap='viridis', vmax=0.01)
plt.axis('off')
plt.colorbar()
plt.show()


# Necessary libraries
import os
import numpy as np
import pandas as pd
from matplotlib import cm
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

# Set Up Environment, import data
os.chdir('C:/Users/ntell/Documents/GitHub/Stanford-ML-Coursera')
data = pd.read_csv('Week 2 - Linear Regression with Multiple Variables/MATLAB/ex1data1.txt', header = None)

# Separate out X and y, store as NumPy arrays
X = data.iloc[:, 0].to_numpy()
y = data.iloc[:, 1].to_numpy()

# Visualize the data
plotData(X, y)

# Implementation of Gradient Descent
m = len(X) # number of examples
X = np.concatenate([np.expand_dims(np.ones(m), axis = 1),
                    np.expand_dims(X, axis = 1)], axis = 1) # add column for intercepts
theta = np.zeros([2, 1]) # Initializing Fitting Parameters
iterations = 1500
alpha = 0.01

computeCost(X, y, theta)
computeCost(X, y, np.array([-1, 2]).reshape(2, 1))

# Run gradient descent
theta, J_history = gradientDescent(X, y, theta, alpha, iterations)

# Plot the linear fit
plt.scatter(X[:, 1], y, c = 'red', marker = 'x', label = 'Training Data')
plt.plot([np.min(X[:, 1]), np.max(X[:, 1])],
         [np.min(X @ theta), np.max(X @ theta)],
         c = 'blue', label = 'Linear Regression')
plt.xlabel('Population of City in 10,000s')
plt.ylabel('Profit in $10,000s')

# Predictions
predict1 = ((np.array([1, 3.5]) @ theta) * 10000)[0]
print('For a population of 35k, we predict a profit of: %8.2f' % predict1)

predict2 = ((np.array([1, 7]) @ theta) * 10000)[0]
print('For a population of 35k, we predict a profit of: %8.2f' % predict2)

# Visualize J(theta), with 2 features instead of 1
theta0 = np.linspace(-10, 10, 100)
theta1 = np.linspace(-1, 4, 100)

# Empty matrix to hold the costs for every permutation of thetas
J_vals = np.zeros([len(theta0), len(theta1)])

# Fill out J
for i in range(len(theta0)):
    for j in range(len(theta1)):
        t = np.expand_dims(np.array([theta0[i], theta1[j]]), axis = 1)
        J_vals[i, j] = computeCost(X, y, t)

theta0, theta1 = np.meshgrid(theta0, theta1)

# Make into 3D Plot
fig = plt.figure()
ax = fig.gca(projection = '3d')
surf = ax.plot_surface(theta1, theta0, J_vals, cmap = cm.coolwarm,
                       linewidth = 0, antialiased = False)

# Contour plot
fig, ax = plt.subplots()
CS = ax.contour(theta0, theta1, J_vals)
plt.scatter(theta[0], theta[1], marker = 'x', c = 'red')
plt.xlabel(r'$\theta_0$')
plt.ylabel(r'$\theta_1$')

Week 2 - Linear Regression with Multiple Variables/Python_Scratch/Exercise1.py


#!/bin/python
import argparse
import numpy as np
from cluster import read_csv, plot_clusters, distance

def kmeans_chosen(data, centers):
    def best_cluster(p):
        distances = [distance(p, c) for c in centers]
        return np.argmin(distances)
    return np.apply_along_axis(best_cluster, 1, data)

def random_point(pmin, pmax):
    return pmin + np.random.random_sample((2,)) * (pmax - pmin)

def kmeans(data, k, EPS=1e-9, iterations=1000, verbose=True):
    pmax = np.max(data, axis=0)
    pmin = np.min(data, axis=0)
    centers = np.array([random_point(pmin, pmax) for c in range(k)])
    eps = np.inf
    it = 0
    while eps > EPS and it < iterations:
        it += 1
        chosen = kmeans_chosen(data, centers)
        while len(set(chosen)) < k:
            for c in range(k):
                if np.count_nonzero(chosen == c) == 0:
                    centers[c] = random_point(pmin, pmax)
            chosen = kmeans_chosen(data, centers)
        new_centers = np.array([np.mean(data[chosen == c, :], axis=0) for c in range(k)])
        eps = distance(centers, new_centers)
        assert(new_centers.shape == centers.shape)
        centers = new_centers
        if verbose:
            print "eps = ", eps
    return chosen

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="run k-means clusterization with given arguments")
    parser.add_argument("-f", dest="filename", type=str, required=True)
    parser.add_argument("-k", dest="clusters", type=int, required=True)
    args = parser.parse_args()
    data = read_csv(args.filename)
    result = kmeans(data, args.clusters)
    plot_clusters(data, result)


"""
Solve least square function
Ref: https://docs.scipy.org/doc/scipy/reference/tutorial/optimize.html#least-squares-minimization-least-squares
"""

import numpy as np
from scipy.optimize import least_squares
import util

def model(x, u):
    return x[0] * (u**2 + x[1] * u) / (u**2 + u * x[2] + x[3])

def cost_fun(x, u, y):
    return model(x, u) - y

def jac(x, u, y):
    J = np.empty((u.size, x.size))
    den = u**2 + u * x[2] + x[3]
    num = u**2 + u * x[1]
    J[:, 0] = num / den
    J[:, 1] = u * x[0] / den
    J[:, 2] = -u * x[0] * num / den**2
    J[:, 3] = -x[0] * num / den**2
    return J

def solve_least_square():
    print(util.Section('Solve Least Square'))
    u = np.array([4.0, 2.0, 1.0, 5.0e-1, 2.5e-1, 1.67e-1, 1.25e-1, 1.0e-1, 8.33e-2, 7.14e-2, 6.25e-2])
    y = np.array([1.957e-1, 1.947e-1, 1.735e-1, 1.6e-1, 8.44e-2, 6.27e-2, 4.56e-2, 3.42e-2, 3.23e-2, 2.35e-2, 2.46e-2])
    x0 = np.array([2.5, 3.9, 4.15, 3.9])
    res = least_squares(cost_fun, x0, jac=jac, bounds=(0, 100), args=(u, y), verbose=2)
    print(f'Result: {res.x}')

if __name__ == '__main__':
    solve_least_square()


import matplotlib.pyplot as plt
import numpy as np

X = np.loadtxt('datos.dat')
x_obs = X[:,0]
y_obs = X[:,1]

plt.scatter(x_obs, y_obs)
plt.show()
plt.close()

def likelihood(y_obs, y_model):
	chi_squared = 1.0/2.0 * sum((y_obs - y_model)**2)
	#return np.exp(-chi_squared)
	return chi_squared

def my_model(x_obs, a, b, c):
	return a*x_obs**2 + b*x_obs + c

a_walk = np.empty(0)
b_walk = np.empty(0)
c_walk = np.empty(0)
l_walk = np.empty(0)

a_walk = np.append(a_walk, np.random.random())
b_walk = np.append(b_walk, np.random.random())
c_walk = np.append(c_walk, np.random.random())

y_init = my_model(x_obs, a_walk[0], b_walk[0], c_walk[0])
l_walk = np.append(l_walk, likelihood(y_obs, y_init))

n_iterations = 20000
for i in range(n_iterations):
	a_prime = np.random.normal(a_walk[i], 0.2)
	b_prime = np.random.normal(b_walk[i], 0.2)
	c_prime = np.random.normal(c_walk[i], 0.2)

	y_init = my_model(x_obs, a_walk[i], b_walk[i], c_walk[i])
	y_prime = my_model(x_obs, a_prime, b_prime, c_prime)

	l_prime = likelihood(y_obs, y_prime)
	l_init = likelihood(y_obs, y_init)

	alpha = np.exp(-(l_prime - l_init))
	if(alpha >= 1.0):
		a_walk = np.append(a_walk, a_prime)
		b_walk = np.append(b_walk, b_prime)
		c_walk = np.append(c_walk, c_prime)
		l_walk = np.append(l_walk, l_prime)

	else:
		beta =  np.random.random()
		if(beta <= alpha):
			a_walk = np.append(a_walk, a_prime)
			b_walk = np.append(b_walk, b_prime)
			c_walk = np.append(c_walk, c_prime)
			l_walk = np.append(l_walk, l_prime)
		else:
			a_walk = np.append(a_walk, a_walk[i])
			b_walk = np.append(b_walk, b_walk[i])
			c_walk = np.append(c_walk, c_walk[i])
			l_walk = np.append(l_walk, l_init)

max_likelihood_index = np.argmax(l_walk[int(n_iterations/2.0):])
best_a = a_walk[max_likelihood_index]
best_b = b_walk[max_likelihood_index]
best_c = c_walk[max_likelihood_index]

print(best_a, best_b, best_c)
y_best = my_model(x_obs, best_a, best_b, best_c)

# plt.scatter(x_obs, y_obs)
# plt.plot(x_obs, y_best)
# plt.show()
# plt.close()

# plt.plot(l_walk)
# plt.show()
# plt.close()

# #Shows histograms
# hist_data_a = plt.hist(a_walk, bins = 30)
# plt.show()
# plt.close()
# hist_data_b = plt.hist(b_walk, bins = 30)
# plt.show()
# plt.close()
# hist_data_c = plt.hist(c_walk, bins = 30)
# plt.show()
# plt.close()


"""This module contains the mathematical formulas to calculate several
stock indicators
"""

__author__ = 'Andres Beltran'
__version__ = '1.0'

import numpy as np

def movingaverage(values, window):
    """Calculates a Simple Moving Average
    Args:
        values (int): The integer value of the current moving average
        window (int): The window used to calculate the current moving average
    Returns:
        int: The Moving Average with the specified values
    """
    weights = np.repeat(1.0, window)/window
    smas = np.convolve(values, weights, 'valid')
    return smas

def rsi_function(prices, period=14):
    """Calculates the Relative Strength Index (RSI)
    Args:
        prices ([int]): The integer value of the current moving average
        period (int): The number of data points used to calculate the RSI
    Returns:
        [int]: The list containg the values for the RSI
    """
    deltas = np.diff(prices)
    seed = deltas[:period+1]
    up = seed[seed >= 0].sum()/period
    down = -seed[seed < 0].sum()/period
    rs = up/down
    rsi = np.zeros_like(prices)
    rsi[:period] = 100. - 100./(1. + rs)

    for i in range(period, len(prices)):
        delta = deltas[i-1]
        if delta > 0:
            upval = delta
            downval = 0.
        else:
            upval = 0.
            downval = -delta

        up = (up*(period-1)+upval)/period
        down = (down*(period-1)+downval)/period
        rs = up/down
        rsi[i] = 100. - 100./(1.+rs)

    return rsi


import numpy as np
import copy

num_state = 2
num_action = 2

# value iteration

p_1 = np.array(
    [
        [3 / 4, 1 / 4],
        [3 / 4, 1 / 4]
    ]
)
p_2 = np.array(
    [
        [1 / 4, 3 / 4],
        [1 / 4, 3 / 4]
    ]
)
r = np.array(
    [
        [-2, -0.5],
        [-1, -3]
    ]
)
transition = np.array([p_1, p_2])

def value_iteration(s_bar):
    bias = -100 * np.ones([num_state])
    _bias = np.zeros_like(bias)
    while np.sum((bias - _bias) ** 2 > 0.000001) != 0:
        _bias = copy.deepcopy(bias)
        bias_max = np.ones(num_state) * (-np.inf)
        for s in range(num_state):
            for a in range(num_action):
                bias_max[s] = \
                    max(bias_max[s], r[s, a] +
                        np.sum(transition[a, s] * bias))
        bias = bias_max - bias_max[s_bar]
        gain = bias_max[s_bar]
        bias = bias - bias[s_bar]

    policy = [np.argmax(
        r[s] +
        np.reshape(
            np.matmul(transition[:, s], np.reshape(bias, [num_state, 1])),
            -1
        )
    ) for s in range(num_state)]

    return gain, bias, np.array(policy)

def policy_iteration(s_bar):
    policy = np.array([0, 1])
    bias = -100 * np.ones([num_state])
    _bias = np.zeros_like(bias)
    for _ in range(10):
        transition_pi = np.zeros([num_state, num_state])
        for i in range(num_state):
            for j in range(num_state):
                transition_pi[i, j] = transition[pi[i], i, j]
        reward_pi = np.zeros([num_state])

        for i in range(num_state):
            reward_pi[i] = r[i, pi[i]]

        while np.sum((bias - _bias) ** 2 > 0.000001) != 0:
            _bias = copy.deepcopy(bias)
            new_bias = [reward_pi[s] + np.sum(transition_pi[:, s] * bias)
                        for s in range(num_state)]
            new_bias = np.array(new_bias)
            bias = new_bias - new_bias[s_bar]
            gain = new_bias[s_bar]

        policy = [np.argmax(
            r[s] +
            np.reshape(
                np.matmul(transition[:, s], np.reshape(bias, [num_state, 1])),
                -1
            )
        ) for s in range(num_state)]

    return gain, bias, np.array(policy)

if __name__ == '__main__':
    g, h, pi = value_iteration(0)
    print(g, h, pi)

    # pi iteration
    g, h, pi = policy_iteration(0)
    print(g, h, pi)

# -0.75048828125 [ 0.         -0.33300781] [1 0]
# -0.7500000011634711 [ 0.         -0.33333333] [1 0]


# =============================================================================
#  ***** num_integration.py *****
#  Python script to plot numerical integration information.
#
#  Author:     Ryan Clement
#  Created:    July 2021
#
#  Change Log:
#  Who:
#  Date:       MM/DD/YYY
#  What:
#
#  Who:
#  Date:       MM/DD/YYYY
#  What:
# =============================================================================

import numpy as np
from matplotlib import pyplot as plt
from matplotlib.patches import Rectangle

def parabola(x):
    return 1.0 + x**2

def solveExact(a,b):
    result = (3*b + b**3 - 3.0*a - a**3)/3.0
    print(f"Exact: {result:.5f}")
    return result

def solveLeftRectangleRule(a,b,n):
    dx = (b-a)/(n-1)
    xPoints = np.linspace(a,b-dx,n-1)
    yPoints = parabola(xPoints)
    result = dx*np.sum(yPoints)
    print(f'Left end-point rectangle rule (LR): {result:.5f}')
    return result

def solveRightRectangleRule(a,b,n):
    dx = (b-a)/(n-1)
    xPoints = np.linspace(a+dx,b,n-1)
    yPoints = parabola(xPoints)
    result = dx*np.sum(yPoints)
    print(f'Right end-point rectangle rule (RR): {result:.5f}')
    return result

def solveTrapezoidRule(a,b,n):
    dx = (b-a)/(2.0*(n-1))
    xPoints = np.linspace(a,b,n)
    yPoints = parabola(xPoints)
    result = dx*np.sum(yPoints[:-1] + yPoints[1:])
    print(f'Trapezoid rule (TR): {result:.5f}')
    return result

def solveSimpsonsRule(a,b,n):
    dx = (b-a)/(3.0*(n-1))
    x = np.linspace(a,b,n)
    y = np.array([1.0 + (i)**2 for i in x])
    result = dx*(y[0]+y[-1]+4.0*np.sum(y[1:-1:2])+2.0*np.sum(y[2:-1:2]))
    print(f"Simpson's rule (SR): {result:.5f}")
    return result

def plotLeftRectangleRule(a,b,n):
    dx = (b-a)/(n-1)
    xPoints = np.linspace(a,b,n)
    yPoints = parabola(xPoints)
    xSmooth = np.linspace(a,b,10*(n))
    ySmooth = parabola(xSmooth)
    # Plot Left Rect.
    figLR, axLR = plt.subplots()
    axLR.set_title(r'Parabola: $y = 1 + x^2$')
    axLR.set_xlabel('x')
    axLR.set_ylabel('y')
    axLR.set_xticks(xPoints)
    axLR.fill_between(xSmooth,0,ySmooth,color='salmon')
    for i in range(n-1):
        axLR.add_patch(Rectangle((xPoints[i],0),dx,yPoints[i],
                      edgecolor='navy',
                      facecolor='cornflowerblue'))
    axLR.plot(xPoints, yPoints, 'o', color='red')
    axLR.plot(xSmooth, ySmooth, color='red')
    # figLR.savefig('parabola_LeftRect.png')

def plotRightRectangleRule(a,b,n):
    dx = (b-a)/(n-1)
    xPoints = np.linspace(a,b,n)
    yPoints = parabola(xPoints)
    xSmooth = np.linspace(a,b,10*n)
    ySmooth = parabola(xSmooth)
    figRR, axRR = plt.subplots()
    axRR.set_title(r'Parabola: $y = 1 + x^2$')
    axRR.set_xlabel('x')
    axRR.set_ylabel('y')
    axRR.set_xticks(xPoints)
    for i in range(n-1):
        axRR.add_patch(Rectangle((xPoints[i],0),dx,yPoints[i+1],
                      edgecolor='navy',
                      facecolor='cornflowerblue'))
    axRR.plot(xPoints, yPoints, 'o', color='red')
    axRR.plot(xSmooth, ySmooth, color='red')
    # figRR.savefig('parabola_RightRect.png')

def plotTrapezoidRule(a,b,n):
    xPoints = np.linspace(a,b,n)
    yPoints = parabola(xPoints)
    xSmooth = np.linspace(a,b,10*n)
    ySmooth = parabola(xSmooth)
    figT, axT = plt.subplots()
    axT.set_title(r'Parabola: $y = 1 + x^2$')
    axT.set_xlabel('x')
    axT.set_ylabel('y')
    axT.set_xticks(xPoints)
    for i in range(n-1):
        axT.fill_between(xPoints,0,yPoints,color='cornflowerblue')
        axT.plot(xPoints[i:i+2],yPoints[i:i+2],color='navy')
        axT.plot((xPoints[i],xPoints[i]),(0,yPoints[i]),color='navy')
    axT.plot((xPoints[-1],xPoints[-1]),(0,yPoints[-1]),color='navy')
    axT.plot(xPoints, yPoints, 'o', color='red')
    axT.plot(xSmooth, ySmooth, color='red')
    # figT.savefig('parabola_trapezoid.png')

if __name__ == '__main__':
    a = 0.0 # Left Boundary
    b = 4.0 # Right Boundary
    n = 5   # Number of points
    plotLeftRectangleRule(a,b,n)
    plotRightRectangleRule(a,b,n)
    plotTrapezoidRule(a,b,n)
    ansLR = solveLeftRectangleRule(a,b,n)
    ansRR = solveRightRectangleRule(a,b,n)
    ansTR = solveTrapezoidRule(a,b,n)
    ansSR = solveSimpsonsRule(a,b,n)
    ansE  = solveExact(a,b)
    print('LR % err: {:.5f}%'.format(abs((ansLR-ansE)/ansE)*100))
    print('RR % err: {:.5f}%'.format(abs((ansRR-ansE)/ansE)*100))
    print('TR % err: {:.5f}%'.format(abs((ansTR-ansE)/ansE)*100))
    print('SR % err: {:.5f}%'.format(abs((ansSR-ansE)/ansE)*100))


from  matplotlib import pyplot as plt
from math import exp, acos, log10
import numpy as np
from sympy import Symbol, integrate, exp, oo
import random

# function for the trapezoidal rule
def TrapezoidalRule(a,b,f,n):
   h = (b-a)/float(n)
   s = 0
   x = a
   for i in range(1,n,1):
       x = x+h
       s = s+ f(x)
   s = 0.5*(f(a)+f(b))+s
   return h*s
# function to perform the Monte Carlo calculations
def MonteCarloIntegration(f,n):
    sum = 0
# Define the seed for the rng
    random.seed()
    for i in range (1, n, 1):
        x = random.random()
        sum = sum +f(x)
    return sum/n

#  function to compute
def function(x):
    return 4/(1+x*x)

# Integration limits for the Trapezoidal rule
a = 0.0; b = 1.0
# define x as a symbol to be used by sympy
x = Symbol('x')
# find result from sympy
#exact = integrate(function(x), (x, a, b))
exact = acos(-1.0)
# set up the arrays for plotting the relative error
log10n = np.zeros(6); Trapez = np.zeros(6); MCint = np.zeros(6);
# find the relative error as function of integration points
for i in range(1, 6):
    npts = 10**(i+1)
    log10n[i] = log10(npts)
    Trapez[i] = log10(abs((TrapezoidalRule(a,b,function,npts)-exact)/exact))
    MCint[i] = log10(abs((MonteCarloIntegration(function,npts)-exact)/exact))
plt.plot(log10n, Trapez ,'b-',log10n, MCint,'g-')
plt.axis([1,6,-14.0, 0.0])
plt.xlabel('$\log_{10}(n)$')
plt.ylabel('Relative error')
plt.title('Relative errors for Monte Carlo integration and Trapezoidal rule')
plt.legend(['Trapezoidal rule', 'Brute force Monte Carlo integration'], loc='best')
plt.savefig('mcintegration.pdf')
plt.show()


"""Machine Learning Related Functions.

Author: Yuhuang Hu
Email : yuhuang.hu@ini.uzh.ch
"""
from __future__ import print_function, absolute_import

import numpy as np

def pca(X, n_components=None, p_var_retained=None):
    """Perform PCA on X.

    # Parameters
    X : np.ndarray
        an array of data with (N x num of features)
    n_components : int
        number of components retained
    p_var_retained : float
        percentage of variance retained
        (0 <= p_var_retained <= 1)

    # Returns
    X_reduce : np.ndarray
        the array with reduced dimension.
    R : np.ndarray
        the rotation matrix
    n_retained : np.ndarray
        number of dimensions retained
    """
    n_dim = X.shape[1]
    n_samples = X.shape[0]
    if n_components is not None:
        assert 1 <= n_components <= n_dim
    if p_var_retained is not None:
        assert 0 < p_var_retained <= 1
    else:
        p_var_retained = 0.99

    # compute covariance matrix
    sigma = 1./n_samples*(X.T.dot(X))

    # SVD - find eigen values and vectors
    u, s, v = np.linalg.svd(sigma)

    # transpose
    X_trans = X.dot(u)

    # determine number of components retained
    if n_components is not None:
        n_retained = n_components
    else:
        acc_eig_vals = np.cumsum(s)/np.sum(s)
        n_retained = np.where(acc_eig_vals > p_var_retained)[0][0]
        n_retained = n_retained+1 if n_retained == 0 else n_retained

    # select
    X_reduce = X_trans[:, :n_retained]

    return X_reduce, u, n_retained

def pca_fit(X, R, n_components=None):
    """Perform PCA on X with rotation matrix R.

    # Parameters
    X : np.ndarray
        an array of data with (N x num of features)
    R : np.ndarray
        an rotation matrix
    n_components : int
        number of components retained

    # Returns
    X_reduce : np.ndarray
        the array with reduced dimension.
    """
    n_dim = X.shape[1]
    if n_components is not None:
        assert n_components <= n_dim

    # transpose
    X_trans = X.dot(R)

    # select
    X_reduce = X_trans[:, :n_components]

    return X_reduce


# Copyright 2021 CR.Sparse Development Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Discrete Cosine Transforms

Adapted from:

* http://www-personal.umich.edu/~mejn/computational-physics/dcst.py
* https://dsp.stackexchange.com/questions/2807/fast-cosine-transform-via-fft
"""

from jax import jit
import jax.numpy as jnp
import jax.numpy.fft as jfft

def dct(y):
    """Computes the 1D Type-II DCT transform

    Args:
        y (jax.numpy.ndarray): The 1D real signal

    Returns:
        jax.numpy.ndarray: The Type-II Discrete Cosine Transform coefficients of y
    """
    n = y.shape[0]
    y2 = jnp.concatenate( (y[:],  y[::-1]))
    c = jfft.rfft(y2, axis=0)[:n]
    ks = jnp.arange(n)
    phi = jnp.exp(-1j*jnp.pi*ks/(2*n))
    prod = (phi*c.T).T
    return jnp.real(prod)

def idct(a):
    """Computes the 1D Type-II Inverse DCT transform

    Args:
        a (jax.numpy.ndarray): The Type-II DCT transform coefficients of a 1D real signal

    Returns:
        jax.numpy.ndarray: The 1D real signal y s.t. a = dct(y)
     """
    n = a.shape[0]
    shape = (1,)+a.shape[1:]
    ks = jnp.arange(n)
    phi = jnp.exp(1j*jnp.pi*ks/(2*n))
    upper = (phi*a.T).T
    lower = jnp.zeros(shape)
    c = jnp.concatenate((upper, lower))
    return jfft.irfft(c, axis=0)[:n]

def orthonormal_dct(y):
    """Computes the 1D Type-II DCT transform such that the transform is orthonormal

    Args:
        y (jax.numpy.ndarray): The 1D real signal

    Returns:
        jax.numpy.ndarray: The orthonormal Type-II Discrete Cosine Transform coefficients of y

    Orthonormality ensures that

    .. math::

        \\langle a, a \\rangle = \\langle y, y \\rangle
    """
    n = y.shape[0]
    factor = jnp.sqrt(1/(2*n))
    ks = jnp.arange(n)
    phi = jnp.exp(-1j*jnp.pi*ks/(2*n))
    # scaling to make the transform orthonormal
    phi = phi.at[0].set(phi[0]*1/jnp.sqrt(2))
    phi = phi * factor

    y2 = jnp.concatenate( (y[:],  y[::-1]))
    c = jfft.rfft(y2, axis=0)[:n]
    prod = jnp.real(phi*c.T).T
    # phi = phi*jnp.sqrt(2)/n
    return prod

def orthonormal_idct(a):
    """Computes the 1D Type-II IDCT transform such that the transform is orthonormal

    Args:
        a (jax.numpy.ndarray): The orthonormal Type-II DCT transform coefficients of a 1D real signal

    Returns:
        jax.numpy.ndarray: The 1D real signal y s.t. a = orthonormal_dct(y)
    """
    n = a.shape[0]
    factor = jnp.sqrt(2*n)
    ks = jnp.arange(n)

    phi = jnp.exp(1j*jnp.pi*ks/(2*n))
    # scaling to make the transform orthonormal
    phi = phi*factor
    phi = phi.at[0].set(phi[0]*jnp.sqrt(2))

    upper = (phi*a.T).T
    lower = jnp.zeros((1,)+a.shape[1:])
    c = jnp.concatenate((upper, lower))
    return jfft.irfft(c, axis=0)[:n]


import scipy as sp
import matplotlib.pyplot as plt

# Doc data tu file
data = sp.genfromtxt("./web_traffic.tsv", delimiter="\t")
print(data[:10])
print (data.shape)

# Tao 2 vector
# x la gio y la luu luong truy cap
####
x = data[:,0]
y = data[:,1]

# print(sp.sum(sp.isnan(y)))
# print(sp.isnan(y))

# Loai bo cac vi du NAN
x = x[~sp.isnan(y)]
y = y[~sp.isnan(y)]

# Ve do thi
plt.scatter(x,y)
plt.title("Luu luong truy cap web")
plt.xlabel("Thoi gian")
plt.ylabel("Truy cap/gio")
plt.xticks([w*7*24 for w in range(5)],['Tuan %i'%(w+1) for w in range(5)])
plt.autoscale(tight=True)
plt.grid()
# plt.show()

# Gia su hoc ham ax + b = y
# Trich rut ham bac nhat tu tap hoc
fp1, residuals, rank, sv, rcond = sp.polyfit(x, y, 1, full = True)
# [a, b]
print(fp1)

# Get ham so cua model
f1 = sp.poly1d(fp1)

# Dinh nghia ham error
def error(f, x, y):
	return sp.sum((f(x) - y)**2)

print (error(f1, x, y))

# Ve do thi
fx = sp.linspace(0, x[-1], 1000) # tao cac gia tri tren truc X
plt.plot(fx, f1(fx), linewidth=4)
plt.legend(["Bac = %i" % f1.order], loc = "upper left")
#plt.show()

f2p = sp.polyfit(x, y, 2)
print(f2p)
f2=sp.poly1d(f2p)
print(error(f2, x, y))
plt.plot(fx, f2(fx), 'r--', label = 'Bac = 2', linewidth=4)
plt.show()


import numpy as np

def to_onehot(labels, n_classes, dtype):
  n_dim = len(labels.shape)
  if n_dim == 2 and labels.shape[1] != 1:
    raise ValueError
  if n_dim > 2:
    raise ValueError
  n_samples = labels.size
  onehot = np.zeros((n_samples, n_classes), dtype=dtype)
  onehot[np.arange(n_samples), labels.flatten().astype(int)] = 1
  return onehot

class MeanCenterStdToOneNorm:

  def __init__(self, epsilon=1e-4):
    self.epsilon = epsilon
    self.mean = None
    self.std = None

  def fit(self, data):
    self.mean = data.mean(axis=0)
    self.std = np.sqrt(data.var(axis=0) + self.epsilon)

  def apply(self, data):
    r = (data - self.mean) / self.std
    if np.all(np.isfinite(r)):
      return r
    else:
      raise ValueError


import VorDiff.nodes.vector
#import vector
from VorDiff.autodiff import AutoDiff as ad
import numpy as np

x = ad.vector([1,2, 3, 4])
a = 6
b = 2

x1 = x[0]
x2 = x[1]
x3 = x[2]
x4 = x[3]

f1 = x1+x2
f2 = x2+x1
f3 = x1-x2
f4 = x2-x1
f5 = x3*x4
f6 = x4*x3
f7 = x1/x2
f8 = x2/x1

# Power functions
h1 = f1 ** b
h2 = b ** f1
h3 = x2 ** x3
h4 = x3 ** x2

# Equal or not equal
e1 = x1+x3
e2 = x3+x1
e3 = x2+x4
e4 = x4+x2

def test_addition():
    """test addition (x1+x2) for both value and derivative"""
    assert f1.get_val() == x1.get_val()+x2.get_val()
    assert f1.get_derivatives().all() == (x1.get_derivatives()+x2.get_derivatives()).all()
    """test addition (x2+x1) for both value and derivative"""
    assert f2.get_val() == x1.get_val()+x2.get_val()
    assert f2.get_derivatives().all() == (x1.get_derivatives()+x2.get_derivatives()).all()
    """test addition of function and constant for both value and derivative"""
    assert (f1+a).get_val() == f1.get_val()+a
    assert (f1+a).get_derivatives().all() == f1.get_derivatives().all()
    """test addition of constant and function for both value and derivative"""
    assert (a+f1).get_val() == f1.get_val()+a
    assert (a+f1).get_derivatives().all() == f1.get_derivatives().all()

test_addition()

def test_subtraction():
    """test subtraction (x1-x2) for both value and derivative"""
    assert f3.get_val() == x1.get_val()-x2.get_val()
    assert f3.get_derivatives().all() == (x1.get_derivatives()-x2.get_derivatives()).all()
    """test subtraction (x2-x1) for both value and derivative"""
    assert f4.get_val() == x2.get_val()-x1.get_val()
    assert f4.get_derivatives().all() == (x2.get_derivatives()-x1.get_derivatives()).all()
    """test subtraction of function and constant for both value and derivative"""
    assert (f1-a).get_val() == f1.get_val()-a
    assert (f1-a).get_derivatives().all() == f1.get_derivatives().all()
    """test subtraction of constant and function for both value and derivative"""
    assert (a-f1).get_val() == a-f1.get_val()
    assert (a-f1).get_derivatives().all() == (-f1.get_derivatives()).all()

test_subtraction()

def test_multiplication():
    """test multiplication (x3*x4) for both value and derivative"""
    assert f5.get_val() == x3.get_val()*x4.get_val()
    assert f5.get_derivatives().all() == (np.array([0,0,1,1])).all()
    """test multiplication (x4*x3) for both value and derivative"""
    assert f6.get_val() == x3.get_val()*x4.get_val()
    assert f6.get_derivatives().all() == (np.array([0,0,1,1])).all()
    """test multiplication of function and constant for both value and derivative"""
    assert (f2*a).get_val() == f2.get_val()*a
    assert ((f2*a).get_derivatives() == np.array([a, a, 0, 0])).all()
    """test multiplication of constant and function for both value and derivative"""
    assert (a*f3).get_val() == f3.get_val()*a
    assert ((a*f3).get_derivatives() == np.array([a, -a, 0, 0])).all()

test_multiplication()

def test_divide():
    """test division (x1/x2) for both value and derivative"""
    assert f7.get_val() == x1.get_val()/x2.get_val()
    assert f7.get_derivatives().all() == (np.array([1/2,-1/4,0,0])).all()
    """test division (x2/x1) for both value and derivative"""
    assert f8.get_val() == x2.get_val()/x1.get_val()
    assert f8.get_derivatives().all() == (np.array([-2,1,0,0])).all()
    """test division of function and constant for both value and derivative"""
    assert (x2/a).get_val() == x2.get_val()/a
    assert ((x2/a).get_derivatives() == np.array([0, 1/a, 0, 0])).all()
    """test division of constant and function for both value and derivative"""
    assert (a/x3).get_val() == a/x3.get_val()
    assert ((a/x3).get_derivatives() == np.array([0, 0, -a/9, 0])).all()

test_divide()

def test_pow():
    """test the function to the power of constant for both value and derivative"""
    assert h1.get_val() == f1.get_val()**b
    assert (h1.get_derivatives() == np.array([6, 6, 0, 0])).all()
    """test the constant to the power of function for both value and derivative"""
    assert h2.get_val() == b**f1.get_val()
    assert (h2.get_derivatives() == np.array([8*np.log(2), 8*np.log(2), 0, 0])).all()
    """test the value of function to the power of function (x2**x3) for both value and derivative"""
    assert h3.get_val() == x2.get_val()**x3.get_val()
    assert (np.round(h3.get_derivatives(),decimals=3) == np.round(np.array([0,8*3/2,8*np.log(2),0]),decimals=3)).all()
    """test the value of function to the power of function (x3**x2) for both value and derivative"""
    assert h4.get_val() == x3.get_val()**x2.get_val()
    assert (np.round(h4.get_derivatives(),decimals=3) == np.round(np.array([0,9*np.log(3),9*2/3,0]),decimals=3)).all()

test_pow()

def test_neg():
    """test negation (-f1) for both value and derivative"""
    assert (-f1).get_val() == -(f1.get_val())
    assert ((-f1).get_derivatives() == -(f1.get_derivatives())).all()

test_neg()

def test_equal():
    """test if two functions (e1, e2) are equal"""
    assert (e1 == e2) == True
    """test if two functions (e1, e3) are equal"""
    assert (e1 == e3) == False
    """test if a function and a constant (e1, a) are equal"""
    assert (e1 == a) == False

test_equal()

def test_notequal():
    """test if two functions (e3, e4) are not equal"""
    assert (e3 != e4) == False
    """test if two functions (e2, e4) are not equal"""
    assert (e2 != e4) == True
    """test if a function and a constant (e1, a) are not equal"""
    assert (e1 != a) == True

test_notequal()

# Define a vector function and get a jacobian of the vector function to vector

f = [f1, f2, f3, f4, f5]
derivatives = []
vals = []

for function in f:
    vals.append(function.get_val())
    derivatives.append(function.get_derivatives())

derivatives = np.array(derivatives)

def test_vectorFunctions():
    assert(vals == [3, 3, -1, 1, 12])
    assert(np.array_equal(derivatives, np.array([[1,1,0,0], [1,1,0,0], [1,-1,0,0], [-1,1,0,0], [0,0,4,3]])))

test_vectorFunctions()


import numpy.testing as npt
import pytest

from cued_sf2_lab.dct import *

class TestDctII:

    def test_basic(self):
        dct4 = dct_ii(4)
        npt.assert_allclose(dct4,
            [[0.5,      0.5,      0.5,      0.5    ],
             [0.65328,  0.27059, -0.27059, -0.65328],
             [0.5,     -0.5,     -0.5,      0.5    ],
             [0.27059, -0.65328,  0.65328, -0.27059]], atol=1e-5)

    @pytest.mark.xfail(raises=ZeroDivisionError)
    def test_zero(self):
        dct0 = dct_ii(0)
        assert dct0.shape == (0, 0)

    def test_one(self):
        dct1 = dct_ii(1)
        assert dct1.shape == (1, 1)
        npt.assert_allclose(dct1, 1)

class TestDCTIV:

    def test_basic(self):
        dct4 = dct_iv(4)
        npt.assert_allclose(dct4,
            [[ 0.69352 ,  0.587938,  0.392847,  0.13795 ],
             [ 0.587938, -0.13795 , -0.69352 , -0.392847],
             [ 0.392847, -0.69352 ,  0.13795 ,  0.587938],
             [ 0.13795 , -0.392847,  0.587938, -0.69352 ]], atol=1e-5)

    @pytest.mark.xfail(raises=ZeroDivisionError)
    def test_zero(self):
        dct0 = dct_iv(0)
        assert dct0.shape == (0, 0)

    def test_one(self):
        dct1 = dct_iv(1)
        assert dct1.shape == (1, 1)
        npt.assert_allclose(dct1, 1)

class TestRegroup:

    def check(self, x, y, m, n):
        assert x.shape == y.shape
        xm, xn = x.shape
        for xi in range(xm):
            i_div, i_mod = divmod(xi, m)
            yi = i_mod*(xm // m) + i_div
            for xj in range(xn):
                j_div, j_mod = divmod(xj, n)
                yj = j_mod*(xn // n) + j_div

                assert x[xi, xj] == y[yi, yj], (xi, xj, yi, yj)

    def test_roundtrip(self):
        x = np.arange(3*4*5*6).reshape(3*4, 5*6)
        y = regroup(x, [3, 5])
        self.check(x, y, 3, 5)

        # regrouping the other axes puts things back the way they were
        z = regroup(y, [4, 6])
        npt.assert_equal(z, x)

    def test_repeated(self):
        x = np.arange(3*4*3*6).reshape(3*4, 3*6)
        y = regroup(x, 3)
        self.check(x, y, 3, 3)

    def test_invalid(self):
        x = np.arange(3*4*5*6).reshape(3*4, 5*6)
        with pytest.raises(ValueError):
            regroup(x, 7)  # 7 is not a divisor

class TestColXFm:

    def test_basic(self):
        C = dct_ii(4)
        X = np.arange(8*2).reshape(8, 2)
        Y = colxfm(X, C)
        assert Y.shape == X.shape
        npt.assert_allclose(Y,
            [[ 6.    ,  8.    ],
             [-4.4609, -4.4609],
             [-0.    , -0.    ],
             [-0.317 , -0.317 ],
             [22.    , 24.    ],
             [-4.4609, -4.4609],
             [-0.    , -0.    ],
             [-0.317 , -0.317 ]], atol=1e-4)

    def test_invalid(self):
        C = dct_ii(5)
        X = np.arange(16).reshape(16, 1)
        with pytest.raises(ValueError):
            colxfm(X, C)  # 5 is not a divisor of 16


import numpy as np
from ..simulations.simulation_schemes import euler_maruyama
from typing import Optional

def merton(mu: float, sigma: float, x0: float,
           n_steps: int, dt: float,
           random_toss: Optional[np.array] = None):
    """
    Generate an interest rate trajectory from merton model, using Euler-Maruyama scheme.
    Model:
        dX(t) = mu*dt + sigma*dWt
    Parameters
    ----------
    mu: float,
     drift parameter
    sigma: float,
     diffusion parameter
    x0: float,
     starting value
    n_steps: int,
     number of grid points to simulate on
    dt: float,
     distance between the grid points
    random_toss: Optional[np.array],
     optional array of +1 and -1 to simulate Wiener Process. If not passed, will be generated automatically.
    """

    return euler_maruyama(x0,
                          a_t=lambda t, x: mu,
                          b_t=lambda t, x: sigma,
                          n_steps=n_steps,
                          dt=dt,
                          random_toss=random_toss)

def vasicek(a: float, b: float, sigma: float, x0: float,
            n_steps: int, dt: float,
            random_toss: Optional[np.array] = None):
    """
    Generate an interest rate trajectory from merton model, using Euler-Maruyama scheme.
    Model:
        dX(t) = b*[a-X(t)]*dt + sigma*dWt
    Parameters
    ----------
    a: float,
     asymptotic, long term level (mean-reversion)
    b: float,
     speed of mean reversion
    sigma: float,
     diffusion parameter
    x0: float,
     starting value
    n_steps: int,
     number of grid points to simulate on
    dt: float,
     distance between the grid points
    random_toss: Optional[np.array],
     optional array of +1 and -1 to simulate Wiener Process. If not passed, will be generated automatically.
    """

    return euler_maruyama(x0,
                          a_t=lambda t, x: b*(a - x),
                          b_t=lambda t, x: sigma,
                          n_steps=n_steps,
                          dt=dt,
                          random_toss=random_toss)

if __name__ == '__main__':
    pass


import numpy as np
import matplotlib.pyplot as plt
from skimage.color import rgb2gray
import cv2
import argparse

def get_image_fft(image_filename, show_original=False, show_grayscale=False, show_fft=False):
    # load image
    original_image = cv2.imread(image_filename)
    if show_original:
        # plot original image and get shape
        cv2.imshow('original image ' + str(original_image.shape), original_image)
        # get original image fft2D
        fft2d_rgb = np.fft.fft2(original_image)
        # plot original image fft2D
        plt.imshow(np.log(abs(fft2d_rgb)), cmap='gray')
        plt.title('FFT2D')
        plt.show()
    if show_grayscale:
        # convert original image to grayscale
        grayscale_image = rgb2gray(original_image)
        # plot grayscale image and get shape
        cv2.imshow('grayscale image ' + str(grayscale_image.shape), grayscale_image)
        # get grayscale image fft2D
        fft2d_gray = np.fft.fft2(grayscale_image)
        # plot grayscale image fft2D
        plt.imshow(np.log(abs(fft2d_gray)), cmap='gray')
        plt.title('FFT2D')
        plt.show()

    return None

if __name__ == "__main__":
    # argument parser
    parser = argparse.ArgumentParser(description = 'Image fft2d plot')
    parser.add_argument('image', help = 'directory of image')
    parser.add_argument('original', help = 'Plot fft for original image', action='store_false')
    parser.add_argument('grayscale', help = 'Plot fft for grayscale image', action='store_true')
    args = parser.parse_args()

    fft2d = get_image_fft(args.image, args.original, args.grayscale)


import numpy as np

#######################################################
# DO NOT MODIFY ANY CODE OTHER THAN THOSE TODO BLOCKS #
#######################################################

def delta(N, D, X, y, w, b, loss="perceptron"):
    """
    Obtain the delta of w and b
    :param N: scalar, number of samples
    :param D: scalar, number of features
    :param X: (N, D) all training samples
    :param y: (N, ) all training labels
    :param w: (D, ), coefficient
    :param b: scalar, bias
    :param loss: the loss that will be applied
    :return: dw, db: the delta of w and b
    """
    dw, db = np.zeros(D), 0.0
    if loss == "perceptron":
        # Given the perceptron loss l(w,b) = 1/N sum( max( 0, -y(wx+b) ) )
        z = np.multiply(y, np.dot(X, w) + b)
        indicators = np.where(z <= 0.0)
        dw = -np.sum(np.multiply(X[indicators].T, y[indicators]), axis=1) / N
        db = -np.sum(y[indicators]) / N
        return dw, db
    else:
        # Given the logistic loss l(w, b) = sum( ln(1+exp( -y(wx+b) )) )
        z = np.multiply(y, np.dot(X, w) + b)
        dw = -np.dot(X.T, np.multiply(sigmoid(-z), y)) / N
        db = -np.sum(np.multiply(sigmoid(-z), y)) / N
        return dw, db

def binary_train(X, y, loss="perceptron", w0=None, b0=None, step_size=0.5, max_iterations=1000):
    """
    Inputs:
    - X: training features, a N-by-D numpy array, where N is the
    number of training points and D is the dimensionality of features
    - y: binary training labels, a N dimensional numpy array where
    N is the number of training points, indicating the labels of
    training data (either 0 or 1)
    - loss: loss type, either perceptron or logistic
	- w0: initial weight vector (a numpy array)
	- b0: initial bias term (a scalar)
    - step_size: step size (learning rate)
    - max_iterations: number of iterations to perform gradient descent

    Returns:
    - w: D-dimensional vector, a numpy array which is the final trained weight vector
    - b: scalar, the final trained bias term

    Find the optimal parameters w and b for inputs X and y.
    Use the *average* of the gradients for all training examples
    multiplied by the step_size to update parameters.
    """
    N, D = X.shape
    assert len(np.unique(y)) == 2

    w = np.zeros(D)
    if w0 is not None:
        w = w0

    b = 0
    if b0 is not None:
        b = b0

    # Transform to (-1, 1) labels
    y_transformed = np.zeros(N)
    for i in range(N):
        y_transformed[i] = -1.0 if y[i] == 0 else 1.0

    if loss == "perceptron":
        # TODO 1 : perform "max_iterations" steps of
        # gradient descent with step size "step_size"
        # to minimize perceptron loss
        for _ in range(max_iterations):
            dw, db = delta(N=N, D=D, X=X, y=y_transformed, w=w, b=b, loss=loss)
            w -= step_size * dw
            b -= step_size * db

    elif loss == "logistic":
        # TODO 2 : perform "max_iterations" steps of
        # gradient descent with step size "step_size"
        # to minimize logistic loss
        for _ in range(max_iterations):
            dw, db = delta(N=N, D=D, X=X, y=y_transformed, w=w, b=b, loss=loss)
            w -= step_size * dw
            b -= step_size * db

    else:
        raise NotImplementedError

    assert w.shape == (D,)
    return w, b

def sigmoid(z):
    """
    Inputs:
    - z: a numpy array or a float number

    Returns:
    - value: a numpy array or a float number after applying the sigmoid function 1/(1+exp(-z)).
    """
    # TODO 3 : fill in the sigmoid function
    value = 1.0 / (1.0 + np.exp(-z))
    return value

def binary_predict(X, w, b):
    """
    Inputs:
    - X: testing features, a N-by-D numpy array, where N is the
    number of training points and D is the dimensionality of features
    - w: D-dimensional vector, a numpy array which is the weight
    vector of your learned model
    - b: scalar, which is the bias of your model

    Returns:
    - preds: N-dimensional vector of binary predictions (either 0 or 1)
    """
    N, D = X.shape

    # TODO 4 : predict DETERMINISTICALLY (i.e. do not randomize)
    preds = np.dot(X, w) + b
    preds[preds > 0.0] = 1
    preds[preds <= 0.0] = 0

    assert preds.shape == (N,)
    return preds

def softmax(z):
    """
    Obtain the softmax of z
    :param z: (C, N) or (C, ), a numpy array
    :return:
    """
    z -= np.max(z, axis=0)
    value = np.exp(z) / np.sum(np.exp(z), axis=0)
    return value

def multiclass_train(X, y, C,
                     w0=None,
                     b0=None,
                     gd_type="sgd",
                     step_size=0.5,
                     max_iterations=1000):
    """
    Inputs:
    - X: training features, a N-by-D numpy array, where N is the
    number of training points and D is the dimensionality of features
    - y: multiclass training labels, a N dimensional numpy array where
    N is the number of training points, indicating the labels of
    training data (0, 1, ..., C-1)
    - C: number of classes in the data
    - gd_type: gradient descent type, either GD or SGD
    - step_size: step size (learning rate)
    - max_iterations: number of iterations to perform (stochastic) gradient descent

    Returns:
    - w: C-by-D weight matrix, where C is the number of classes and D
    is the dimensionality of features.
    - b: a bias vector of length C, where C is the number of classes

    Implement multinomial logistic regression for multiclass
    classification. Again for GD use the *average* of the gradients for all training
    examples multiplied by the step_size to update parameters.

    You may find it useful to use a special (one-hot) representation of the labels,
    where each label y_i is represented as a row of zeros with a single 1 in
    the column that corresponds to the class y_i. Also recall the tip on the
    implementation of the softmax function to avoid numerical issues.
    """

    N, D = X.shape

    w = np.zeros((C, D))
    if w0 is not None:
        w = w0

    b = np.zeros(C)
    if b0 is not None:
        b = b0

    np.random.seed(42)  # DO NOT CHANGE THE RANDOM SEED IN YOUR FINAL SUBMISSION

    # Transform y to one-hot representation
    y1hot = np.zeros((N, C))
    for i in range(N):
        y1hot[i][y[i]] = 1.0

    if gd_type == "sgd":

        for it in range(max_iterations):
            n = np.random.choice(N)
            # TODO 5 : perform "max_iterations" steps of
            # stochastic gradient descent with step size
            # "step_size" to minimize logistic loss. We already
            # pick the index of the random sample for you (n)
            x = X[n]
            P = softmax(np.dot(w, x.T) + b) - y1hot[n]
            dw, db = np.dot(P.reshape(C, 1), x.reshape(1, D)), P
            w -= step_size * dw
            b -= step_size * db

    elif gd_type == "gd":
        # TODO 6 : perform "max_iterations" steps of
        # gradient descent with step size "step_size"
        # to minimize logistic loss.
        for _ in range(max_iterations):
            P = softmax(np.dot(w, X.T) + b[:, None]) - y1hot.T
            dw, db = np.dot(P, X), np.sum(P, axis=1)
            w -= step_size * dw / N
            b -= step_size * db / N

    else:
        raise NotImplementedError

    assert w.shape == (C, D)
    assert b.shape == (C,)

    return w, b

def multiclass_predict(X, w, b):
    """
    Inputs:
    - X: testing features, a N-by-D numpy array, where N is the
    number of training points and D is the dimensionality of features
    - w: weights of the trained model, C-by-D
    - b: bias terms of the trained model, length of C

    Returns:
    - preds: N dimensional vector of multiclass predictions.
    Predictions should be from {0, 1, ..., C - 1}, where
    C is the number of classes
    """
    N, D = X.shape
    # TODO 7 : predict DETERMINISTICALLY (i.e. do not randomize)

    y = np.dot(X, w.T) + b
    preds = np.argmax(y, axis=1)

    assert preds.shape == (N,)
    return preds


"""Functions needed for the CKM quark mixing matrix."""

from math import cos,sin
from cmath import exp, sqrt
import numpy as np

def ckm_standard(t12, t13, t23, delta):
    r"""CKM matrix in the standard parametrization and standard phase
    convention.

    Parameters
    ----------

    - `t12`: CKM angle $\theta_{12}$ in radians
    - `t13`: CKM angle $\theta_{13}$ in radians
    - `t23`: CKM angle $\theta_{23}$ in radians
    - `delta`: CKM phase $\delta=\gamma$ in radians
    """
    c12 = cos(t12)
    c13 = cos(t13)
    c23 = cos(t23)
    s12 = sin(t12)
    s13 = sin(t13)
    s23 = sin(t23)
    return np.array([[c12*c13,
        c13*s12,
        s13/exp(1j*delta)],
        [-(c23*s12) - c12*exp(1j*delta)*s13*s23,
        c12*c23 - exp(1j*delta)*s12*s13*s23,
        c13*s23],
        [-(c12*c23*exp(1j*delta)*s13) + s12*s23,
        -(c23*exp(1j*delta)*s12*s13) - c12*s23,
        c13*c23]])

def tree_to_wolfenstein(Vus, Vub, Vcb, gamma):
    laC = Vus/sqrt(1-Vub**2)
    A = Vcb/sqrt(1-Vub**2)/laC**2
    rho = Vub*cos(gamma)/A/laC**3
    eta = Vub*sin(gamma)/A/laC**3
    rhobar = rho*(1 - laC**2/2.)
    etabar = eta*(1 - laC**2/2.)
    return laC, A, rhobar, etabar

def ckm_wolfenstein(laC, A, rhobar, etabar):
    r"""CKM matrix in the Wolfenstein parametrization and standard phase
    convention.

    This function does not rely on an expansion in the Cabibbo angle but
    defines, to all orders in $\lambda$,

    - $\lambda = \sin\theta_{12}$
    - $A\lambda^2 = \sin\theta_{23}$
    - $A\lambda^3(\rho-i \eta) = \sin\theta_{13}e^{-i\delta}$

    where $\rho = \bar\rho/(1-\lambda^2/2)$ and
    $\eta = \bar\eta/(1-\lambda^2/2)$.

    Parameters
    ----------

    - `laC`: Wolfenstein parameter $\lambda$ (sine of Cabibbo angle)
    - `A`: Wolfenstein parameter $A$
    - `rhobar`: Wolfenstein parameter $\bar\rho = \rho(1-\lambda^2/2)$
    - `etabar`: Wolfenstein parameter $\bar\eta = \eta(1-\lambda^2/2)$
    """
    rho = rhobar/(1 - laC**2/2.)
    eta = etabar/(1 - laC**2/2.)
    return np.array([[sqrt(1 - laC**2)*sqrt(1 - A**2*laC**6*((-1j)*eta + rho)*((1j)*eta + rho)),
        laC*sqrt(1 - A**2*laC**6*((-1j)*eta + rho)*((1j)*eta + rho)),
        A*laC**3*((-1j)*eta + rho)],
        [-(laC*sqrt(1 - A**2*laC**4)) - A**2*laC**5*sqrt(1 - laC**2)*((1j)*eta + rho),
        sqrt(1 - laC**2)*sqrt(1 -  A**2*laC**4) - A**2*laC**6*((1j)*eta + rho),
        A*laC**2*sqrt(1 - A**2*laC**6*((-1j)*eta + rho)*((1j)*eta + rho))],
        [A*laC**3 - A*laC**3*sqrt(1 - laC**2)*sqrt(1 - A**2*laC**4)*((1j)*eta + rho),
        -(A*laC**2*sqrt(1 - laC**2)) - A*laC**4*sqrt(1 - A**2*laC**4)*((1j)*eta + rho),
        sqrt(1 - A**2*laC**4)*sqrt(1 - A**2*laC**6*((-1j)*eta + rho)*((1j)*eta + rho))]])

def ckm_tree(Vus, Vub, Vcb, gamma):
    r"""CKM matrix in the tree parametrization and standard phase
    convention.

    In this parametrization, the parameters are directly measured from
    tree-level $B$ decays. It is thus particularly suited for new physics
    analyses because the tree-level decays should be dominated by the Standard
    Model. This function involves no analytical approximations.

    Relation to the standard parametrization:

    - $V_{us} = \cos \theta_{13} \sin \theta_{12}$
    - $|V_{ub}| = |\sin \theta_{13}|$
    - $V_{cb} = \cos \theta_{13} \sin \theta_{23}$
    - $\gamma=\delta$

    Parameters
    ----------

    - `Vus`: CKM matrix element $V_{us}$
    - `Vub`: Absolute value of CKM matrix element $|V_{ub}|$
    - `Vcb`: CKM matrix element $V_{cb}$
    - `gamma`: CKM phase $\gamma=\delta$ in radians
    """
    return np.array([[sqrt(1 - Vub**2)*sqrt(1 - Vus**2/(1 - Vub**2)),
        Vus,
        Vub/exp(1j*gamma)],
        [-((sqrt(1 - Vcb**2/(1 - Vub**2))*Vus)/sqrt(1 - Vub**2)) - (Vub*exp(1j*gamma)*Vcb*sqrt(1 - Vus**2/(1 - Vub**2)))/sqrt(1 - Vub**2),
        -((Vub*exp(1j*gamma)*Vcb*Vus)/(1 - Vub**2)) + sqrt(1 - Vcb**2/(1 - Vub**2))*sqrt(1 - Vus**2/(1 - Vub**2)),
        Vcb],
        [(Vcb*Vus)/(1 - Vub**2) - Vub*exp(1j*gamma)*sqrt(1 - Vcb**2/(1 - Vub**2))*sqrt(1 - Vus**2/(1 - Vub**2)),
        -((Vub*exp(1j*gamma)*sqrt(1 - Vcb**2/(1 - Vub**2))*Vus)/sqrt(1 - Vub**2)) - (Vcb*sqrt(1 - Vus**2/(1 - Vub**2)))/sqrt(1 - Vub**2),
        sqrt(1 - Vub**2)*sqrt(1 - Vcb**2/(1 - Vub**2))]])


"""
CS 156a: Final Exam
Anthony Bartolotta
Problems 7,8,9,10
"""
import numpy as np

def readInData(filepath):
    F = open(filepath,"r")
    rawLines = F.readlines()
    X_store = []
    y_store = []
    for line in rawLines:
        entries = line.split()
        X_store.append(map(float, entries[1:]))
        y_store.append(int(float(entries[0])))
    X_vec = np.array(X_store)
    y_vec = np.array(y_store)
    return [X_vec, y_vec]

def transformInputSpace(X_vec, NonlinearBool):
    # Perform transform of raw data
    if NonlinearBool:
    # If NonlinearBool==True, perform a nonlinear transform of the input
    # space
        c1 = np.ones((len(X_vec[:,0]),1))
        c4 = X_vec[:,0]*X_vec[:,1]
        c5 = X_vec[:,0]**2
        c6 = X_vec[:,1]**2
        tVec = np.column_stack([c1, X_vec, c4, c5, c6])
    else:
    # If NonlinearBool==False, just add the constant dimension to the
    # input space
        c1 = np.ones((len(X_vec[:,0]),1))
        tVec = np.column_stack([c1, X_vec])
    return tVec

def processData_NversusALL(n, y_vec):
    # Find digits with value "n"
    ind = (y_vec == n)
    y_class = np.zeros((len(y_vec),))
    y_class[ind] = 1
    y_class[~ind] = -1
    return y_class

def processData_NversusM(n, m, X_vec, y_vec):
    # Make local copies of data
    X_temp = X_vec.copy()
    y_temp = y_vec.copy()
    # Find digits with values "n" and "m"
    n_ind = (y_temp == n)
    m_ind = (y_temp == m)
    # Process and trim data
    y_temp[n_ind] = 1
    y_temp[m_ind] = -1
    y_trimmed = y_temp[n_ind + m_ind]
    x_trimmed = X_temp[n_ind + m_ind, :]
    return [x_trimmed, y_trimmed]

def pseudoInverse(X, lamb):
    xPrime = np.dot(np.transpose(X), X)
    L = lamb * np.identity(xPrime.shape[0])
    xPseudo = np.dot(np.linalg.inv(xPrime + L), np.transpose(X))
    return xPseudo

def regulatedLinearRegression(X_vec, y_vec, lamb):
    # Calculate pseudo-inverse including regulator
    xPseudo = pseudoInverse(X_vec, lamb)
    # Perform linear regression using pseudo-inverse
    wVec = np.dot(xPseudo, y_vec)
    return wVec

def sampleError(X_vec, y_vec, wVec):
    # Classify sample points
    wClass = np.sign(np.dot(X_vec, wVec))
    # Find fraction of mismatch
    fMismatch = float(sum(y_vec != wClass)) / len(y_vec)
    return fMismatch

def problems_7_8_9(inSamplePath, outSamplePath):
    # Load in-sample and out-of-sample data from files
    [X_in_raw, y_in] = readInData(inSamplePath)
    [X_out_raw, y_out] = readInData(outSamplePath)
    # Prepare data in both standard and nonlinearly transformed ways
    X_in_lin_pre = transformInputSpace(X_in_raw, False)
    X_out_lin_pre = transformInputSpace(X_out_raw, False)
    X_in_nonlin_pre = transformInputSpace(X_in_raw, True)
    X_out_nonlin_pre = transformInputSpace(X_out_raw, True)
    # Prepare data for n vs. all digit classification for all possible n
    in_data = [ [X_in_lin_pre, X_in_nonlin_pre, \
                         processData_NversusALL(n, y_in)] for n in range(10)]
    out_data = [ [X_out_lin_pre, X_out_nonlin_pre, \
                         processData_NversusALL(n, y_out)] for n in range(10)]
    # For each possible classification task, evaluate performance of original
    # and nonlinearly transformed data both in-sample and out-of-sample. Use
    # linear regression with regularization parameter Lambda = 1.
    results = []
    for n in range(10):
        # Load in-sample data and perform linear regression
        [X_in_l, X_in_nl, y_in] = in_data[n]
        w_l = regulatedLinearRegression(X_in_l, y_in, 1)
        w_nl = regulatedLinearRegression(X_in_nl, y_in, 1)
        # Load out-of-sample data. Score E_in and E_out for original and
        # nonlinearly transformed data
        [X_out_l, X_out_nl, y_out] = out_data[n]
        E_in_l = sampleError(X_in_l, y_in, w_l)
        E_out_l = sampleError(X_out_l, y_out, w_l)
        E_in_nl = sampleError(X_in_nl, y_in, w_nl)
        E_out_nl = sampleError(X_out_nl, y_out, w_nl)
        # Store results as [digit, Bool_transform, E_in, E_out]
        results.append([n, False, E_in_l, E_out_l])
        results.append([n, True, E_in_nl, E_out_nl])
    return results

def problem_10(inSamplePath, outSamplePath):
    # Load in-sample and out-of-sample data from files
    [X_in_raw, y_in_raw] = readInData(inSamplePath)
    [X_out_raw, y_out_raw] = readInData(outSamplePath)
    # Prepare nonlinearly transformed data
    X_in_pre = transformInputSpace(X_in_raw, True)
    X_out_pre = transformInputSpace(X_out_raw, True)
    # Consider 1 vs 5 classification task
    [X_in, y_in] = processData_NversusM(1, 5, X_in_pre, y_in_raw)
    [X_out, y_out] = processData_NversusM(1, 5, X_out_pre, y_out_raw)
    # Compare performance with Lambda = .01 and Lambda = 1.
    lambda_values = [.01, 1]
    results = []
    for lamb in lambda_values:
        # Perform linear regression with regularization
        w_vec = regulatedLinearRegression(X_in, y_in, lamb)
        # Find E_in and E_out
        E_in = sampleError(X_in, y_in, w_vec)
        E_out = sampleError(X_out, y_out, w_vec)
        # Store results as [lambda, E_in, E_out]
        results.append([lamb, E_in, E_out])
    return results

def main(inSamplePath, outSamplePath):
    r_7_8_9 = problems_7_8_9(inSamplePath, outSamplePath)
    print("Problems 7, 8, and 9: ")
    print("n vs. all classification with and without a nonlinear transform.")
    print("Columns arranged as n, (transformed?), E_in, E_out :")
    print(repr(np.array(r_7_8_9)) + "\n")
    r_10 = problem_10(inSamplePath, outSamplePath)
    print("Problem 10: ")
    print("1 vs 5 classification with nonlinear transform.")
    print("Columns arranged as lambda, E_in, E_out :")
    print(repr(np.array(r_10)) + "\n")
    return

# The training and test data files originally used with this script
# have not been included in this GitHub repository. The original
# dataset consisted of three tab delimited columns derived from the
# MNIST dataset. The first column was the digit's classification
# (0 throught 9, stored as float). The second and third columns were
# high level features extracted from each sample (floats).
inSamplePath = "features.train"
outSamplePath = "features.test"
main(inSamplePath, outSamplePath)


import numpy as np
from sympy import *
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter

def initOneSoliton(off, v, L, N, S):
    psi = np.zeros(N, dtype=np.complex_)
    t = 0
    h = L/N
    a = np.sqrt(2)
    B = 3/2 - 2 * S
    for i in range(N):
        x = i * h - off
        f = (2 * a * exp(a * x)) / (1 + B * exp(2 * a * x))
        psi[i] = f * exp(I * t + I * v * x)
    return psi

def initTwoSoliton(x1off, v1, x2off, v2, L, N, S):
    psi = np.zeros(N, dtype=np.complex_)
    t = 0
    h = L/N
    a = np.sqrt(2)
    B = 3/2 - 2 * S
    for i in range(N):
        x1 = i * h - x1off
        f1 = ( 2 * a * exp(a * x1)) / (1 + B * exp(2 * a * x1) )
        x2 = i * h - x2off
        f2 = ( 2 * a * exp(a * x2)) / (1 + B * exp(2 * a * x2) )
        psi[i] = ( f1 * exp(I * t + I * v1 * x1) + f2 *
                    exp(I * t + I * v2 * x2) )
    return psi

def computeN(psi1, psi2, L, N):
    N1 = np.trapz(abs(psi1), dx=L/N)
    N2 = np.trapz(abs(psi2), dx=L/N)
    return np.abs(N1 - N2)

def plot2D(y, L, N):
    plt.plot(np.linspace(0, L, num=N), abs(y))
    plt.show()

def plot3D(psiEv, L, N, T, tau):
    fig = plt.figure(figsize=(20,10))
    ax = fig.gca(projection='3d')

    # Make data.
    X = np.arange(0, L, L/N)
    Y = np.arange(0, T, tau)
    X, Y = np.meshgrid(X, Y)

    # Plot the surface.
    surf = ax.plot_surface(X, Y, psiEv, cmap=cm.jet, linewidth=10,
       antialiased=True, rstride=1, cstride=1)

    # Customize the z axis.
    ax.set_zlim(0, 2)
    ax.zaxis.set_major_locator(LinearLocator(10))
    #ax.zaxis.set_major_formatter(FormatStrFormatter('%.1f
    #ax.view_init(30, 190)

    # Add a color bar which maps values to colors.
    fig.colorbar(surf, shrink=0.5, aspect=10)

    plt.show()


import logging
import numpy as np
import matplotlib.pyplot as plt
from numpy import angle
from colorsys import hls_to_rgb

class ComplexDraw:

    def __init__(self, xmin=-10, xmax=10, ymin=-10, ymax=10, samples=500, ColorFunc=None):
        # set ranges for the axes
        self._xmin = xmin
        self._xmax = xmax
        self._ymin = ymin
        self._ymax = ymax
        # plot settings
        self._samples = samples
        # coloring details
        self.ColorFunc = ColorFunc if ColorFunc is not None else self.DomainColoringColorFunc
        self.colorArr = np.empty([samples, samples, 3], dtype=np.uint8)
        self._updatedImage = False
        # create domain
        self.CreateDomain()
        #configurate logging
        logging.basicConfig(format="%(levelname)s | %(module)s: %(message)s", level=logging.INFO)

    # This is a function to create an array of points representing an x, y plane.
    def CreateDomain(self):
        x = np.linspace(self._xmin, self._xmax, self._samples)
        y = np.linspace(self._ymin, self._ymax, self._samples)
        self.xx, self.yy=np.meshgrid(x,y)

    # This is the default coloring function. It is a good example for what this program might be used for.
    def DomainColoringColorFunc(self, cNums, arr, a=0.9):
        # This function calculates a color based on some of the attributes associated with each complex number.
        # For more information on domain coloring see: https://en.wikipedia.org/wiki/Domain_coloring
        rowCount = 0
        pointCount = 0
        for row in cNums:
            pointCount = 0
            for c in row:
                H = angle(c)
                L = (1 - a**(np.abs(c)))
                S = 1
                rgb = hls_to_rgb(H, L, S)
                rgb = list(map(lambda x: 255*x, rgb))
                arr[rowCount, pointCount] = rgb
                pointCount += 1
            rowCount += 1

    # This function return the set of complex numbers that each correspond to pixels on the screen.
    def GetComplexNums(self):
        return self.xx + 1j*self.yy

    # Function to get the color corresponding to each point.
    def GetColours(self):
        self.ColorFunc(self.GetComplexNums(), self.colorArr)

    # This function shows the created plot of the complex plane.
    def CreateImage(self):
        self.GetColours()
        plt.imshow(self.colorArr)
        #Hide x and y axes
        plt.gca().get_xaxis().set_visible(False)
        plt.gca().get_yaxis().set_visible(False)

    # Function to plot the complex plane.
    def Plot(self):
        if not self._updatedImage:
            self.CreateImage()
            self._updatedImage = True
        plt.show()

    # Function to save the image of the complex plane to a file.
    def SaveFig(self, filename, dpi=100):
        if not self._updatedImage:
            self.CreateImage()
            self._updatedImage = True
        # Save without white borders.
        logging.info("Saving plot of complex plane in file {}.".format(filename))
        plt.savefig(filename, bbox_inches='tight', pad_inches=0, dpi=dpi)


# Lab 0
# Linear Least Squares Fit
# Author Caspar Lant

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

# load csv file
DATA = "data.csv";
frequency, current, twicecurrent, field = np.loadtxt(DATA, skiprows=1 , unpack=True, delimiter=',');

def least_squares_fit (x, y):
    xavg = x.mean()
    slope = ( y * ( x - xavg)).sum() / (x*(x-xavg)).sum()
    intercept = y.mean()-slope*xavg
    return slope, intercept

slope, intercept = least_squares_fit(field, frequency);

y1 = slope *  10  + intercept;  # y1 = m(x1) + b
y2 = slope *  2   + intercept;   # y2 = m(x2) + b
x_range = [2, 10];             # array of x values
y_range = [y2, y1];             # array of y values

# plot temperature vs. pressure + error bars
plt.xlabel("Magnetic Field Strength (mT)");
plt.ylabel("Resonant Frequency (MHz)");
plt.title("Resonant Frequency vs. Magnetic Field Strength");
plt.errorbar(field, frequency, yerr=2, ecolor='red', c='red',marker='.', linestyle='');
plt.plot(x_range, y_range, '-', color="blue");
plt.show()
print(slope)
print(intercept)
# # linear least squares fit line
# def least_squares_fit (x, y):
#     xavg = x.mean()
#     slope = ( y * ( x - xavg)).sum() / (x*(x-xavg)).sum()
#     intercept = y.mean()-slope*xavg
#     return slope, intercept
#
# slope, intercept = least_squares_fit(voltage, deflection);
#
# # create arrays to plot
# y1 = slope *  15 + intercept;  # y1 = m(x1) + b
# y2 = slope *  0   + intercept;   # y2 = m(x2) + b
# x_range = [-15, 15];             # array of x values
# y_range = [y2, y1];             # array of y values
#
# print("slope: %d intercept: %d", slope, intercept)
#
# # show the graph
# # plt.plot(x_range, y_range, color="blue");
# plt.show();


# -------------------------------------------------------------------------------------------------------------------- #
# Import packages
# -------------------------------------------------------------------------------------------------------------------- #
import numpy as np

from .nurbs_surface import NurbsSurface

# -------------------------------------------------------------------------------------------------------------------- #
# Define the bilinear NURBS surface class
# -------------------------------------------------------------------------------------------------------------------- #
class NurbsSurfaceExtruded:

    """ Create the NURBS surface obtained by sweeping the NURBS curve `C(u)` a distance `d` along a direction `D`

        Create the NURBS surface given by
            S(u,v) = C(u) + v*d*D

    Parameters
    ----------
    C : NURBS curve object
        See NurbsSurface class documentation

    D : ndaray with shape (3,)
        Sweeping/extrusion direction. D may be a unitary or a non-unitary vector

    d : scalar
        Sweeping/extrusion length. d may be positive, negative or zero

    References
    ----------
    The NURBS book. Chapter 8.3
    L. Piegl and W. Tiller
    Springer, second edition

    """

    def __init__(self, C, D, d):

        # Declare input variables as instance variables
        self.C = C
        self.D = D/np.sum(D**2)**(1/2)
        self.d = d

        # Check the number of dimensions of the problem
        if np.shape(C.P)[0] != 3: raise Exception("The input NURBS must be three-dimensional")
        if np.shape(D)[0] != 3: raise Exception("The sweeping direction must be a three-dimensional vector")

        # Make the extrusion surface NURBS representation
        self.NurbsSurface = None
        self.make_Nurbs_surface()

    def make_Nurbs_surface(self):

        """ Make a NURBS surface representation of the extruded surface """

        # Define the array of control points
        P = np.concatenate((self.C.P[:, :, np.newaxis], self.C.P[:, :, np.newaxis] + self.d*self.D[:, np.newaxis, np.newaxis]), axis=2)

        # Define array of control point weights
        W = np.concatenate((self.C.W[:, np.newaxis], self.C.W[:, np.newaxis]), axis=1)

        # Maximum index of the control points (counting from zero)
        m = np.shape(P)[2] - 1

        # Define the order of the basis polynomials
        # Linear (p = 1), Quadratic (p = 2), Cubic (p = 3), etc.
        # Set p = n (number of control points minus one) to obtain a Bezier
        p = self.C.p
        q = 1

        # Define the knot vectors (clamped spline)
        # p+1 zeros, n minus p equispaced points between 0 and 1, and p+1 ones.  In total r+1 points where r=n+p+1
        # q+1 zeros, m minus q equispaced points between 0 and 1, and q+1 ones. In total s+1 points where s=m+q+1
        U = self.C.U
        V = np.concatenate((np.zeros(q), np.linspace(0, 1, m - q + 2), np.ones(q)))

        # Create the NURBS surface
        self.NurbsSurface = NurbsSurface(control_points=P, weights=W, u_degree=p, v_degree=q, u_knots=U, v_knots=V)


#!/usr/bin/env python

# from sympy import lambdify, diff, hessian, jacobi, cos, sin, pprint
# from sympy.matrices import Matrix
from sympy.abc import x,y,w,z

from Linear_system import *
from Error import *
from Log import *

MAX = 200
PATH = 'log/quasi-newton/'
TOLERANCE = 0.00000001 # 10**(-8)

PL = 15     # weight * lenght
K = 100     # proportionality
M = Matrix([[K * (x    ) - ((7 * PL) / 2 ) * cos(x) - K * (y - x)],
            [K * (y - x) - ((5 * PL) / 2 ) * cos(y) - K * (w - y)],
            [K * (w - y) - ((3 * PL) / 2 ) * cos(w) - K * (z - w)],
            [K * (z - w) - ((    PL) / 2 ) * cos(z)]])

def quasi_newton(fn, point, tol, nmax) :
    # l = Log()
    e = Error()
    ls = Linear_system()
    j = ls.jacobiana(fn,[x,y,w,z])
    f = lambdify([x,y,w,z], fn)
    previous = point

    jj = j(float(point[0]),float(point[1]),float(point[2]),float(point[3]))
    L, U, _ = Matrix(jj).LUdecomposition()

    for n in range(nmax) :
        ff = f(float(point[0]),float(point[1]),float(point[2]),float(point[3]))
        g = ls.gauss_jordan(Matrix(L), Matrix(-ff))
        point = point + ls.gauss_jordan(Matrix(U), Matrix(g))
        e.matrix_norm(point, previous)

        # l.append([float(point[0]), float(point[1]), float(point[2]), float(point[3]),
        #           float(previous[0]),float(previous[1]),float(previous[2]),float(previous[3]),
        #           float(e._norm)])

        if (e._norm < tol) :
            # l.set_header(['X axes'  ,'Y axes',  'W axes'  ,'Z axes',
            #     'X-1 axes','Y-1 axes','W-1 axes','Z-1 axes',
            #     'Matrix Norm'])
            # l.list2file((PATH+'main-jab-pr'))
            # l.time(PATH+'time-qn-sys_pr')
            return point
            breakpoint
        previous = point
    pprint(point)
    return False

if __name__ == "__main__" :
    seed = Matrix([[1],[1],[1],[1]])
    for i in range(1):
        r =  quasi_newton(M, seed, TOLERANCE, MAX)
    pprint(r)


"""
Author: npgh2009
Polynomial potential implementation
"""

import numpy as np
from numpy.polynomial.polynomial import polyval
import matplotlib.pyplot as plt

class PolynomialPotential(object):

	def __init__(self, x, coeff, lambd = 1):
		"""
		Parameters
		-----------
		x : numpy.linspace array of length N
		coeff : coefficient for polynomial, in ascending power
		lambd : strength of potential, default to 1
		"""

		# Validation of array inputs
		self.x = np.asarray(x)
		N = self.x.size
		assert self.x.shape == (N,)
		self.N = N

		# Set internal parameters
		self.coeff = np.asarray(coeff)
		self.lambd = lambd

		# Compute potential
		self.potential = polyval(x, lambd*self.coeff)

def main():
	x = np.linspace(-3,3,200)
	polypot = PolynomialPotential(x, [0, -5, -7, 0.5, 1], lambd = 1)
	# plt.xlim(-4,4)
	# plt.ylim(-22,22)
	plt.plot(x, polypot.potential, label = 'potential')
	#plt.legend()
	plt.show()

if __name__ == "__main__":
	main()


import numpy as np
import optwrapper as ow

## pg. 25 of LSSOL's manual

Q = np.zeros( (9,9) )
Q[0:5,0:5] = 1
Q[ [0,1,2,3,4], [0,1,2,3,4] ] = 2

L = -1 * np.ones( (9,) )
L[0] = -4
L[7] = -.1
L[8] = -.3

C = np.ones( (3,9) )
C[0,-1] = 4
C[1,1] = 2
C[1,2] = 3
C[1,3] = 4
C[1,4] = -2
C[2,1] = -1
C[2,3] = -1

Clb = -2 * np.ones( (3,) )
Cub = 1.5 * np.ones( (3,) )
Cub[2] = 4

prob = ow.qp.Problem( N=9, Nconslin=3 )
prob.consBox( lb = -2 * np.ones( (9,) ),
              ub =  2 * np.ones( (9,) ) )
prob.objFctn( quad=Q, lin=L )
prob.consLinear( C, lb=Clb, ub=Cub )

solver = ow.qpoases.Solver( prob ) ## change this line to use another solver
solver.debug = True
# solver.options[ "printFile" ] = "debugp.txt"
# solver.options[ "summaryFile" ] = "debugs.txt"
# solver.options[ "enableRamping" ] = ow.qpoases.Params.BT_FALSE

optimal_soln = np.array( [ 2, -.23333333, -.26666667, -.3, -.1, 2, 2, -1.77777778, -.45555556 ] )
optimal_value = -8.067777633666992

print( "The results of both runs should be..." )
print( "Value: " + str( optimal_value ) )
print( "Final point: " + str( optimal_soln ) )

print( "\nFirst run..." )
solver.initPoint( np.zeros( (9,) ) )
solver.solve()
print( prob.soln.getStatus() )
print( "Value: " + str( prob.soln.value ) )
print( "Final point: " + str( prob.soln.final ) )
print( "Retval: " + str( prob.soln.retval ) )

solver.warmStart()
print( "\nSecond run..." )
solver.solve()
print( prob.soln.getStatus() )
print( "Value: " + str( prob.soln.value ) )
print( "Final point: " + str( prob.soln.final ) )
print( "Retval: " + str( prob.soln.retval ) )


from __future__ import division, print_function, absolute_import

import numpy as np

__all__ = ['clarkson_woodruff_transform']

def cwt_matrix(n_rows, n_columns):
    """
    TODO: Document Function
    """
    S = np.zeros((n_rows, n_columns))
    nz_positions = np.random.randint(0, n_rows, n_columns)
    values = np.random.choice([1, -1], n_columns)
    for i in range(n_columns):
        S[nz_positions[i]][i] = values[i]

    return S

def clarkson_woodruff_transform(input_matrix, sketch_size, direcction="rows"):
    """
    Given a matrix A (input_matrix) of size (n, d), compute a matrix A' of size  (n, s) which holds:
        $||Ax|| = (1 \pm \epsilon) ||A'x||$
    with high probability.
    To obtain A' we create a matrix S of size (d, s) where every column of transpose(S) has only one position distinct to zero
    with value +1 or -1. We multiply S*A to obtain A'.
    Parameters
    ----------
    input_matrix (A) : (n, d) array_like
        Input matrix
    n_columns (s) : int
        number of columns for A'
    Returns
    -------
    A' : (n, s) array_like
        Sketch of A
    Notes
    -----
    This is an implementation of the Clarckson-Woodruff Transform (also known as CountSketch) introduced for
    first time in Kenneth L. Clarkson and David P. Woodruff. Low rank approximation and regression in input sparsity time. In STOC, 2013.
    A' can be computed in O(nnz(A)) but we don't take advantage of sparse matrix in this implementation
    """
    #TODO: Rewrite function documentation

    if (direcction == "rows"):
        S = cwt_matrix(sketch_size, input_matrix.shape[0])
        return np.dot(S, input_matrix)
    elif (direcction == "columns"):
        S = cwt_matrix(input_matrix.shape[1], sketch_size)
        return np.dot(input_matrix, S)
    else:
        raise ValueError('Value of direrction must be "rows" or "columns"')


#! /usr/bin/env python

"""
File: integrate_exp.py
Copyright (c) 2016 Austin Ayers
License: MIT

Course: PHYS227
Assignment: HW 5
Date: March 18
Email: ayers111@mail.chapman.edu
Name: Austin Ayers
Description:
"""
import numpy as np
import matplotlib.pyplot
def trapezoidal(f, a, b, n):
    """Trapezoidal integration via iteration."""
    h = (b-a)/float(n)
    I = f(a) + f(b)
    for k in xrange(1, n, 1):
        x = a + k*h
        I += 2*f(x)
    I *= h/2
    return I
def func(x):
    return np.exp(-1 * (x ** 2))
def part_a():
    x = np.linspace(-10,10,1001)
    y = func(x)
    plt.plot(x,y)
    plt.show()
    print "The plot is symmetric"
def run():
    n = [100,200,300,400,500]
    L = [2,4,6,8,10]

    for elem_n in n:
        for elem_L in L:
            I = trapezoidal(func, 0, elem_L, elem_n)
            I *= 2
            print "I: " + str(I) + ", Error: " + str(I - np.sqrt(np.pi)),
        print " "


import numpy as np
import sys

def peakdet(v, delta=None):
    """
    Peak detection. Modified version from https://gist.github.com/endolith/250860

    A point counts as peak if it is maximal and is preceeded by a value lower by delta.

    :param v: array of values
    :param delta: threshold; set to 99.9%ile - median of v if None
    :return: maxima, maximum indices, minima, minimum indices
    """
    maxtab = []
    maxidx = []

    mintab = []
    minidx = []
    v = np.asarray(v)
    if delta is None:
        up = int(np.min([1e5, len(v)]))
        tmp = np.abs(v[:up])
        delta = np.percentile(tmp, 99.9) - np.percentile(tmp, 50)

    if not np.isscalar(delta):
        sys.exit('Input argument delta must be a scalar')

    if delta <= 0:
        sys.exit('Input argument delta must be positive')

    mn, mx = np.Inf, -np.Inf
    mnpos, mxpos = np.NaN, np.NaN

    lookformax = True
    n = len(v)
    for i in range(len(v)):
        this = v[i]
        if this > mx:
            mx = this
            mxpos = i

        if this < mn:
            mn = this
            mnpos = i

        if lookformax:
            if this < mx - delta:
                maxtab.append(mx)
                maxidx.append(mxpos)
                mn = this
                mnpos = i
                lookformax = False

        else:
            if this > mn + delta:
                mintab.append(mn)
                minidx.append(mnpos)
                mx = this
                mxpos = i
                lookformax = True

    return np.asarray(maxtab), np.asarray(maxidx, dtype=int), np.asarray(mintab), np.asarray(minidx, dtype=int)


from scipy.optimize import fsolve

class ARR:
    '''Average Rate of Return, 平均收益率
    '''
    def __init__(self, investment_amount, numbers_of_years, interest_rate, future_value):
        '''
        Argument:
            - investment_amount: float, 投资额
            - numbers_of_years: Tuple[int], 领取时间与领取期限
            - interest_rate: float, 领取期限内的利率
            - future_value: float, 终值
        '''
        self._ia = investment_amount
        self._nys = numbers_of_years[:2]
        self._ir = interest_rate
        self._fv = future_value

    def monthly(self):
        raise NotImplementedError

    def yearly(self):
        func = lambda i: self._fv + self._ia*self._ir*self._s_ddot(self._nys[1], i) \
            - self._ia*(1+i)**sum(self._nys)
        return fsolve(func, 1)[0]

    def _s_ddot(self, n, i):
        '''n 期标准期初年金的终值
        '''
        return ((1+i)**n-1) / (i/(i+1))

if __name__ == '__main__':
    # 小金猪定期年金
    for args in (
        (1_000, (5,  5), 0.02, 1_349),
        (2_000, (5,  5), 0.02, 2_698),
        (3_000, (5,  5), 0.02, 4_047),
        (1_000, (5, 15), 0.02, 1_753),
        (2_000, (5, 15), 0.02, 3_506),
        (3_000, (5, 15), 0.02, 5_259),
    ):
        print(ARR(*args).yearly())


# qr_lstsq_eigs.py
"""Volume 1A: QR 2 (Least Squares and Computing Eigenvalues).
<Name>
<Class>
<Date>"""

import numpy as np
from cmath import sqrt
from scipy import linalg as la
from matplotlib import pyplot as plt

# Problem 1
def least_squares(A, b):
    """Calculate the least squares solutions to Ax = b using QR decomposition.

    Inputs:
        A ((m,n) ndarray): A matrix of rank n <= m.
        b ((m, ) ndarray): A vector of length m.

    Returns:
        x ((n, ) ndarray): The solution to the normal equation.
    """
    raise NotImplementedError("Problem 1 Incomplete")

# Problem 2
def line_fit():
    """Load the data from housing.npy. Use least squares to calculate the line
    that best relates height to weight.

    Plot the original data points and the least squares line together.
    """
    raise NotImplementedError("Problem 2 Incomplete")

# Problem 3
def polynomial_fit():
    """Load the data from housing.npy. Use least squares to calculate
    the polynomials of degree 3, 6, 9, and 12 that best fit the data.

    Plot the original data points and each least squares polynomial together
    in individual subplots.
    """
    raise NotImplementedError("Problem 3 Incomplete")

def plot_ellipse(a, b, c, d, e):
    """Plot an ellipse of the form ax^2 + bx + cxy + dy + ey^2 = 1."""
    theta = np.linspace(0, 2*np.pi, 200)
    cos_t, sin_t = np.cos(theta), np.sin(theta)
    A = a*(cos_t**2) + c*cos_t*sin_t + e*(sin_t**2)
    B = b*cos_t + d*sin_t
    r = (-B + np.sqrt(B**2 + 4*A))/(2*A)

    plt.plot(r*cos_t, r*sin_t, lw=2)
    plt.gca().set_aspect("equal", "datalim")

# Problem 4
def ellipse_fit():
    """Load the data from ellipse.npy. Use least squares to calculate the
    ellipse that best fits the data.

    Plot the original data points and the least squares ellipse together.
    """
    raise NotImplementedError("Problem 4 Incomplete")

# Problem 5
def power_method(A, N=20, tol=1e-12):
    """Compute the dominant eigenvalue of A and a corresponding eigenvector
    via the power method.

    Inputs:
        A ((n,n) ndarray): A square matrix.
        N (int): The maximum number of iterations.
        tol (float): The stopping tolerance.

    Returns:
        (foat): The dominant eigenvalue of A.
        ((n, ) ndarray): An eigenvector corresponding to the dominant
            eigenvalue of A.
    """
    raise NotImplementedError("Problem 5 Incomplete")

# Problem 6
def qr_algorithm(A, N=50, tol=1e-12):
    """Compute the eigenvalues of A via the QR algorithm.

    Inputs:
        A ((n,n) ndarray): A square matrix.
        N (int): The number of iterations to run the QR algorithm.
        tol (float): The threshold value for determining if a diagonal block
            is 1x1 or 2x2.

    Returns:
        ((n, ) ndarray): The eigenvalues of A.
    """
    raise NotImplementedError("Problem 6 Incomplete")


# -*- coding: utf-8 -*-
"""
Solution to Project Euler problem 75 - Singular integer right triangles

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

Given a pair if integers, m and n such that m > n > 0, a pythagorian triple is:
a = m**2 - n**2, b = 2*m*n, c= m**2 + n**2
The length of the sides, L, is:
    L = a + b + c
    L = 2*m**2 + 2*m*n
    L = 2*m(m + n)

Lmax = 1,500,000
assuming m = n+1, Lmax = 2*(n+1)(2n+1) => max(n) = 611.62
"""

import numpy as np

def run():
    #%% New attempt - 9 March 2018
    makeTriple = lambda m, n: [m ** 2 - n ** 2, 2 * m * n, m ** 2 + n ** 2]

    Lmax = 1500000
    # Step 1: Generate triples based on above formula
    Triples = []
    for n in range(1, 611 + 1):
        m = n + 1
        while 2 * m * (m + n) < Lmax:
            Triples.append(makeTriple(m, n))
            m += 1
    Triples = np.sort(Triples)

    """
    The above algorithm does not generate all pythagorean triples. by
    multiplying the created triples by an integer, k, all triples can be found.
    """

    moreTriples = []
    for t in Triples:
        k = 2
        while sum(k * t) < Lmax:
            moreTriples.append(list(k * t))
            k += 1

    Triples = np.vstack([Triples, moreTriples])

    # eliminate repeated triples
    Triples = np.unique(Triples, axis=0)
    """
    This should be all the triples with L < Lmax. so lets find L for each triple
    and count occurennces.
    """
    L = Triples.sum(1)
    unique, counts = np.unique(L, return_counts=True)

    return sum(counts == 1)

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