# -*- coding: utf-8 -*-
"""
Created on Fri Sep 20 10:33:25 2019
copied from: https://aaronschlegel.me/black-scholes-formula-python.html
@author: shirui
"""

import numpy as np
import scipy.stats as si
import math
import matplotlib.pyplot as plt
import operator

import torch
from tqdm import tqdm

"""
Deltas and explicit solution for euro_vanilla_call
"""
def euro_vanilla_call(S, K, T, r, sigma):

    #S: spot price
    #K: strike price
    #T: time to maturity
    #r: risk free interest rate
    #sigma: volatility of underlying asset

    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    d2 = (np.log(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))

    call = (S * si.norm.cdf(d1, 0.0, 1.0) - K * np.exp(-r * T) * si.norm.cdf(d2, 0.0, 1.0))

    return call

def delta(S, K, T, r, sigma):
    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    return si.norm.cdf(d1, 0.0, 1.0)

def gamma(S, K, T, r, sigma):
    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    n_d1 = si.norm.pdf(d1, 0.0, 1.0)
    return n_d1 / (S * sigma * np.sqrt(T))

def theta(S, K, T, r, sigma):
    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    d2 = (np.log(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))

    n_d1 = si.norm.pdf(d1, 0.0, 1.0)
    N_d2 = si.norm.cdf(d2, 0.0, 1.0)

    return -n_d1 * S * sigma / (2 * np.sqrt(T)) - r * K * np.exp(-r * T) * N_d2

def euro_vanilla_put(S, K, T, r, sigma):

    #S: spot price
    #K: strike price
    #T: time to maturity
    #r: interest rate
    #sigma: volatility of underlying asset

    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    d2 = (np.log(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))

    put = (K * np.exp(-r * T) * si.norm.cdf(-d2, 0.0, 1.0) - S * si.norm.cdf(-d1, 0.0, 1.0))

    return put

def sampling_nonlinear(interval,npoints):

    LB = interval[0]
    RB = interval[1]
    init = np.linspace(LB,RB,npoints)
    y = pow((init-LB),3)
    inv = np.linspace(np.min(y),np.max(y),npoints)
    return (pow(inv,1/3.0) + LB)

# [S0, K, T, r, sigma] can be frozen with boolean index array
def generate_space(n=100000, frozen=[False for i in range(5)]):

    num_per = int(n**(1./(len(frozen) - sum(frozen))))

    if frozen[0]:
        S0 = np.array([1.0 for i in range(num_per)])
    else:
        S0 = sampling_nonlinear([.5,1.2],num_per)
        #S0 = np.linspace(0.01,2,num_per)
    K = np.linspace(1,1,num_per)
    #m = np.linspace(0.6,1.4,10)

    T = .5-sampling_nonlinear([0,.5-0.01],num_per)
    #T = np.linspace(0.01,1.0,num_per)

    if frozen[3]:
        #r = np.array([0.0 for i in range(num_per)])
        r = np.array([0.03 for i in range(num_per)])
    else:
        r = np.linspace(0.01,0.05,num_per)

    if frozen[4]:
        sigma = np.array([0.65 for i in range(num_per)])
    else:
        sigma = np.linspace(0.3,1.0,num_per)

    dataset = np.concatenate((S0,K,T,r,sigma),axis=0)
    return np.reshape(dataset,(np.size(S0),-1),order='F')

def get_call_option_dataset(frozen=[False for i in range(5)]):

    dataset = generate_space(frozen=frozen)

    nc = [len(set(dataset[:,i])) for i in range(np.shape(dataset)[1])]
    n = np.product(nc)

    option_call = np.zeros((n,6))
    i=0
    for S0 in list(set(dataset[:,0])):
        for K in list(set(dataset[:,1])):
            for T in list(set(dataset[:,2])):
                for r in list(set(dataset[:,3])):
                    for sigma in list(set(dataset[:,4])):
                        temp = euro_vanilla_call(S0, K, T, r, sigma)
                        option_call[i,:] = [S0,K,T,r,sigma, temp]
                        i = i+1
    return option_call

# Creates stochastically random dataset based off brownian motion with
# fixed interest rate and volatility
def get_brownian_call_option_dataset(length, k=3, r=.03, sigma=.65, seed=-1):
    if seed != -1:
        np.random.seed(seed)

    # Generate time steps
    T = np.linspace(0.01, 1.0, length)

    # Generate initial stock value stochastically
    S = np.zeros((length))
    S[0] = np.random.rand() * 2
    val = np.zeros((length))
    val[0] = euro_vanilla_call(S[0], k, T[0], r, sigma)

    # Generate via brownian motion
    for i in range(1, length):
        d_t = T[i] - T[i-1]
        z = np.random.normal()
        S[i] = S[i-1] * np.exp((r - .5*sigma**2)*d_t + sigma * np.sqrt(d_t)*z)
        # Find value of option
        val[i] = euro_vanilla_call(S[i], k, T[i], r, sigma)

    # Generate formatted dataset
    option_call = np.zeros((length, 6))
    option_call[:, 0] = S
    option_call[:, 1] = k
    option_call[:, 2] = T
    option_call[:, 3] = r
    option_call[:, 4] = sigma
    option_call[:, 5] = val

    return option_call

def normal_pdf(y, mean=0, sigma=1.0):
	numerator = math.exp((-1 * math.pow((y - mean), 2)) / 2 * math.pow(sigma, 2))
	denominator =  math.sqrt(2.0 * math.pi) * sigma
	return numerator / denominator

def _vega(S, K, T, r, sigma):
	""" Calculate derivative of option price with respect to volatility
		vega = s * tau^(1/2) * N(d1)

	Args:
		S (float): stock price
		K (float): strike price
		r (float): risk-free interest rate
		sigma (float: standard deviation of log returns (volatility)
		tau (float): time to option expiration expressed in years
	"""

	d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))

	return S * math.sqrt(T) * normal_pdf(d1)

def implied_volatility(S, K, T, r, mp, option_type="call", precision=1e-5, iterations=1000):
	""" Newton-Raphson method of successive approximations to find implied volatility
    mp : option market price
	"""

	# initial estimation
	sigma = 0.5
	for i in range(0, iterations):
		print (i)
		# price of an option as per Black Scholes
		bs_p = euro_vanilla_call(S, K, T, r, sigma)
		diff = mp - bs_p
		# check if difference is acceptable
		if (operator.abs(diff) < precision):

			return sigma

		vega = _vega(S, K, T, r, sigma)

		print(vega)

		# update sigma with addition of difference divided by derivative
		sigma = sigma + (diff / vega)
		print(sigma)

	# closest estimation
	return sigma

if __name__ == "__main__":
    option_call_dataset = get_call_option_dataset(frozen=[False, True, False, True, True])
    np.savetxt('option_call_dataset_simplified.txt',option_call_dataset,delimiter=',')

# =============================================================================
#     proc_dataset = torch.zeros(0, 6)
#     full_dataset = np.zeros((0, 6))
#     num_paths = 500
#     path_length = 500
#     for i in tqdm(range(num_paths)):
#         # Generate path
#         path = torch.as_tensor(get_brownian_call_option_dataset(path_length))
#         full_dataset = np.concatenate((full_dataset, path), 0)
#         # Keep only S, T, and value and concate the next step
#         path = torch.cat((path[:,0:1], path[:,2:3], path[:,-1].unsqueeze(1)), 1)
#         path = torch.cat((path[1:], path[:-1]), 1)
#
#         proc_dataset = torch.cat((proc_dataset, path), 0)
#
#     torch.save(proc_dataset, 'brownian_dataset_500_500.pth')
#     np.savetxt('option_call_dataset_brownian_500_500.txt',full_dataset,delimiter=',')
# =============================================================================

def evaluate(model, dataset):
    k = dataset[:,1]
    dataset = torch.cat((dataset[:,0:1], dataset[:,2:]), 1)
    pred_value = model(dataset[:,:2])

    # MSE of function
    f_MSE = ((pred_value.detach().cpu().view(-1) - dataset[:,-1].cpu())**2).mean()

    # MSE of delta
    pred_delta = model.get_delta(dataset[:,:2])
    real_delta = delta(dataset[:,0].cpu().numpy(), k.cpu().numpy(),
                       dataset[:,1].cpu().numpy(), dataset[:,2].cpu().numpy(), dataset[:,3].cpu().numpy())
    d_MSE = ((pred_delta.detach().cpu().view(-1) - torch.as_tensor(real_delta))**2).mean()

    # MSE of gamma
    pred_gamma = model.get_gamma(dataset[:,:2])
    real_gamma = gamma(dataset[:,0].cpu().numpy(), k.cpu().numpy(),
                       dataset[:,1].cpu().numpy(), dataset[:,2].cpu().numpy(), dataset[:,3].cpu().numpy())
    g_MSE = ((pred_gamma.detach().cpu().view(-1) - torch.as_tensor(real_gamma))**2).mean()

    # MSE of theta
    pred_theta = model.get_theta(dataset[:,:2])
    real_theta = theta(dataset[:,0].cpu().numpy(), k.cpu().numpy(),
                       dataset[:,1].cpu().numpy(), dataset[:,2].cpu().numpy(), dataset[:,3].cpu().numpy())
    t_MSE = ((pred_theta.detach().cpu().view(-1) - torch.as_tensor(real_theta))**2).mean()

    print("Function MSE: %.8f" % f_MSE)
    print("Delta MSE: %.8f" % d_MSE)
    print("Gamma MSE: %.8f" % g_MSE)
    print("Theta MSE: %.8f" % t_MSE)
    print("Predicted Sigma: %.4f" % model.sigma.cpu().item())


import numpy as np
import matplotlib.pyplot as plt
#take in Data in the form [[x1,y1],[x2,y2]...]
a = np.array([[1, 4],[2,2],[3,0],[5,3]], dtype=float)

#Define the function S.
b = len(a) - 1
s = np.zeros(((4*b),(4*b)), dtype=float)
B = np.zeros(4*b, dtype=float)
def S1(x,n,ns):
    s[2*ns, 4*ns] = 1.0
    B[2*ns] = (a[ns, 1])
    pass
def S(x,n, ns):
    s[2*ns+1, 4*ns] = 1.0
    s[2*ns+1, 4*ns + 1] = (x - n)
    s[2*ns+1, 4*ns + 2] = ((x - n)**2)
    s[2*ns+1, 4*ns + 3] = ((x - n)**3)
    B[2*ns+1] = (a[ns+1, 1])
    pass

#Populate the matrix
c = 0
while c < b:
    S1(a[c, 0], a[c, 0], c)
    S(a[c+1, 0], a[c, 0], c)
    c = c +1
    pass
print(s)

#Set fprime equivalencies
c = c + b
e = 0
while e < b-1:
    n1 = (a[e,0])
    x = (a[e+1,0])
    n2 = (a[e+1,0])
    s[c, 4*e+1] = 1
    s[c, 4*e+2] = (2*x - 2*n1)
    s[c, 4*e+3] = (3*(x**2) - 6*n1*x + 3*n1**2)
    s[c, 4*e+5] = -1
    s[c, 4*e+6] = -(2*x - 2*n2)
    s[c, 4*e+7] = -(3*(x**2) - 6*n2*x + 3*n2**2)
    c = c + 1
    e = e + 1
    pass
print (s)

#Set fsecondprime equivalencies
e = 0
while e < b-1:
    n1 = a[e,0]
    x = a[e+1,0]
    n2 = a[e+1,0]
    s[c, 4*e+2] = 2
    s[c, 4*e+3] = (6*x - 6*n1)
    s[c, 4*e+6] = -2
    s[c, 4*e+7] = -(6*x - 6*n2)
    c = c + 1
    e = e + 1
    pass
print (s)

# set boundary condition
n1 = (a[0,0])
x1 = (a[0,0])
n2 = (a[b-1,0])
x2 = (a[b,0])
s[c, 2] = 2
s[c, 3] = (6*x1 - 6*n1)
B[c] = 0.0
c = c + 1
s[c, 4*b-2] = 2
s[c, 4*b-1] = (6*x2 - 6*n2)
B[c] = 0.0

#Solve and Rearrange
s = np.array(s, dtype=float)
B = np.reshape(B,(len(B),1))
print(s)
print(B)
print(np.linalg.solve(s,B))
SolutionVector = np.linalg.solve(s,B)
SolutionMatrix = np.reshape(SolutionVector, (b,4))
print(SolutionMatrix)

#Define S(x) to use when making the data
def Su(a, b, c, d, n, x):
    return a + b*(x-n) + c*((x-n)**2) + d*((x-n)**3)

#Create list to plot
e = 0
k = float(0)
h = .1
plotVector = []
kVector = []
while e < b:
    while k <= a[e+1,0]:
        ai = float(SolutionMatrix[e,0])
        bi = float(SolutionMatrix[e,1])
        ci = float(SolutionMatrix[e,2])
        di = float(SolutionMatrix[e,3])
        ni = float(a[e,0])
        plotVector.append(round(Su(ai,bi,ci,di,ni,k,), 6))
        k = round(k + h, 6)
        kVector.append(k)
        pass
    e = round(e + 1, 6)
    pass
print(plotVector)
print(len(plotVector))

#Plot the data
plt.plot(kVector,plotVector, '.')
plt.show()


import numpy as np
from scipy.optimize import minimize

def objective(x):
	return(pow((pow(x[0],2) + x[1] - 11),2) + pow((pow(x[1],2) + x[0] - 7),2))

def constraint(x):
    return(-26.0 + pow((x[0]-5.0), 2) + pow(x[1],2))

x0 = np.array([0.11, 0.1])

# show initial objective
print('Initial SSE Objective: ' + str(objective(x0)))

# optimize
bnds = ((0,10), (0,10))
con1 = {'type': 'ineq', 'fun': constraint}
cons = ([con1])
solution = minimize(objective,x0,method='SLSQP', bounds=bnds, constraints=cons)
x = solution.x

# show final objective
print('Final SSE Objective: ' + str(objective(x)))

# print solution
print('x1 = ' + str(x[0]))
print('x2 = ' + str(x[1]))


# MÓDULO DE OPERAÇÕES COM VETORES

from sympy import *

def escalar(v1, v2):
    if (len(v1) == 2 and len(v2) == 2):
        return v1[0]*v2[0]+v1[1]*v2[1]
    if (len(v1) == 3 and len(v2) == 3):
        return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]
    if (len(v1) > 3 and len(v2) > 3):
        print('Vetor maior que 3 dimensões (x,y,z)')
    else:
        print('Erro de dimensão de vetores.')

def absoluto(v1):
    if len(v1) == 2:
        resultado = sqrt(v1[0]**2+v1[1]**2)
        resultado = resultado.evalf()
        return resultado
    if len(v1) == 3:
        resultado = sqrt(v1[0] ** 2 + v1[1] ** 2 + v1[2] ** 2)
        resultado = resultado.evalf()
        return resultado
    if len(v1) > 3:
        print('Vetor maior que 3 dimensões (x,y,z)')

def vetorial(v1, v2):
    vi = (v1[1]*v2[2]-v1[2]*v2[1])
    vj = -(v1[0]*v2[2]-v1[2]*v2[0])
    vk = (v1[0]*v2[1]-v1[1]*v2[0])
    return Matrix([[vi, vj, vk]])

def versor(v1):
    abt = absoluto(v1)
    return Matrix([[v1[0]/abt, v1[1]/abt, v1[2]/abt]])

def angulo(v1, v2):
    teta = acos(escalar(v1, v2)/(absoluto(v1)*absoluto(v2)))*180/pi
    teta = teta.evalf()
    return teta

def projecao(v1, v2):
    proj = (escalar(v1, v2)/escalar(v2, v2)) * v2
    proj = proj.evalf()
    return proj

'''
# *************************************************************************
# EXEMPLO DE USO
init_printing()

print('\nDeclarando um vetor no R2')
vec1 = Matrix([[1, 2]])
vec2 = Matrix([[3, 4]])
pprint(vec1)
pprint(vec2)
print('A dimensão do vetor é: ' + str(len(vec1)))

print('\nDeclarando um vetor no R3')
vec3 = Matrix([[1, 2, 3]])
vec4 = Matrix([[4, 5, 6]])
pprint(vec3)
pprint(vec4)
print('A dimensão do vetor é: ' + str(len(vec4)))

print('\nSoma de vetores')
pprint(vec1+vec2)
pprint(vec3+vec4)
#pprint(vec1+vec4)   #Erro de diferença de dimensão

print('\nMultiplicação por um escalar')
pprint(5*vec1)

print('\nProduto Escalar')
print(escalar(vec1, vec2))

print('\nProduto vetorial')
pprint(vetorial(vec3, vec4))

print('\nMódulo de um vetor')
print(absoluto(vec1))
print(absoluto(vec4))

print('\nVersor')
pprint(versor(vec4))

print('\nÂngulo entre dois vetores')
print(angulo(vec3, vec4))

print('\nProjeção de v1 sobre v2')
pprint(projecao(vec3, vec4))
'''


import numpy

def branin_mesh(X0, X1):
    # b,c,t = 5.1/(4.*(pi)**2), 5./pi, 1./(8.*pi)
    b, c, t = 0.12918450914398066, 1.5915494309189535, 0.039788735772973836
    u = X1 - b*X0**2 + c*X0 - 6
    r = 10.*(1. - t) * numpy.cos(X0) + 10
    Z = u**2 + r

    return Z

def create_mesh(npoints):
    X0_vec = numpy.linspace(-5., 10., npoints)
    X1_vec = numpy.linspace(0., 15., npoints)
    X0, X1 = numpy.meshgrid(X0_vec, X1_vec)
    Z = branin_mesh(X0, X1)

    return X0, X1, Z


import numpy as np
import matplotlib.pyplot as plt

# Generate sample data.
m = 50
X = np.random.randn(m, 2)
X[:, 0] = 1
# Assume k and b for y = kx + b
k = 1.3
b = 0.9
y = k * X[:, 1] + b + np.random.randn(m, 1)[:, 0]
# Draw the graphic
plt.scatter(X[:, 1], y)
plt.show()

# Define parameters
theta = [0, 0]
alpha = 0.1

# Hypothesis function h
def h(x):
    global theta
    return theta[1] * x + theta[0]

# Cost function J
def J():
    global theta, X, y, m
    cost = 0
    for i in range(m):
        x = X[i, 1]
        cost += (h(x) - y[i]) ** 2
    return cost / 2 / m

# Goal
def minJ(j):
    global theta, X, y, m
    delta = 0
    for i in range(m):
        x = X[i, 1]
        delta += (h(x) - y[i]) * X[i, j]
    return delta / m

# Gradient Descent
def GD():
    global theta, alpha
    new_theta = theta.copy()
    for j in range(len(theta)):
        new_theta[j] -= alpha * minJ(j)
    return new_theta

# Training step
for iteration in range(100):
    print("Iteration:", iteration, "Cost:", J(), "theta:", theta)
    theta = GD()

    plt.cla()
    plt.scatter(X[:, 1], y)
    xx = np.linspace(np.min(X[:, 1]), np.max(X[:, 1]))
    yy = xx * theta[1] + theta[0]
    plt.plot(xx, yy)
    plt.show(block=False)
    plt.pause(0.01)
plt.show()


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

def countMx(N, data):
	Mx = np.sum(data)/N
	return Mx;

def countD(N, data, Mx):
	D = 0
	for u in data:
		D += (u - Mx) ** 2
	D = D / N
	return D;

def countS(D):
	return np.sqrt(D);

def countK(N, data, Mx, D):
	K = []
	for f in range(1,N+1):
		top = 0
		for i in range(0,N-f-1):
			top += (data[i] - Mx) * (data[i+f] - Mx)
		bot = D * N
		K.append(top / bot)
	return K;

def countP(data):
    N = np.size(data)
    min = np.min(data)
    max = np.max(data)
    n_steps = int(np.trunc( (max - min) / H))+1
    estimated = np.full(n_steps,1/(n_steps))
    real = np.zeros(n_steps)
    result = real
    for i in range(0,n_steps):
        for x in range(0,N-1):
            if ( (data[x] >= min + i * H) and (data[x] <= min + (i+1) * H) ):
                real[i] += 1
    for x in range(0,n_steps):
        result[x] = (real[x] / N) / estimated[x]
    return result;

def countI(data):
    N = np.size(data)
    min = np.min(data)
    max = np.max(data)
    n_steps = int(np.trunc( (max - min) / H))+1
    real = np.zeros(n_steps)
    count = 0
    for i in range(0,n_steps):
        for x in range(0,N-1):
            if ( (data[x] >= min + i * H) and (data[x] <= min + (i+1) * H) ):
                count+= 1
        real[i] = count
    for x in range(0,n_steps):
        real[x] = (real[x] / N)
    real = np.sort(real)
    return real;

def run1(N, data):
	mx = countMx(N, data)
	d = countD(N, data,mx)
	s = countS(d)
	print(mx, " ",d);
	k = countK(N, data, mx, d)
	plt.plot(k, 'ro', color='blue')
	plt.show()
	return 0;

def run2(N, data, h):

    x = np.linspace(0, 1, num=int(1 / H))
    plt.plot(x, countP(data), 'ro', color='blue')
    plt.show()

    return 0;

def run3(N, data,h):

    x = np.linspace(0, 1, num=int(1 / H))
    plt.plot(x, countI(data), 'ro', color='blue')
    plt.show()
    return 0;

TASK = int(sys.argv[1])

N = 10000
H = 0.001
data = np.random.rand(N)

if (TASK == 1):
    run1(N, data)
elif (TASK == 2):
    run2(N, data, H)
elif (TASK == 3):
    run3(N, data, H)


import numpy as np
import math
#from scipy import io, integrate, linalg, signal
#import scipy.linalg as la
#from scipy.sparse.linalg import eigs

def QR_householder(A):

    '''
     First find the size of the matrix
    '''
    m = A.shape[0]
    n = A.shape[1]
    beta = np.zeros(n)
    j=0
    for j in range(0, n):
        [v,beta[j]] = myhouse(A[j:m,j],m-j) #v is a row vector
        print(v)
        print(beta)
        A[j:m,j:n] = np.matmul((np.eye(m-j)-beta[j]*np.outer(v,v)),A[j:m,j:n])

        if j < m-1:
            A[j+1:m,j] = v[1:m-j]
    [Q,R,rank] = unpack(A,beta)
    return Q,R,rank

def myhouse(x,n):
    sigma = x[1:n] @ x[1:n]
    a1 = np.array([1.])
    v = np.concatenate((a1,x[1:n]))
    if abs(sigma) < 1e-10:
        beta = 0
    else:
        mu = math.sqrt(x[0]**2 + sigma)
        if x[0] <= 0:
            v[0] = x[0] - mu
        else:
            v[0] = -sigma/(x[0]+mu)
        beta = 2*v[0]**2/(sigma+v[0]**2)
        v = v/v[0]
    return v,beta

def unpack(H,beta):

    m = H.shape[0]
    n = H.shape[1]
    Q = np.eye(m)
    min_dim = min(m,n)
    R = np.zeros((m,n))
    rank = 0
    for i in range(0,min_dim):
        if abs(H[i,i]) > 1e-9:
            R[i,i:n] = H[i,i:n]
            # if 'v1' in locals():
            #     v1.clear()
            # if 'P' in locals():
            #     P.clear()
            a1 = np.array([1.])
            v1 = np.concatenate((a1,H[i+1:m,i]))
            Q[:,i:m] = np.matmul(Q[:,i:m],np.eye(m-i)-beta[i]*np.outer(v1,v1))
            rank = i+1
        else:
            rank = i
            break
    return Q,R,rank
'''
The main code
'''
#A = np.array([[1.,2.,3.],[4.,5.,6.],[7.,8.,9.],[10.,11.,12.]])
A = np.array([  [  0.0623,    4.3117,    1.8908],
   [-0.6859,    7.4452,   -1.5081],
    [0.5314,  -11.7046,   -0.9195]])
[Q,R,rank] = QR_householder(A)
print(np.matmul(Q.T,Q))
print(np.matmul(Q,R))
print(rank)


import numpy as np
from sklearn.metrics import *

def slope(pred,true):
    return ( np.sum(true*pred) / np.sum(pred*pred) )

def Rsquared0(pred,true):
    true_mean = np.mean(true)
    yr0 = pred * slope(pred,true)
    first_term = (true - yr0)**2 #(true - yr0)
    second_term = (true-true_mean)**2 #(true-true_mean)
    return (1 - ( np.sum(first_term) / np.sum(second_term) ) )

#squared correlation coefficient
def Rsquared(pred,true):
    true_mean = np.mean(true)
    pred_mean = np.mean(pred)
    first_term = np.sum( (true-true_mean) * (pred - pred_mean) )
    second_term = np.sqrt( np.sum( (true-true_mean)**2) * np.sum( (pred-pred_mean)**2) )
    div = first_term / second_term
    return div*2

#crossvalidated coefficient of determination
def Qsquared(pred,true):
    true_mean = np.mean(true)
    first_term = (np.abs(pred-true))**2
    second_term = (np.abs(true-true_mean))**2
    ret = 1 - (np.sum(first_term) / np.sum(second_term))
    return ret

def RMSE(pred,true):
    rmse = np.sqrt(mean_squared_error(true,pred))
    return rmse

class ValidationMetrics:
      def __init__(self,pred,true):
          self.RMSE = RMSE(pred,true)
          self.Qsquared = Qsquared(pred,true)
          self.Rsquared = Rsquared(pred,true)
          self.Rsquared0 = Rsquared0(pred,true)
          self.slope = slope(pred,true)


import numpy as np
import matplotlib.pyplot as plt

def logistic_loss(x):

    return np.log(1 + np.exp(1 - x))

def hinge_loss(x):

    tmp = 1 - x

    tmp[np.where(tmp <= 0)] = 0

    return tmp

def squared_hinge_loss(x):

    tmp = 1 - x

    tmp[np.where(tmp <= 0)] = 0

    return np.square(tmp)

x = np.arange(-4, 4, 0.001)

plt.plot(x, logistic_loss(x), 'r')
plt.plot(x, hinge_loss(x), 'g')
plt.plot(x, squared_hinge_loss(x), 'b')
plt.legend(["logistic loss", "hinge loss", "squared hinge loss"])
plt.title("Loss function")
plt.show()


"""
This module contains Linear Regression Model class.

Author: Phyruz
"""
import numpy as np
import logging
from numpy import ndarray
from typing import Dict,Tuple

class LinearRegression():
    """A Linear Regression class"""

    batch: Dict[str, ndarray] = {}
    weights: Dict[str, ndarray] = {}
    forward_info: Dict[str, ndarray] = {}
    loss_gradients: Dict[str, ndarray] = {}

    def initialise_weights(self, nins:int) -> Tuple[ndarray]:
        return np.random.rand(nins,1), np.random.rand(1,1)

    def forward_pass(self) -> float:
        """Start from """
        # Matrix multiplication between input and weights
        self.forward_info['N'] = np.matmul(
            self.batch['X'], self.weights['W']
            )
        # Adding bias
        self.forward_info['P'] = self.forward_info['N'] + self.weights['b']

        # Calculate loss
        self.forward_info['loss'] = np.mean((self.batch['y'] - self.forward_info['P'])**2)

    def backward_pass(self) -> ndarray:

        # Calculate derivative with respect to weights (dLdW)
        # Last derivative for the loss function (dLdP)
        dLdP = -2*(self.batch['y'] - self.forward_info['P'])

        # Adding bias function (dPdN)
        dPdN = np.ones_like(self.forward_info['N'])

        # Matrix multiplication operation (dNdW)
        dNdW = np.transpose(self.batch['X'])

        dLdN = dLdP*dPdN
        dLdW = np.matmul(dNdW,dLdN)

        # Derivative with respect to bias
        dPdB = np.ones_like(self.batch['y'])
        dLdB = (dLdP*dPdB).sum(axis=0)

        self.loss_gradients['W'] = dLdW
        self.loss_gradients['b'] = dLdB

    def train(self,
            X_batch: ndarray,
            y_batch: ndarray,
            n_epochs: int,
            learning_rate: float = 0.001,
             ) -> None:

        self.batch['X'] = X_batch
        self.batch['y'] = y_batch
        self.weights['W'], self.weights['b'] = self.initialise_weights(X_batch.shape[1])
        self.weights['W'] = np.transpose(self.weights['W'], (0,1))
        for _ in range(n_epochs):
            self.forward_pass()
            print(self.forward_info['loss'])
            self.backward_pass()
            for key in self.weights.keys():
                self.weights[key] -= learning_rate * self.loss_gradients[key]

if __name__=='__main__':
    X_batch = np.array([[0,], [1,], [2,], [3,], [4,], [5,], [6,], [7,], [8,], [9,]])
    y_batch = np.array([[10], [12], [14], [16], [18], [20], [22], [24], [26], [28]])
    model = LinearRegression()
    model.train(X_batch, y_batch, n_epochs=3000)
    print(model.weights)


#!/usr/bin/env python3
import numpy as np
from sys import exit, argv
np.random.seed(17)

def relu(x):
    return x * (x > 0)

def relu_derivative(x):
    return 1. * (x > 0)

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

def sigmoid_derivative(x):
    return x * (1. - x)

class NeuralNetwork(object):

    def __init__(self, x, y, eta, func1, func2, func1_derivative, func2_derivative):
        self.input = x
        self.weights1 = np.random.rand(4, self.input.shape[1])
        self.weights2 = np.random.rand(1, 4)
        self.y = y
        self.output = np.zeros(self.y.shape)
        self.eta = eta

        self._func1 = func1
        self._func2 = func2
        self._func1_derivative = func1_derivative
        self._func2_derivative = func2_derivative

    def feedforward(self):
        self.layer1 = self._func1(np.dot(self.input, self.weights1.T))
        self.output = self._func2(np.dot(self.layer1, self.weights2.T))

    def backprop(self):
        delta2 = (self.y - self.output) * self._func2_derivative(self.output)
        d_weights2 = self.eta * np.dot(delta2.T, self.layer1)

        delta1 = self._func1_derivative(self.layer1) * \
            np.dot(delta2, self.weights2)
        d_weights1 = self.eta * np.dot(delta1.T, self.input)

        self.weights1 += d_weights1
        self.weights2 += d_weights2

if __name__ == "__main__":

    if len(argv) < 2:
        exit('usage: ./ex-1.py <XOR|OR|AND>')

    operation = argv[1]

    runs = [
        # (eta, func1, func2, func1 derivative, func2 derivative), comment
        ((0.0001, relu, relu, relu_derivative, relu_derivative),
         r'all relu, eta=0.0001; when rounded to nearest integer it gives good results; '
         r'curiously – the results are sometimes about 0.25 too high'),
        ((0.01, sigmoid, relu, sigmoid_derivative, relu_derivative),
         r'sigmoid & relu, eta=0.01; not that great, but still rounding it gives good results'),
        ((0.01, relu, sigmoid, relu_derivative, sigmoid_derivative),
         r'relu & sigmoid, eta=0.01; very close to the actual sought value'),
        ((0.1, sigmoid, sigmoid, sigmoid_derivative, sigmoid_derivative),
         r'all sigmoid, eta=0.1; interestingly, for very high eta (>20) „OR” and „XOR” '
         r'operation had almost 100% accurate results; but it was unstable for „AND”; '),
    ]

    for run in runs:
        X = np.array([
            [0, 0, 1],
            [0, 1, 1],
            [1, 0, 1],
            [1, 1, 1],
        ])
        # a column of ones is neccessary to include a bias

        # define the „correct” answer
        y = np.array([[0], [1], [1], [0]])

        # other operations
        if operation == 'OR':
            y = np.array([[0], [1], [1], [1]])
        elif operation == 'AND':
            y = np.array([[0], [0], [0], [1]])

        nn = NeuralNetwork(X, y, *run[0])

        # train the neural network
        for _ in range(5000):
            nn.feedforward()
            nn.backprop()

        np.set_printoptions(precision=3)
        # print the output
        print(nn.output)
        # print the comment
        print(run[1])
        print()


#isPSD(mt)              :   Checks whether matrix is PSD or not

import numpy as np

__all__ = ['isPSD']

def isPSD(mt, tol = 1e-12, flag = False):
    r"""Takes a matrix, returns True if is Positive Semi-definite, otherwise
    returns False

    Parameters
    ----------
    mt : numpy.ndarray

    tol : float
          Optional, default value 1e-12

    flag : bool
           Optional, Returns eigenvalues and of mt if True

    Returns
    ----------
    When flag is False, returns pos, else returns (pos, val, vec)

    pos : bool
          True if mt is positive semi-definite up to some numerical tolerance;
          False otherwise

    val : numpy.ndarray
          Eigenvalues of mt

    vec : numpy.ndarray
          Eigenvectors of mt

    """
    #Square Matrix
    (row, col) = np.shape(mt)
    sqr = row == col
    if not sqr:
        return False

    #Hermitian
    mtDag = mt.conj().T
    diff = mt - mtDag
    herm = np.linalg.norm(diff) < 10*tol
    if not herm:
        return False

    #Positivity
    mt2 = (mt + mt.conj().T)/2.
    val, vec = np.linalg.eigh(mt2)
    pos = all(val.real > -tol) & all(val.imag > -tol)

    if flag:
        return (pos, val, vec)
    else:
        return pos


# ***Question 3***

import numpy as np
from scipy import interpolate
import matplotlib.pyplot as plt
from polyFit import *
from swap import *
from error import *

Re = np.array([0.2,2,20,200,2000,20000]) # the Re values given to us, on x axis
cD = np.array([103,13.9,2.72,0.800,0.401,0.433]) # the cD values given to us, on y axis

plt.figure(1)
plt.loglog(Re,cD) # plotting Re and cD on a log-log scale

f = interpolate.interp1d(Re,cD,kind='cubic') # using cubic spline to interpolate Re vs. cD plot

newRe = np.array([5,50,500,5000]) # an array of the values at which we want Re
newcD = f(newRe) # making the y values of the cubic function using the new Re values we are using

plt.loglog(Re,cD,'o',newRe,newcD,'-') # first plot is circles, new plot is dashes
plt.title('Re vs cD on loglog scale')
plt.xlabel('logRe')
plt.ylabel('logcD')

print "\n\n Cubic spline interpolation results:" # printing the numerical value of the function at the given new Re values when using the cubic spline interpolation

print "Value at Re = 5: " + (str(f(5)))
print "Value at Re = 50: " + (str(f(50)))
print "Value at Re = 500: " + (str(f(500)))
print "Value at Re = 5000: " + (str(f(5000)))

print "\n\n Polynomial interpolation results:" # printing the numerical value of the function at the given new Re values when using the polynomial/barycentric interpolation

print "Value at Re = 5: " + (str(interpolate.barycentric_interpolate(Re,cD,5)))
print "Value at Re = 50: " + (str(interpolate.barycentric_interpolate(Re,cD,50)))
print "Value at Re = 500: " + (str(interpolate.barycentric_interpolate(Re,cD,500)))
print "Value at Re = 5000: " + (str(interpolate.barycentric_interpolate(Re,cD,5000)))

lRe=np.log(Re)
lcD=np.log(cD)

p = polyFit(lRe,lcD,3) # this gives the coefficients of the polynomial on the logged values of Re and cD
print "The polynomial interpolation results are: "
print p

x = np.arange(np.log(Re[0]),np.log(Re[5]),0.1) # making a range of the relevant Re log values to use with our polyfit
y = p[0]+x*(p[1])+(x**2)*(p[2])+(x**3)*(p[3]) # the polyfit

plt.loglog(np.e**x, np.e**y, '+') # putting them back into exponentials

plt.show(1)

plt.figure(2)
plt.plot(Re,cD, '-')
plt.title('Re vs cD (not loglog)')
plt.xlabel('Re')
plt.ylabel('cD')
plt.axis([-500,20500,-10,110])
plt.show(2)

ExamPrep/Shit Comp/SciComp Exam 2016/Assignments 15-16/A1Q3 loglog plots interpolate interp1d cubic spline interpolation polynomial interpl barycentric polyfit.py


import scipy.stats as stats
import numpy as np
import math
from sympy import *

#after x months the mean and the variance of the cash position;
def msv(drift,variance,initial,time):
    m=drift*time+initial
    v=variance*time
    s=math.sqrt(v)
    i=initial
    return m,v,s,i

#the probability of a negative cash position at the end of x months;
def pro(mu,sigma):
    probability_cdf = stats.norm.cdf(-(mu/sigma),0,1)
    return probability_cdf

#have a less than x% chance of a negative cash position by the end of x months;
#beware the initial in paramaters is the initial position given by quiz;
def inipos(sigma,mu,initial):
    ppf=stats.norm.ppf(0.05,0,1)
    m=mu-initial
    x=-ppf*sigma-m
    return x

mu,var,sigma,initial=msv(0.01, 0.14, 0.05, 10)
p=pro(mu, sigma)
ini=inipos(sigma, mu, initial)
print("\n")
print("The mean and the variance of the cash position are " + str(mu) + ", " + str(var) + ".\n")
print("The probability is " + str(p) + ".\n")
print("The initial position is " + str(ini) + ".\n")


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
ch7Python.py. Multivariate regression.
This is demonstration code, so it is transparent but inefficient.
"""
import matplotlib.pyplot as plt
import numpy as np
import statsmodels.api as sm
from scipy import stats
import warnings # python complains about small n, so turn off warnings.
warnings.filterwarnings('ignore')
x1 = [1.00,1.25,1.50,1.75,2.00,2.25,2.50,2.75,3.00,3.25,3.50,3.75,4.00]
x2 = [7.47,9.24,3.78,1.23,5.57,4.48,4.05,4.19,0.05,7.20,2.48,1.73,2.37]
y = [3.34,4.97,4.15,5.40,5.21,4.56,3.69,5.86,4.58,6.94,5.57,5.62,6.87]

# Set donorm=1 to use standardized regressors to compare coefficients.
donorm = 0
if donorm==1:
    x1 = x1 / np.std(x1)
    x2 = x2 / np.std(x2)
    y = y / np.std(y)
    print('Using standardized regressors ...')

# convert data to vectors.
x1 = np.array(x1)
x2 = np.array(x2)
y = np.array(y)
n = len(y)

###############################
# FULL model. Repeat twice:
# 1) by hand (vector-marix) then 2) check using standard library.
###############################
ymean = np.mean(y)
ones = np.ones(len(y)) # 1 x n vector
Xtr = [x1, x2, ones]   # 3 x n matrix
X = np.transpose(Xtr)  # n x 3 matrix
y = np.transpose(y)    # 1 x n vector

# find slopes and intercept using vector-matrix notation.
Xdot = np.dot(Xtr,X)
Xdotinv = np.linalg.pinv(Xdot)
XdotinvA = np.dot(Xdotinv,Xtr)
params = np.dot(XdotinvA,y)

b0 = params[2] # 2.148
b1 = params[0] # 0.966
b2 = params[1] # 0.138

print('slope b1 = %6.3f' % b1)
print('slope b2 = %6.3f' % b2)
print('intercept b0 = %6.3f' % b0)

# PLOT DATA.
fig = plt.figure(1)
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X[:,0], X[:,1], y, marker='.', color='red')
ax.set_xlabel("x1")
ax.set_ylabel("x2")
ax.set_zlabel("y")

# PLOT BEST FITTING PLANE.
x1s = np.tile(np.arange(10), (10,1))
x2s = np.tile(np.arange(10), (10,1)).T
yhats = x1s*b1 + x2s*b2 + b0
ax.plot_surface(x1s,x2s,yhats, alpha=0.4)
plt.show()

# find vertical projection of data onto plane.
yhat = np.dot(X,params)
SSExplainedFULL1 = sum((ymean-yhat)**2)
ax.scatter(X[:,0], X[:,1], yhat, marker='.', color='blue')

SSExpFULL = sum((yhat-ymean)**2) # 7.804
print('SSExplainedFULL (vector-matrix) = %6.4f' % SSExpFULL )

SSNoiseFULL = sum((yhat-y)**2)

# find coefficient of variation r2.
r2 = np.var(yhat) / np.var(y) # 0.548
print('coefficient of variation r2 = %6.3f' % r2)

# Compare to STANDARD LIBRARY OUTPUT.
modelFULL = sm.OLS(y, X).fit()

SSExplainedFULL = modelFULL.ess # 7.804
print('SSExplainedFULL (vector-matrix) = %6.4f' % SSExpFULL )
print('SSExplainedFULL (standard library) = %6.4f' % SSExplainedFULL )

print('\n\nFULL MODEL SUMMARY')
print(modelFULL.summary())
###############################
# REDUCED model. Repeat twice:
# 1) by hand (vector-matrix) then 2) check using standard library.
###############################
XREDtr = [x1, ones]
XRED = np.transpose(XREDtr)

# 1) Find slopes and intercept of best fitting plane.
Xdot = np.dot(XREDtr,XRED)
Xdotinv = np.linalg.pinv(Xdot)
XdotinvA = np.dot(Xdotinv,XREDtr)
paramsRED = np.dot(XdotinvA,y)
yhatRED = np.dot(XRED,paramsRED) # projection of data onto plane.
SSExplainedRED1 = sum((ymean-yhatRED)**2) # 6.643
print('SSExplainedRED (vector-matrix) = %6.3f' % SSExplainedRED1)

# 2) STANDARD LIBRARY OUTPUT.
modelRED = sm.OLS(y, XRED).fit()
SSExplainedRED = modelRED.ess # 6.643
print('SSExplainedRED (standard library) = %6.3f' % SSExplainedRED)
print('\n\nREDUCED MODEL SUMMARY')
print(modelRED.summary())

###############################
# Extra sum of squares method (partial F-test). Repeat twice:
# 1) by hand (vector-marix) then 2) check using standard library.
###############################
# 1) Vector-matrix: Results of extra sum of squares method.
print('\nVector-matrix: Results of extra sum of squares method:')
dofDiff = 1 # Difference in dof between full and partial model.
numparamsFULL = 3 # params in full model.
num = (SSExplainedFULL - SSExplainedRED) / dofDiff
den = SSNoiseFULL / (n-numparamsFULL)
Fpartial = num / den
print("Fpartial = %0.3f" % Fpartial)
p_valuepartial = stats.f.sf(Fpartial, dofDiff, n-numparamsFULL)
print("p_valuepartial (vector-matrix) = %0.3f" % p_valuepartial) # 0.209

# 2) STANDARD LIBRARY: Results of extra sum of squares method.
# test hypothesis that x2=0
hypothesis = '(x2 = 0)'
f_test = modelFULL.f_test(hypothesis)
print('\nSTANDARD LIBRARY: Results of extra sum of squares method:')
print('F df_num = %.3f df_denom = %.3f'
% (f_test.df_num, f_test.df_denom)) # 1, 10
print('F partial = %.3f' % f_test.fvalue) # 1.805
print('p-value (standard library) = %.3f' % f_test.pvalue) # 0.209
# END OF FILE.

import numpy,from scipy,import statsmodels


__version__ = '0.1'
__email__ = 'mariolpantunes@gmail.com'
__status__ = 'Development'

import math
import typing
import joblib
import logging
import tempfile
import numpy as np

from tqdm import tqdm

logger = logging.getLogger(__name__)

# Cache from joblib
location = tempfile.gettempdir()
memory = joblib.Memory(location, verbose=0)

def simulated_annealing(objective:typing.Callable, bounds:np.ndarray, n_iter:int=200, step_size:float=0.01, temp:float=20.0, cached=False, debug=False) -> list:
    """
    Simulated annealing algorithm.

    Args:
        objective (typing.Callable): objective fucntion
        bounds (np.ndarray): the bounds of valid solutions
        n_iter (int): the number of iterations (default 200)
        step_size (float): the step size (default 0.01)
        temp (float): initial temperature (default 20.0)

    Returns:
        list: [solution, solution_cost]
    """

    # cache the initial objective function
    if cached:
        # Cache from joblib
        location = tempfile.gettempdir()
        memory = joblib.Memory(location, verbose=0)
        objective_cache = memory.cache(objective)
    else:
        objective_cache = objective

	# min and max for each bound
    bounds_max = bounds.max(axis = 1)
    bounds_min = bounds.min(axis = 1)
    # generate an initial point
    best = bounds[:, 0] + np.random.rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
	# evaluate the initial point
    best_cost = objective_cache(best)
	# current working solution
    curr, curr_cost = best, best_cost
    cost_iter = []
	# run the algorithm
    for i in tqdm(range(n_iter), disable=not debug):
		# take a step
        candidate = curr + np.random.randn(len(bounds)) * step_size
        # Fix out of bounds value
        candidate = np.minimum(candidate, bounds_max)
        candidate = np.maximum(candidate, bounds_min)
		# evaluate candidate point
        candidate_cost = objective_cache(candidate)
		# check for new best solution
        #print(f'{i}/{n_iterations} -> {candidate} -> {candidate_cost}')
        if candidate_cost < best_cost:
			# store new best point
            best, best_eval = candidate, candidate_cost
            cost_iter.append(best_eval)
			# report progress
            #logger.info('>%d f(%s) = %.5f' % (i, best, best_cost))
		# difference between candidate and current point evaluation
        diff = candidate_cost - curr_cost
        # calculate temperature for current epoch
        t = temp / float(i + 1)
        # calculate metropolis acceptance criterion
        metropolis = np.exp(-diff / t)
        # check if we should keep the new point
        if diff < 0 or np.random.rand() < metropolis:
            # store the new current point
            curr, curr_cost = candidate, candidate_cost

    if cached:
        memory.clear(warn=False)

    if debug:
        return (best, best_eval, np.array(cost_iter))
    else:
        return (best, best_eval)


from math import isclose
from typing import Tuple, Union

from sympy import Symbol, diff, sympify
from sympy.core.function import Function
from sympy.parsing.sympy_parser import (convert_xor, function_exponentiation,
                                        implicit_multiplication_application,
                                        parse_expr, standard_transformations)

from ..error_handler import InfiniteIteration

x = Symbol('x')
transformations = standard_transformations + \
    (convert_xor, implicit_multiplication_application, function_exponentiation)

def fixed_point(f: Function, n: float, rational: bool = False,
                iterated_data: bool = False) -> Union[float, Tuple[float, list]]:
    """
    Using Fixed-Point method, returns float (or tupled with iterated data).
    - Known as the method of successive submission.

    ..Note:
        - Return iterated_data defaults to False
        - Always use 'x' as a symbol
        - Originally was to take list of formulae. Modularising thos method
        means the need to opt it out.

    ..Usage:
        * Find all the possible iterative formula of f(x),
        Transform them to x = f(x)
            Example:
                f(x) = x^2-8x+11 can be transformed to:
                    x = (x^2+11)/8;
                    x = sqrt(8x-11)
                    x = (8x-11)/x

    Algorithm
    =========
    1. Solve for the new value of n [f(n)]
    2. If error % is converging to 0, return n as root
    3. if previous n is converging with current n, return n as root

    Examples
    ========
    ** Non-pythonic expressions will be parsed by SymPy module
    >>> fixed_point('(x^2+11)/8', 3)
    1.7639910281905442

    ** Using pythonic expressions is also accepted
    >>> fixed_point('(x**2+11)/8', 3)
    1.7639910281905442

    ** Turning rational True
    >>> fixed_point('(8x-11)/x', 3, rational=True)
    153301943/24583261

    ** Turning iterated_data True
    >>> fixed_point('(8x-11)/x', 3, iterated_data=True)
    (6.236029589402317, {0: {'Xn': 3, 'e%': None}, ...)

    Iterated data
    =============
    count / iteration :
        - The first key you see in the dictionary

    Xn :
        - Value of the iterated approximate root

    e% :
        - Percent error, how accurate the approximate root

    Exceptions
    ==========
    InfiniteIteration :
        - Raised when the function passed is indefinite and
        iteration reaches 99, assuming it is indefinite.

    Parameters
    ==========
    f :
        - Should be STRING
        - Mathematical expression
        - A mathematical function
        - Example:
            '(x^2+11)/8'
            '(x**2+11)/8'
            '(8x-11)/x'

    n :
        - the 'x' value of the function

    rational :
        - Returns fraction/rational value
        - Defaults to False

    iterated_data:
        - Returns the iterated data in dictionary
        - Defaults to False
    """

    f = parse_expr(f, transformations=transformations)
    n = sympify(n)

    data = {}
    count = 0
    prev_n = 0

    while True:
        error = abs(((n-prev_n)/n)*100)
        data[count] = {'Xn': n, 'e%': error if count > 0 else None}

        prev_n = n
        n = f.subs(x, n)

        if isclose(error, 0.0000, rel_tol=1e-4):
            break
        elif isclose(prev_n, n, abs_tol=1e-4):
            break
        elif count >= 99:
            raise InfiniteIteration

        count += 1

    if not rational:
        n = float(n)

    if iterated_data:
        return n, data
    else:
        return n

def newton_raphson(f: Function, n: float, rational: bool = False,
                   iterated_data: bool = False) -> Union[float, Tuple[float, list]]:
    """
    Using Newton-Raphson method, returns float (or tupled with iterated data).
    - Utilizes the derivative of f(x)
    - is an open method that finds the root x of a function such that f(x)

    ..Note:
        - Return iterated_data defaults to False
        - Always use 'x' as a symbol

    Algorithm
    =========
    1. Solve f(x), f'(x), error %
    2. n = n - (f(x)/f'(x))
    3. if error % is converging to 0, return n as root
    4. if previous f'(x) is converging to next f'(x), return n as root

    Examples
    ========
    ** Non-pythonic expressions will be parsed by SymPy module
    >>> from newton_raphson import newton_raphson
    >>> newton_raphson('x^2-8x+11', 1)
    1.763932022500022

    ** Using pythonic expressions is also accepted
    >>> newton_raphson('x**2-8*x+11', 1)
    1.763932022500022

    ** Turning rational True
    >>> newton_raphson('x^3-3x+1', 0, rational=True)
    170999/492372

    ** Turning iterated_data True
    >>> newton_raphson('x^3-3x+1', 0, iterated_data=True)
    (0.347296353163868, {0: {'Xn': 0, 'fx': 1, 'fpx': -3, 'e%': None}, ...)

    Iterated data
    =============
    count / iteration :
        - The first key you see in the dictionary

    Xn :
        - Value of the iterated approximate root

    fx :
        - Value of the f(n)

    fpx :
        - Value of the f'(n) [computed derived f(n)]

    e% :
        - Percent error, how accurate the approximate root

    Exceptions
    ==========
    InfiniteIteration :
        - Raised when the function passed is indefinite and
        iteration reaches 99, assuming it is indefinite.

    Parameters
    ==========
    f :
        - Should be STRING
        - Mathematical expression
        - A mathematical function
        - Example:
            'x^2-8x+11'
            'x**3-3*x+1'
            'x^3+10x^2-5'

    n :
        - the 'x' value of the function

    rational :
        - Returns fraction/rational value
        - Defaults to False

    iterated_data:
        - Returns the iterated data in dictionary
        - Defaults to False
    """
    f = parse_expr(f, transformations=transformations)
    n = sympify(n)

    data = {}
    count = 0
    prev_n = 0
    fp = diff(f, x)

    while True:
        fXn = f.subs(x, n)
        fpXn = fp.subs(x, n)
        error = abs(((n-prev_n)/n)*100)

        data[count] = {'Xn': n, 'fx': fXn, 'fpx': fpXn,
                       'e%': error if count > 0 else None}

        prev_n = n
        n = n - (fXn/fpXn)

        if isclose(round(error, 4), 0.0, rel_tol=1e-4):
            break
        elif isclose(fpXn, fp.subs(x, n), rel_tol=1e-4):
            break
        elif count >= 99:
            raise InfiniteIteration

        count += 1

    if not rational:
        n = float(n)

    if iterated_data:
        return n, data
    else:
        return n


import numpy as np
import pandas as pd

df=pd.DataFrame(
    {
        "var_1":np.arange(0.01,1,0.1),
        "var_2":1-np.arange(0.01,1,0.1)
    }
)

def entropy(x):
    return -np.sum(x*np.log2(x))

df["entropy"]=df.apply(
    lambda x: entropy([x["var_1"],x["var_2"]]),
    axis=1
)
print(df)
'''
   var_1  var_2   entropy
0   0.01   0.99  0.080793
1   0.11   0.89  0.499916
2   0.21   0.79  0.741483
3   0.31   0.69  0.893173
4   0.41   0.59  0.976500
5   0.51   0.49  0.999711
6   0.61   0.39  0.964800
7   0.71   0.29  0.868721
8   0.81   0.19  0.701471
9   0.91   0.09  0.436470
'''


from sage.all import ceil, log, sqrt, pi, floor, ln, gcd

from dissect.traits.trait_interface import compute_results
from dissect.utils.custom_curve import CustomCurve

def a08_curve_function(curve: CustomCurve):
    """
    Computes the lower and upper bound of class number of the maximal order of the endomorphism algebra

    Upper bound:
    Inequality class number<= sqrt(d)*log(d)*constant (see below)
    #https://en.wikipedia.org/wiki/Class_number_formula#Dirichlet_class_number_formula
    #https://math.stackexchange.com/questions/1887252/class-number-upper-bound-for-imaginary-quadratic-fields

    Lower bound:
    https://mathworld.wolfram.com/ClassNumber.html

    """
    cm_disc = curve.cm_discriminant()
    frob_disc_factor = curve.frobenius_disc_factorization()
    if frob_disc_factor.timeout():
        return {"upper": frob_disc_factor.timeout_message(), "lower": frob_disc_factor.timeout_message()}
    fact_d = [f for f, e in frob_disc_factor.factorization(unpack=False) if e % 2 == 1]
    if cm_disc % 4 == 0:
        fact_d.append(2)

    w = {4: 4, 3: 6}.get(-cm_disc, 2)
    upper_bound = ceil(log(-cm_disc) * sqrt(-cm_disc) * w / (2 * pi))

    fact_d = sorted(fact_d)[:-1]
    lower_bound = 1
    for f in fact_d:
        lower_bound *= (1 - floor(2 * sqrt(f)) / (f + 1)) * ln(-cm_disc)
    if gcd(cm_disc, 5077) == 1:
        lower_bound *= (1 / 55)
    else:
        lower_bound *= (1 / 7000)
    lower_bound = floor(lower_bound)
    curve_results = {"upper": upper_bound, "lower": lower_bound}
    return curve_results

def compute_a08_results(curve_list, desc="", verbose=False):
    compute_results(curve_list, "a08", a08_curve_function, desc=desc, verbose=verbose)


from sympy import *
from sympy.solvers import solve
from sympy import Symbol
import matplotlib.pyplot as plt
import numpy as np

x=Symbol('x')
a1=Symbol('a1')
a2=Symbol('a2')
a3=Symbol('a3')
wf1=Symbol('wf1')
wf2=Symbol('wf2')
eqn=[]

u=2+(x-1)*a1+(x*x-1)*a2+a3*(x**3-1)
up=diff(u,x)
n=[x-1,x*x-1,x**3-1]
print(n)
for i in range(3):
    print(n[i])
    w=n[i]*(x**2)*(5-2*u)-integrate(diff(n[i],x)*(x**2)*up,x)+integrate((x-1)*n[i],x)
    wf1=w.subs(x,1)
    wf2=w.subs(x,2)
    eqn.append(wf2-wf1)
print(w)
print(eqn)
sol=solve(eqn,[a1, a2, a3])
print(sol)

u_ext=[]
u_gal=[]
y = []
i=1
while i<=2:
    y.append(i)
    u_ext.append(((0.1)*(29.9096-(5*x)-(4.9096/x))+log(x)).subs(x,i))
    u_gal.append((((u.subs(a1,sol.get(a1))).subs(a2,sol.get(a2))).subs(a3,sol.get(a3))).subs(x,i))
    i+=0.01
plt.plot(y, u_ext, label="Exact")
plt.plot(y, u_gal, label="Galerkin")
plt.legend()
plt.xlabel('x', fontsize=16)
plt.ylabel('u', fontsize=16)
plt.suptitle('Exact soluton vs Galerkin weak form')
plt.show()


import numpy as np

def l1_prox(y, weight):
    """Projection onto the l1-ball.
    """
    return np.maximum(np.abs(y) - weight, 0) * np.sign(y)

def l2_prox(y, weight):
    """Projection onto the l2-ball.
    """
    return (1.0 / (weight + 1)) * y

def norm1(x):
    """Returns the l1 norm `x`.
    """
    return np.linalg.norm(x, 1)

def norm2sq(x):
    """Returns the l2 norm squared of `x`.
    """
    return (1.0 / 2) * np.linalg.norm(x) ** 2


import numpy as np

def regularization(w, type='L2', alpha=.00001, jac=False):
    """Used to set a penalty the model.

    Args:
        w (Array): Weight matrix.
        type (str, optional): Choose between L1 and L2 Regularization. Defaults to 'L2'.
        alpha ([Float,integer], optional): Alpha hyperparameter. Used to Adjust the importance of the penalty. Defaults to .00001
        jac (bool, optional): If True, Jacobian version of regularization will be returned. Defaults to False.

    Raises:
        ValueError: if invalid value is provided as "type". only [L1, L2] is supported.

    Returns:
        Float
    """
    if type == 'L2':
        if not jac:
            return alpha * (w.T @ w)[0, 0]
        return alpha * w
    elif type == 'L1':
        return alpha * np.sum(np.abs(w))
    else:
        raise ValueError(f"{type} is not supported. only [L1, L2] is supported.")

class Loss:
    """Contains Loss functions for machine learning models.
    List of loss functions currently available: {Mean sqaured error, binary cross entropy, cross entropy}
    """
    @classmethod
    def _use_app_loss(cls, app_loss):

        if app_loss == 'mse':
            return cls.mse
        elif app_loss == 'binary_cross_entropy':
            return cls.binary_cross_entropy
        elif app_loss == 'cross_entropy':
            return cls.cross_entropy

    @staticmethod
    def mse(p, y,vectorized=True):
        """Mean Squared Error loss function.

        Args:
            p (Array): Predicted value.
            y (Array): Target value.
            vectorized (bool, optional): If True, vectorized version of MSE is used. Defaults to True.

        Returns:
            float
        """
        dls = np.average((np.square(p - y)))
        if vectorized:
            dls = 1/len(y) * ((p - y).T @ (p - y))[0, 0]
        return dls

    @staticmethod
    def binary_cross_entropy(p, y):
        """binary cross entropy loss function for binary classification.

        Args:
            p (Array): Predicted value.
            y (Array): Target value.

        Returns:
            Float
        """
        return np.average((-y * np.log(p))-((1-y)*np.log(1 - p)))

    @staticmethod
    def cross_entropy(p, y):
        """Cross entropy loss function for binary or multiclass classification.

        Args:
            p (Array): Predicted value.
            y (Array): Target value.

        Returns:
            Float
        """
        return np.average(-y * np.log(p))


from sympy import *

def derivative_maximum_value_calculator(function_expression, interval):
    # find maximum value of derivation function at a given interval
    derivative_symbol = symbols('x')
    derivative_function = sympify(function_expression)
    return calculus.util.maximum(derivative_function, derivative_symbol, Interval(interval[0], interval[1]))

def trapezoid_integration(interval, function_expression, partitions=6):
    h = (interval[1] - interval[0]) / partition
    function_variable = var("x")
    function = sympify(function_expression)
    integration_value = function.subs(function_variable, interval[0]) / 2  # calculating function value
    for i in range(1, partitions):
        integration_value += function.subs(function_variable, interval[0] + i * h)  # calculating function value
    integration_value += function.subs(function_variable, interval[1]) / 2  # calculating function value
    second_derivative = diff(function, "x", 2)  # differentiate function by sympy
    second_derivative_maximum_value = derivative_maximum_value_calculator(second_derivative, interval)
    maximum_integration_error = -(pow(h, 3) / 12) * second_derivative_maximum_value
    return "integration value: {}, integration maximum error: {}".format(integration_value, maximum_integration_error)

if __name__ == '__main__':
    given_interval = eval(input("please enter and interval like [a, b] where a and b are numbers: "))
    given_function = input("please enter a function like 2 * x + 3 * sin(x)")
    print(trapezoid_integration(given_interval, given_function))


from abc import ABC
import numpy as np

from Operators.DummyAlgorithm import DummyAlgorithm

class FeatureVectorDistance(DummyAlgorithm, ABC):
    name = '特征向量距离度量'
    __version__ = 'v1.0.20210325'

    def feature_vector_check(self, _vector_1, _vector_2):
        assert _vector_1.ndim == _vector_2.ndim == 1, 'two vector must be 1 D'

class EuclideanDistance(FeatureVectorDistance):
    name = '欧式距离'
    __version__ = 'v1.0.20210325'

    def execute(self, _feature_vector_1, _feature_vector_2):
        self.feature_vector_check(_feature_vector_1, _feature_vector_2)
        return np.linalg.norm(np.array(_feature_vector_1)-np.array(_feature_vector_2))

class CosineDistance(FeatureVectorDistance):
    name = '余弦距离'
    __version__ = 'v1.0.20210325'

    def execute(self, _feature_vector_1, _feature_vector_2):
        self.feature_vector_check(_feature_vector_1, _feature_vector_2)
        vector_1 = np.array(_feature_vector_1)
        vector_1_norm = np.linalg.norm(vector_1)
        vector_2 = np.array(_feature_vector_2)
        vector_2_norm = np.linalg.norm(vector_2)
        return 1 - (vector_1 @ vector_2.T) / (vector_1_norm * vector_2_norm)

if __name__ == '__main__':
    feature_vector_1 = np.random.uniform(10, 20, (10, ))
    feature_vector_2 = feature_vector_1 + 1
    euclidean_distance_handler = EuclideanDistance(False)
    cosine_distance_handler = CosineDistance(False)
    print(euclidean_distance_handler.execute(feature_vector_1,feature_vector_2))
    print(cosine_distance_handler.execute(feature_vector_1,feature_vector_2))


import scipy.constants as c
from math import factorial as ff
import cmath as math
import numpy as np

# Question 2
def degToRad(deg):
    """
    Convert deg to rad. 5 decimal places output

    :param: deg(float): degrees
    :output: rad(float): radians
    """
    # Convert to float if int
    if type(deg) == int:
        deg = float(deg)

    assert type(deg) == float
    return round(deg * 3.14159265359 / 180, 5)

def radToDeg(rad):
    """
    Convert rad to deg. 5 decimal places output

    :param: rad(float): radians
    :output: deg(float): degrees
    """
    # Convert to float if int
    if type(rad) == int:
        rad = float(rad)

    assert type(rad) == float
    return round(rad * 180 / 3.14159265359, 5)

def sphericalToCartesian(r, theta, phi):
    '''
    convert spherical coord to cartesian coord
    :param r: radius
    :param theta: theta angle
    :param phi: phi angle
    :return: (x, y, z) tuple of floats
    '''
    x = float(r) * np.sin(theta) * np.cos(phi)
    y = float(r) * np.sin(theta) * np.sin(phi)
    z = float(r) * np.cos(theta)

    return round(x, 5), round(y, 5), round(z, 5)

def cartesianToSpherical(x, y, z):
    x = float(x)
    y = float(y)
    z = float(z)
    r = round(np.sqrt(x ** 2 + y ** 2 + z ** 2), 5)
    theta = round(np.arctan2(y, x), 5)
    phi = round(np.arctan2(np.sqrt(x ** 2 + y ** 2), z), 5)

    return r, phi, theta
'''
def p00(theta):
    return 1

def p01(theta):
    return np.cos(theta)

def p02(theta):
    return 0.5*(3*np.cos(theta)**2-1)

def p03(theta):
    return 0.5*(5*np.cos(theta)**3-3*np.cos(theta))

def p11(theta):
    return np.sin(theta)

def p12(theta):
    return 3*np.sin(theta)*np.cos(theta)

def p13(theta):
    return -1.5*np.sin(theta)*(5*np.cos(theta)**2-1)

def p22(theta):
    return 3*np.sin(theta)**2

def p23(theta):
    return 15*np.sin(theta)**2*np.cos(theta)

def p33(theta):
    return -15*np.sin(theta)**3

 def assoc_legendre(m,l):
    if m < 0:
        m = -m
    if m==0 and l==0:
        return p00
    elif m==0 and l==2:
        return p02
    elif m==1 and l==1:
        return p11
    elif m==3 and l==3:
        return p33
    elif m==0 and l==1:
        return p01
    elif m==2 and l==3:
        return p23
    elif m==2 and l==2:
        return p22
    elif m==1 and l==3:
        return p13
    elif m==1 and l==2:
        return p12
    elif m==0 and l==3:
        return p03
    else:
        return None

def l00(x):
    return 1

def l01(x):
    return -x+1

def l02(x):
    return x*x-4*x+2

def l03(x):
    return (-x)**3+9*x**2-18*x+6

def l10(x):
    return 1

def l11(x):
    return -2*x+4

def l12(x):
    return 3*x*x-18*x+18

def l13(x):
    return -4*x*x*x+48*x*x-144*x+96

def l20(x):
    return 2

def l21(x):
    return -6*x+18

def l23(x):
    return -20*x*x*x+300*x*x-1200*x+1200

def l22(x):
    return 12*x*x-96*x+144

def l30(x):
    return 6

def l31(x):
    return -24*x+96

def l32(x):
    return 60*x*x-600*x+1200

def l33(x):
    return -120*(x**3 - 18*x**2 + 90*x - 120)

def assoc_laguerre(p,qmp):
    if p==0 and qmp==0:
        return l00
    elif p==0 and qmp==1:
        return l01
    elif p==0 and qmp==2:
        return l02
    elif p==0 and qmp==3:
        return l03
    elif p==1 and qmp==0:
        return l10
    elif p==1 and qmp==1:
        return l11
    elif p==1 and qmp==2:
        return l12
    elif p==1 and qmp==3:
        return l13
    elif p==2 and qmp==0:
        return l20
    elif p==2 and qmp==1:
        return l21
    elif p==2 and qmp==2:
        return l22
    elif p==2 and qmp==3:
        return l23
    elif p==3 and qmp==0:
        return l30
    elif p==3 and qmp==1:
        return l31
    elif p==3 and qmp==2:
        return l32
    elif p==3 and qmp==3:
        return l33
    else:
        return None
'''

def p00(theta):
    return 1

def p01(theta):
    return np.cos(theta)

def p02(theta):
    return 0.5*(3*np.cos(theta)**2-1)

def p03(theta):
    return 0.5*(5*np.cos(theta)**3-3*np.cos(theta))

def p04(theta):
    return 0.125 * (35 * np.cos(theta) ** 4 - 30 * np.cos(theta) ** 2 + 3)

def p11(theta):
    return np.sin(theta)

def p12(theta):
    return 3*np.sin(theta)*np.cos(theta)

def p13(theta):
    return 1.5*np.sin(theta)*(5*np.cos(theta)**2-1)

def p14(theta):
    return 2.5 * (7 * np.cos(theta) ** 3 - 3 * np.cos(theta)) * np.sin(theta)

def p20(theta):
    return 0.5 * (3 * (np.cos(theta) ** 2) - 1)

def p22(theta):
    return 3*np.sin(theta)**2

def p23(theta):
    return 15*np.sin(theta)**2*np.cos(theta)

def p24(theta):
    return 7.5 * (7 * np.cos(theta) ** 2 - 1) * np.sin(theta) ** 2

def p33(theta):
    return 15*np.sin(theta)*(1-np.cos(theta)**2)

def p34(theta):
    return 105 * np.cos(theta) * np.sin(theta) ** 3

def p43(theta):
    return 105 * np.cos(theta) * np.sin(theta) ** 3

def p44(theta):
    return 105 * np.sin(theta) ** 4

def assoc_legendre(m,l):
    m=abs(m)
    if m==0 and l==0:
        return p00
    elif m==0 and l==1:
        return p01
    elif m==0 and l==2:
        return p02
    elif m==0 and l==3:
        return p03
    elif m==0 and l==4:
        return p04
    elif m==1 and l==1:
        return p11
    elif m==1 and l==2:
        return p12
    elif m==1 and l==3:
        return p13
    elif m==1 and l==4:
        return p14
    elif m==2 and l==0:
        return p20
    elif m==2 and l==2:
        return p22
    elif m==2 and l==3:
        return p23
    elif m==2 and l==4:
        return p24
    elif m==3 and l==3:
        return p33
    elif m==3 and l==4:
        return p34
    elif m==4 and l==3:
        return p43
    elif m==4 and l==4:
        return p44
    else:
        return None

def l00(x):
    return 1

def l01(x):
    return -x+1

def l02(x):
    return x*x-4*x+2

def l03(x):
    return -x*x*x+9*x*x-18*x+6

def l04(x):
    return x ** 4 - 16 * x ** 3 + 72 * x ** 2 - 96 * x +24

def l10(x):
    return 1

def l11(x):
    return -2*x+4

def l12(x):
    return 3*x*x-18*x+18

def l13(x):
    return -4*x*x*x+48*x*x-144*x+96

def l14(x):
    return 5 * x ** 4 - 100 * x ** 3 + 600 * x ** 2 - 1200 * x + 600

def l15(x):
    return -720 * (x - 6)

def l20(x):
    return 2

def l21(x):
    return -6*x+18

def l22(x):
    return 12*x*x-96*x+144

def l23(x):
    return -20*x*x*x+300*x*x-1200*x+1200

def l24(x):
    return 30 * x ** 4 - 720 * x ** 3 + 5400 * x ** 2 - 14400 * x + 10800

def l30(x):
    return 6

def l31(x):
    return -24*x+96

def l32(x):
    return 60*x*x-600*x+1200

def l33(x):
    return -120 * x ** 3 + 2160 * x ** 2 - 10800 * x + 14400

def l34(x):
    return -210 * x ** 4 + 5880 * x ** 3 - 52920 * x ** 2 + 176400 * x - 176400

def l44(x):
    return 1680 * x ** 4 - 53760 * x ** 3 + 564480 * x ** 2 - 2257920 * x + 2822400

def l50(x):
    return 120

def l51(x):
    return -720 * (x - 6)

def l70(x):
    return 5040

def assoc_laguerre(p,qmp):
    if p==0 and qmp==0:
        return l00
    elif p==0 and qmp==1:
        return l01
    elif p==0 and qmp==2:
        return l02
    elif p==0 and qmp==3:
        return l03
    elif p==0 and qmp==4:
        return l04
    elif p==1 and qmp==0:
        return l10
    elif p==1 and qmp==1:
        return l11
    elif p==1 and qmp==2:
        return l12
    elif p==1 and qmp==3:
        return l13
    elif p==1 and qmp==4:
        return l14
    elif p==1 and qmp==5:
        return l15
    elif p==2 and qmp==0:
        return l20
    elif p==2 and qmp==1:
        return l21
    elif p==2 and qmp==2:
        return l22
    elif p==2 and qmp==3:
        return l23
    elif p==2 and qmp==4:
        return l24
    elif p==3 and qmp==0:
        return l30
    elif p==3 and qmp==1:
        return l31
    elif p==3 and qmp==2:
        return l32
    elif p==3 and qmp==3:
        return l33
    elif p==3 and qmp==4:
        return l34
    elif p==4 and qmp==4:
        return l44
    elif p==5 and qmp==0:
        return l50
    elif p==5 and qmp==1:
        return l51
    elif p==7 and qmp==0:
        return l70
    else:
        return None

def angular_wave_func(m,l,theta,phi):
    if m >0:
        eps = (-1)**(m)
    else:
        eps = 1

    a = (2*l + 1)/(4*np.pi)
    cca = np.math.factorial(l-np.absolute(m))
    ccb = np.math.factorial(l+np.absolute(m))
    b = float(cca)/float(ccb)
    sqr = np.sqrt(a*b)
    #print sqr

    expon = np.exp(1j*m*float(phi))
    #print expon

    pfunc = assoc_legendre(m,l)
    y = pfunc(float(theta))

    #print(y)
    final = sqr*expon*y
    final = eps * final.real
    #return complex(round(final.real,5), round(final.imag,5))
    return np.round(final,5)

def complex_angular_wave_func(m,l,theta,phi):
    if m >0:
        eps = (-1)**(m)
    else:
        eps = 1

    a = (2*l + 1)/(4*np.pi)
    cca = np.math.factorial(l-np.absolute(m))
    ccb = np.math.factorial(l+np.absolute(m))
    b = float(cca)/float(ccb)
    sqr = np.sqrt(a*b)
    #print sqr

    expon = np.exp(1j*m*float(phi))
    #print expon

    pfunc = assoc_legendre(m,l)
    y = pfunc(float(theta))

    #print(y)
    final = eps*sqr*expon*y
    return complex(round(final.real,5), round(final.imag,5))

def radial_wave_func2(n,l,r):
    a = c.physical_constants['Bohr radius'][0]
    L = assoc_laguerre(2*l+1,n-l-1)
    C1 = (2.0/(n*a))**3
    C2 = np.math.factorial(n-l-1)/float(2*n*np.math.factorial(n+l)**3)
    root = np.sqrt(C1*C2)
    exp = np.exp(-r/(n*a))
    r2na = r*2/(n*a)
    R = ((root*exp)*(r2na**l)*(L(r2na))) / (a**(-1.5))
    return round(R,5)

def fact(n):
    result=1
    while n>1:
        result*=n
        n-=1
    return result

def radial_wave_func(n,l,r):
    a = c.physical_constants['Bohr radius'][0]
    AA = (2.0 / (n*a))**3
    B = fact(n-l-1)
    Ca = 2.0*n*((fact(n+l))**3)
    BB= float(B)/Ca
    #print BB
    sqre = np.sqrt(AA*BB)
    #print sqre

    expp = np.exp(-float(r)/(n*a))

    Lexp = ((2*float(r))/(n*a))**l

    pfunc = assoc_laguerre(2*l+1, n-l-1)
    y = pfunc(((2*r)/(n*a)))

    return round(sqre*expp*Lexp*y / a**(-3.0/2),5)
'''
a = c.physical_constants["Bohr radius"][0]
print radial_wave_func(1,0,0)
print radial_wave_func(2,1,a) == 0.12381
print radial_wave_func(2,1,2*a) == 0.15019
print radial_wave_func(3,1,2*a) == 0.08281
print radial_wave_func(1,0,3*a) == 0.09957
'''

def hydrogen_wave_func(n, l, m, roa, Nx, Ny, Nz):
    # To find overall wavefunction
    # psi = Y(angle?,angle?) * R(y)

    #if m! = 0 real wave function is a linear combinaton of two stationary states

    a = c.physical_constants['Bohr radius'][0]

    # need to make the grid first
    X = np.linspace(-roa,roa,Nx)
    Y = np.linspace(-roa,roa,Ny)
    Z =  np.linspace(-roa,roa,Nz)

    xx,yy,zz = np.meshgrid(X,Y,Z)

    # convert the grid into spherical coordinate
    CTOS = np.vectorize(cartesianToSpherical)
    r, t, p = CTOS(xx,yy,zz)

    rr = r * a

    Rad = np.vectorize(radial_wave_func)
    Ang = np.vectorize(angular_wave_func)
    cAng = np.vectorize(complex_angular_wave_func)

    if m == 0:
        mag = Rad(n,l,rr)* Ang(m,l,t,p)
        absmag = np.absolute(mag)**2

    # return the x,y,z values and magnitude

    elif m > 0:
        ang = cAng(m,l,t,p) - cAng(-m,l,t,p)
        comb = (1/np.sqrt(2))*(Rad(n,l,rr)*ang)
        if m == 2:
            absmag = np.absolute(comb)**2
        else:
            absmag = np.absolute(comb.real)**2

    elif m < 0:
        ang = cAng(m,l,t,p) + cAng(-m,l,t,p)
        comb = (1/(1j*np.sqrt(2)))*(Rad(n,l,rr)*ang)
        absmag = np.absolute(comb.real)**2
        if m == -2:
            absmag = np.absolute(comb)**2
        else:
            absmag = np.absolute(comb.real)**2

    return np.round(xx,5), np.round(yy,5), np.round(zz,5), np.round(absmag,5)

if __name__ == "__main__":
    print angular_wave_func(1,1,np.pi-0.2,0.12411)

    '''
    x,y ,z, mag = hydrogen_wave_func(4,3,3,3,5,4,3)
    print "x,y,z"
    print x,y,z
    print
    print "mag"
    print mag
    '''


import numpy as np
import matplotlib.pyplot as plt

def generate_water_stats():
    cov  = np.array([[1.2, 1], [1, 1]])
    mean = np.array([3.2, 3.5])

    values = np.random.multivariate_normal(mean=mean, cov=cov, size=100)

    return values[:, 0]*5, values[:, 1]

def plot_stats_without_lobf(x, y):
    plt.scatter(x, y)
    plt.title("Fake water consumption study")
    plt.xlabel("Temperature in °C")
    plt.ylabel("Liters of water")
    plt.show()

def plot_stats_with_lobf(x, y, a, b):
    lobf = a*x + b
    plt.scatter(x, y)
    plt.plot(x, lobf)
    plt.title("Fake water consumption study with line of best fit")
    plt.xlabel("Temperature in °C")
    plt.ylabel("Liters of water")
    plt.show()

def calculate_lobf(x, y):
    denom = x.mean() * x.sum() - x.dot(x)

    a = (x.sum() * y.mean() - x.dot(y)) / denom
    b = (x.dot(y) * x.mean() - y.mean() * x.dot(x)) / denom

    return a, b

x, y = generate_water_stats()
plot_stats_without_lobf(x, y)
a, b = calculate_lobf(x, y)
plot_stats_with_lobf(x, y, a, b)

print(f"Line of best fit: y = {a:.2f}*x + {b:.2f}")


# coding: utf-8
# Author: Zhejian Peng
# Brute Force: double for loop inversion, find the Max. number of Inversion

def inversion(array):
    counter = 0
    for i in range(len(array)):
        temp = array[i+1:]
        for j in temp:
            if array[i] > j:
                counter += 1
    return counter

# recursive method, in O(NlogN)

def merge_and_count(a, b):
    c = []
    counter = 0
    while len(a) != 0 and len(b) != 0:
        if a[0] < b[0]:
            c.append(a[0])
            a.remove(a[0])
        else:
            counter += len(a)
            c.append(b[0])
            b.remove(b[0])
    if len(a) == 0:
        c += b
    else:
        c += a
        # print(a)
    return c, counter

def fast_inversion(array):
    if len(array) <= 1:
        return array, 0
    else:
        n = len(array)
        half_point = n // 2
        # print(half_point)
        # print(array[0:half_point])
        b, x = fast_inversion(array[:half_point])
        c, y = fast_inversion(array[half_point:])
        d, z = merge_and_count(b, c)
    return d, x+y+z

# Define Test Case:
test0 = [1, 2, 4, 6, 5]
a, b = fast_inversion(test0)
print('test 0', b)

test1 = [1, 3, 5, 2, 4, 6]
a, b = fast_inversion(test1)
print('test 1', b)
assert(b == 3)

test2 = [1, 5, 3, 2, 4]
a, b = fast_inversion(test2)
print('test 2', b)
assert(b == 4)

test3 = [5, 4, 3, 2, 1]
a, b = fast_inversion(test3)
print('test 3', b)
assert(b == 10)

test4 = [9, 12, 3, 1, 6, 8, 2, 5, 14, 13, 11, 7, 10, 4, 0]
a, b = fast_inversion(test4)
print('test 4', b)
assert(b == 56)

test5 = [4, 80, 70, 23, 9, 60, 68, 27, 66, 78, 12, 40, 52, 53, 44, 8, 49, 28, 18, 46, 21, 39, 51, 7, 87, 99, 69, 62, 84, 6, 79, 67, 14, 98, 83, 0, 96, 5, 82, 10, 26, 48, 3, 2, 15, 92, 11, 55, 63, 97,
         43, 45, 81, 42, 95, 20, 25, 74, 24, 72, 91, 35, 86, 19, 75, 58, 71, 47, 76, 59, 64, 93, 17, 50, 56, 94, 90, 89, 32, 37, 34, 65, 1, 73, 41, 36, 57, 77, 30, 22, 13, 29, 38, 16, 88, 61, 31, 85, 33, 54]
a, b = fast_inversion(test5)
print('test 5', b)
assert(b == 2372)
# Define test case to test speed
# import numpy as np
# test_array = np.linspace(0, 10000, 10000)
# np.random.shuffle(test_array)
# test_array = list(test_array)

# # PA2
text_file = open("input_dgrcode_66_100000.txt")
pa2 = text_file.read().split()
print(len(pa2))
temp, result = fast_inversion(pa2)
print('PA2 result:', result)
print(all(temp[i] <= temp[i+1] for i in range(len(temp)-1))
      )
# assert(result == 2507917401)

xarray = [7, 6, 5, 4, 3]
count = 0

def InversionsCount(x):
    global count
    midsection = int(len(x) / 2)
    leftArray = x[:midsection]
    rightArray = x[midsection:]
    if len(x) > 1:
        InversionsCount(leftArray)
        InversionsCount(rightArray)
        i, j = 0, 0
        a = leftArray
        b = rightArray
        for k in range(len(a) + len(b) + 1):
            if a[i] <= b[j]:
                x[k] = a[i]
                i += 1
                if i == len(a) and j != len(b):
                    while j != len(b):
                        k += 1
                        x[k] = b[j]
                        j += 1
                    break
            elif a[i] > b[j]:
                x[k] = b[j]
                count += (len(a) - i)
                j += 1
                if j == len(b) and i != len(a):
                    while i != len(a):
                        k += 1
                        x[k] = a[i]
                        i += 1
                    break

InversionsCount(pa2)
print(count)


import random
import time
import numpy as np

# Time complexity = O(logn)
def binary_search(sorted_arr: np.ndarray, ele_to_search) -> int or None:
    len_arr = len(sorted_arr)
    if len_arr == 1:
        if sorted_arr[0] == ele_to_search:
            return 0
        else:
            return None
    else:
        # Split array in half
        len_left = len_arr//2
        left_arr, right_arr = sorted_arr[:len_left], sorted_arr[len_left:]

        if ele_to_search > left_arr[-1]:
            relative_idx = binary_search(right_arr, ele_to_search)
            if relative_idx is None:
                return None
            else:
                return len_left + relative_idx
        else:
            return binary_search(left_arr, ele_to_search)

if __name__ == "__main__":
    array_length = int(1e7)
    sorted_array = np.sort(np.round(np.random.rand(array_length), decimals=7))
    random_idx = random.randint(0, array_length)
    element_to_search = sorted_array[random_idx]
    print(f"Searching element {element_to_search}, index {random_idx} of the original sorted array.")

    start = time.time()
    idx = binary_search(sorted_array, element_to_search)
    print(f"Time = {time.time() - start}s")
    print(f"Result: {idx}")
    print(f"Correct result: {sorted_array[idx] == element_to_search if idx else element_to_search not in sorted_array}")


import numpy as np

from uutils.torch_uu.metrics.cca.cca_core import get_cca_similarity

def svcca_with_keeping_fixed_dims(x: np.ndarray, y: np.ndarray, dims_to_keep: int,
                                  epsilon: float = 1e-10, verbose: bool = False,
                                  full_matrices: bool = False, keepdims: bool = True, axis: int = 1):
    """
    Computes CCA statistics after doing the SV step from SVCCA.
    Incoming data is of shape [D1, N], [D2, N].
    To get svcca similirty do see note.

    Alg:
      - preprocessing:
        - 1) center the incoming raw data
        - 2) SV of centered incoming raw data
        - 3) then cca_core (which does not center but divides by max of incoming data, which due to 2 is centered.)

    Note:
      - To compute svcca distance do: svcca: float = np.mean(svcca_baseline["cca_coef1"])
      - Input data is assumed to be of size [D, N] to make it consistent with the original tutorial: https://github.com/google/svcca/blob/master/tutorials/001_Introduction.ipynb
      - Centering code does not make a difference because get_cc_similarity uses np.cov and cov(x,y) = E[(x-mu_x)(y-mu_y)]
      so it's already centering. But to my surprise giving the SV part non-centered data doesn't make a difference but
      I would have expected a difference.
    """
    # Mean subtract baseline activations
    # cx = center(x, axis=axis, keepdims=keepdims)
    # cy = center(y, axis=axis, keepdims=keepdims)
    cx = x
    cy = y

    # Perform SVD
    Ux, sx, Vx = np.linalg.svd(cx, full_matrices=full_matrices)
    Uy, sy, Vy = np.linalg.svd(cy, full_matrices=full_matrices)

    svx = np.dot(sx[:dims_to_keep] * np.eye(dims_to_keep), Vx[:dims_to_keep])
    svy = np.dot(sy[:dims_to_keep] * np.eye(dims_to_keep), Vy[:dims_to_keep])

    # Recenter after SVD since CCA assumes incoming stuff is centered - this is something I added myself to match
    # ultimate anatome's code but it doesn't seem to make a difference.
    # svx = center(svx, axis=axis, keepdims=keepdims)
    # svy = center(svy, axis=axis, keepdims=keepdims)

    svcca_baseline = get_cca_similarity(svx, svy, epsilon=epsilon, verbose=verbose)
    # print("Baseline", np.mean(svcca_baseline["cca_coef1"]), "and MNIST", np.mean(svcca_results["cca_coef1"]))
    svcca: float = np.mean(svcca_baseline["cca_coef1"])
    if verbose:
        print("SVCCA:", svcca)
    return svcca_baseline

def center(x: np.ndarray, axis: int = 1, keepdims=True):
    """
    Centers data assuming data is of shape [D, N].
    """
    cx = x - np.mean(x, axis=axis, keepdims=keepdims)
    return cx


import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import warnings
warnings.filterwarnings("ignore")
import yfinance as yf
yf.pdr_override()
import datetime as dt
import scipy.stats as  scs

# input
symbol = 'AMD'
market = 'SPY'
start = dt.date.today() - dt.timedelta(days = 365*5)
end = dt.date.today()

# Read data
dataset = yf.download(symbol,start,end)

# Create more data
dataset['Increase_Decrease'] = np.where(dataset['Volume'].shift(-1) > dataset['Volume'],1,-1)
dataset['Buy_Sell_on_Open'] = np.where(dataset['Open'].shift(-1) > dataset['Open'],1,-1)
dataset['Buy_Sell'] = np.where(dataset['Adj Close'].shift(-1) > dataset['Adj Close'],1,-1)
dataset['Returns'] = dataset['Adj Close'].pct_change()
dataset = dataset.dropna()
dataset.head()

# ## Measuring Central Tendency
print("Mean Values in the Distribution")
print("-"*35)
print(dataset.mean())
print("***********************************")
print("Median Values in the Distribution")
print("-"*35)
print(dataset.median())

print("Mode Value")
print(dataset.mode())

# ## Measuring Variance
# Measuring Standard Deviation
print("Measuring Standard Deviation")
print(dataset.std())

# Measuring Skewness
print("Measuring Skewness")
print(dataset.skew())

# ## Normal Distribution
import math

# Define Variables
mu = dataset['Returns'].mean() # Mean Returns
sigma = dataset['Returns'].std() # Volatility

[n,bins,patches] = plt.hist(dataset['Returns'], 100)
# Daily returns using normal distribution
s = scs.norm.pdf(bins, mu, sigma)
# Create the bins and histogram
plt.plot(bins, s, color='y', lw=2)
plt.title("Stock Returns on Normal Distribution")
plt.xlabel("Returns")
plt.ylabel("Frequency")
plt.show()

from scipy.stats import norm

mu = dataset['Returns'].mean()
sigma = dataset['Returns'].std()

x_min = dataset['Returns'].min()
x_max = dataset['Returns'].max()

def plot_normal(x_range, mu=0, sigma=1, cdf=False, **kwargs):
    x = x_range
    if cdf:
        y = norm.cdf(x, mu, sigma)
    else:
        y = norm.pdf(x, mu, sigma)
    plt.plot(x, y, **kwargs)

x = np.linspace(x_min, x_max, 100)
plot_normal(x)
plot_normal(x, cdf=True)

plot_normal(x, -2, 1, color='red', lw=2, ls='-', alpha=0.5)
plot_normal(x, 2, 1.2, color='blue', lw=2, ls='-', alpha=0.5)
plot_normal(x, 0, 0.8, color='green', lw=2, ls='-', alpha=0.5)

mu, std = norm.fit(dataset['Returns'])

# Plot the histogram.
plt.hist(dataset['Returns'], bins=25, alpha=0.6, color='g')

# Plot the PDF.
xmin, xmax = plt.xlim()
x = np.linspace(xmin, xmax, 100)
p = norm.pdf(x, mu, std)
plt.plot(x, p, 'k', linewidth=2)
title = "Fit results: mu = %.2f,  std = %.2f" % (mu, std)
plt.title(title)

plt.show()

# # Gamma Distribution
from scipy import stats

# Read data
dataset1 = yf.download(symbol,start,end)
dataset2 = yf.download(market,start,end)

stock_ret = dataset1['Adj Close'].pct_change().dropna()
mkt_ret = dataset2['Adj Close'].pct_change().dropna()

beta, alpha, r_value, p_value, std_err = stats.linregress(mkt_ret, stock_ret)
print(beta, alpha)

from scipy.stats import gamma
mu, std = gamma.stats(dataset['Returns'])

# Plot the histogram.
plt.hist(dataset['Returns'], bins=25, alpha=0.6, color='g')

# Plot the PDF.
xmin, xmax = plt.xlim()
x = np.linspace(xmin, xmax, 1171)
p = gamma.pdf(x, alpha, scale=1/beta)
plt.plot(x, p, 'k', linewidth=2)
plt.title("Gamma Distribution for Stock")

plt.show()

# ## Binomial Distribution
from scipy.stats import binom

n = 10 # number of trials
p = 0.5 # probaility of success and failure
k = np.arange(0,21) # * number of repeat the trial
binomial = binom.pmf(k, n, p)
binomial

data_binom = binom.rvs(n=len(dataset['Adj Close']),p=0.5,size=1000)

plt.figure(figsize=(16,10))
ax = sns.distplot(data_binom,
                  kde=False,
                  color='skyblue',
                  hist_kws={"linewidth": 15,'alpha':1})
ax.set(xlabel='Binomial Distribution', ylabel='Frequency')

# ## Poisson Distribution
from scipy.stats import poisson

mu = dataset['Returns'].mean()
dist = poisson.rvs(mu=mu, loc=0, size=1000)
print("Mean: %g" % np.mean(dataset['Returns']))
print("SD: %g" % np.std(dataset['Returns'], ddof=1))

plt.hist(dist, bins=10, density=True)
#plt.xlabel()
plt.title('Poisson Distribution Curve')
plt.show()

# ## Bernoulli Distribution
from scipy.stats import bernoulli

countIncrease = dataset[dataset.Increase_Decrease == 1].Increase_Decrease.count()
countAll = dataset.Increase_Decrease.count()

Increase_dist = bernoulli(countIncrease / countAll)
# the given value is the probability of outcome 1 (increase) (let's call it p). # The probability of the opposite outcome (0 - decrease) is 1 - p.

_, ax = plt.subplots(1, 1)
ax.vlines(0, 0, Increase_dist.pmf(0), colors='r', linestyles='-', lw=5, label="probability of decrease")
ax.vlines(1, 0, Increase_dist.pmf(1), colors='b', linestyles='-', lw=5, label="probability of increase")
ax.legend(loc='best', frameon=False)
plt.title("Bernoulli distribution of increase variable")
plt.show()

# ## Exponential Distribution
from scipy.stats import expon

mu = dataset['Returns'].mean()
sigma = dataset['Returns'].std()

x_m = dataset['Returns'].max()

def plot_exponential(x_range, mu=0, sigma=1, cdf=False, **kwargs):
    if cdf:
        y = expon.cdf(x, mu, sigma)
    else:
        y = expon.pdf(x, mu, sigma)
    plt.plot(x, y, **kwargs)

x = np.linspace(0, x_m, 5000)
plot_exponential(x, 0, 1, color='red', lw=2, ls='-', alpha=0.5, label='pdf')
plot_exponential(x, 0, 1, cdf=True, color='blue', lw=2, ls='-', alpha=0.5, label='cdf')
plt.xlabel('Adj Close')
plt.ylabel('Probability')
plt.legend(loc='best')
plt.show()

# # Discrete random variable
from scipy.stats import rv_discrete

increase_probability = pd.DataFrame({'probability': dataset.groupby(by = "Increase_Decrease", as_index=False).size() / dataset.Increase_Decrease.count()}).reset_index()

values = increase_probability.Increase_Decrease
probabilities = increase_probability.probability
custom_discrete_dist = rv_discrete(values=(values, probabilities))

x = dataset['Returns']

_, ax = plt.subplots(1, 1)
ax.plot(x, custom_discrete_dist.pmf(x), 'ro', lw=2)
plt.title('Custom discrete distribution of values between 0 and 4')
plt.show()

# ## P-Value
from scipy import stats

# Read data
dataset1 = yf.download(symbol,start,end)
dataset2 = yf.download(market,start,end)

stock_ret = dataset1['Adj Close'].pct_change().dropna()
mkt_ret = dataset2['Adj Close'].pct_change().dropna()

beta, alpha, r_value, p_value, std_err = stats.linregress(mkt_ret, stock_ret)
print(beta, alpha)
print("R-squared=", r_value**2)
print("p-value =", p_value)

if p_value < alpha:  # null hypothesis: x comes from a normal distribution
    print("The null hypothesis can be rejected")
else:
    print("The null hypothesis cannot be rejected")

# ## Correlation
sns.pairplot(dataset, kind="scatter")
plt.show()

# # Chi-square Test
from scipy import stats

x = dataset['Adj Close']
fig,ax = plt.subplots(1,1)

linestyles = [':', '--', '-.', '-']
deg_of_freedom = [1, 4, 7, 6]
for df, ls in zip(deg_of_freedom, linestyles):
  ax.plot(x, stats.chi2.pdf(x, df), linestyle=ls)

plt.xlim(0, 10)
plt.ylim(0, 0.4)

plt.xlabel('Value')
plt.ylabel('Frequency')
plt.title('Chi-Square Distribution')

plt.legend()
plt.show()

# ## Linear Regression
sns.regplot(x = "Adj Close", y = "Open", data = dataset)
plt.show()


"""!
\brief Statistical functionals module for computing the latter from a
given numpy matrix.

@author Efthymios Tzinis {etzinis@gmail.com}
@copyright National Technical University of Athens
"""

import numpy as np
from scipy.stats import kurtosis
from scipy.stats import skew

def compute(features_block):
    """!
    \brief Computes a predefined set of statistical functionals
    for the features_block given.
    \details The selected 18 functionals are self explanatory from the
    code

    \param features_block (\a numpy 2D array) 2D numpy block which
    represents the raw features over time that we want to extract
    stats from. (n_samples, n_features)

    \warning Caller function is responsible for checking the validity
    of both parameters.

    \returns \b np_feat_stats (\a numpy array) Statistics for the
    given feat_col in a 1D array of shape: (18*n_features,) """

    (n_samples, n_features) = features_block.shape
    stats_list = []

    stats_list.append(np.mean(features_block, axis=0))
    stats_list.append(np.var(features_block, axis=0))
    stats_list.append(kurtosis(features_block, axis=0))
    stats_list.append(skew(features_block, axis=0))
    stats_list.append( np.median(features_block, axis=0))

    sorted_block = np.sort(features_block, axis=0)

    stats_list.append(sorted_block[0, :])
    stats_list.append(sorted_block[-1, :])

    selected_perc = [x/100.0 for x in [1,5,25,50,75,95,99]]
    for p in selected_perc:
        perc = sorted_block[int(p*n_samples)]
        stats_list.append(perc)

    ranges = [(big/100.0, small/100.0)
               for (big, small) in
               [(99, 1), (75, 25), (50, 25), (75, 50)]]

    for (big, small) in ranges:
        iqr = sorted_block[int(big*n_samples)] - sorted_block[int(
            small*n_samples)]
        stats_list.append(iqr)

    return np.concatenate(stats_list, axis=0)

def sanity_test():
    n_frames = 3
    n_features = 2
    list_of_features = [np.random.normal(0., 1., n_frames)
                        for x in np.arange(n_features)]

    dummy_block = np.transpose(np.array(list_of_features))

    stats = compute(dummy_block)
    print stats.shape

if __name__ == "__main__":
    sanity_test()


import os
os.system('cls')
# reference: https://web.stanford.edu/class/cs231a/section/section1.pdf
# Lists
empty_list = list()
also_empty_list = []
zeros_list = [0]*5
print(zeros_list)
number_list = [16]*5
print(number_list)

print(empty_list)
empty_list.append(1)
print(empty_list)
print(len(empty_list))

# List indexing
list_var = range(10)
print(list_var)
print(list_var[4])
print(list_var[4:7])
print(list_var[0::3])

print(list_var)
print(list_var[-1])
print(list_var[::-1])
print(list_var[3:1:-1])

# Dictionaries
empty_dict = dict()
also_empty_dict = {}
filled_dict = {3:'Hello,',4:'World!'}
print(filled_dict)
print(filled_dict[3]+filled_dict[4])

filled_dict[5]=' Me '
filled_dict[6]='machine'
print(filled_dict)
print(filled_dict[3]+filled_dict[4]+filled_dict[5]+filled_dict[6])

del filled_dict[3]
print(filled_dict)
print(len(filled_dict))
print("")

# Functions
def add_numbers(a,b):
    return a+b

print(add_numbers(2,3))

lambda_add_number = lambda a,b: a+b
print(lambda_add_number(4,6))

# Loops, List and Dictionary Comprehensions
for i in range(10):
    print('Looping %d' % i)

filled_list=[a/2 for a in range(10)]
print(filled_list)
filled_dict={a:a**2 for a in range(5)}
print(filled_dict)

# Matrices and vectors
print("# Matrices and vectors")
print("")

import numpy as np

M=np.array([[1,2,3],
           [4,5,6],
           [7,8,9]])

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

print(M.shape)
print(v.shape)

v_single_dim = np.array([1,2,3])
print(v_single_dim.shape)

print(v+v)
print(" ")
print(3*v)
print(" ")

# other ways of creating matrices and vectors

a=np.zeros((2,2)) # 2x2 zero matrix
print(a)
print("")

b=np.ones((1,2))  # 1X2 unit matrix
print(b)
print("")

c=np.full((2,2),7)# 2x2 matrix filled with 7
print(c)
print("")

d=np.eye(2)       # 2x2 identity matrix
print(d)
print("")

e=np.random.random((2,2)) #2x2 matrix of random numbers
print(e)
print("")

v1=np.array([1,2,3])
v2=np.array([4,5,6])
v3=np.array([7,8,9])
M=np.vstack([v1,v2,v3])
print(M)
print("")
c1=np.array([[1],
             [2],
             [3]])
c2=np.array([[4],
             [5],
             [6]])
c3=np.array([[7],
             [8],
             [9]])
N=np.hstack([c1,c2,c3])
print(N)
print("")

# Matrix indexing
print("# Matrix indexing")
print("")

print(M[:2,1:3])
print("")
print(N[0,2])

# M Template
# __            __
# | [  ,   ,   ] |
# | [  ,   ,   ] |
# | [  ,   ,   ] |
# | [  ,   ,   ] |
# --            --
c1=np.array([[],
             [],
             []])

# Dot product of matrices and vectors
print("# Dot product of matrices and vectors")
print("")

c1=np.array([[3],
             [2],
             [0]])
c2=np.array([[0],
             [0],
             [1]])
c3=np.array([[2],
             [-2],
             [1]])

M=np.hstack([c1,c2,c3])
v=np.array([[1],
            [2],
            [3]])
print(M)
print(v)
print("")

print(M.dot(v))  # Dot product
print("")
print(v.T.dot(v))
print("")

# Cross product of matrices and vectors
print("# Cross product of matrices and vectors")
print("")

v1=np.array([[3],
             [-3],
             [1]])
v2=np.array([[4],
             [9],
             [2]])

print(np.cross(v1,v2,axisa=0,axisb=0).T) # Slightly convoluted because np.cross() assumes
print("")

# Element wise multiplication
print("# Element wise multiplication")
print("")

print(M)
print("")
print(v)
print("")
print(np.multiply(M,v))
print("")
print(np.multiply(v,v))
print("")

# Transpose of a matrix
print("# Transpose of a matrix")
print("")

print(M.T)
print("")
print(v.T)
print("")
print(M.shape)
print(M.T.shape)
print("")
print(v.shape)
print(v.T.shape)
print("")

# Determinant of a matrix
print("# Determinant of a matrix")
print("")

print(np.linalg.det(M))
print("")

# Inverse of a matrix
print("# Inverse of a matrix")
print("")

print(np.linalg.inv(M))
print("")

# Eigenvalues and eigenvectors of a matrix
print("# Eigenvalues and eigenvectors of a matrix")
print("")

c1=np.array([[0],
             [-2]])

c2=np.array([[1],
             [-3]])
M=np.hstack([c1,c2])
print("Matrix")
print(M)
print("")

eigvals,eigvecs = np.linalg.eig(M)
print("Eigenvalues")
print(eigvals)
print("")
print("Eigenvectors")
print(eigvecs)
print("")

# Singular Value Decomposition
print("# Singular Value Decomposition")
print("")

c1=np.array([[3],
             [2],
             [0]])
c2=np.array([[0],
             [0],
             [1]])
c3=np.array([[2],
             [-2],
             [1]])

M=np.hstack([c1,c2,c3])
print("Matrix")
print(M)
print("")
U,S,Vtranspose = np.linalg.svd(M)
print("U")
print(U)
print("")
print("S")
print(S)
print("")
print("Vtranspose")
print(Vtranspose)
print("")


"""
worley
~~~~~~

Image data sources that create Worley noise.
"""
from typing import Sequence

import numpy as np

from imggen.noise import Seed, Noise

# Public classes.
class Worley(Noise):
    """Fill a space with Worley noise.

    Worley noise is a type of cellular noise. The color value of each
    pixel within the space is determined by the distance from the pixel
    to the nearest of a set of randomly located points within the
    image. This creates structures within the noise that look like
    cells or pits.

    This implementation is heavily optimized from code found here:
    https://code.activestate.com/recipes/578459-worley-noise-generator/

    :param points: The number of cells in the image. A cell is a
        randomly placed point and the range of pixels that are
        closer to it than any other point.
    :param volume: (Optional.) The size of the volume that the points
        will be placed in. The default is for them to be evenly spread
        through the space generated during the fill.
    :param origin: (Optional.) The location of the upper-top-left
        corner of the volume that contains the points. This defaults
        to the upper-top-left corner of the space generated during the
        fill.
    :param seed: (Optional.) An int, bytes, or string used to seed
        therandom number generator used to generate the image data.
        If no value is passed, the RNG will not be seeded, so
        serialized versions of this source will not product the
        same values. Note: strings that are passed to seed will
        be converted to UTF-8 bytes before being converted to
        integers for seeding.
    :return: :class:Worley object.
    :rtype: imggen.worley.Worley
    """
    def __init__(self, points: int,
                 volume: Sequence[int] = None,
                 origin: Sequence[int] = (0, 0, 0),
                 seed: Seed = None) -> None:
        self.points = points
        self.volume = volume
        self.origin = origin
        super().__init__(seed)

    def fill(self, size: Sequence[int],
             loc: Sequence[int] = (0, 0, 0)) -> np.ndarray:
        """Return a space filled with noise."""
        a = np.zeros(size, dtype=float)
        volume_size = self.volume
        if volume_size is None:
            volume_size = size
        volume = np.array(volume_size)

        # Place the seeds in the overall volume of noise.
        seeds = self._rng.random((self.points, 3))
        seeds = np.round(seeds * (volume - 1))
        seeds += np.array(self.origin)

        # Map the distances to the points.
        indices = np.indices(size)
        max_dist = np.sqrt(sum(n ** 2 for n in size))
        dist = np.zeros(size, dtype=float)
        dist.fill(max_dist)
        for i in range(self.points):
            point = seeds[i]
            work = self._hypot(point, indices)
            dist[work < dist] = work[work < dist]

        act_max_dist = np.max(dist)
        a = dist / act_max_dist
        return a

    # Private methods.
    def _hypot(self, point: Sequence[int], indices: np.ndarray) -> np.ndarray:
        axis_dist = [p - i for p, i in zip(point, indices)]
        return np.sqrt(sum(d ** 2 for d in axis_dist))


import numpy as np

def MultiForEachInd(arr):
    new_arr = np.ones((len(arr), 1))
    np.array(arr)
    k = len(arr)
    for i in range(k):
        for j in range(k):
            if j != i:
                new_arr[j] *= arr[i]
    return new_arr

#Solution with products of numbers before the i'th index and after i'th index

def products(arr):
    #Generate prefix products
    prefix_products = []

    for num in arr:
        if prefix_products:
            prefix_products.append(prefix_products[-1] * num)
        else:
            prefix_products.append(num)

    #Generate Sufix products

    suffix_products = []
    for num in reversed(arr):
        if suffix_products:
            suffix_products.append(suffix_products[-1] * num)
        else:
            suffix_products.append(num)

    suffix_products = list(reversed(suffix_products))

    #Generate result

    result = []
    for i in range(len(arr)):
        if i == 0:
            result.append(suffix_products[i+1])
        elif i == len(arr) - 1:
            result.append(prefix_products[i-1])
        else:
            result.append(prefix_products[i-1] * suffix_products[i+1])
    return result

    #Works only for arrays without 0
def vectorized_products(array):
    arr_a = np.array(array)
    arr_b = np.ones(len(array))
    arr_b /= arr_a
    arr_b *= np.prod(arr_a)
    return arr_b

    #Speed comparision between implementations
    test_array = [1,2,3,4,5,6,7]
    %timeit products(test_array)
    %timeit MultiForEachInd(test_array)


import numpy as np
import cPickle

def one_hot(y, nb_classes=None):
    N = len(y)
    y = np.asarray(y, dtype='int32')
    if len(y.shape) > 1:
        y = y.flatten()
    if nb_classes is None:
        nb_classes = 1 + np.max(y)
    Y = np.zeros((N,nb_classes))
    Y[np.arange(N),y] = 1.
    return Y

def np_softmax(X):
    """
    numpy version of softmax
    X: np.array, nb_samples * nb_features
    """
    e_x = np.exp(X - X.max(axis=1,keepdims=True))
    out = e_x / e_x.sum(axis=1, keepdims=True)
    return out

def DataIterator(fn_list,batch_size):
    for fn in fn_list:
        with open(fn,'rb') as f:
            [X,y] = cPickle.load(f)
        N = len(X)
        for start, end in zip(range(0,N,batch_size), range(batch_size,N,batch_size)):
            yield X[start:end], y[start:end]