import numpy as np
import pandas as pd
import math
import scipy
np.set_printoptions(suppress=True)

# Function computing a least squares fit
def beta_ols(Y, X):
    '''
    Estimate OLS coefficients

    Parameters
    ----------
    Y : Nx1 Matrix
    X : Matrix

    Returns
    -------
    beta_hat : vector of coefficients
    '''

    if len(Y.shape) != 1:
        return print('ERROR: Y must be an Nx1 matrix')
    elif Y.shape[0] != X.shape[0]:
        return print('ERROR: Y and X must have the same number of observations')
    else:
        left = X.transpose().dot(X).values
        right = X.transpose().dot(Y).values
        beta_hat = np.linalg.inv(left).dot(right)
        return beta_hat

def resids(Y, X):
    '''
    Estimate OLS residuals

    Parameters
    ----------
    Y : Nx1 Matrix
    X : Matrix

    Returns
    -------
    e : vector of residuals
    '''
    e = beta_ols(Y,X).dot(X.values.T)-Y
    return e

def Sigma(Y,X):
    '''
    ≈

    Parameters
    ----------
    Y : Nx1 Matrix
    X : Matrix

    Returns
    -------
    Sigma : var-cov matrix as pandas df
    '''
    e = resids(Y,X)
    std_hat = e.dot(e.T)/(X.shape[1]-1)
    Sigma = std_hat*np.linalg.inv(X.transpose().dot(X).values)
    return pd.DataFrame(Sigma)

def variance_ols(Y,X):
    '''
    Estimate OLS variance-covariance matrix

    Parameters
    ----------
    Y : Nx1 Matrix
    X : Matrix

    Returns
    -------
    var : variance of coefficients
    '''
    diags = np.diagonal(Sigma(Y, X))
    var = np.sqrt(diags)
    return var

def r2_ols(Y, X):
    '''
    Estimate R^2 for OLS

    Parameters
    ----------
    Y : Nx1 Matrix
    X : Matrix

    Returns
    -------
    R2 : value of R^2
    '''

    y_hat = beta_ols(Y,X).dot(X.values.T)
    y_bar = np.mean(Y)

    SSR = np.sum((y_hat - y_bar)**2)
    SST = np.sum((Y - y_bar)**2)

    r2 = SSR / SST
    return r2

def least_sq(Y, X):
    '''
    Output nicely OLS results

    Parameters
    ----------
    Y : Nx1 Matrix
    X : Matrix

    Returns
    -------
    R2 : value of R^2
    '''

    print('Coefficients = ', beta_ols(Y, X))
    print('Coeff. SErrs = ', np.sqrt(np.diagonal(Sigma(Y,X))))
    print('')
    print('95% Confidence Interval for Coefficients')
    print('     Lower Bound:', beta_ols(Y, X) - 1.96*np.sqrt(np.diagonal(Sigma(Y,X))))
    print('     Upper Bound:', beta_ols(Y, X) + 1.96*np.sqrt(np.diagonal(Sigma(Y,X))))
    print('')
    print('R-Squared:', r2_ols(Y,X))
    print('')
    print("Variance-Covariance Matrix:")
    print(Sigma(Y,X))


import numpy as np
from scipy.stats import norm
from matplotlib import pyplot

np.random.seed(3)
num_per_class = 40
X = np.hstack((norm.rvs(2, size=num_per_class, scale=2), norm.rvs(8, size=num_per_class, scale=3)))
y = np.hstack((np.zeros(num_per_class), np.ones(num_per_class)))

def lr_model(clf, X):
    return 1.0 / (1.0 + np.exp(-(clf.intercept_ + clf.coef_ * X)))

from sklearn.linear_model import LogisticRegression

logclf = LogisticRegression()
print(logclf)
logclf.fit(X.reshape(num_per_class * 2, 1), y)
print(np.exp(logclf.intercept_), np.exp(logclf.coef_.ravel()))
print("P(x=-1)=%.2f\tP(x=7)=%.2f" % (lr_model(logclf, -1), lr_model(logclf, 7)))
X_test = np.arange(-5, 20, 0.1)
pyplot.figure(figsize=(10, 4))
pyplot.xlim((-5, 20))
pyplot.scatter(X, y, c=y)
pyplot.xlabel("feature value")
pyplot.ylabel("class")
pyplot.grid(True, linestyle='-', color='0.75')
pyplot.savefig("log_reg_example_data.png", bbox_inches="tight")

def lin_model(clf, X):
    return clf.intercept_ + clf.coef_ * X

from sklearn.linear_model import LinearRegression

clf = LinearRegression()
print(clf)
clf.fit(X.reshape(num_per_class * 2, 1), y)
X_odds = np.arange(0, 1, 0.001)
pyplot.figure(figsize=(10, 4))
pyplot.subplot(1, 2, 1)
pyplot.scatter(X, y, c=y)
pyplot.plot(X_test, lin_model(clf, X_test))
pyplot.xlabel("feature value")
pyplot.ylabel("class")
pyplot.title("linear fit on original data")
pyplot.grid(True, linestyle='-', color='0.75')

X_ext = np.hstack((X, norm.rvs(20, size=100, scale=5)))
y_ext = np.hstack((y, np.ones(100)))
clf = LinearRegression()
clf.fit(X_ext.reshape(num_per_class * 2 + 100, 1), y_ext)
pyplot.subplot(1, 2, 2)
pyplot.scatter(X_ext, y_ext, c=y_ext)
pyplot.plot(X_ext, lin_model(clf, X_ext))
pyplot.xlabel("feature value")
pyplot.ylabel("class")
pyplot.title("linear fit on additional data")
pyplot.grid(True, linestyle='-', color='0.75')
pyplot.savefig("log_reg_log_linear_fit.png", bbox_inches="tight")

pyplot.figure(figsize=(10, 4))
pyplot.xlim((-5, 20))
pyplot.scatter(X, y, c=y)
pyplot.plot(X_test, lr_model(logclf, X_test).ravel())
pyplot.plot(X_test, np.ones(X_test.shape[0]) * 0.5, "--")
pyplot.xlabel("feature value")
pyplot.ylabel("class")
pyplot.grid(True, linestyle='-', color='0.75')
pyplot.savefig("log_reg_example_fitted.png", bbox_inches="tight")

X = np.arange(0, 1, 0.001)
pyplot.figure(figsize=(10, 4))
pyplot.subplot(1, 2, 1)
pyplot.xlim((0, 1))
pyplot.ylim((0, 10))
pyplot.plot(X, X / (1 - X))
pyplot.xlabel("P")
pyplot.ylabel("odds = P / (1-P)")
pyplot.grid(True, linestyle='-', color='0.75')

pyplot.subplot(1, 2, 2)
pyplot.xlim((0, 1))
pyplot.plot(X, np.log(X / (1 - X)))
pyplot.xlabel("P")
pyplot.ylabel("log(odds) = log(P / (1-P))")
pyplot.grid(True, linestyle='-', color='0.75')
pyplot.savefig("log_reg_log_odds.png", bbox_inches="tight")


'''
Interpolation Methods in Scipy
'''
'''
x = [0,20,40,60,80,100]
y = [26.0,48.6,61.6,71.2,74.8,75.2]
from scipy.interpolate import interp1d, lagrange
#f = interp1d(x,y, 'quadratic')
f = interp1d(x,y, 'cubic')
print(f(50))
'''
'''
Lagrange Method
'''
'''
L = lagrange(x, y)
print(L)
print(L(40))
'''
#################################################
'''
Curve Fitting Functions in Scipy
'''
# Linear Regression:
'''
from scipy.stats import linregress
x = [3,4,5,6,7,8]
y = [0,7,17,26,35,45]
L = linregress(x,y)
print(L)
print(L, slope)
print(L, intercept)
print('y = (%.2f) + (%.2f)x'%(L.intercept, L.slope))
a,b = curve_fit(f,x,y)
'''
# Curve Fitting
from scipy.optimize import curve_fit
x = [3,4,5,6,7,8]
y = [0,7,17,26,35,45]
def f2(x,a0,a1,a2):
    return a0 + a1*x + a2 * x**2
def f3(x,a0,a1,a2,a3):
    return a0 + a1*x + a2 * x**2 + a3 * x**3
a,b = curve_fit(f3, x, y)
print(a)
a,_ = curve_fit(f3,x,y)
print(a)


#!/usr/bin/python
import numpy as np
import math as m

def vector_dot(u,v):
    return u[0]*v[0] + u[1]*v[1] + u[2]*v[2]
def vector_norm(u):
    return m.sqrt(u[0]*u[0] + u[1]*u[1] + u[2]*u[2])
def vector_angle(u,v):
    t = vector_dot(u,v) / (vector_norm(u)*vector_norm(v))
    if (t > 1):
        t = 1
    elif (t < -1):
        t = -1
    return m.acos(t)
    #return m.acos(vector_dot(u,v) / (vector_norm(u)*vector_norm(v)))
def vector_cross(u,v):
    s = np.zeros((3,))
    s[0] = u[1]*v[2] - u[2]*v[1]
    s[1] = u[2]*v[0] - u[0]*v[2]
    s[2] = u[0]*v[1] - u[1]*v[0]
    return s

def quat_normalize(q):
    n = m.sqrt(q[1]*q[1] + q[2]*q[2] + q[3]*q[3])
    return [q[0], q[1]/n, q[2]/n, q[3]/n]

def quat_multiply(p,q): # out = p*q
    out = [0]*4
    out[0] =  p[0]*q[0]-p[1]*q[1]-p[2]*q[2]-p[3]*q[3];
    out[1] =  p[0]*q[1]+p[1]*q[0]+p[2]*q[3]-p[3]*q[2];
    out[2] =  p[0]*q[2]-p[1]*q[3]+p[2]*q[0]+p[3]*q[1];
    out[3] =  p[0]*q[3]+p[1]*q[2]-p[2]*q[1]+p[3]*q[0];
    return out

def quat_norm(q): # return |q|
    return m.sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3])

def quat_dot(p,q): # p dot q
  return p[0]*q[0]+p[1]*q[1]+p[2]*q[2]+p[3]*q[3];

def quat_conj(q): # return conj(q)
    return [q[0], -q[1], -q[2], -q[3]]

def quat_vec_rot(src,q):
  # quat_vec_rot(vector &dest, vector &src, quaternion &q) dest = q*src*conj(q)
  dest = [0]*3
  aa=[q[0]*q[0], q[1]*q[1], q[2]*q[2], q[3]*q[3]]
  ab=[q[0]*q[1], q[0]*q[2], q[0]*q[3], q[1]*q[2], q[1]*q[3], q[2]*q[3]]
  dest[0] = (aa[0]+aa[1]-aa[2]-aa[3])*src[0]+\
            ((ab[3]-ab[2])*src[1]+(ab[1]+ab[4])*src[2])*2.0;
  dest[1] = (aa[0]-aa[1]+aa[2]-aa[3])*src[1]+\
            ((ab[2]+ab[3])*src[0]+(ab[5]-ab[0])*src[2])*2.0;
  dest[2] = (aa[0]-aa[1]-aa[2]+aa[3])*src[2]+\
            ((ab[4]-ab[1])*src[0]+(ab[0]+ab[5])*src[1])*2.0;
  return dest;

def quat_fvu_rot(fvu,q):
    f = quat_vec_rot(fvu[0],q)
    v = quat_vec_rot(fvu[1],q)
    u = quat_vec_rot(fvu[2],q)
    return np.array([f,v,u])

def tu2rotquat(theta,u): # theta and u to rotational quat
    u = np.divide(u,vector_norm(u))
    return [m.cos(theta/2.0),\
               u[0]*m.sin(theta/2.0),\
               u[1]*m.sin(theta/2.0),\
               u[2]*m.sin(theta/2.0)]

def rotquat2tu(q): # rotational quat to theta and u
    theta = 2.0*m.acos(q[0])
    u = [0]*3
    u[0] = q[1] / m.sin(theta/2.0)
    u[1] = q[2] / m.sin(theta/2.0)
    u[2] = q[3] / m.sin(theta/2.0)
    return theta,u


import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans

# data inicial dada por el problema
DATA = np.array([
    [8, 2],
    [9, 7],
    [2, 12],
    [9, 1],
    [10, 7],
    [3, 14],
    [8, 1],
    [1, 13],
])

# 1ra iteracion
# CENTROID = np.array([
#     [10,7],
# ])
# kmeans = KMeans(n_clusters=1, init=CENTROID, n_init=1)
# kmeans.fit(DATA)

# 2da iteracion
# CENTROID = np.array([
#     [10,7],
#     [6.25,7.125],
# ])
# kmeans = KMeans(n_clusters=2, init=CENTROID, n_init=1)
# kmeans.fit(DATA)

# 3ra iteracion
# CENTROID = np.array([
#     [6.25, 7.125],
#     [8.8, 3.6],
#     [2,  13]
# ])
# kmeans = KMeans(n_clusters=3, init=CENTROID, n_init=1)
# kmeans.fit(DATA)

# kMeans con clustering
kmeans = KMeans(n_clusters=3)
kmeans.fit(DATA)

# grafica los puntos de la data
plt.scatter(DATA[:, 0], DATA[:, 1], c=kmeans.labels_, cmap="rainbow")

# grafica los centroides del conjunto de datos
plt.scatter(kmeans.cluster_centers_[:, 0],
            kmeans.cluster_centers_[:, 1],
            color="black"
            )

# imprimimos los centroides
print(kmeans.cluster_centers_)

# imprimo las predicciones
predicts = kmeans.predict(DATA)
print(predicts)

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

# imprimo las clases
for x,y in enumerate(kmeans.labels_):
    print(DATA[x])

plt.show()


"""
Module for deriving the relevant geography (distance matrix)
"""
from itertools import product
import math
from typing import List

import numpy as np

from traveling_salesperson import City

def distance_matrix(cities: List[City], distance_metric_key: str = 'euclidean'):
    """Compute the matrix of distances between all cities, using the named distance metric.

    Args:
        cities: A list of cities to be visited visit
        distance_metric_key: The name of the distance metric to use
    Returns:
        A symmetric matrix of distances between cities.  The i and j indexes correspond to the index
            in the original list of cities
    """
    distance_metric_dict = {
        'euclidean': _euclidean_distance,
        'manhattan': _manhattan_distance
    }
    distance_metric = distance_metric_dict[distance_metric_key]

    distances = np.zeros((len(cities), len(cities)))

    for (i, start), (j, end) in product(enumerate(cities), repeat=2):
        if j <= i:
            continue
        distances[i][j] = distances[j][i] = distance_metric(start, end)
    return distances

def _euclidean_distance(city_a: City, city_b: City) -> int:
    """Helper method to compute the euclidean distance between two cities, rounded to the nearest
    integer."""
    delta_x = city_a.x - city_b.x
    delta_y = city_a.y - city_b.y
    return round(math.sqrt(pow(delta_x, 2) + pow(delta_y, 2)))

def _manhattan_distance(city_a: City, city_b: City) -> int:
    """Helper method to compute the manhattan distance between two cities, rounded to the nearest
    integer."""
    delta_x = abs(city_a.x - city_b.x)
    delta_y = abs(city_a.y - city_b.y)
    return int(delta_x + delta_y)


import numpy as np
import argparse

parser = argparse.ArgumentParser(description='Make lookup table (LUT) for spherical-to-cylindrical conversion')
parser.add_argument('input_width',type=int,help='width of input (spherical) panorama image')
parser.add_argument('input_height',type=int,help='height of input (spherical) panorama image')
parser.add_argument('output_width',type=int,help='width of output (cylindrical) panorama image')
parser.add_argument('output_height',type=int,help='height of output (cylindrical) panorama image')
parser.add_argument('bottom',type=float,help='bottom height value of cylinder')
parser.add_argument('top',type=float,help='top height value of cylinder')
# output
parser.add_argument('--lut_target', default='data/lut.npy',
                                    help='output lookup table location')
parser.add_argument('--intrinsics_target', default='data/intrinsics.txt',
                                           help='intrinsics location')
args = parser.parse_args()

# allocate arrays for lookup table
# lutx[y,x] maps y,x in output image to x coordinate in input image
# similar for luty
lutx = np.zeros((args.output_height,args.output_width))
luty = np.zeros((args.output_height,args.output_width))

# make arrays of equally spaced angle and height values
thetas = np.linspace(-np.pi,np.pi,num=args.output_width,endpoint=False)
heights = np.linspace(args.bottom,args.top,num=args.output_height,endpoint=True)

for r in range(args.output_height):
    height = heights[r]
    for c in range(args.output_width):
        theta = thetas[c]

        # get XYZ point
        X = np.sin(theta)
        Y = height
        Z = np.cos(theta)

        # get vertical angle
        phi = np.arcsin(Y/np.sqrt(X*X+Y*Y+Z*Z))

        # project to spherical panorama image
        x = args.input_width*(0.5*theta/np.pi+0.5)
        y = args.input_height*(phi/np.pi+0.5)

        lutx[r,c] = x
        luty[r,c] = y

print(lutx)
print(luty)
lut = np.concatenate([np.expand_dims(lutx,axis=-1),np.expand_dims(luty,axis=-1)],axis=-1)
np.save(args.lut_target,lut)

# solve for theta intrinsics
x0 = 0
x1 = len(thetas)-1
theta0 = thetas[0]
theta1 = thetas[-1]
c_theta = (theta0*x1 - theta1*x0)/(theta0 - theta1)
f_theta = (x0 - x1)/(theta0 - theta1)

# solve for Z intrinsics
y0 = 0
y1 = len(heights)-1
Z0 = heights[0]
Z1 = heights[-1]
c_Z = (Z0*y1 - Z1*y0)/(Z0 - Z1)
f_Z = (y0 - y1)/(Z0 - Z1)

print('Intrinsics:')
print('  f_theta: {}'.format(f_theta))
print('  c_theta: {}'.format(c_theta))
print('  f_Z: {}'.format(f_Z))
print('  c_Z: {}'.format(c_Z))

# save intrinsics to file
with open(args.intrinsics_target,'w') as f:
    f.write('%.15f %.15f %.15f %.15f' % (f_theta,c_theta,f_Z,c_Z))


#!/usr/bin/env python3

import arkouda as ak
import math

# dot product or two arkouda pdarrays
def ak_dot(u, v):
    if isinstance(u, ak.pdarray) and isinstance(v, ak.pdarray):
        return ak.sum(u*v)
    else:
        raise TypeError("u and v must be pdarrays")

# magnitude/L_2-norm of arkouda pdarray
def ak_mag2(u):
    if isinstance(u, ak.pdarray):
        return math.sqrt(ak_dot(u,u))
    else:
        raise TypeError("u must be a pdarray")

# cosine distance of two arkouda pdarrays
# should function similarly to scipy.spatial.distance.cosine
def ak_cos_dist(u, v):
    if isinstance(u, ak.pdarray) and isinstance(v, ak.pdarray):
        return (1.0 - ak_dot(u,v)/(ak_mag2(u)*ak_mag2(v)))
    else:
        raise TypeError("u and v must be pdarrays")

if __name__ == "__main__":
    from scipy.spatial import distance
    import numpy as np
    import argparse, sys, gc, time

    parser = argparse.ArgumentParser(description="Example of cosine distance/similarity in arkouda")
    parser.add_argument('--server', default="localhost", help='server/Hostname of arkouda server')
    parser.add_argument('--port', type=int, default=5555, help='Port of arkouda server')
    args = parser.parse_args()

    ak.v = False
    ak.connect(server=args.server, port=args.port)

    u1 = [1, 0, 0]
    v1 = [0, 1, 0]
    d1 = ak_cos_dist(ak.array(u1), ak.array(v1))
    print("d1 = ", d1)
    # d1 should be 1.0
    assert (np.allclose(d1, distance.cosine(u1,v1)))

    u2 = [100, 0, 0]
    d2 = ak_cos_dist(ak.array(u2), ak.array(v1))
    print("d2 = ", d2)
    # d2 should be 1.0
    assert (np.allclose(d2, distance.cosine(u2,v1)))

    u3 = [1, 1, 0]
    d3 = ak_cos_dist(ak.array(u3), ak.array(v1))
    print("d3 = ", d3)
    # d3 should be 0.29289321881345254
    assert (np.allclose(d3, distance.cosine(u3,v1)))

    ak.disconnect()


import numpy as np
from typing import TypeVar, Generic

T = TypeVar('T')

# Class for activation functions

class ActivationFunction(Generic[T]):
    def __init__(self, function_name):
        if function_name == 'sigmoid':
            self.activation_function = self._sigmoid
        elif function_name == 'tanh':
            self.activation_function = self._tanh
        elif function_name == 'relu':
            self.activation_function = self._relu
        elif function_name == 'softmax':
            self.activation_function = self._softmax
        elif function_name == "identity":
            self.activation_function = self._identity

    def activate(self, x: T, derivative=False) -> T:
        if derivative:
            return self.activation_function(x, derivative=True)
        return self.activation_function(x)

    def _sigmoid(self, x: T, derivative=False) -> T:
        if derivative:
            # y = self._sigmoid(x)
            y = x
            return y * (1 - y)
        return 1/(1 + np.exp(-x))

    def _tanh(self, x: T, derivative=False) -> T:
        tan = 2/(1 + np.exp(-2*x)) - 1
        if derivative:
            return (1-tan**2)
        return tan

    def _relu(self, x: T, derivative=False) -> T:
        if derivative:
            return (x > 0).astype(int)
        return np.max(0, x)

    def _softmax(self, x: T, derivative=False) -> T:
        if derivative:
            return x * (1 - x)
        # np.exp(x)/np.sum(np.exp(x))
        exponentials = np.exp(x)
        total = np.sum(exponentials)
        return exponentials/total

    def _identity(self, x: T, derivative=False) -> T:
        if derivative:
            return np.ones_like(x)
        return x


# okay, ehre is where I'm going to try to do my gaussian processes beginning in python.
#I'm first going to attempt to do a simple GP prior draw. from there we will move onto inference in toy problems, and hopefully beyond.

from __future__ import division
import numpy as np
import matplotlib.pyplot as plt

N = 100
l=0.01

#this generates my xgrid. it's probably really inefficient, but hey.
xgrid = []
for i in xrange(N):
	xgrid.append(-0.5+(1/N)*i)
xgrid = np.array(xgrid)
print xgrid.shape

def kernel(x,y,l):
	return np.exp(-(x-y)**2/l)
	#this is a very simple pseudogaussian kernel. should be pretty straightforward.

def construct_covmatrix(xgrid,l):
	sigma = []
	for i in xrange(len(xgrid)):
		col = []
		for j in xrange(len(xgrid)):
			col.append(kernel(xgrid[i],xgrid[j],l))
		col = np.array(col)
		sigma.append(col)
	sigma=np.array(sigma)
	return sigma

sigma = construct_covmatrix(xgrid,l)

def drawGpPrior(N,covmatrix): # we're assuming zero mean for now!
	mus = np.zeros(N)
	print mus.shape
	draw = np.random.multivariate_normal(mus,covmatrix)
	return draw

prior = drawGpPrior(N,sigma)
plt.plot(xgrid,prior)
plt.show()
#Wow! Holy crap it actually works. This straight up gives me a good prior draw. yay. So the distribution over such draws of functions is our prior. That actually makes sense.The multivariate normal is our distribution.Also, this isn't saved is it. That's def something we nered to do before we go to forresthill or something, so this can update the file sysetems. lert's now get back to work


# region Starting Values
import numpy as np
np.set_printoptions(suppress=True)

matrix = [[7.25, 0.98, 1.09, 1.105],
          [0.98, 3.17, 1.3, 0.16],
          [1.09, 1.3, 6.43, 2.1],
          [1.105, 0.16, 2.1, 5.11]]

N = len(matrix)
rounding = 5

# endregion Starting Values

# region Identity

def Identity(N):
    matrixForIdentity = [[0 for x in range(N)] for y in range(N)]
    for i in range(0, N):
        matrixForIdentity[i][i] = 1
    return matrixForIdentity

# endregion Identity

# region Dot

def Dot(matrix1: list, matrix2: list, N: int) -> list:
    res = [[0 for x in range(N)] for y in range(N)]

    for i in range(len(matrix1)):
        for j in range(len(matrix2[0])):
            for k in range(len(matrix2)):

                # resulted matrix
                res[i][j] += matrix1[i][k] * matrix2[k][j]
    return res

# endregion Dot

# region Prints

# print matrix
def PrintMatrix(matrixName,matrix):
    print("\n", matrixName,"=")
    for i in matrix:
        for j in i:
            print(round(j, rounding), end=" \t")
            if len(str(j)) <= 6:
                print(end=" \t")
        print()

# print matrix
def PrintMatrixAsNp(matrixName,matrix):
    print("\n", matrixName,"=")
    npMatrix = np.array(matrix)
    print(npMatrix.round(rounding))

# print additional parametrs
def PrintParametrs():
    print("\nN =", N)

# just printing
def PrintAll():
    PrintMatrix("Start Matrix", matrix)

    PrintParametrs()

# endregion Prints

PrintAll()

S_matrix = Identity(N)

for x in range(N - 1, 0, -1):
    M_matrix = Identity(N)

    M_matrixInverted = Identity(N)

    # Fill matrix b and minus one b
    for y in range(N):
        if y == x - 1:
            M_matrix[x - 1][y] = 1 / matrix[x][x - 1]
        else:
            M_matrix[x - 1][y] = matrix[x][y] / matrix[x][x - 1] * (-1)
        M_matrixInverted[x - 1][y] = matrix[x][y]

    print("\nIteration -", N - x)

    PrintMatrixAsNp("M Matrix", M_matrix)

    S_matrix = Dot(S_matrix, M_matrix, N)

    PrintMatrixAsNp("S Matrix", S_matrix)

    PrintMatrixAsNp("M Matrix Inverted", M_matrixInverted)

    matrix = Dot(M_matrixInverted, Dot(matrix, M_matrix, N), N)

    PrintMatrixAsNp("Intermediate result", matrix)

PrintMatrixAsNp("Final result as Frobenius Matrix", matrix)


'''
description: parametric lines in 3D space
author: ao wang
date: 09/02/2020
'''
import math

import sympy
from IPython.display import Math, display
from sympy.matrices import Matrix
from sympy.vector import CoordSys3D, matrix_to_vector

from axiomathbf.environment import isnotebook

class ParametricLine():
    '''A ParametricLine class that determines if lines are parallel,
       intersecting, or skew, point of intersection, and displaying
       the equations in latex.

    :param point: a point
    :type point: sympy.geometry.point.Point3D
    :param vector: a directonal vector
    :type vector: sympy.matrices.dense.MutableDenseMatrix
    '''

    def __init__(self, point, vector):
        self.point = sympy.Point(point)

        # Simplifies the directional vector
        self.vector = Matrix(vector)/sympy.gcd(list(vector))

    def __repr__(self):
        if isnotebook():
            display(Math(self.get_point_vector()))
            return ''
        return self.__str__()

    def __str__(self):
        x, y, z = self.point
        v1, v2, v3 = self.vector
        return '<x, y, z> = <{}, {}, {}> + <{}, {}, {}>t'.format(x, y, z, v1, v2, v3)

    def __eq__(self, other):
        # Checks equality of two Parametric Lines given they have the same point and same direction vectors
        return self.point == other.point and (self.vector == other.vector or self.vector == -other.vector)

    def get_point(self):
        '''Gets the point class attribute

        :return: the point class attribute
        :rtype: sympy.geometry.point.Point3D
        '''
        return self.point

    def set_point(self, point):
        '''Sets the point class attribute

        :param point: the point class attribute
        :type point: sympy.geometry.point.Point3D
        '''
        self.point = point

    def get_vector(self):
        '''Gets the vector class attribute

        :return: the vector class attribute
        :rtype: sympy.matrices.dense.MutableDenseMatrix
        '''
        return self.vector

    def set_vector(self, vector):
        '''Sets the vector class attribute

        :param vector: the vector class attribute
        :type vector: sympy.matrices.dense.MutableDenseMatrix
        '''
        self.vector = vector

    def compare(self, other):
        '''Compares two lines to see if they're intersecting, parallel, or skew

        :param other: the other line
        :type other: axiomathbf.parametric_line.ParametricLine
        :return: string that shows if intersecting, parallel, or skew
        :rtype: str
        '''
        if self.intersect(other):
            if self.vector.dot(other.vector) == 0:
                symbol = 'Perpendicular'
            else:
                symbol = 'Intersecting'
        elif self.vector.cross(other.vector).norm() == 0:
            symbol = 'Parallel'
        else:
            symbol = 'Skew'
        return symbol

    def distance(self, other):
        '''Calculates the distance between another ParametricLine object or sympy.Point object

        :param other: the other 3D object
        :type other: sympy.geometry.point.Point3D or axiomathbf.parametric_line.ParametricLine
        :return: the distance between the two objects
        :rtype: sympy.core.numbers.Floats
        '''
        if isinstance(other, ParametricLine):
            pq = Matrix(other.point-self.point)
            lines = self.compare(other)
            if lines == 'Skew':
                return abs(pq.dot(other.vector.cross(self.vector)))/(other.vector.cross(self.vector).norm())
            elif lines == 'Parallel':
                v = (pq.dot(self.vector)/(self.vector.norm())**2)*self.vector
                return (pq - v).norm()
            else:
                return 0
        elif isinstance(other, sympy.Point):
            pq = Matrix(other - self.point)
            return pq.cross(self.vector).norm()/self.vector.norm()

    def get_point_vector(self):
        '''Returns latex form of the vector in point vector form

        :return: renders latex of parametric line
        :rtype: str
        '''
        x, y, z = self.point
        v1, v2, v3 = self.vector
        return sympy.latex('$\\vec{\\ell(t)} = \\langle' + '{}, {}, {}'.format(x, y, z)
                           + '\\rangle +t \\langle ' + ' {}, {}, {}'.format(v1, v2, v3) + '\\rangle$')

    def intersect(self, other):
        '''Returns the point of intersection of two lines

        :return: the point of intersection
        :rtype: returns list of ints when intersecting, None if not intersecting
        '''
        x, y = sympy.symbols('x y')
        indices = [(i, j) for i in range(3) for j in range(i+1, 3)]

        solutions = []
        for i in indices:
            first, latter = i
            r1 = [self.vector[first], -other.vector[first],
                  other.point[first]-self.point[first]]
            r2 = [self.vector[latter], -other.vector[latter],
                  other.point[latter]-self.point[latter]]
            if r1 == r2:
                continue
            a = Matrix([r1, r2])
            solutions.append(sympy.solve_linear_system(a, x, y))
        if None not in solutions and solutions.count(solutions[0]) == len(solutions):
            return [pt + v*solutions[0][x] for (pt, v) in zip(self.point, self.vector)]
        return None


import numpy as np

from ..abstract import Model

class LinRegSGD(Model):
    """
    Linear regression model with stochastic gradient descent

    Args:
        l1_reg (float): L1 regularization strength
        l2_reg (float): L2 regularization strength
        max_loss (float): loss limitation
        random_seed (int): value for numpy random number generator initialization

    Methods:
        fit (X_train, y_train, learning_rate=1e-4, epochs=100): perform model learning
                    for training dataset
        predict (X): perform model prediction for array of samples

    """
    def __init__(
        self,
        l1_reg: float = 0.,
        l2_reg: float = 0.,
        max_loss: float = 1e12,
        random_seed: int = 0
    ):
        self.l1_reg = l1_reg
        self.l2_reg = l2_reg
        self.max_loss = max_loss
        self.random_seed = random_seed

    def fit(
        self,
        X_train: np.ndarray,
        y_train: np.ndarray,
        learning_rate: float = 1e-4,
        epochs: int = 100,
    ):
        """
        Perform model learning for training dataset

        Args:
            X_train (np.ndarray): train samples decision matrix
            y_train (np.ndarray): train samples ground-truth value
            epochs (int): Number of train loops for fit method
            learning_rate (float): SGD learning rate

        """
        num_weights = X_train.shape[1] + 1
        np.random.seed(self.random_seed)
        self.weights = np.random.rand(num_weights) * 2 - 1
        for _ in range(epochs):
            permutation = np.random.permutation(X_train.shape[0])
            for X_sample, y_sample in zip(X_train[permutation], y_train[permutation]):
                y_pred = self.predict(X_sample.reshape(1, -1))
                if self.l2_reg != 0:
                    l2_norm = np.linalg.norm(self.weights, ord=2)
                else:
                    l2_norm = 0
                if self.l1_reg != 0:
                    l1_norm = np.linalg.norm(self.weights, ord=1)
                else:
                    l1_norm = 0
                mse_der = 2 * (y_pred - y_sample)
                loss = np.clip(
                    mse_der + self.l2_reg * l2_norm + self.l1_reg * l1_norm,
                    -self.max_loss,
                    self.max_loss
                )
                grad_b = learning_rate * loss
                grad_w = learning_rate * loss * X_sample
                self.weights[0] = self.weights[0] - grad_b
                self.weights[1:] = self.weights[1:] - grad_w

    def predict(self, X: np.ndarray):
        """
        Perform model prediction for array of samples

        Args:
            X (np.ndarray): samples decision matrix

        """
        X_with_bias = np.concatenate([np.ones(X.shape[0]).reshape(-1, 1), X], axis=1)
        y_pred = np.sum(self.weights * X_with_bias, axis=1)
        return y_pred


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jan  8 08:42:56 2020

@author: aimsg
"""
#[s0+v0*t+0.5*a0*t**2+a0*t*(t-t1)]
import numpy as np
import matplotlib.pyplot as plt
#Below are the constants needed in this problem
rho=1.2e-2;h=8.3;c=1000;a=0.3;S0=1367;epsilon=0.6;sigma=5.67e-8#costants given
'''Exact Solution'''
Eq_T=(((1-a)*S0)/(4*epsilon*sigma))**(1/4)#Equilibrium temperature
constant=(-4*epsilon*sigma*(Eq_T**3))/(rho*c*h)
t=np.arange(0.0,500.0,14)
Temp=[]#Create an empty list T
for i in t:
    Temp.append(10*np.exp(constant*i)+Eq_T) #For every value of t, compute the exact solution of the equation and append it to Temp

'''APPROXIMATE SOLUTION '''
T=[300.0] #create a list yo
def f(t,y):
    return ((1.0-a)*S0-4.0*epsilon*sigma*(y**4.0))/(4.0*h*rho*c)
for j in t[:-1]:
    K1=f(j,T[-1]) #calculate the value of K1 as solved in the assignment
    K2=f(j+0.75*14,T[-1]+0.75*14*K1)#calculates the value of k2
    #print(K1,K2)
    T.append(T[-1]+(1/3)*14*(K1+2*K2)) #using the initial temp, it calucaltes fot T_n+1 for each value of t

plt.plot(t,Temp,label="Exact") #plots the exact soluton
plt.plot(t,T,label="Approx")  #Plots the approximate solution
plt.ylabel("Temperature")
plt.xlabel("time")
plt.title("Exact and Approximate solutions for the conservation of energy\n")
plt.legend()
plt.grid()
plt.savefig('graph.png')
#


import numpy as np
import sys
if "../" not in sys.path:
    sys.path.append("../")
from lib.envs.gridworld import GridworldEnv

env = GridworldEnv()

def policy_eval(policy, env, v, df=1.0, theta=0.00001):
    while True:
        v_new = np.zeros(env.nS)
        delta = 0
        for i in range(env.nS):
            for j in range(env.nA):
                for prob, next_state, reward, done in env.P[i][j]:
                    v_new[i] += (policy[i][j] * (reward + (df * prob * v[next_state])))
            delta = max(abs(v_new[i] - v[i]), delta)
        if delta > theta:
            for i in range(env.nS):
                v[i] = v_new[i]
        else:
            break
    return np.array(v)

#initiate with uniform policy and zeroed value function
random_policy = np.ones([env.nS, env.nA]) / env.nA
v = np.zeros(env.nS)
v = policy_eval(random_policy, env, v)

# Test: Make sure the evaluated policy is what we expected
expected_v = np.array([0, -14, -20, -22, -14, -18, -20, -20, -20, -20, -18, -14, -22, -20, -14, 0])
print "expected_v: ", expected_v
print "evaluated_v: ", v
np.testing.assert_array_almost_equal(v, expected_v, decimal=2)


import numpy as np

def ndarray_integer_arange(min_value, max_value, step_value):
    """max_value is not include in array"""
    return np.arange(min_value, max_value, step_value)

def ndarray_float_arange(min_value, max_value, split_number):
    """max_value is include in array"""
    return np.linspace(min_value, max_value, split_number)

def n_dimensional_zero_array(*array_shape):
    """generate n-dimensional array with number zero\r\n
    eg.
        one dimensional :    n_dimensional_zero_array(2)\r\n
        two dimensional :    n_dimensional_zero_array(2,2))\r\n
        three dimensional:    n_dimensional_zero_array(2,3,4))
    """
    return np.zeros(array_shape)

def n_dimensional_one_array(*array_shape):
    """generate n-dimensional array with number one"""
    return np.ones(array_shape)

def n_dimensional_array_full_number(full_number, *array_shape):
    """generate n-dimensional array with with the given value\r\n
        eg. n_dimensional_array_full_number(np.pi, 3, 4), this create 3x4 matrix full of π
    """
    return np.full(array_shape, full_number)

def n_dimensional_array_random_number(*array_shape):
    """random_sample, function equals rand, unlike rand, can accept a tuple as argument """
    return np.random.random_sample(array_shape)

def n_dimensional_array_random_number_normal(*array_shape):
    """standard_normal, function equals randn, unlike randn, can accept a tuple as argument\r\n
     return random number in normal distribution (Gaussian distribution)
     """
    return np.random.standard_normal(array_shape)

def get_array_rank(array):
    """equal to len(numpy.shape)"""
    return np.ndim(array)

def get_array_shape(array):
    """get an array's list of axis lengths
     , rank is equal to the shape's length."""
    return np.shape(array)

def get_array_size(array):
    """the total number of elements,
    which is the product of all axis lengths (eg. 3*4=12)"""
    return np.size(array)

def get_array_universal_functions(array, np_function_name):
    for func in (np.min, np.max, np.sum, np.std, np.var, np.mean, np.prod, np.square, np.abs,
                 np.sqrt, np.exp, np.log, np.sign, np.ceil, np.modf, np.isnan, np.cos):
        if func.__name__ == np_function_name:
            return func(array)

def save_numpy_array(file_name, file_type, array):
    if file_type is None:
        np.save(file_name, array)
    elif file_type == 'text':
        np.savetxt(''.join((file_name, '.csv')), array, delimiter=',')

def save_zipped_numpy_array(file_name, compress, array):
    if compress is False:
        np.savez(file_name, array)
    else:
        np.savez_compressed(file_name, array)

def load_numpy_array(file_name, file_type):
    if file_type is None:
        return np.load(''.join((file_name, '.npy')))
    elif file_type == 'text':
        return np.loadtxt(''.join((file_name, '.csv')), delimiter=',')

def load_zipped_numpy_array(file_name):
    return np.load(''.join((file_name, '.npz'))).get('arr_0')

# print(get_array_shape(two_rank_dimensional(4, 2)))
# print(get_array_size(two_rank_dimensional(4, 2)))
# print(get_array_rank(two_rank_dimensional(4, 2)))
# print(ndarray_integer_arange(0, 5/3, 5/9))
# print(ndarray_float_arange(0, 5/3, 4))
# print(n_dimensional_array_random_number(2, 3))
# print(n_dimensional_array_random_number_normal(2, 3))
# a = np.array([[-2.5, 3.1, 7], [10, 11, 12]])
# print(get_array_universal_functions(a, 'cos'))


'''Spiral Dataset

Author: Andrei-Claudiu Roibu, 2019

This code has been created to compare the speed difference between a numpy dot product and a slow dot product. This code was written in support of my learning.

The original code comes from these two sources:

    # https://deeplearningcourses.com/c/deep-learning-prerequisites-the-numpy-stack-in-python
    # https://www.udemy.com/deep-learning-prerequisites-the-numpy-stack-in-python

Description:

This code generates and plots the spiral dataset. It parameterizes the radius and angle, and makes them both proportional to a parametr t.

The ideea here is to increase the radius from low to high, while also increasing the angle proportional to the radius.

X is defined as radius * cos(angle), while y is defined as r * sin(angle)

'''

import numpy as np
import matplotlib.pyplot as plt

def generate_radius_and_angle(arms,number_of_points):
    """ Radius and Angle generator

    This function generates the information required for the radius and angle.

    Args:
        arms (int): Number of spiral arms to be generated.
        number_of_points (int): Number of points to be generated for each arm

    Returns:
        radius (np.array): The radius of each arm
        thetas (np.array): An array containing the angles for each of the arms

    """

    radius = np.linspace(1,10,number_of_points)
    thetas = np.empty((arms,number_of_points))

    for arm_index in range(arms):
        start_angle = np.pi * arm_index / 3.0
        end_angle = start_angle + np.pi / 2
        angles = np.linspace(start_angle, end_angle, number_of_points)
        thetas[arm_index] = angles

    return radius, thetas

def generate_data(arms,number_of_points):
    """ Data point generator

    Function generating the points required for the concentric circles

    Args:
        arms (int): Number of spiral arms to be generated.
        number_of_points (int): Number of points to be generated for each arm

    Returns:
        X (np.array): Array of required points
    """

    radius, thetas = generate_radius_and_angle(arms,number_of_points)
    x1 = np.empty((arms,number_of_points))
    x2 = np.empty((arms,number_of_points))
    for arm_index in range(arms):
        x1[arm_index] = radius * np.cos(thetas[arm_index])
        x2[arm_index] = radius * np.sin(thetas[arm_index])

    X = np.empty((number_of_points * arms, 2))
    X[:,0] = x1.flatten()
    X[:,1] = x2.flatten()

    X += np.random.randn(X.shape[0], X.shape[1]) * 0.5 # Adding some gaussian noise

    return X

def generate_labels(arms,number_of_points):
    """ Label Generator

    Function which generates the required labels for the data

   Args:
        arms (int): Number of spiral arms to be generated.
        number_of_points (int): Number of points to be generated for each arm

    Returns:
        y (np.array): Labels array

    """

    N = int(number_of_points)
    y = [0]*N + [1]*N
    y = y * int(arms//2)
    y = np.array(y)

    return y

def plot_spiral(arms,number_of_points):
    """ Spiral plotter

    Function plotting the XOR distribution.

   Args:
        arms (int): Number of spiral arms to be generated.
        number_of_points (int): Number of points to be generated for each arm
    """

    X = generate_data(arms,number_of_points)
    y = generate_labels(arms,number_of_points)
    plt.scatter(X[:,0], X[:,1], c=y)
    plt.show()

if __name__ == "__main__":
    number_of_points = 2000
    arms = 6
    plot_spiral(arms,number_of_points)


import numpy as np
import pandas as pd
from morpheus.core.utils import log

class GaussianElimnation:
    """
    An algorithm for solving system of linear equations.
    https://en.wikipedia.org/wiki/Gaussian_elimination
    """
    def __init__(self, A: np.ndarray, x: list, b: np.ndarray, partial_pivot=True, decimals=4, use_streamlit=True):
        self.A = A
        self.x = x
        self.b = b
        self.partial_pivot = partial_pivot
        self.decimals = decimals
        self.augmented_matrix = np.hstack((A, b))
        self.m, self.n = self.augmented_matrix.shape
        self.row_ids = ["R{}".format(i) for i in range(1, self.m + 1)]
        self.U = None
        self.use_streamlit = use_streamlit

    def forward_elimnation(self):
        """
        Forward elimnation of the augmented matrix
        leading to a Upper Triangular matrix (U)
        """
        log("Initial matrix is \n", self.use_streamlit)
        log(pd.DataFrame(self.augmented_matrix, columns=self.x + ["b"], index=self.row_ids), self.use_streamlit)

        mat = self.augmented_matrix

        for col in range(0, self.n - 1):
            log("\n Iterating over column {} \n".format(col + 1), self.use_streamlit)
            for row in range(0, self.m):
                if col == row == 0:
                    col_max = mat[:, col].argmax()
                    if col_max != col:
                        log("\n\n  Operation R{0} <-> R{1}\n".format(col + 1, col_max + 1), self.use_streamlit)
                        mat[[row, col_max], :] = mat[[col_max, row], :]
                        log(pd.DataFrame(mat, columns=self.x + ["b"], index=self.row_ids), self.use_streamlit)

                if mat[row, col] != 0 and row > col:
                    mult_factor = mat[row, col] / mat[col, col]
                    log("\n\n Operaton : R{row_num} -> R{row_num} - R{col} * {mult_factor} \n".format(row_num=row + 1,
                                                                                mult_factor=mult_factor,
                                                                                col=col + 1), self.use_streamlit)

                    mat[row, :] = mat[row, :] - (mult_factor * mat[col, :])
                    log(pd.DataFrame(mat, columns=self.x + ["b"], index=self.row_ids), self.use_streamlit)

                mat = mat.round(decimals=self.decimals)
        self.U = mat

    def backward_substitution(self):
        """
        Substitute values from backward to find the
        values of unknown.

        https://algowiki-project.org/en/Backward_substitution
        """

        unknowns =  np.zeros(len(self.x))
        for r in range(len(self.x) -1 ,-1,-1):
            row = self.U[r,:self.n-1]
            b = self.U[r][self.n -1]
            if np.count_nonzero(row) == 1:

                unknowns[r] = 1
                unknowns[r] = b / np.dot(row, unknowns)
            else:

                leading_val = row[r]

                if leading_val > 0:
                    unknowns[r] = (b - np.dot(row,unknowns)) / leading_val
                else:
                    unknowns[r] = 0

        result = pd.DataFrame(np.hstack((np.array(self.x).reshape(-1,1),unknowns.reshape(-1,1))), columns = ["unknowns","root"])
        result["root"] = result.apply(lambda x : float(x["root"]),axis =1)
        log("# Solution of the Linear equation \n", self.use_streamlit)
        log(result, self.use_streamlit)
        return result


from typing import Sequence

import numpy as np

def pv(y: float, C: Sequence[float], due=False):
    """
    Compute the present value of a set of cash flows

    :param y: yield
    :param C: cash received
    :param due: True if the first flow occurs at the present time, or the next period otherwise
    :return: present value of cash flow
    """
    disc = np.power(1 + y, -np.arange(len(C)) - (0 if due else 1))
    return np.sum(disc * C)

def fv(y: float, C: Sequence[float]):
    """
    Compute the future value of a set of cash flows
    :param y:
    :param C:
    :return:
    """
    disc = np.power(1 + y, -np.arange(0, len(C))[::-1])
    return np.sum(disc * C)

def compound2(r: float, m: int, n: int = 0):
    """
    Convert an interest rate compounded m times per annum
    into the equivalent rate compounded n times per annum

    :param r: interest rate
    :param m: compound periods per annum of input, 0 for continuous compounding
    :param n: compound periods per annum of output, 0 for continuous compounding
    :return:
    """
    if m == n:
        return r
    c = r if m == 0 else m * np.log(1 + r / m)
    if n == 0:
        return c
    return n * (np.exp(c / n) - 1)

def amortize(PV: float, n: int, r: float, m: int = 12):
    """
    Compute the level payment of fully amortized traditional mortgages.
    Note that r is bond-equivalent if m = 2, or mortgage-equivalent if m = 12

    <! WARNING: outdated comments>
    Newton's method is used to find the solution.
    However, it is guaranteed to find the solution in less than one iteration
    due to the constant derivative of present value with respect to level payment.
    <! outdated comments>

    The current computation uses the fact that
    the first derivative of present value with respect to level payment is constant

    :param PV: present value of original balance
    :param n: maturity in years
    :param r: annual interest rate, default is 12
    :param m: compound period
    :return: level payment of fully amortized mortgage
    """
    y = 1 + r / m
    return PV * r / m / (1 - y ** (-m * n))

if __name__ == '__main__':
    print(amortize(250000, 15, 0.08))


# Copyright 2018 - Jonathan Alcantara e Osmar Fernandes

# 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

#     http://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.

import numpy as np

tolerance = 0.00000001
iterations_limit = 10000

def newton(x0, f, f_derivative):

    x_previous = x0
    for iteration in range(iterations_limit):
        x_current = x_previous - f(x_previous)/f_derivative(x_previous)
        if(abs(x_current - x_previous) < tolerance):
            return x_current

        x_previous = x_current

    return x_current

def f(x):
    return pow(x, 2) - 4*np.cos(x);

def f_derivative(x):
    return 2*x + 4*np.sin(x)

print(newton(10.0, f, f_derivative))


import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from py_expression_eval import Parser
import math
parser = Parser()

class Diff_F(object):
    """Differentiate a given function at any given point"""

    def __init__(self, f_expr):
        self.f_raw = parser.parse(f_expr)
        self.n = 1
        self.h = 0.3
        self.ans = float('nan')

    def f(self, x):
        return self.f_raw.evaluate({'x': x})

    @property
    def sol(self):
        return self.ans

    def differentiate(self, order, x, h=0.3, method='central'):
        """
        Numerically compute nth derivative of any given function
        This is numerically VERY unstable (as the errors propogate)
        In my tests, it works reliably for n ~ 1 ... 12
        """
        # nCk
        choose = lambda n,k: 1 if k == 0 else n * choose(n-1,k-1) / k

        n = order
        self.n = n
        self.h = h
        self.method = method

        result = 0.0
        if method.lower() == 'central':
            for k in range(n+1):
                result += pow(-1,k)*choose(n,k)*self.f(x+(n/2 - k)*h)
        elif method.lower() == 'forward':
            for k in range(n+1):
                result += pow(-1,k)*choose(n,k)*self.f(x+(n-k)*h)
        elif method.lower() == 'backward':
            for k in range(n+1):
                result += pow(-1,k)*choose(n,k)*self.f(x-k*h)
        else:
            raise Exception(f'method `{method}` not implemented')

        self.ans = result / pow(h,n)
        return self.ans

    def table(self, range, num_pts=500):
        xs = np.linspace(*range, num_pts)
        y_s = [self.differentiate(self.n, x, self.h, self.method) for x in xs]
        ys = [self.f(x) for x in xs]
        return xs, ys, y_s

    def visualize(self, range, num_pts=500):
        xs, ys, y_s = self.table(range, num_pts)
        plt.subplot(211)
        plt.plot(xs, ys, c='b', label='f')
        plt.plot(xs,[0]*len(xs), c='k', label='X-axis')
        yl = plt.gca().get_ylim()
        plt.legend(loc='upper left')

        plt.subplot(212)
        plt.plot(xs,y_s, c='r', label=f'f^({self.n})', zorder=2)
        plt.plot(xs,[0]*len(xs), c='k', label='X-axis', zorder=1)
        plt.legend(loc='upper left')
        plt.gca().set_ylim(yl)
        plt.show()


from  matplotlib import pyplot as plt
import numpy as np

# Define dimension of matrix and vectors
Dim = 2
#Setting up a transition probability matrix
TransitionMatrix = np.matrix('0.25 0.5; 0.75 0.5')
# Making a copy of the transition matrix
W = TransitionMatrix
print(W)
# our first state
wold = np.zeros(Dim)
wold[0] = 1.0
wnew = np.zeros(Dim)

# diagonalize and obtain eigenvalues, not necessarily sorted
EigValues, EigVectors = np.linalg.eig(TransitionMatrix)
# sort eigenvectors and eigenvalues
permute = EigValues.argsort()
EigValues = EigValues[permute]
EigVectors = EigVectors[:,permute]
for i in range(Dim):
    print(EigValues[i])
FifthEigvector = EigVectors[:,1]

print(FifthEigvector)

difference = np.linalg.norm(FifthEigvector-wold,2)
print(difference)
eps = 1.0E-10
count = 0
while count < 10:
      for i in range(Dim):
          for j in range(Dim):
              wnew[i] = wnew[i]+W[i,j]*wold[j]
      count = count + 1
      print(count, wnew)
#      difference = np.linalg.norm(FifthEigvector-wnew,2)
#      print difference
      wold = wnew
#plt.plot(r, FirstEigvector**2 ,'b-',r, SecondEigvector**2 ,'g-',r, ThirdEigvector**2 ,'r-')
#plt.axis([0,4.6,0.0, 0.025])
#plt.xlabel(r'$r$')
#plt.ylabel(r'Radial probability $r^2|R(r)|^2$')
#plt.title(r'Radial probability distributions for three lowest-lying states')
#plt.savefig('eigenvector.pdf')
#plt.show()


# coding: utf-8

# In[184]:

import numpy as np
import pylab
import scipy
import seaborn as sns
get_ipython().magic(u'matplotlib inline')
get_ipython().magic(u"config InlineBackend.figure_format = 'retina'")

# # Importance sampling
#
# We'll look at an example where we can compute the posterior exactly and compare it to an approximation computed via importance sampling.
#
# Suppose we have the following model:
# \begin{align}
# \mu &\sim N(0, 9) \\
# x_{1:n} &\sim N(\mu, 1)
# \end{align}
#
# Because this is a conjugate model, we can compute the posterior exactly:
# $$p(\mu | x_{1:n}) = N\left(\mu \,\bigg|\, \frac{\sum_i x_i}{(1/9 + n)}, 9/(1+9n) \right).$$
#
# To compute the importance sampling procedure, we first collect samples from some importance distribution $\mu_i \sim q(\mu)$,
# and then compute the unnormalized weights:
# $$ w_i \propto \frac{p(\mu_i) p(x_{1:n} | \mu_i)}{q(\mu_i)}$$
#
# The normalized weights $w_i$ give us an approximation to the posterior.
# Here $q$ is some distribution with the same support as the posterior that we know how to sample from. In general we want $q$ to have longer tails than the posterior.

# In[15]:

def generate_data(n=100):
    mu = np.random.normal(0, 9)
    return np.random.normal(mu, 1, n)

# In[16]:

n=100
data = generate_data(n)

# In[189]:

c = 1./9 + n
vals = [scipy.stats.distributions.norm.pdf(m, data.sum()/c, np.sqrt(1./c))
        for m in np.arange(12.5,13.5,0.01)]

# In[185]:

pylab.plot(np.arange(12.5,13.5,0.01), vals)

# In[126]:

def importance_sample(data, nsamps=100):
    from scipy.stats.distributions import norm
    mus = np.random.normal(0, 5, nsamps)

    wts = np.zeros(nsamps)
    for i, mu in enumerate(mus):
        wts[i] = norm.logpdf(mu, 0, 3) + sum(norm.logpdf(data, mu, 1)) - norm.logpdf(mu, 0, 5)

    # stabilize weights
    wts - wts.max()
    wts = wts - np.log(sum(np.exp(wts)))

    return np.exp(wts), mus

# In[187]:

wts, mus = importance_sample(data, 100000)

# In[188]:

inds = np.argsort(mus)
wts_s = wts[inds]
mus_s = mus[inds]
pylab.plot(mus_s, wts_s)
pylab.xlim((12.5,13.5))
pylab.axvline(sum(mus*wts), ls='dotted')

# Above we've plotted the importance weights and the posterior mean.

# In[ ]:


import numpy as np
import matplotlib.pyplot as plt

class Monte_Carlo_Estimator():
    """
    This estimator creates a monte-carlo-simulation. The simulation builds n
    points on a area of 2x2 (uniformly distributed) and returns the ratio of
    the number of points that landed in the unit circle compared with the one
    who do not.

    """

    def __init__(self, n=1000):

        self.n = n
        self.x = np.random.uniform(-1,1,self.n)
        self.y = np.random.uniform(-1,1,self.n)

    def estimate_pi(self):
        """
        Function to estimate pi given n uniformly distributed points on a area 2X2.

        """

        # count all points that are in the unit circle
        count_unit = sum(1 if (self.x[i]**2 + self.y[i]**2 <= 1) else 0
                         for i in range(self.n))

        # calculate pi estimation
        pi_est = 4*count_unit/self.n

        # determine the error
        error = np.round(100*abs(pi_est - np.pi)/np.pi, 4)

        return 'Estimation of pi: {}, error: {}%'.format(pi_est, error)

    def circle_plot(self):
        """
        Function to plot the unit circle and the simulated points.

        """

        seq = np.linspace(0, 2*np.pi, 100)

        u = np.cos(seq)
        v = np.sin(seq)

        fig, ax = plt.subplots(1)

        # for loop to plot the points and color them
        for i in range(self.n):
            if self.x[i]**2 + self.y[i]**2 <= 1:
                ax.plot(self.x[i],self.y[i],'r.')
            else:
                ax.plot(self.x[i],self.y[i],'b.')

        ax.plot(u, v)

        ax.set_aspect(1)

        plt.xlim(-1.25,1.25)
        plt.ylim(-1.25,1.25)

        plt.grid(linestyle='--')

        plt.title('plot unit circle for pi estimation', fontsize=8)

        plt.show()


# ISLR Ch 10 by Carol Cui

import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
from scipy.spatial import distance
from scipy.cluster.hierarchy import linkage, dendrogram, cut_tree
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans

# ----------------------------------------------------------------------------
# Q7
USArrests  = pd.read_csv('C:\\Users\\Carol\\Desktop\\USArrests.csv')
state_name = USArrests.iloc[:,0] # abstract a list of state names
# rename index of each row to its corresponding state name
USArrests  = USArrests.rename(index = lambda x: state_name[x])
# drop the column of state name from the original data frame
USArrests.drop(USArrests.columns[[0]], axis=1, inplace=True)

scaled_x  = StandardScaler().fit_transform(USArrests)
scaled_tx = scaled_x.transpose()

Edis  = distance.pdist(scaled_tx, metric='euclidean')
Edis  = distance.squareform(Edis)
Edis2 = Edis**2
corr  = np.corrcoef(scaled_x, rowvar=False)
prop  = (1-corr)/Edis2
print(prop) # 0.01

# ----------------------------------------------------------------------------
# Q8
# (a)
pca       = PCA()
reduced_x = pca.fit_transform(scaled_x)
pve1      = pca.explained_variance_ratio_
print(pve1)

# (b)
pve2 = np.zeros(4)
for i in range(0,4):
    pve2[i] = np.sum(np.matmul(pca.components_[i,:],scaled_tx)**2)/np.sum(scaled_tx**2)
print(pve2)

# ----------------------------------------------------------------------------
# Q9
# (a)
hc_complete1 = linkage(USArrests, 'complete')

# (b)
res1            = pd.DataFrame(cut_tree(hc_complete1, n_clusters = 3), index=state_name)
res1.index.name = 'states'
res1.rename(columns={0: 'ID'}, inplace=True)

# (c)
hc_complete2    = linkage(scaled_x, 'complete')
res2            = pd.DataFrame(cut_tree(hc_complete2, n_clusters = 3), index=state_name)
res2.index.name = 'states'
res2.rename(columns={0: 'ID'}, inplace=True)

# (d)
res = res1.join(res2, lsuffix='_or', rsuffix='_sd')

# plots
fig1, (ax1, ax2) = plt.subplots(2,1)
ax1.scatter(range(0,len(state_name)), res1)
ax1.set_title('original data')
ax2.scatter(range(0,len(state_name)), res2, color='red')
ax2.set_title('scaled data')

# dendrogram
plt.figure(2)
plt.title('Hierarchical Clustering Dendrogram original data')
plt.xlabel('states')
plt.ylabel('Ecludian distance')
dendrogram(hc_complete1, labels=res1.index, leaf_rotation=90, leaf_font_size=8)
plt.axhline(y=150, c='k', ls='dashed')
plt.show()

plt.figure(3)
plt.title('Hierarchical Clustering Dendrogram scaled data')
plt.xlabel('states')
plt.ylabel('Ecludian distance')
dendrogram(hc_complete2, labels=res2.index, leaf_rotation=90, leaf_font_size=8)
plt.axhline(y=4.45, c='k', ls='dashed')
plt.show()

# Before scaling, cluster sizes are more equal.
# Scaling puts more states in one particular cluster.
# Scaling is better cuz crime frequencies and variable units are different.

# ----------------------------------------------------------------------------
# Q10
# (a)
n = 60
p = 50

np.random.seed(1)
y = np.concatenate((np.repeat(0,20), np.repeat(1,20), np.repeat(2,20)))
x = np.random.rand(n,p)
x[1:20, 1:20]   = x[1:20, 1:20] + 3
x[21:40, 21:40] = x[21:40, 21:40] - 4

# (b)
pca       = PCA()
reduced_x = pca.fit_transform(x)
plt.scatter(reduced_x[:,0], reduced_x[:,1], c=y, cmap=mpl.cm.Paired)
plt.xlabel('Z1')
plt.ylabel('Z2')

# (c)
kmeans3 = KMeans(n_clusters=3, n_init=20, random_state=2).fit(x)
pd.crosstab(index=kmeans3.labels_, columns=y, rownames=['K-Means 3'], colnames=['y'])
# Kmeans correctly identifies 3 clusters.

# (d)
kmeans2 = KMeans(n_clusters=2, n_init=20, random_state=3).fit(x)
pd.crosstab(index=kmeans2.labels_, columns=y, rownames=['K-Means 2'], colnames=['y'])
# Kmeans assign y0 and y2 to the same cluster.

# (e)
kmeans4 = KMeans(n_clusters=4, n_init=20, random_state=4).fit(x)
pd.crosstab(index=kmeans4.labels_, columns=y, rownames=['K-Means 4'], colnames=['y'])
# Kmeans splits y2 into 2 different clusters.

# (f)
kmeans3pca = KMeans(n_clusters=3, n_init=20, random_state=5).fit(reduced_x[:,0:2])
pd.crosstab(index=kmeans3pca.labels_, columns=y, rownames=['K-Means PCA 3'], colnames=['y'])
# Kmeans correctly identifies 3 clusters.

# (g)
scaled_x  = StandardScaler().fit_transform(x)
kmeans3sd = KMeans(n_clusters=3, n_init=20, random_state=6).fit(scaled_x)
pd.crosstab(index=kmeans3sd.labels_, columns=y, rownames=['K-Means scaled 3'], colnames=['y'])
# Kmeans correctly identifies 3 clusters.

# ----------------------------------------------------------------------------
# Q11
# (a)
df = pd.read_csv('C:\\Users\\Carol\\Desktop\\Ch10Ex11.csv', header=None)
df = df.T

# (b)
# dendrograms
all_hc   = []
linkages = ['complete', 'average', 'single']
for i, link in zip(range(1,4), linkages):
    hc = linkage(y=df, method=link, metric='correlation')
    all_hc.append(hc)
    plt.figure(i)
    plt.title('linkage: %s' %link)
    plt.xlabel('genes')
    plt.ylabel('correlation-based distance')
    dendrogram(hc, labels=df.index, leaf_rotation=90, leaf_font_size=10)

# cluster results
# complete: identify the decreased group correctly
res1 = pd.DataFrame(cut_tree(all_hc[0], n_clusters = 2))
res1.index.name = 'patients'
res1.rename(columns={0: 'ID_complete'}, inplace=True)
res1

# average: identify the decreased group correctly
res2 = pd.DataFrame(cut_tree(all_hc[1], n_clusters = 2))
res2.index.name = 'patients'
res2.rename(columns={0: 'ID_average'}, inplace=True)
res2

# single: fail to identify the decreased group
res3 = pd.DataFrame(cut_tree(all_hc[2], n_clusters = 2))
res3.index.name = 'patients'
res3.rename(columns={0: 'ID_single'}, inplace=True)
res3

# Yes, my results depend on the type of linkage used.

# (c)
pca       = PCA()
reduced_x = pca.fit_transform(df)
pve       = pca.explained_variance_ratio_

fig, (ax1, ax2) = plt.subplots(1,2)
ax1.scatter(range(0, len(pve)), pve)
ax1.set_xlabel('principal component')
ax1.set_ylabel('PVE')
ax2.scatter(range(0, len(pve)), np.cumsum(pve), color='brown')
ax2.set_xlabel('principal component')
ax2.set_ylabel('cumulative PVE')
# There is an elbow after 1st principal component.

# conclusion
PC1                    = pd.DataFrame({'gene': range(1, len(df.T)+1), 'loading_vec': pca.components_[0,:]})
PC1['abs_loading_vec'] = abs(PC1['loading_vec'])
PC1_top5               = PC1.sort_values(by=['abs_loading_vec'], ascending=False)['gene'][:5]
print('Top 5 genes that differ the most across 2 groups: %s' %np.array(PC1_top5))


# -*- coding: utf-8 -*-
"""
These are functions created to calculate the l_i and l_i_prime terms for
lagrange and hermite interpolation.

Last update: 11/11/2018
Ben St. Aubin
"""
import numpy as np

def l_i(x,t_data,i):
    #If x is an array, returns an array of values, where out[n] = l_i(x[n])
    #
    #If x is a single value, returns a single value l_i(x)
    t = np.delete(t_data,i)
    if np.size(x)==1:
        return np.product(x-t)/np.product(t_data[i]-t)
    else:
        num = np.subtract.outer(x,t)
        return np.product(num,axis=1)/np.product(t_data[i]-t)

def l_i_array(x,t_data):
    #if x is a single value, outputs a 1-D array "out", where out[i] = l_i(x)
    #
    #if x is an array, outputs a 2-D array "out", where out[i,n] is l_i(x[n])
    if np.size(x)==1:
        out = np.zeros(len(t_data))
        for i in range(len(t_data)):
            t = np.delete(t_data,i)
            out[i] = np.product(x-t)/np.product(t_data[i]-t)
    else:
        out = np.zeros((len(t_data),len(x)))
        for i in range(len(t_data)):
            t = np.delete(t_data,i)
            num = np.subtract.outer(x,t)
            out[i,:] = np.product(num,axis=1)/np.product(t_data[i]-t)
    return out

def l_i_p_array(t_nodes):
    #output is "l_prime", where l_prime[i] = l_i_prime(t_i), for t_i nodes
    x = np.array(t_nodes,float)
    l_prime = np.zeros(len(x))
    for i in range(len(x)):
        t = np.delete(t_nodes,i)
        l_prime[i] = np.sum(1/(t_nodes[i]-t))
    return l_prime

def l_i_prime(t_nodes,i):
    #output is l_i_prime(t_i) for t_i nodes input
    x = np.delete(t_nodes,i)
    return np.sum(1/(t_nodes[i]-x))


# -*- coding: utf-8 -*-
"""
Ejercicio 3: Descomposición LU de una matriz para resolver un sistema lineal
de ecuaciones.

Función LU: Para una matriz cuadrada A calcula las matirces L y tales que A = L*U, con
U triangular superior y L triangular inferior.

Argumentos de entrada:
         A: matriz cuadrada (array numpy de dos dimensiones)

Argumentos de salida:
         L: matriz triangular inferior (array numpy de dos dimensiones).
         U: matriz triangular superior (array numpy de dos dimensiones).

Ejemplos:
         A = np.array([[2., 1, 1], [1, 2, 1], [1, 1, 2]])
         b = np.array([2.,4,6])
         L,U = LU(A)
         print('L=')
         print(L)
         print('U=')
         print(U)
          Salida:
              L =
               [[1.   0.   0.  ]
               [0.5  1.   0.  ]
               [0.5  0.33 1.  ]]
              U =
               [[2.   1.   1.  ]
               [0.   1.5  0.5 ]
               [0.   0.   1.33]

"""
import numpy as np

# Función LU
#-----------------------------------------------------------------------------
def LU(A):
    m,n = A.shape   # dimensiones de la matriz A
    # Comprobamos que la matriz A es cuadrada
    if m != n:
        print('La matriz A no es cuadrada')
        return
    U = np.copy(A)  # hacemos una copia de A
    L = np.eye(n)
    for k in range(0,n):               # bucle para recorrer las columnas
        for i in range(k+1,m): # bucle para recorrer las filas
            f = U[i,k]/U[k,k]                # coeficiente f
            U[i,:] -= f*U[k]              # Fila i - f veces la Fila k
            L[i,k] = f               # el elemento (i,k) de L es el correspondiente coeficiente f
    return L,U

#--------------------------------------
# Ejemplos
#--------------------------------------

# Ejemplo de prueba
#-------------------------
A = np.array([[2., 1, 1], [1, 2, 1], [1, 1, 2]])
b = np.array([2.,4,6])
L,U = LU(A)
print('L=')
print(L)
print('U=')
print(U)

# Función sus_prog (ver ejercicio1.py)
#-----------------------------------------------------------------------------
def sus_prog(L,b):
    m,n = L.shape   # dimensiones de la matriz L
    # Comprobamos que la matriz L es cuadrada
    if m != n:
        print('La matriz L no es cuadrada')
        return
    # Comprobamos que las dimensiones de L y b son adecuadas
    if n != len(b):
        print('Las dimensiones no son correctas')
        return
    # Comprobamos que la matriz L es no singular
    d = np.diag(L)
    for i in range(0,len(d)):
        if d[i] == 0:
            print("La matriz L es singular")
            return

    # Resolvemos el sistema
    x = np.zeros(len(b))              # definimos el vector solución x
    x[0] = b[0]/L[0,0]   # primera coordenada de x
    for i in range(0,len(b)):
        sumatorio = 0
        for j in range(0,i):
            sumatorio += (L[i,j]*x[j])
        x[i] = (1/L[i,i])*(b[i] - sumatorio)       # restantes coordenadas de x
    return x

# Función sus_regre (ver ejercicio2.py)
#-----------------------------------------------------------------------------
def sus_regre(U,b):
    m,n = U.shape   # dimensiones de la matriz U
    # Comprobamos que la matriz U es cuadrada
    if m != n:
        print('La matriz U no es cuadrada')
        return
    # Comprobamos que las dimensiones de U y b son adecuadas
    if n != len(b):
        print('Las dimensiones no son correctas')
        return
    # Comprobamos que la matriz U es no singular
    d = np.diag(U)
    for i in range(0,len(d)):
        if d[i] == 0:
            print("La matriz U es singular")
            return
    # Resolvemos el sistema
    x = np.zeros(len(b))          # definimos el vector solución x
    x[-1] = b[-1]/U[len(b)-1][len(b)-1]   # última coordenada de x
    for i in range(n-1,-1,-1):
        sumatorio = 0
        for j in range(i+1,n):
            sumatorio += (U[i,j]*x[j])
        x[i] = (1/U[i,i])*(b[i] - sumatorio) # restantes coordenadas de x
    return x

#--------------------------------------
# Ejercicios
#--------------------------------------

# Ejercicio 1
#--------------------------------------
y = sus_prog(L,b)
x = sus_regre(U,y)
print('Solucion del sistema 1 =', x)

# Ejercicio 2
#--------------------------------------
n = 5
np.random.seed(4)
A = np.random.random((n,n))
b = np.random.random(n)
L,U = LU(A)
y = sus_prog(L,b)
x = sus_regre(U,y)

print('\n A')
print(A)
print('\n b')
print(b)
print('Solucion del sistema 2 =',x)


"""
Students can put comments in this main docstring. Such comments will be
 important for you (and your teammates in the group project) to remember
 what your definition block does.
"""
from scipy import *
import sys

def orbital_properties(a = 15000, e = 0.3, mu_earth = 3.986*10**5):
    """
    {'username':'cnilsen','assignment':'Conic Sections Intermediate Mastery','course':'spring-2017-aae-251','variables':
    {'a':'semi-major axis, km',
     'e':'orbital eccentricity, nondimensional',
     'rp':'periapsis radius, km',
     'vp':'periapsis velocity, km/s',
     'ra':'apoapsis radius, km',
     'va':'apoapsis velocity, km/s'}}
    """

    ########
    # Student's code and comments go here.
    ########

    rp = a*(1-e)
    ra = a*(1+e)

    energy = -mu_earth/(2*a)

    va = sqrt(2*(energy + (mu_earth/ra)))
    vp = sqrt(2*(energy + (mu_earth/rp)))
    return rp, vp, ra, va

# The following allows you to run the script directly from the command line
if __name__ == '__main__':
    orbital_properties(*[float(val) for val in sys.argv[1:]])


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

import numpy as np

x = []
y = []
alpha = 0.01

with open("test/resource/ex1data1.txt", "r") as infile:
    for line in infile:
        pos = line.strip().split(',')
        x.append(float(pos[0]))
        y.append(float(pos[1]))

# print ("x:{x}, min:{min_x}, max:{max_x}".format(x=x, min_x=min(x), max_x=max(x)))
# print ("y:{y}, min:{min_y}, max:{max_y}".format(y=y, min_y=min(y), max_y=max(y)))

def compute_cost(list_of_x, list_of_real_y, theta_0, theta_1):
    m = len(list_of_x)
    total = 0.0
    for i in range(m):
        temp = list_of_x[i] * theta_1 + theta_0 - list_of_real_y[i]
        total += temp * temp
    return total / 2 / m

def f_0(x, theta_0, theta_1, read_y):
    return theta_0 + theta_1 * x - read_y

def f_1(x, theta_0, theta_1, read_y):
    return (theta_0 + theta_1 * x - read_y) * x

def gcd_line(list_of_x, list_of_real_y, theta_0_p, theta_1_p):
    total_0 = theta_0_p
    total_1 = theta_1_p
    theta_0 = theta_0_p
    theta_1 = theta_1_p

    while abs(total_0) > 0.01 or abs(total_1) > 0.01:
        total_0 = 0.0
        total_1 = 0.0
        m = len(list_of_x)
        for i in range(m):
            total_0 += f_0(list_of_x[i], theta_0, theta_1, list_of_real_y[i])
            total_1 += f_1(list_of_x[i], theta_0, theta_1, list_of_real_y[i])
        total_0 = total_0 / m
        total_1 = total_1 / m
        theta_0 = theta_0 - alpha * total_0
        theta_1 = theta_1 - alpha * total_1
        # cost = compute_cost(list_of_x, list_of_real_y, theta_0, theta_1)
        # print("total_0: {total_0}, total_1: {total_1}".format(total_0=total_0, total_1=total_1))
        # print("theta_0: {t0}, theta_1: {t1}, cost: {cost}".format(t0=theta_0, t1=theta_1, cost = cost))

    cost_min = compute_cost(list_of_x, list_of_real_y, theta_0, theta_1)
    print("theta_0: {t0}, theta_1: {t1}, cost: {cost}".format(t0=theta_0, t1=theta_1, cost=cost_min))
    return theta_0, theta_1

def drew_1():
    import matplotlib.pyplot as plt
    theta_0, theta_1 = gcd_line(x, y, 100, 100)

    point_start_y = theta_0 + min(x) * theta_1
    point_end_y = theta_0 + max(x) * theta_1
    # print("point_end_y: {max_y}".format(max_y = point_end_y))

    plt.figure(1)
    plt.title('Linear regression With GCD')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.scatter(x, y, marker='o', color='k', s=10, label='point')
    plt.legend(loc='lower right')
    plt.plot([min(x), max(x)], [point_start_y, point_end_y])
    plt.show()

def drew_J_theta():
    import matplotlib.pyplot as plt
    from matplotlib import cm
    from matplotlib.ticker import LinearLocator, FormatStrFormatter

    theta_0_list = np.arange(-10, 10, 0.1)
    theta_1_list = np.arange(-1, 4, 0.1)
    size_t0 = len(theta_0_list)
    size_t1 = len(theta_1_list)

    cost = np.zeros((size_t0, size_t1))
    for i in range(len(theta_0_list)):
        for j in range(len(theta_1_list)):
            cost[i, j] = compute_cost(x, y, theta_0_list[i], theta_1_list[j])
            print("theta_0: {t0}, theta_1: {t1}, cost: {c}".
                  format(t0=theta_0_list[i], t1=theta_1_list[j], c=cost[i, j]))

    X = np.asarray(theta_0_list)
    Y = np.asarray(theta_1_list)
    X, Y = np.meshgrid(X, Y)
    Z = np.asmatrix(cost)

    fig = plt.figure()
    ax = fig.gca(projection='3d')
    surf = ax.plot_surface(X, Y, np.transpose(Z), cmap=cm.coolwarm, linewidth=0, antialiased=False)

    # Customize the z axis.
    ax.set_zlim(0, 300)
    ax.zaxis.set_major_locator(LinearLocator(10))
    ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

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

    plt.show()


# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as mp

FIRST_N = 50
MAX_STEP = 50

#######################
#  Resolution methods #
#######################
# conventions:
# ------------
# y is an array of values
# f is an array of functions
#######################

# step_<name>(y,t,h,f) : calculates one step

def step_euler(y, t, h, f):
    """ Euler method  """
    n = y.size
    yn = range(0, n)
    for i in range(0, n):
        yn[i] = y[i] + h * f[i](t, y)
    return np.array(yn)

def step_middle(y, t, h, f):
    """ Middle method  """
    n = y.size
    yn = range(0, n)
    y1 = range(0, n)
    step = range(0, n)
    for i in range(0, n):
        y1[i] = y[i]+(h/2.)*f[i](t,y)
        step[i] = f[i](t+h/2., y1)
        yn[i] = y[i] + h*step[i]
    return np.array(yn)

# Heun
def step_heun(y, t, h, f):
    """ Heun method  """
    n = y.size
    yn = range(0, n)
    step1 = range(0, n)
    step2 = range(0, n)
    y1= range(0, n)
    for i in range(0, n):
        step1[i] = f[i](t,y)
        y1[i] = y[i]+h*step1[i]
        step2[i] = f[i](t+h,y1)
        yn[i] = y[i]+(h/2.)*(step1[i]+step2[i])
    return np.array(yn)

# Runge-Kutta
def step_kutta(y, t, h, f):
    """ Runge-Kutta method """
    n = y.size
    yn = range(0, n)
    step1 = range(0, n)
    step2 = range(0, n)
    step3 = range(0, n)
    step4 = range(0, n)
    y1= range(0, n)
    y2= range(0, n)
    y3= range(0, n)
    for i in range(0, n):
        step1[i] = f[i](t,y)
        y1[i] = y[i]+ 0.5*h*step1[i]
        step2[i] = f[i](t+0.5*h,y1)
        y2[i] = y[i]+0.5*h*step2[i]
        step3[i] = f[i](t+0.5*h,y2)
        y3[i] = y[i]+h*step3[i]
        step4[i] = f[i](t+h,y3)
        yn[i] = y[i] + (1/6.)*h*(step1[i]+2*step2[i]+2*step3[i]+step4[i])
    return np.array(yn)

# meth_n_step(y0,t0,N,h,f,meth) : calculates N steps of size h #
def meth_n_step(y0, t0, N, h, f, meth):
    """ Compute n values """
    for i in range(0, N):
        y0 = meth(y0, t0, h, f)
        t0 = t0 + h
    return y0

def meth_n_step_printer(y0, t0, N, h, f, meth):
    """ Return an array of values """
    y_tab = np.zeros([N,y0.size])
    for i in range(0,N):
        y0 = meth(y0, t0, h, f)
        t0 = t0 + h
        y_tab[i] = y0
    return y_tab

# Solution with an error parameter eps
def meth_epsilon(y0, t0, tf, eps, f, meth):
    """ Returns an array of values """
    flag = 0
    error = eps + 1
    N = first_n
    h = (tf-t0) / float(N)
    yf_old = meth_n_step(y0, t0, N, h, f, meth)
    while (error > eps and flag < MAX_STEP):
        N *= 2
        h /= 2
        yf = meth_n_step(y0, t0, N, h, f, meth)
        error = np.linalg.norm(yf - yf_old)
        yf_old = yf
        flag += 1
    if flag == MAX_STEP:
        print("More steps are needed")
    return yf

def meth_epsilon_printer(y0, t0, tf, eps, f, meth, first_n = 2):
    flag = 0
    error = eps + 1
    N = first_n
    h = (tf-t0) / float(N)
    yf_old = meth_n_step(y0, t0, N, h, f, meth)
    while (error > eps and flag < MAX_STEP):
        N *= 2
        h /= 2
        yf = meth_n_step(y0, t0, N, h, f, meth)
        error = np.linalg.norm(yf - yf_old)
        yf_old = yf
        flag += 1
    y_tab = meth_n_step_printer(y0, t0, N, h, f, meth)
    if flag == MAX_STEP:
        print("More steps are needed")
    return y_tab

# slope field

def slope_field (deriv_x, deriv_y, n_x, n_y):
        h = 0.5
        X = np.arange(-n_x/2, n_x/2+1, h)
        Y = np.arange(-n_y/2, n_y/2+1, h)
        for i in X:
            for j in Y:
                mp.quiver(i, j, deriv_x(i, j),deriv_y(i, j))
        mp.show()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on November 12 2019
@author: Quentin Lutz <qlutz@enst.fr>
"""
from math import log
from typing import Union, Optional

import numpy as np
from scipy import sparse

from sknetwork.path.shortest_path import distance
from sknetwork.ranking.base import BaseRanking
from sknetwork.utils.check import check_format, check_square, check_connected

class Closeness(BaseRanking):
    """Closeness centrality of each node in a connected graph, corresponding to the average length of the
    shortest paths from that node to all the other ones.

    For a directed graph, the closeness centrality is computed in terms of outgoing paths.

    Parameters
    ----------
    method :
        Denotes if the results should be exact or approximate.
    tol: float
        If ``method=='approximate'``, the allowed tolerance on each score entry.
    n_jobs:
        If an integer value is given, denotes the number of workers to use (-1 means the maximum number will be used).
        If ``None``, no parallel computations are made.

    Attributes
    ----------
    scores_ : np.ndarray
        Closeness centrality of each node.

    Example
    -------
    >>> from sknetwork.ranking import Closeness
    >>> from sknetwork.data import cyclic_digraph
    >>> closeness = Closeness()
    >>> adjacency = cyclic_digraph(3)
    >>> scores = closeness.fit_transform(adjacency)
    >>> np.round(scores, 2)
    array([0.67, 0.67, 0.67])

    References
    ----------
    Eppstein, D., & Wang, J. (2001, January).
    `Fast approximation of centrality.
    <http://jgaa.info/accepted/2004/EppsteinWang2004.8.1.pdf>`_
    In Proceedings of the twelfth annual ACM-SIAM symposium on Discrete algorithms (pp. 228-229).
    Society for Industrial and Applied Mathematics.
    """

    def __init__(self, method: str = 'exact', tol: float = 1e-1, n_jobs: Optional[int] = None):
        super(Closeness, self).__init__()

        self.method = method
        self.tol = tol
        self.n_jobs = n_jobs

    def fit(self, adjacency: Union[sparse.csr_matrix, np.ndarray]) -> 'Closeness':
        """Closeness centrality for connected graphs.

        Parameters
        ----------
        adjacency :
            Adjacency matrix of the graph.

        Returns
        -------
        self: :class:`Closeness`
        """
        adjacency = check_format(adjacency)
        check_square(adjacency)
        check_connected(adjacency)
        n = adjacency.shape[0]

        if self.method == 'exact':
            n_sources = n
            sources = np.arange(n)
        elif self.method == 'approximate':
            n_sources = min(int(log(n) / self.tol ** 2), n)
            sources = np.random.choice(np.arange(n), n_sources, replace=False)
        else:
            raise ValueError("Method should be either 'exact' or 'approximate'.")

        dists = distance(adjacency, n_jobs=self.n_jobs, sources=sources)

        self.scores_ = ((n - 1) * n_sources / n) / dists.T.dot(np.ones(n_sources))

        return self


import math

import numpy as np

def euler(drift, diffusion, x0, T, Tstep, Nsim):
    """
    Simulate solution of Stochastic Differential Equation by discretization using
    Euler's method
    :param drift: lambda function with signature x, t
    :param diffusion: lambda function with signature x, t
    :param x0: initial position
    :param T: terminal time in double
    :param Tstep: number of time steps
    :param Nsim: number of path simulated
    :return: np array of simulated stochastic process
    """
    dt = T / (Tstep - 1)
    dW = np.random.normal(0, math.sqrt(dt), Nsim * Tstep).reshape(Nsim, Tstep)

    x = np.zeros([Nsim, Tstep])
    t = np.linspace(0, T, Tstep)
    x[:, 0] = x0

    for i in range(1, Tstep):
        x[:, i] = x[:, i - 1] + drift(x[:, i - 1], t[i - 1]) * dt + diffusion(x[:, i - 1], t[i - 1]) * dW[:, i - 1]
    return x

def euler2d(drift0, drift1, diffusion0, diffusion1, rho, x0, y0, T, Tstep, Nsim):
    """
    :param drift0:
    :param drift1:
    :param diffusion0:
    :param diffusion1:
    :param rho:
    :param x0:
    :param y0:
    :param T:
    :param Tstep:
    :param Nsim:
    :return:
    """
    dt = T / (Tstep - 1)
    dW0 = np.random.normal(0, dt, Nsim * Tstep).reshape(Nsim, Tstep)
    dW1 = np.random.normal(0, dt, Nsim * Tstep).reshape(Nsim, Tstep)

    x = np.zeros([Nsim, Tstep])
    y = np.zeros([Nsim, Tstep])
    t = np.linspace(0, T, Tstep)

    x[:, 0] = x0
    y[:, 0] = y0

    for i in range(1, Tstep):
        dWy = rho * dW0[:, i - 1] + np.sqrt(1.0 - rho ** 2) * dW1[:, i - 1]
        x[:, i] = x[:, i - 1] + drift0(x[:, i - 1], y[:, i - 1], t[i - 1]) * dt \
                  + diffusion0(x[:, i - 1], y[:, i - 1], t[i - 1]) * dW0[:, i - 1]
        y[:, i] = y[:, i - 1] + drift1(x[:, i - 1], y[:, i - 1], t[i - 1]) * dt \
                  + diffusion1(x[:, i - 1], y[:, i - 1], t[i - 1]) * dWy[:, i - 1]

    return x, y


import numpy as np
from matplotlib import pyplot as plt

x0 = 0
y0 = 0
xf = 1
n = 5
deltax = (xf-x0)/(n-1)
x = np.linspace(x0,xf,n)

def f(x,y):
	return x+2*y

y = np.zeros([n])
y[0] = y0

for i in range(1,n):
	y[i] = deltax*f(x[i-1],y0) + y0
	y0 = y[i]

print("x_n\t    y_n")
for i in range(n):
	print(x[i],"\t",format(y[i],'6f'))

plt.plot(x,y,'o')
plt.xlabel("Value of x")
plt.ylabel("Value of y")
plt.title("Approximation Solution with Euler's Method")
plt.show()

#http://calculuslab.deltacollege.edu/ODE/7-C-1/7-C-1-h-c.html


#!/usr/bin/env python

"""
@file compute_logloss.py
@brief compute logloss
@author ChenglongChen
"""

import sys
import numpy as np
import pandas as pd

def softmax(score):
    num = score.shape[0]
    maxes = np.amax(score, axis=1).reshape((num, 1))
    e = np.exp(score - maxes)
    prob = e / np.sum(e, axis=1).reshape((num, 1))
    return prob

def computeLogloss(prob, label, eps=1e-15):
    # clip
    prob = np.clip(prob, eps, 1 - eps)
    # normalization
    prob /= prob.sum(axis=1)[:,np.newaxis]
    p = prob[np.arange(len(label)),label.astype(int)]
    loss = -np.mean(np.log(p))
    return loss

def main():
    list_file = sys.argv[1]
    prob_file = sys.argv[2]

    list_in = np.loadtxt(list_file, dtype=str)
    true_label = np.asarray(list_in[:,1], dtype="int")

    prob = pd.read_csv(prob_file, index_col=0).values
    if len(sys.argv) == 4 and sys.argv[3] == "raw":
        prob = softmax(prob)
    #prob = 1e-5
    #prob = sp.maximum(sp.minimum(prob, 1.0-eps), eps)
    logloss = computeLogloss(prob, true_label)
    print( logloss )

if __name__ == "__main__":
    main()


'''
Created on Jun 10, 2014

@author: renat

Collection of various mathematical functions
'''

import numpy as np
from numpy import pi
from lmfit import Parameters,minimize

def weightedAveStd(values, error):
    """
    Returns the weighted average and standard deviation.

    values, weights -- Numpy ndarrays with the same shape.
    """
    weights = np.abs(values)/np.array(error)
    weights = weights/sum(weights)
    average = np.average(values, weights=weights)
    variance = np.dot(weights, (values-average)**2)/weights.sum()  # Fast and numerically precise
    return (average, np.sqrt(variance))

def fitCirc(x,y,xerr = None, rIni = None, aveR=False):

    """
    Performs a circle fit to data using least square residuals.

    Parameters
    ----------
    x : An array of length N.
    y : An array of length N.
    xerr : None or an array of length N,
        If provided, it is the standard-deviation of points.
        This vector, if given, will be used as weights in the fit.
    rIni : is a maximum radius of the circle to be fitted.
    aveR : if True, returns the average deviation from the fit.

    Returns
    -------
    xc, yc, R   : center and the radius of the circle.
    errorbars : errorbars on the center x, y and the radius.
    aveResid : (optional) average residual
    """

    x=np.array(x)
    y=np.array(y)
    if x.size<2:
        print('fitCirc: not enough data points to fit circle')
        return
    x_m = np.mean(x)
    y_m = np.mean(y)
    if xerr == None or all(xerr)==0:
        xerr = np.ones(len(x))
    else:
        xerr=np.array(xerr)
        xerr[np.where(xerr==0)]=100
    def calc_R(xc, yc):
        """ calculate the distance of each 2D points from the center (xc, yc) """
        return np.sqrt((x-xc)**2 + (y-yc)**2)

    def resid(pars):
        """ calculate the algebraic distance between the 2D points and the mean circle centered at c=(xc, yc) """
#         xc,yc, radius = pars
        v = pars.valuesdict()
        xc,yc, radius = v['xc'],v['yc'],v['radius']
        Ri = calc_R(xc,yc)
        if rIni is not None and radius>rIni:
            return 10000000*(Ri - radius)
        return (Ri - radius)/np.array(xerr)

    center_estimate = x_m, y_m
    radius = calc_R(*center_estimate).mean()
    if rIni is not None and radius>rIni: radius = rIni

    params = Parameters()
    params.add('xc', x_m)
    params.add('yc', y_m)
    params.add('radius', radius, min=0)
    minzer=minimize(resid,params=params)
    res = minzer.params
    xc, yc, R = res['xc'].value,res['yc'].value,res['radius'].value
    errorbars = [res['xc'].stderr,res['yc'].stderr,res['radius'].stderr]
    aveResid = sum(abs(minzer.residual))/x.size
    if rIni is not None and R>rIni: print('radius greater than initial, resid=',aveResid)
    if aveR: return xc,yc,R,errorbars,aveResid
    else: return xc,yc,R, errorbars

def fitLine(xdata, ydata, ysigma=None, xsigma=None):

    """
    Performs a linear fit to data.

    Parameters
    ----------
    xdata : An array of length N.
    ydata : An array of length N.
    sigma : None or an array of length N,
        If provided, it is the standard-deviation of ydata.
        This vector, if given, will be used as weights in the fit.

    Returns
    -------
    a, b   : Optimal parameter of linear fit (y = a*x + b)
    sa, sb : Uncertainties of the parameters
    """
    if xsigma is not None:
        w=1.0/(ysigma**2+xsigma**2)
    elif ysigma is None:
        w = np.ones(len(ydata)) # Each point is equally weighted.
    else:
        w=1.0/(ysigma**2)

    w=w/sum(w)
    sw = sum(w)
    wx = w*xdata # this product gets used to calculate swxy and swx2
    swx = sum(wx)
    swy = sum(w*ydata)
    swxy = sum(wx*ydata)
    swx2 = sum(wx*xdata)

    a = (sw*swxy - swx*swy)/(sw*swx2 - swx*swx)
    b = (swy*swx2 - swx*swxy)/(sw*swx2 - swx*swx)

    if ysigma is None:
        chi2 = sum(((a*xdata + b)-ydata)**2)
    else:
        chi2 = sum((((a*xdata + b)-ydata)/ysigma)**2)
    dof = len(ydata) - 2
    rchi2 = np.sqrt(chi2/dof)

    sa = rchi2*np.sqrt(sw/(sw*swx2 - swx*swx))
    sb = rchi2*np.sqrt(swx2/(sw*swx2 - swx*swx))
    return a, b, sa, sb

def rotate(x,y,angle):

    '''
    Rotation of data by specified angle.

    Parameters
    ----------
    x : An array of length N.
    y : An array of length N.
    angle : angle in radians.
    '''

    x = np.array(x)
    y = np.array(y)
    xNew = x*np.cos(angle) - y*np.sin(angle) #rotate data
    yNew = x*np.sin(angle) + y*np.cos(angle)
    return xNew, yNew

def getAngle(x, y, xerr=None, yerr=None, index=None):

    '''
    Calculates angle in degrees between the data with errorbars and the positive x-axis using linear fit.

    Parameters
    ----------
    x : An array of length N.
    y : An array of length N.
    xerr, yerr : None or an array of length N,
        If provided, it is the standard-deviation of x and y data.
    index : indices of the points to use for alignment

    Returns
    -------
    xAlign, yAlign : Arrays of length N with aligned x and y coordinates.
    errAlign : An array on length N with 1D uncertainty for each point.
    aAngle : angle used for the aligning in radians.
    '''

    tol = 0.005
    aligned = False
    if xerr is not None and yerr!=None: xerr = np.sqrt(xerr**2 + yerr**2)
    elif yerr is not None: xerr = yerr
    else: xerr = np.ones_like(x)
    angleFin = 0 #getAnglePC(x,y)
    xNew, yNew = rotate(x, y, angleFin)
    if abs(np.std(xNew))<abs(np.std(yNew)):angleFin+=pi/2
    while not aligned:
        xNew, yNew = rotate(x, y, angleFin)
        if index == None: slope, inter, se, ie = fitLine(xNew, yNew, xerr) #find slope
        elif index.size <= 1: break
        else: slope, inter, se, ie = fitLine(xNew[index], yNew[index], xerr[index])
        if abs(slope)< tol:
            aligned = True
            break
        angle = -np.arctan(slope)
        angleFin += angle #angle to turn the data

    if np.sign(xNew.mean())<0: angleFin += pi
    aAngle = -angleFin
    if aAngle>=2*pi: angleFin -= 2*pi
    if aAngle<0: aAngle += 2*pi
    return aAngle #minus comes from conversion from turning angle to angle of data w/ X axis

def getSubIndex(a, left, right):
    if left>right: left, right = right, left
    if a[0]>a[-1]: return a.size-getSubIndex(a[::-1], left, right)-1
    else: return np.where(a[np.where(a <= right)[0]] >= left)[0]

def getSig(x):
    x=abs(x)
    if x!=np.inf and not np.isnan(x): return -int(np.floor(np.log10(x)))
    else: return 0


"""
AKS primality test.
"""
from sage.all import *

from a1_euclidean_algorithm import euclidean_algorithm

import timeit
from _auxiliary_algorithms import repeated_square

def miller_rabin_is_prime(n, k=10):
    """
    Checks if n is probably prime, with k tries.

    Returns True if n is probably prime after k tries, False if it is certainly composite.
    """
    # Make sure this is a sage integer
    n = ZZ(n)

    # Input checks
    if n <= 1:
        raise ValueError("The number n must be an integer greater than 2")

    if n == 2 or n == 3:
        return True

    # Write n as 2^r * d + 1, d odd
    d = n - 1
    r = 0
    while d % 2 == 0:
        d = d.quo_rem(2)[0]
        r += 1

    # We try to find a witness k times
    for _ in range(k):
        # Choose a random number, and check if it is a witness
        a = randint(2, n - 2)

        # The test is based on checking a^d mod n, so we calculate it efficiently
        x = repeated_square(a, d, n)

        # For a to be a witness, two conditions must hold:
        # (1) a^d != 1 (mod n)
        # (2) For all 0 <= s <= r - 1, (a^d)^(2^s) != -1 (mod n).

        # We check condition (1) and condition (2) for s = 0
        if x == 1 or x == n - 1:
            continue

        # We check condition 2 for s in [1, n-1]
        is_witness = True
        for _ in range(n - 1):
            x = repeated_square(x, 2, n)

            if x == n - 1:
                is_witness = False
                break   # No point in trying more, it is not a witness

        if is_witness:
            # a is a witness, so the number is composite
            return False

    # If none of the iterations have found a witness, then n is probably prime
    return True

def main():
    """ Execute the examples. """
    miller_rabin_is_prime(5)

    start, end = 2, 200
    for n in range(start, end) + [randint(1000, 100000) for _ in range(100)]:
        probably_prime = miller_rabin_is_prime(n)
        if is_prime(n):
            if probably_prime:
                print 'PROBABLY PRIME for PRIME number {n}'.format(n=n)
            else:
                print '!!!!! COMPOSITE for PRIME number {n}'.format(n=n)
        else:
            if probably_prime:
                print 'PROBABLY PRIME for COMPOSITE number {n}'.format(n=n)
            else:
                print 'COMPOSITE for COMPOSITE number {n}'.format(n=n)

if __name__ == '__main__':
    main()