import matplotlib
import matplotlib.pyplot as plt
import mnist
import numpy as np

# Gradient descent optimization
# The learning rate is specified by eta
class GDOptimizer(object):
    def __init__(self, eta):
        self.eta = eta

    def initialize(self, layers):
        pass

    # This function performs one gradient descent step
    # layers is a list of dense layers in the network
    # g is a list of gradients going into each layer before the nonlinear activation
    # a is a list of outputs from previous layer
    def update(self, layers, g, a):
        m = a[0].shape[1]
        for layer, curGrad, curA in zip(layers, g, a):
            # TODO: PART E ###############################################################
            # PART E #####################################################################
            layer.W -= self.eta * np.dot(curGrad, curA.T) / m
            layer.b -= self.eta * np.mean(curGrad, axis=1).reshape((-1,1))

# Cost function used to compute prediction errors
class QuadraticCost(object):

    # Compute the squared error between the prediction yp and the observation y
    # This method should compute the cost per element such that the output is the
    # same shape as y and yp
    @staticmethod
    def fx(y,yp):
        # TODO: PART B ###################################################################
        # PART B #########################################################################
        return np.square(np.subtract(y,yp)) / 2.0

    # Derivative of the cost function with respect to yp
    @staticmethod
    def dx(y,yp):
        # TODO: PART B ###################################################################
        # PART B #########################################################################
        return np.subtract(yp,y)

# Sigmoid function fully implemented as an example
class SigmoidActivation(object):
    @staticmethod
    def fx(z):
        # PART C Example #################################################################
        return 1 / (1 + np.exp(-z))
        # PART C #########################################################################

    @staticmethod
    def dx(z):
        # PART C Example #################################################################
        # PART C #########################################################################
        return np.multiply(fx(z), 1-fx(z))

# Hyperbolic tangent function
class TanhActivation(object):

    # Compute tanh for each element in the input z
    @staticmethod
    def fx(z):
        # TODO: PART C ###################################################################
        # PART C #########################################################################
        return np.tanh(z)

    # Compute the derivative of the tanh function with respect to z
    @staticmethod
    def dx(z):
        # TODO: PART C ###################################################################
        # PART C #########################################################################
        return 1 - np.square(np.tanh(z))

# Rectified linear unit
class ReLUActivation(object):
    @staticmethod
    def fx(z):
        # TODO: PART C ###################################################################
        # PART C #########################################################################
        return z * (z>0)

    @staticmethod
    def dx(z):
        # TODO: PART C ###################################################################
        # PART C #########################################################################
        return z > 0

# Linear activation
class LinearActivation(object):
    @staticmethod
    def fx(z):
        # TODO: PART C ###################################################################
        # PART C #########################################################################
        return z

    @staticmethod
    def dx(z):
        # TODO: PART C ###################################################################
        # PART C #########################################################################
        return np.ones(z.shape)

# This class represents a single hidden or output layer in the neural network
class DenseLayer(object):

    # numNodes: number of hidden units in the layer
    # activation: the activation function to use in this layer
    def __init__(self, numNodes, activation):
        self.numNodes = numNodes
        self.activation = activation

    def getNumNodes(self):
        return self.numNodes

    # Initialize the weight matrix of this layer based on the size of the matrix W
    def initialize(self, fanIn, scale=1.0):
        s = scale * np.sqrt(6.0 / (self.numNodes + fanIn))
        self.W = np.random.normal(0, s, (self.numNodes,fanIn))
        self.b = np.random.uniform(-1, 1, (self.numNodes,1))

    # Apply the activation function of the layer on the input z
    def a(self, z):
        return self.activation.fx(z)

    # Compute the linear part of the layer
    # The input a is an n x k matrix where n is the number of samples
    # and k is the dimension of the previous layer (or the input to the network)
    def z(self, a):
        return self.W.dot(a) + self.b # Note, this is implemented where we assume a is k x n

    # Compute the derivative of the layer's activation function with respect to z
    # where z is the output of the above function.
    # This derivative does not contain the derivative of the matrix multiplication
    # in the layer.  That part is computed below in the model class.
    def dx(self, z):
        return self.activation.dx(z)

    # Update the weights of the layer by adding dW to the weights
    def updateWeights(self, dW):
        self.W = self.W - dW

    # Update the bias of the layer by adding db to the bias
    def updateBias(self, db):
        self.b = self.b - db

# This class handles stacking layers together to form the completed neural network
class Model(object):

    # inputSize: the dimension of the inputs that go into the network
    def __init__(self, inputSize):
        self.layers = []
        self.inputSize = inputSize

    # Add a layer to the end of the network
    def addLayer(self, layer):
        self.layers.append(layer)

    # Get the output size of the layer at the given index
    def getLayerSize(self, index):
        if index >= len(self.layers):
            return self.layers[-1].getNumNodes()
        elif index < 0:
            return self.inputSize
        else:
            return self.layers[index].getNumNodes()

    # Initialize the weights of all of the layers in the network and set the cost
    # function to use for optimization
    def initialize(self, cost, initializeLayers=True):
        self.cost = cost
        if initializeLayers:
            for i in range(0,len(self.layers)):
                if i == len(self.layers) - 1:
                    self.layers[i].initialize(self.getLayerSize(i-1))
                else:
                    self.layers[i].initialize(self.getLayerSize(i-1))

    # Compute the output of the network given some input a
    # The matrix a has shape n x k where n is the number of samples and
    # k is the dimension
    # This function returns
    # yp - the output of the network
    # a - a list of inputs for each layer of the newtork where
    #     a[i] is the input to layer i
    #     (note this does not include the network output!)
    # z - a list of values for each layer after evaluating layer.z(a) but
    #     before evaluating the nonlinear function for the layer
    def evaluate(self, x):
        curA = x.T
        a = [curA]
        z = []
        for layer in self.layers:
            z.append(layer.z(curA))
            curA = layer.a(z[-1])
            a.append(curA)
        yp = a.pop()
        return yp, a, z

    # Compute the output of the network given some input a
    # The matrix a has shape n x k where n is the number of samples and
    # k is the dimension
    def predict(self, a):
        a, _, _ = self.evaluate(a)
        return a.T

    # Computes the gradients at each layer. y is the true labels, yp is the
    # predicted labels, and z is a list of the intermediate values in each
    # layer. Returns the gradients and the forward pass outputs (per layer).
    #
    # In particular, we return a list of dMSE/dz_i. The reasoning behind this is that
    # in the update function for the optimizer, we do not give it the z values
    # we compute from evaluating the network.
    def compute_grad(self, x, y):
        # Feed forward, computing outputs of each layer and
        # intermediate outputs before the non-linearities
        yp, a, z = self.evaluate(x)

        # d is inialized here to be (dMSE / dyp)
        d = self.cost.dx(y.T, yp)
        grad = []
        # Backpropogate the error
        for layer, curZ in zip(reversed(self.layers), reversed(z)):
            # TODO: PART D ###################################################################
            # grad[i] should correspond with the gradient of the output of layer i before the
            # activation is applied (dMSE / dz_i); be sure values are stored in the correct
            # ordering!
            # PART D #########################################################################
            grad.append(d * layer.dx(curZ))
            d = layer.W.T @ grad[-1]
        grad = reversed(grad)
        return grad, a

    # Train the network given the inputs x and the corresponding observations y
    # The network should be trained for numEpochs iterations using the supplied
    # optimizer
    def train(self, x, y, numEpochs, optimizer):

        # Initialize some stuff
        n = x.shape[0]
        x = x.copy()
        y = y.copy()
        hist = []
        optimizer.initialize(self.layers)

        # Run for the specified number of epochs
        for epoch in range(0,numEpochs):

            # Compute the gradients
            grad, a = self.compute_grad(x, y)

            # Update the network weights
            optimizer.update(self.layers, grad, a)

            # Compute the error at the end of the epoch
            yh = self.predict(x)
            C = self.cost.fx(y, yh)
            C = np.mean(C)
            hist.append(C)
        return hist

    def trainBatch(self, x, y, batchSize, numEpochs, optimizer):
        # Copy the data so that we don't affect the original one when shuffling
        x = x.copy()
        y = y.copy()
        hist = []
        n = x.shape[0]

        for epoch in np.arange(0,numEpochs):

            # Shuffle the data
            r = np.arange(0,x.shape[0])
            x = x[r,:]
            y = y[r,:]
            e = []

            # Split the data in chunks and run SGD
            for i in range(0,n,batchSize):
                end = min(i+batchSize,n)
                batchX = x[i:end,:]
                batchY = y[i:end,:]
                e += self.train(batchX, batchY, 1, optimizer)
            hist.append(np.mean(e))

        return hist

if __name__ == '__main__':
    N0 = 3
    N1 = 9

    # Switch these statements to True to run the code for the corresponding parts
    # Part E
    SGD = True
    # Part F
    DIFF_SIZES = True

    # Generate the training set
    np.random.seed(9001)
    y_train = mnist.train_labels()
    y_test = mnist.test_labels()
    X_train = (mnist.train_images()/255.0)
    X_test = (mnist.test_images()/255.0)
    train_idxs = np.logical_or(y_train == N0, y_train == N1)
    test_idxs = np.logical_or(y_test == N0, y_test == N1)
    y_train = y_train[train_idxs].astype('int')
    y_test = y_test[test_idxs].astype('int')
    X_train = X_train[train_idxs]
    X_test = X_test[test_idxs]
    y_train = (y_train == N0).astype('int')
    y_test = (y_test == N0).astype('int')
    y_train *= 2
    y_test *= 2
    y_train -= 1
    y_test -= 1
    X_train = X_train.reshape(X_train.shape[0], -1)
    X_test = X_test.reshape(X_test.shape[0], -1)
    y_test = y_test[:, np.newaxis]
    y = y_train[:, np.newaxis]
    x = X_train
    xLin=np.linspace(-np.pi,np.pi,250).reshape((-1,1))

    yHats = {}

    activations = dict(ReLU=ReLUActivation,
                       tanh=TanhActivation,
                       linear=LinearActivation)
    lr = dict(ReLU=0.02,tanh=0.02,linear=0.005)
    names = ['ReLU','linear','tanh']

    #### PART E ####
    if SGD:
        print('\n----------------------------------------\n')
        print('Using SGD')
        for key in names[1:2]:
            for batchSize in [10, 50, 100, 200]:
                for epoch in [10, 20, 40]:
                    activation = activations[key]
                    model = Model(x.shape[1])
                    model.addLayer(DenseLayer(4,activation()))
                    model.addLayer(DenseLayer(1,LinearActivation()))
                    model.initialize(QuadraticCost())
                    hist = model.trainBatch(x, y, batchSize, epoch, GDOptimizer(eta=lr[key]))
                    y_hat_train = model.predict(x)
                    y_pred_train = np.sign(y_hat_train)
                    y_hat_test = model.predict(X_test)
                    y_pred_test = np.sign(y_hat_test)
                    error_train = np.mean(np.square(y_hat_train - y))/2
                    error_test = np.mean(np.square(y_hat_test - y_test))/2

                    print('Batch size: ', batchSize ,'Epoch: ', epoch, 'Train Error: ', error_train, 'Test Error: ', error_test)

    #### PART F ####
    # Train with different sized networks
    if DIFF_SIZES:
        print('\n----------------------------------------\n')
        print('Training with various sized network')
        names = ['ReLU', 'tanh']
        widths = [2, 4, 8, 16, 32]
        errors = {}
        for key in names[1:]:
            error = []
            for width in widths:
                activation = activations[key]
                model = Model(x.shape[1])
                model.addLayer(DenseLayer(width,activation()))
                model.addLayer(DenseLayer(1,LinearActivation()))
                model.initialize(QuadraticCost())
                epochs = 256
                hist = model.trainBatch(x,y,x.shape[0],epochs,GDOptimizer(eta=lr[key]))

                y_hat_train = model.predict(x)
                y_hat_test = model.predict(X_test)

                error_train = np.mean(np.square(y_hat_train - y))/2
                error_test = np.mean(np.square(y_hat_test - y_test))/2

                print(key+' neural nework width('+str(width)+') train MSE: '+str(error_train))
                print(key+' neural network width('+str(width)+') test MSE: '+str(error_test))

if DIFF_SIZES:
    print('\n----------------------------------------\n')
    print('Training with various sized network')
    names = ['ReLU', 'tanh']
    widths = [2, 4, 8, 16, 32]
    errors = {}
    for key in names[1:]:
        error = []
        for width in widths:
            activation = activations[key]
            model = Model(x.shape[1])
            model.addLayer(DenseLayer(width,activation()))
            model.addLayer(DenseLayer(1,LinearActivation()))
            model.initialize(QuadraticCost())
            epochs = 256
            hist = model.trainBatch(x,y,x.shape[0],epochs,GDOptimizer(eta=lr[key]))

            y_hat_train = model.predict(x)
            y_hat_test = model.predict(X_test)

            error_train = np.mean(np.square(y_hat_train - y))/2
            error_test = np.mean(np.square(y_hat_test - y_test))/2

            print(key+' neural nework width('+str(width)+') train MSE: '+str(error_train))
            print(key+' neural network width('+str(width)+') test MSE: '+str(error_test))


import numpy as np
import scipy.signal as ssi

def corr_fun(X, Y, dt, norm=True, biased=True, method='auto'):
    """
    Estimates the correlation function between X and Y using ssi.correlate.
    For now, we require both signals to be of equal length.

    Input:
        X: First array to be correlated. ............................. (Nx1) np.array
        Y: Second array to be correlated. ............................ (Nx1) np.array
        dt: Time step of the time series. ............................ float
        norm: Normalizes the correlation function to a maxima of 1 ... bool
        biased: Trigger estimator biasing. ........................... bool
        method: 'direct', 'fft' or 'auto'. Passed to ssi.correlate ... string

    For biased=True, the result is divided by X.size.
    For biased=False, the estimator is unbiased and returns the result
    divided by X.size-|k|, where k is the lag.
    The unbiased estimator diverges for large lags, and
    for small lags and large X.size, the difference is trivial.
    """

    assert(X.size==Y.size)

    if norm:
        Xn = (X-X.mean())/X.std()
        Yn = (Y-Y.mean())/Y.std()
    else:
        Xn = X
        Yn = Y

    R = ssi.correlate(Xn, Yn, mode='full', method = method)

    k = np.arange(-(X.size-1), X.size)
    tb = k*dt

    if biased:
        R /= X.size
    else:
        R /= (X.size-np.abs(k))

    return tb, R

# End of file correlation_function.py


# Importing the dependancies
import numpy as np
import matplotlib.pyplot as plt

# Creating random data with 3 input features and 2 output features
X = np.random.randn(3, 1000)
y = np.random.randint(2, size=1000)

# Defining the sigmoid function
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

def forward_prop(X, y, params):

    """"
    Propagate forward by computing:
    A = sigmoid(W.X + b)

    Arguments:
    X -- input data (num_of_features, training_size)
    y -- input data (1, training_size)
    W -- weights (num_of_features, 1)
    b -- scalar value

    Returns:
    A -- the prediction
    cost -- the cost function
    """

    m = X.shape[1]

    Z = np.dot(params['W'].T, X) + params['b']
    A = sigmoid(Z)

    cost = -(1/m)*np.sum((y*np.log(A) + (1-y)*np.log(1-A)))

    return A, cost

def back_prop(X, A):

    """
    Propagate backwards by computing the gradients:
    dA = -(y/A) + (1-y)/(1-A)
    dZ = A - y
    dW = (1/m)*X.dZ
    db = (1/m)*sum(dZ)

    Arguments:
    X -- input data (num_of_features, training_size)
    A -- the prediction

    Returns:
    dW, db -- gradients with same shape as W, b respectively
    """

    m = X.shape[1]

    dZ = A - y
    dW = (1/m)*np.dot(X, dZ.T)
    db = (1/m)*np.sum(dZ)

    grads = {'dW': dW, 'db': db}

    return grads

def update_parameters(params, grads, learning_rate=0.001):

    """
    Update the parameters:
    W = W - lr*dW
    b = b - lr*db

    Arguments:
    W -- weights (num_of_features, 1)
    b -- scalar value
    dW, db -- gradients
    learning_rate -- the rate at which the params should update (default = 0.001)

    Returns:
    W, b -- updated parameters
    """

    params['W'] -= learning_rate*grads['dW']
    params['b'] -= learning_rate*grads['db']

    return params

def model(X, y, epochs, learning_rate=0.001, visualize=False):

    """
    Logistic Regression model

    Arguments:
    X -- input data (num_of_features, training_size)
    y -- input data (1, training_size)
    learning_rate -- the rate at which the params should update (default = 0.001)
    epochs -- number of iterations
    visualize -- represent the loss on a graph (default = False)

    Returns:
    W, b -- parameters
    """

    # initialise the parameters
    W = np.zeros((X.shape[0], 1))
    b = 0

    params = {'W': W, 'b': b}

    # initialise the gradients
    dW = np.zeros((X.shape[0], 1))
    db = 0

    grads = {'dW': dW, 'db': db}

    cost = [0]*epochs

    # running the algorithm
    for i in range(epochs):

        # forward prop
        A, cost[i] = forward_prop(X, y, params)

        # printing the cost
        if i%100 == 0:
            print(f'loss after {i} iterations = {cost[i]}')

        # backwards prop
        grads = back_prop(X, A)

        # updating the params
        params = update_parameters(params, grads, learning_rate)

    if visualize:

        plt.style.use('fivethirtyeight')

        plt.plot(cost, label = 'cost')
        plt.xlabel('Epochs')
        plt.ylabel('Cost')
        plt.legend()
        plt.show()

    return params

# Calling the function
p = model(X, y, 10000, visualize=True)


from time import time
from pick import pick

# Functions

def f(x):
	return eval(function_string)

def LeftRiemannSums(j):
	sum=0
	for i in range(j):
		sum+=f((i/j)*(end-start)+start)*((end-start)/j)
#		print(sum)
	return sum
def RightRiemannSums(j):
	sum=0
	for i in range(1,j+1,1):
		sum+=f((i/j)*(end-start)+start)*((end-start)/j)
#		print(sum)
	return sum

def TrapezoidalSums(j):
	sum=0
	for i in range(j):
		sum+=0.5*( f((i/j)*(end-start)+start) + f(((i+1)/j)*(end-start)+start) )*((end-start)/(j))
#		print(sum)
	return sum

def MonteCarlo1(j,k): # j=number of slots, k=number of points per slot
	in_dots=0
	out_dots=0
	space=linspace(start,end,j)
	y=vf(space)
	for i in space:
		for l in range(k):
			if random.uniform(0.,max(y))<=f(i):
				in_dots+=1
			else:
				out_dots+=1
	return (in_dots/(out_dots+in_dots))*max(y)*(end-start)

def MonteCarlo2(j,k=100):
	in_d=0
	out_d=0
	h=max(vf(linspace(start,end,k)))
	p=0
	for i in range(j):
		p=[random.uniform(start,end),np.random.uniform(0,h)]
		if p[1]<=f(p[0]):
			in_d+=1
		else:
			out_d+=1
	return (in_d/(out_d+in_d))*h*(end-start)

def exclude(ex,n,strt=0,stp=1):
	'''
	Gives an Integer iterator [0,ex)U(ex,n)
	'''
	return [q for q in range(strt,n,stp) if q!=ex]

def PC(j):
	'''
	Polinomial Coefficient
	'''
	p=1
	for m in exclude(j,k):
		p*=(x-xp[m])/(xp[j]-xp[m])
	return p

def LS():
	'''
	Lagrange Sums
	'''
	p=0
	for i in range(k):
		p+=yp[i]*PC(i)
	return p

# Inputs

print("Demo to numerically integrate numpy real valued functions. \nAll functions have to be written with the x variable. ")
function_string=input("Function: ")
start=float(input("From: "))
end=float(input("To: "))
if (start==end):
	print('\n\n',0)
	quit()

# Pick Method

title = 'Select an Integration Method: '
options = ['Riemman sums','Trapezoid Rule','Monte Carlo 1','Monte Carlo 2',"SymPy Symbolic Integration", "Lagrange Polynomial Interpolation"]
method, indexp = pick(options, title)
print('Method Selected: %s'%(method))

# Riemann sums

if (method=='Riemman sums'):
	from numpy import *
	n=int(input('Number of partitions for the Riemann sums: '))
	print('')
	t1=time()
	print('Left Riemann Sums:  %f'%(LeftRiemannSums(n)))
	print('Right Riemann Sums: %f'%(RightRiemannSums(n)))
	print('Total calculation time: %f'%(time()-t1))

# Trapezoid Rule

if (method=='Trapezoid Rule'):
	from numpy import *
	n=int(input('Number of partitions for the Trapezoid Rule: '))
	print('')
	t1=time()
	print('Result: %f'%(TrapezoidalSums(n)))
	print('Total calculation time: %f'%(time()-t1))

# Monte Carlo 1

if (method=='Monte Carlo 1'):
	from numpy import *
	vf=vectorize(f)
	n=int(input('Number of partitions for Monte Carlo: '))
	m=int(input('Number of points per partition: '))
	print('')
	t1=time()
	print('Result: %f'%(MonteCarlo1(n,m)))
	print('Total calculation time: %f'%(time()-t1))

# Monte Carlo 2

if (method=='Monte Carlo 2'):
	from numpy import *
	vf=vectorize(f)
	n=int(input('Number of dots for Monte Carlo: '))
	print('')
	t1=time()
	print('Result: %f'%(MonteCarlo2(n)))
	print('Total calculation time: %f'%(time()-t1))

# SymPy

if (method=="SymPy Symbolic Integration"):
	from sympy import *
	x=symbols('x')
	g=eval(function_string)
	t1=time()
	G=integrate(g,x)
	print("Indefinite integral",G)
	print("Definite integral",G.subs(x,end)-G.subs(x,start))
	print("Total calculation time: %f"%(time()-t1))

# Lagrange

if (method=="Lagrange Polynomial Interpolation"):
	from sympy import *
	x=symbols('x')
	g=eval(function_string)
	t1=time()

	k=int(input("Degree of each Lagrange Polynomial Interpolation: "))
	from numpy import linspace,vectorize
	xp=linspace(start,end,k+1)
	def gfunc(x):
		return eval(str(g))
	vgfunc=vectorize(gfunc)
	yp=vgfunc(xp)
	pol_string=str(expand(LS()))
	def pol(x):
		return eval(pol_string)
	import matplotlib.pyplot as plt
	space=linspace(start,end,100)
	plt.figure()
	plt.plot(space,vgfunc(linspace(start,end,100)))
	plt.plot(space,list(map(pol,space)))
	plt.scatter(xp,list(map(pol,xp)))
	plt.show()


import numpy as np
import matplotlib.pyplot as plt

#ma+bv+kx=0 (no out force)
#define: (b/m)=r , (k/m)=w^2
#x''+rx'+(w^2)x=0
#dx/dt=v, dv/dt=-rv-(w^2)x
#define: tau=wt
#dx/dtau=v/w, dv/dtau=-(r/w)v-wx
#define: u=v/w
#dx/dtau=u
#du/dtau=-(r/w)u-x
#let y1=x, y2=u
#dy1/dtau=y2=g1, dy2/dtau=-(r/w)y2-y1=g2

#parameter:
gamma=[0.1,1,2,3] #damping coefficient
omega_0=1.0 # natural frequency
N=2000
h=0.01
t=np.arange(N)*h

#initial condition: x(0)=X0, v(0)=0
x0=1
v0=0

def g1(y1,y2):
    return (y2)

def g2(y1,y2,gamma_i):
    return (-y1-(gamma_i/omega_0)*y2)

#calculate the value of the next moment by RK2 method
def y_rk2(y1,y2,gamma_i):#with (w1,w2,alpha,beta) = (0.5,0.5,1,1)
    k1=g1(y1,y2)
    q1=g2(y1,y2,gamma_i)
    k2=g1(y1+h*k1,y2+h*q1)
    q2=g2(y1+h*k1,y2+h*q1,gamma_i)
    y1_prime=y1+h*(0.5*k1+0.5*k2)
    y2_prime=y2+h*(0.5*q1+0.5*q2)
    return y1_prime,y2_prime

def SHO(gamma_i):
    x=[]
    v=[]
    x.append(x0)
    v.append(v0)
    for i in range(0,N-1):
        a,b=y_rk2(x[i],v[i],gamma_i)
        x.append(a)
        v.append(b)
    return x,v

def visualize(x,v,gamma_i):
    plt.plot(t/np.pi, x, label="x(t)")
    plt.plot(t/np.pi, v, label="v(t)")
    plt.axhline(y=1, linestyle="--")
    plt.axhline(y=-1, linestyle="--")
    plt.title("RK2, SHO with $\gamma/\omega0=$%1.1f, x(0)=%1.1f,v(0)=%1.1f"%(gamma_i/omega_0, x0, v0))
    plt.xlabel("$t/\pi$")
    plt.ylabel("$y_n(t)$")
    plt.legend()
    plt.show()

#main function:
for j in gamma:
    x,v=SHO(j)
    visualize(x,v,j)


# -*- coding: utf-8 -*-
"""
Created on Mon Dec 13 15:32:20 2021

@author: Oscar
"""
"Tutorial 5 Numerical Simulation of chaos, the Lorenz System"
from scipy.integrate import solve_ivp
import numpy as np
import math
import matplotlib.pyplot as plt

# Define Function models
def model(t, y):
    rho = 28
    beta = 8/3
    sigma = 10

    y_1 = y[0]
    y_2 = y[1]
    y_3 = y[2]

    f1 = sigma * (y_2 - y_1)
    f2 = rho * y_1 - y_2 - y_1 * y_3
    f3 = -beta * y_3 + y_1 * y_2

    return [f1, f2, f3]

# Define Function models
def model2(t, y):
    rho = 10
    beta = 8/3
    sigma = 10

    y_1 = y[0]
    y_2 = y[1]
    y_3 = y[2]

    g1 = sigma * (y_2 - y_1)
    g2 = rho * y_1 - y_2 - y_1 * y_3
    g3 = -beta * y_3 + y_1 * y_2

    return [g1, g2, g3]

# Define initial Conditions
t = 0
t_f = 30

y0_1 = 5
y0_2 = 5
y0_3 = 5

# Define time interval
t_eval = np.linspace(t, t_f, num= 5000)

# Solution
y = solve_ivp(model, [t, t_f], [y0_1, y0_2, y0_3], t_eval= t_eval)
z = solve_ivp(model2, [t, t_f], [y0_1, y0_2, y0_3], t_eval= t_eval)
# ------------------------------------------------------
# Plot Results
plt.figure(1)
plt.plot(y.t, y.y[0,:] , 'b-', y.t,y.y[1,:],
         'r-', y.t, y.y[2,:], 'g-')
plt.xlabel('t')
plt.ylabel('y_1(t), y_2(t), y_3(t)')
# ------------------------------------------------------

# plot results
plt.figure(2)
plt.plot(y.y[0,:] ,y.y[1,:],'-')
plt.xlabel('y_1')
plt.ylabel('y_2')
# ------------------------------------------------------

# plot results
plt.figure(3)
plt.plot(y.y[0,:] ,y.y[2,:],'-')
plt.xlabel('y_1')
plt.ylabel('y_3')
# ------------------------------------------------------

plt.show()
# ------------------------------------------------------
# Plot Results
plt.figure(4)
plt.plot(z.t, z.y[0,:] , 'b-', z.t,z.y[1,:],
         'r-', z.t, z.y[2,:], 'g-')
plt.xlabel('t')
plt.ylabel('y_1(t), y_2(t), y_3(t)')
# ------------------------------------------------------

# plot results
plt.figure(5)
plt.plot(z.y[0,:] ,z.y[1,:],'-')
plt.xlabel('y_1')
plt.ylabel('y_2')
# ------------------------------------------------------

# plot results
plt.figure(6)
plt.plot(z.y[0,:] ,z.y[2,:],'-')
plt.xlabel('y_1')
plt.ylabel('y_3')

# print results in a text file (for later use if needed)
file_name= 'output.dat'
f_io = open(file_name,'w')
n_step = len(y.t)
for i in range(n_step):
    s1 = str(i)
    s2 = str(y.t[i])
    s3 = str(y.y[0,i])
    s4 = str(y.y[1,i])
    s_tot = s1 + ' ' + s2 + ' ' + s3  + ' ' + s4
    f_io.write(s_tot + '\n')
f_io.close()
# ------------------------------------------------------


import numpy as np
from scipy.linalg import logm

""" UTILITY FUNCTIONS """

def hat(w):
    """ Function takes in a vector of size 3 and returns
    its corresponding skew-symmetric matrix """
    w1 = w[0]
    w2 = w[1]
    w3 = w[2]
    what  = np.array( [ [0,-w3,w2], [w3,0,-w1], [-w2,w1,0] ] )
    return what

def unhat(what):
    """ Function takes in a skew-symmetric matrix and returns
    its corresponding vector """
    w1 = what[2,1]
    w2 = what[0,2]
    w3 = what[1,0]
    w  = np.array( (w1,w2,w3) )
    return w

def qmult(q1,q2):
    """ Function takes in quaternions q1 and q2, and performs
    quaternion multiplication:  q3 = q1*q2 """
    v1 = q1[0:3]
    s1 = q1[3]
    q3 = np.block([ [s1*np.identity(3) + hat(v1), v1[:,np.newaxis] ], [-v1, s1] ]) @ q2
    return q3

def qconj(q):
    """ Function takes in a quaternion and returns its conjugate """
    v = q[0:3]
    v = -v
    qplus = np.concatenate((v,q[3,np.newaxis]),axis=0)
    return qplus

def phi_to_quat(phi):
    """ Function takes in a rotation parameterized by
    Euler Axis & Angle and returns its corresponding quaternion """
    if np.linalg.norm(phi) > 10*np.pi/180:
        theta = np.linalg.norm(phi)
        r     = phi/theta
        qvec  = r*np.sin(theta/2)
        qsca  = np.array(np.cos(theta/2))
        q     = np.hstack((qvec,qsca))
    else:
        qvec  = phi/2
        qsca  = np.array(1-1/8*np.dot(phi,phi))
        q     = np.hstack((qvec,qsca))
    return q

def quat_to_phi(q):
    """ Function takes in a rotation parameterized by
    a quaternion and returns its corresponding Euler Axis & Angle """
    Q = quat_to_rot(q)
    phi = unhat(logm(Q))
    return phi

def quat_to_rot(q):
    """ Function takes in a rotation parameterized by
    a quaternion and returns its corresponding rotation matrix """
    v = q[0:3]
    s  = q[3]
    A = np.identity(3) + 2*hat(v) @ (s*np.identity(3) + hat(v))
    #A = np.transpose(A)
    return A

""" Below is another way to convert from quaternion to rotation matrix
def quat_to_rot(q):
    q1 = q[0]
    q2 = q[1]
    q3 = q[2]
    q4 = q[3]
    Q  = np.array( [ [0,-q3,+q2], [+q3,0,-q1], [-q2,q1,0] ] )
    A  = (q4**2 - (q1**2+q2**2+q3**2))*np.identity(3) + 2*np.outer(np.array([q1,q2,q3]), np.array([q1,q2,q3])) - 2*q4 * Q
    return A
"""


import numpy as np

class Complejo():
    def __init__(self,real,imag):
        self.real = real
        self.imaginario = imag
        self.norma = np.sqrt(self.real**2 + self.imaginario**2)
    def conjugado(self):
        self.imaginario = -self.imaginario
    def calcula_norma(self):
        self.norma = np.sqrt(self.real**2 + self.imaginario**2)
    def pow(self,n):
        resultado = Complejo(self.real,self.imaginario)
        for i in range(n-1):
            resultado = Complejo(self.real*resultado.real - self.imaginario*resultado.imaginario,self.imaginario*resultado.real + self.real*resultado.imaginario)
        return(resultado)


### Bernstein Basis
import numpy as np

## Ex 4.1
from scipy.special import binom

def B1(i,n,t):
    """Restituisce il polinomio di Bernstein (i,n) valutato in t,
    usando la definizione binomiale"""
    if i < 0 or i > n:
        return 0
    return binom(n,i)* t**i * (1-t)**(n-i)

def B2(i,n,t):
    """Restituisce il polinomio di Bernstein (i,n) valutato in t,
    usando una definizione ricorsiva"""
    if i < 0 or i > n:
        return 0
    elif n == 0:
        return 1

    return (1-t) * B2(i,n-1,t) + t * B2(i-1,n-1,t)

def B3(k,n,t):
    """Restituisce il polinomio di Bernstein (i,n) valutato in t,
    usando l'espressione in serie di potenze"""
    return sum([(-1)**(i-k) * binom(n,i) * binom(i,k) * t**i
         for i in range(k, n+1)])

## Ex 4.2
import cProfile

cProfile.run("B1(7,20,1)")
cProfile.run("B2(7,20,1)")
cProfile.run("B3(7,20,1)")

## Ex 4.3
from matplotlib import pylab as plt

# Segue: plot di B1(i, n, x) per n in [20,40,80,160,320].
step = 2**(-7)
plotNodes = np.arange(0, 1+step, step)
for n in 10 * (2**np.arange(1,6,1)):
    for i in range(n+1):
        plt.plot(plotNodes, [B1(i,n,x) for x in plotNodes])
    plt.title("B1(i, "+ str(n) + ", x)")
    plt.show()

# Segue: codice per il plot di B2.
# ! E' stato commentato in quanto l'algoritmo ricorsivo impiega un
# tempo eccessivo anche solo per calcolare la griglia per n = 20.

#plotNodes = np.arange(0, 1+step, step)
#for n in 10 * (2**np.arange(1,6,1)):
#    for i in range(n+1):
#       plt.plot(plotNodes, [B2(i,n,x) for x in plotNodes])
#    plt.title("B2(i, "+ str(n) + ", x)")
#    plt.show()

# Segue: codice per il plot di B3
# ! Per ridurre il tempo di esecuzione l'algoritmo calcola B3(i, n, x)
# solo per n = 20, 40.
plotNodes = np.arange(0, 1+step, step)
for n in 10 * (2**np.arange(1,3,1)):
    for i in range(n+1):
        plt.plot(plotNodes, [B3(i,n,x) for x in plotNodes])
    plt.title("B3(i, "+ str(n) + ", x)")
    plt.show()
# Nel grafico per n = 40 si possono già notare gravi errori
# di approssimazione nelle vicinanze di 1, dovuti alla presenza
# di molte somme di termini molto piccoli.

## Ex 4.4
# Segue una reimplementazione della definizione di B3 con il modulo
# scipy.polynomial.
import numpy.polynomial as P

def B3Poly(i,n):
    """Restituisce il polinomio di Bernstein (i,n), implementato con
    numpy.polynomial e usando l'espressione in serie di potenze"""
    outPoly = P.Polynomial([0])
    for k in range(i,n+1):
        nextTerm = k*[0]
        nextTerm.append((-1)**(i-k) * binom(n,i) * binom(i,k))
        outPoly += nextTerm
    return outPoly

def DB3Poly(i,n):
    """Restituisce la derivata del polinomio di Bernstein (i,n),
    implementato con numpy.polynomial e usando l'espressione in serie
    di potenze"""
    return B3Poly(i,n).deriv()

# Tuttavia questa implementazione ha ancora problemi di stabilità
# numerica non risolti dalla rappresentazione con numpy.polynomial.
# Svolgendo i conti a mano per la derivata di B1 otteniamo la
# seguente funzione, numericamente più stabile.

def DB1(i,n,x):
    return n * (B1(i-1,n-1,x) - B1(i,n-1,x))

## Ex 4.5
def B(n,f,x):
    return sum([B1(i,n,x) * f(i/n) for i in range(n+1)])

for j in 4**np.arange(1,5,1):
    plt.plot(plotNodes,
             [B(j, lambda y: np.cos(16*y), x)
              for x in plotNodes])
    plt.title(str(j) + "th Bernstein approximation of cos(16*x)")
    plt.show()


'''
Purpose
-------
Sample from a 2-dim. Normal distribution using a Random Walk Sampler.
This is the Metropolis MCMC algorithm with a Gaussian proposal with controllable stddev

Target distribution:
# mean
>>> mu_D = np.asarray([-1.0, 1.0])
# covariance
>>> cov_DD = np.asarray([[2.0, 0.95], [0.95, 1.0]])

'''

import numpy as np
import scipy.stats
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('whitegrid')

from RandomWalkSampler import RandomWalkSampler2D

def calc_target_log_pdf(z_D):
    ''' Compute log pdf of provided z value under target bivariate Normal distribution

    Args
    ----
    z_D : 1D array, size (D,)
        Value of the random variable at which we should compute log pdf

    Returns
    -------
    logpdf : float real scalar
        Log probability density function value at provided input
    '''
    ## TODO compute logpdf of z_D value under target distribution
    return -0.5 * np.sum(np.square(z_D)) # fixme

if __name__ == '__main__':
    n_samples = 10000   # total number of iterations of MCMC
    n_keep = 5000       # number samples to keep
    random_state = 42   # seed for random number generator
    prng = np.random.RandomState(random_state)

    # Two initializations, labeled 'A' and 'B'
    z_initA_D = np.zeros(2)
    z_initB_D = np.asarray([1.0, -1.0])

    # Look at a range of std. deviations
    rw_stddev_grid = np.asarray([0.01, 0.1, 1.0, 10.0])
    G = len(rw_stddev_grid)

    # Prepare a plot to view samples from two chains (A/B) side-by-side
    _, ax_grid = plt.subplots(
        nrows=2, ncols=G, sharex=True, sharey=True,
        figsize=(2*G, 2*2))

    for rr, rw_stddev in enumerate(rw_stddev_grid):

        # TODO Create samplers and run them for specified num iterations
        # Make sure to provide rw_stddev and random_state as args

        # TODO Stack list of samples into a 2D array of size (S, D)
        # Keeping only the last n_keep samples (and thus discarding burnin)
        zA_SD = prng.randn(n_keep, 2)  # fixme
        zB_SD = prng.randn(n_keep, 2)  # fixme

        # TODO unpack info about accept rates
        samplerA_accept_rate_last_half = 0.0
        samplerB_accept_rate_last_half = 0.0

        # Plot samples as scatterplot
        # Use small alpha transparency value for visual debugging of rare/frequent samples
        ax_grid[0,rr].set_title("rw_stddev = %.2F" % rw_stddev)
        ax_grid[0,rr].plot(zA_SD[:,0], zA_SD[:,1], 'r.', alpha=0.05)
        ax_grid[1,rr].plot(zB_SD[:,0], zB_SD[:,1], 'b.', alpha=0.05)
        # Mark initial points with "X"
        ax_grid[0,rr].plot(z_initA_D[0], z_initA_D[1], 'rx')
        ax_grid[1,rr].plot(z_initB_D[0], z_initB_D[1], 'bx')

        # Pretty print some stats for the samples
        # To give a way to check "convergence" from the terminal's stdout
        msg_pattern = ("RW stddev %5.2f from init %s | kept %d of %d samples | accept rate %.3f"
            + "\n    percentiles z0: 10th % 5.2f   50th % 5.2f   90th % 5.2f"
            + "\n    percentiles z1: 10th % 5.2f   50th % 5.2f   90th % 5.2f"
            )
        print(msg_pattern % (
            rw_stddev, 'A', n_keep, n_samples,
            samplerA_accept_rate_last_half,
            *tuple(np.percentile(zA_SD[:,0:1], [10, 50, 90], axis=0)),
            *tuple(np.percentile(zA_SD[:,1:2], [10, 50, 90], axis=0)),
            ))
        print(msg_pattern % (
            rw_stddev, 'B', n_keep, n_samples,
            samplerB_accept_rate_last_half,
            *tuple(np.percentile(zB_SD[:,0:1], [10, 50, 90], axis=0)),
            *tuple(np.percentile(zB_SD[:,1:2], [10, 50, 90], axis=0)),
            ))

    # Make plots pretty and standardized
    for ax in ax_grid.flatten():
        ax.set_xlim([-5, 5]);
        ax.set_ylim([-5, 5]);
        ax.set_aspect('equal', 'box');
        ax.set_xticks([-4, -2, 0, 2, 4])
        ax.set_yticks([-4, -2, 0, 2, 4])

    plt.tight_layout()
    plt.show()


"""parab.py: Parabola fit around three points to find a true vertex."""

import numpy as np

def fit_peak(f, x):
	'''
	Uses solution to parabola to fit peak and two surrounding points
	This assumes there is a peak (i.e. parabola second deriv is negative)

	Parameters
	----------
	f : array f(x)
	x : array x with the indices corresponding to f

	If interested, this is educational to see with sympy
	 import sympy
	 y1, y2, y3 = sympy.symbols('y1 y2 y3')
	 A = sympy.Matrix([[(-1)**2, -1, 1],[0**2, 0, 1],[(1)**2,1,1]])
	 C = sympy.Matrix([[y1],[y2],[y3]])
	 D = A.inv().multiply(C)
	 D contains the values of a, b, c in ax**2 + bx + c
	 Peak position is at x = -D[1]/(2D[0])
	'''

	pk = np.argmax(f)

	y1 = f[pk - 1]
	y2 = f[pk]
	y3 = f[pk + 1]

	a = 0.5 * y1 - y2 + 0.5 * y3
	b = -0.5 * y1 + 0.5 * y3
	c = y2

	xindex = -b / (2 * a)
	findex = xindex * (x[1] - x[0]) + x[1]
	yindex = a * xindex ** 2 + b * xindex + c

	return findex, yindex, xindex

def ridge_finder(spectrogram, freq_bin):
	'''
	Uses parabolda to fit peak and two surrounding points
	This takes a spectrogram and the frequency bin spacing and wraps parab.fit_2d

	Parameters
	----------
	spectrogram : ndarray
		Returned by scipy.signal.spectrogram or stft or cwt
		Arranged in (frequencies, times) shape

	freq_bin : ndarray
		arrays corresponding the frequencies in the spectrogram

	Returns
	-------
	xindex : ndarray
		1D array of the frequency bins returned by parabolic approximation
	yindex : ndarray
		1D array of the peak values at the xindices supplied
	'''
	_argmax = np.argmax(np.abs(spectrogram), axis=0)
	cols = spectrogram.shape[1]

	# generate a (3, cols) matrix of the spectrogram values
	maxspec = np.array([spectrogram[(_argmax - 1, range(cols))],
						spectrogram[(_argmax, range(cols))],
						spectrogram[(_argmax + 1, range(cols))]])

	return fit_2d(maxspec, _argmax, freq_bin)

def fit_2d(f, p, dx):
	'''
	Uses solution to parabola to fit peak and two surrounding points
	This assumes there is a peak (i.e. parabola second deriv is negative).

	This is a broadcast version for speed purposes

	Parameters
	----------
	f : 2-d array f(x) of size (3 , samples)

	p : 1-d array with the peak positions for f

	dx : 1-d array with the frequency (x values) of f
	'''

	if f.shape[0] != 3:
		raise ValueError('Must be exactly 3 rows')

	a = 0.5 * f[0, :] - f[1, :] + 0.5 * f[2, :]
	b = -0.5 * f[0, :] + 0.5 * f[2, :]
	c = f[1, :]

	xindex = -b / (2 * a)
	findex = xindex * (dx[1] - dx[0]) + dx[p]
	yindex = a * (xindex ** 2) + b * xindex + c

	return findex, yindex, xindex

def fit_peak_old(f, x):
	"""
	f = array
	x = index of peak, typically just argmax

	Uses parabola equation to fit to the peak and two surrounding points
	"""

	x1 = x - 1
	x2 = x
	x3 = x + 1

	y1 = f[x - 1]
	y2 = f[x]
	y3 = f[x + 1]

	d = (x1 - x3) * (x1 - x2) * (x2 - x3)

	A = (x1 * (y3 - y2) + x2 * (y1 - y3) + x3 * (y2 - y1)) / d

	B = (x1 ** 2.0 * (y2 - y3) +
		 x2 ** 2.0 * (y3 - y1) +
		 x3 ** 2.0 * (y1 - y2)) / d

	C = (x2 * x3 * (x2 - x3) * y1 +
		 x3 * x1 * (x3 - x1) * y2 +
		 x1 * x2 * (x1 - x2) * y3) / d

	xindex = -B / (2.0 * A)
	yindex = C - B ** 2.0 / (4.0 * A)

	return xindex, yindex


import numpy as np

def array_info(array: np.ndarray) -> None:
    print(f"ndim: {array.ndim}")
    print(f"shape: {array.shape}")
    print(f"size: {array.size}")
    print(f"dtype: {array.dtype}")
    print(f"values:\n{array}\n")

if __name__ == '__main__':
    # my_np_array = np.array([1, 2, 3.14, 5, 4, 3], dtype="float32")
    # my_np_array = np.zeros(shape=(3, 5), dtype=float)
    # my_np_array = np.arange(start=0, stop=20, step=2)
    my_np_array = np.linspace(start=0, stop=1, num=5)
    array_info(my_np_array)

    print("====")

    # my_rand_array = np.random.randint(low=0, high=10, size=(3, 3)) # high not inclusive
    my_rand_array = np.random.random(size=(3, 3)) # gaussian
    array_info(my_rand_array)


import numpy as np
from timeit import default_timer as timer

def seminorm_loop(x, p, display = False):
    """
    Calculate for a given complex vector and some 1 <= p < inf the l_p-semi-norm
    using loops and scalar arithmetic
    """
    if p < 1:
        raise ValueError("p must be >= 1")

    # Using scalar arithmetic to calculate each elements absolute value raised to p
    x_abs_p = x.real**2 + x.imag**2 * (1j)
    x_abs_p = ((x_abs_p.real + x_abs_p.imag) ** 0.5) ** p

    # Sum all elements with an uneven index
    sum = 0
    for j in range(1, len(x_abs_p)+1, 2):
        # Since arrays in python are zero-based, substract 1 from j
        j -= 1
        sum += x_abs_p[j]

    # Raise to 1/p to get the l_p-semi-norm
    result = sum**(1/p)

    if display:
        print(result)

    return result

def seminorm(x, p, display = False):
    """
    Calculate for a given complex vector and some 1 <= p < inf the l_p-semi-norm
    using vector functions and arithmetics
    """
    if p < 1:
        raise ValueError("p must be >= 1")

    # Using slicing to get every second element, then calculate the absulte value for each element
    # raised to p, then take the sum of them which is raised to 1/p
    result = np.sum(np.abs(x[::2])**p)**(1/p)

    if display:
        print(result)

    return result

def main():
    # Test functions
    x = np.array([1+1j, 2+2j, 3+3j])
    seminorm_loop(x, 3, True)
    seminorm(x, 3, True)

    #---------------------------------------------------------
    print("### Test performance ###")
    # Generate random complex vector with dim 10**5
    np.random.seed(0)
    x = np.random.random(10**7) + np.random.random(10**7) * 1j
    p = np.random.randint(1, 1000)

    # Method 1: using loops and scalar arithmetic
    tic = timer()
    seminorm_loop(x, p)
    toc = timer()
    print("Method /w loops: ", toc - tic, "s")

    # Method 2: using vector functios and arithmetics
    tic = timer()
    seminorm(x, p)
    toc = timer()
    print("Method /w vec-fns: ", toc - tic, "s")

    """ Result (on my machine)
    Method /w loops:    3.6782882 s
    Method /w vec-fns:  0.3709317 s

    Interpretation:
    Using numpy vector function are apparently faster then larger the vector size gets.
    """

if __name__ == "__main__":
    main()


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

# # https://realpython.com/python-matplotlib-guide/

# In[2]:

import os

import numpy as np
np.random.seed(444)
import pandas as pd
from scipy import stats

import seaborn as sns
get_ipython().run_line_magic('matplotlib', 'inline')
import matplotlib.pyplot as plt
plt.style.use('ggplot')
sns.set(style='ticks', context='talk')

import requests

# In[81]:

from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score, explained_variance_score

# In[3]:

# setting directories for file loads and saves
raw_dir = "../data/raw/"
load_dir = save_dir = "../data/interim/"
final_dir = "../data/processed/"

logs_dir = "../data/logs/"

# In[ ]:

# In[4]:

nap = pd.read_csv(save_dir + '2017_year_7_results_schools_info.csv', index_col=0)
nap.head()

# In[30]:

nap_model = nap.dropna()

# In[176]:

x = nap_model['mean']
y = nap_model['icsea']

# In[182]:

gradient,intercept,r_value,p_value,std_err = stats.linregress(x,y)

print("Gradient and intercept",gradient,intercept)
print("R-squared",r_value**2)
print("p-value",p_value)

# In[218]:

xstat = np.linspace(x.min(), x.max(), len(x))
ystat = []
for i in range(len(xstat)):
    ystat.append(((gradient * xstat[i]) + intercept))
plt.plot(xstat, ystat)

# In[ ]:

# In[219]:

fig, ax = plt.subplots(figsize=(10, 6))
ax.scatter(x, y)
ax.set_title('Mean naplan versus ICSEA, 2017, Year 7')
ax.set_ylabel('ICSEA')
ax.set_xlabel('Naplan (mean)')
plt.plot(xstat, ystat,
         color = 'red')
#fig.tight_layout()

# In[ ]:

# In[178]:

gradient,intercept,r_value,p_value,std_err = stats.linregress(x,y)

print("Gradient and intercept",gradient,intercept)
print("R-squared",r_value**2)
print("p-value",p_value)

# In[181]:

plt.plot([((gradient * 400) + intercept), 800], [400, (800 - intercept) / gradient])

# In[ ]:

# In[ ]:

# In[58]:

# initialise instance or LR model
lm = LinearRegression(fit_intercept=True)

# Create model
lm.fit(x[:, np.newaxis], y)

print('Estimated intercept coefficient:', lm.intercept_, '\n'
     'Number of coefficients:', len(lm.coef_))

# In[ ]:

# In[63]:

# create model data over range of naplan results
xfit = np.linspace(x.min(), x.max(), len(y))
yfit = lm.predict(xfit[:, np.newaxis])

# In[64]:

fig, ax = plt.subplots(figsize=(10, 6))
ax.scatter(x, y)
ax.plot(xfit, yfit)
ax.set_title('Mean naplan versus ICSEA, 2017, Year 7')
ax.set_ylabel('ICSEA')
ax.set_xlabel('Naplan (mean)')

#fig.tight_layout()

# In[82]:

# The mean squared error
print("Mean squared error: %.2f"
      % mean_squared_error(y.sort_values(), yfit))
# r2_score: 1 is perfect prediction
print('Variance score: %.2f' % r2_score(y.sort_values(), yfit))

# Explained variance score: 1 is perfect prediction
print('Variance score: %.2f' % explained_variance_score(y.sort_values(), yfit))

# In[172]:

from scipy import stats

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[85]:

from sklearn.model_selection import train_test_split

# In[147]:

x = nap_model['mean'].values.reshape(-1, 1)
y = nap_model['icsea'].values

# In[159]:

X_train, X_test, Y_train, Y_test = train_test_split(x, y, test_size = 0.5, random_state = 5)

# In[160]:

print(X_train.shape, X_test.shape, Y_train.shape, Y_test.shape)

# In[161]:

lm2 = LinearRegression(fit_intercept=True)

# In[162]:

print(type(X_test), X_test.shape)

# In[163]:

lm2.fit(X_train, Y_train)

# In[164]:

pred_train = lm2.predict(X_train)
pred_test = lm2.predict(X_test)

# In[165]:

print('Fit a model X_train, and calculate MSE with Y_train:',
      np.mean((Y_train - lm.predict(X_train)) ** 2)
     )

print('Fit a model X_train, and calculate MSE with X_test, Y_test:',
      np.mean((Y_test - lm.predict(X_test)) ** 2))

# In[170]:

plt.scatter(X_train, pred_train)
plt.scatter(X_test, pred_test)

# In[ ]:

# In[93]:

url = ("http://www.dcc.fc.up.pt/~ltorgo/Regression/cal_housing.tgz")

# Packages the request, send the request and catch the response: r
r = requests.get(url)

# type the response
type(r)

# In[ ]:


import numpy as np

def FE_logistic(p, u0, dt, Nt):
    u = np.zeros(Nt+1)
    u[0] = u0
    for n in range(Nt):
        u[n+1] = u[n] + dt*(1 - u[n])**p*u[n]
    return u

def BE_logistic(p, u0, dt, Nt, choice='Picard',
                eps_r=1E-3, omega=1, max_iter=1000):
    # u[n] = u[n-1] + dt*(1-u[n])**p*u[n]
    # -dt*(1-u[n])**p*u[n] + u[n] = u[n-1]
    if choice == 'Picard1':
        choice = 'Picard'
        max_iter = 1

    u = np.zeros(Nt+1)
    iterations = []
    u[0] = u0
    for n in range(1, Nt+1):
        c = -u[n-1]
        if choice == 'Picard':
            def F(u):
                return -dt*(1-u)**p*u + u + c

            u_ = u[n-1]
            k = 0
            while abs(F(u_)) > eps_r and k < max_iter:
                # u*(1-dt*(1-u_)**p) + c = 0
                u_ = omega*(-c/(1-dt*(1-u_)**p)) + (1-omega)*u_
                k += 1
            u[n] = u_
            iterations.append(k)

        elif choice == 'Newton':
            def F(u):
                return -dt*(1-u)**p*u + u + c

            def dF(u):
                return dt*p*(1-u)**(p-1)*u - dt*(1-u)**p + 1

            u_ = u[n-1]
            k = 0
            while abs(F(u_)) > eps_r and k < max_iter:
                u_ = u_ - F(u_)/dF(u_)
                k += 1
            u[n] = u_
            iterations.append(k)
    return u, iterations

def CN_logistic(p, u0, dt, Nt):
    # u[n+1] = u[n] + dt*(1-u[n])**p*u[n+1]
    # (1 - dt*(1-u[n])**p)*u[n+1] = u[n]
    u = np.zeros(Nt+1)
    u[0] = u0
    for n in range(0, Nt):
        u[n+1] = u[n]/(1 - dt*(1 - u[n])**p)
    return u

def test_asymptotic_value():
    T = 100
    dt = 0.1
    Nt = int(round(T/float(dt)))
    u0 = 0.1
    p = 1.8

    u_CN = CN_logistic(p, u0, dt, Nt)
    u_BE_Picard, iter_Picard = BE_logistic(
        p, u0, dt, Nt, choice='Picard',
        eps_r=1E-5, omega=1, max_iter=1000)
    u_BE_Newton, iter_Newton = BE_logistic(
        p, u0, dt, Nt, choice='Newton',
        eps_r=1E-5, omega=1, max_iter=1000)
    u_FE = FE_logistic(p, u0, dt, Nt)

    for arr in u_CN, u_BE_Picard, u_BE_Newton, u_FE:
        expected = 1
        computed = arr[-1]
        tol = 0.01
        msg = 'expected=%s, computed=%s' % (expected, computed)
        print msg
        assert abs(expected - computed) < tol

from scitools.std import *

def demo():
    T = 12
    p = 1.2
    try:
        dt = float(sys.argv[1])
        eps_r = float(sys.argv[2])
        omega = float(sys.argv[3])
    except:
        dt = 0.8
        eps_r = 1E-3
        omega = 1
    N = int(round(T/float(dt)))

    u_FE = FE_logistic(p, 0.1, dt, N)
    u_BE31, iter_BE31 = BE_logistic(p, 0.1, dt, N,
                                    'Picard1', eps_r, omega)
    u_BE3, iter_BE3 = BE_logistic(p, 0.1, dt, N,
                                  'Picard', eps_r, omega)
    u_BE4, iter_BE4 = BE_logistic(p, 0.1, dt, N,
                                  'Newton', eps_r, omega)
    u_CN = CN_logistic(p, 0.1, dt, N)

    print 'Picard mean no of iterations (dt=%g):' % dt, \
          int(round(mean(iter_BE3)))
    print 'Newton mean no of iterations (dt=%g):' % dt, \
          int(round(mean(iter_BE4)))

    t = np.linspace(0, dt*N, N+1)
    plot(t, u_FE, t, u_BE3, t, u_BE31, t, u_BE4, t, u_CN,
         legend=['FE', 'BE Picard', 'BE Picard1', 'BE Newton', 'CN gm'],
         title='dt=%g, eps=%.0E' % (dt, eps_r), xlabel='t', ylabel='u',
         legend_loc='lower right')
    filestem = 'logistic_N%d_eps%03d' % (N, log10(eps_r))
    savefig(filestem + '_u.png')
    savefig(filestem + '_u.pdf')
    figure()
    plot(range(1, len(iter_BE3)+1), iter_BE3, 'r-o',
         range(1, len(iter_BE4)+1), iter_BE4, 'b-o',
         legend=['Picard', 'Newton'],
         title='dt=%g, eps=%.0E' % (dt, eps_r),
         axis=[1, N+1, 0, max(iter_BE3 + iter_BE4)+1],
         xlabel='Time level', ylabel='No of iterations')
    savefig(filestem + '_iter.png')
    savefig(filestem + '_iter.pdf')
    raw_input()

def test_solvers():
    p = 2.5
    T = 5000
    dt = 0.5
    eps_r = 1E-6
    omega_values = [1]
    tol = 0.01
    N = int(round(T/float(dt)))

    for omega in omega_values:
        u_FE = FE_logistic(p, 0.1, dt, N)
        u_BE31, iter_BE31 = BE_logistic(p, 0.1, dt, N,
                                        'Picard1', eps_r, omega)
        u_BE3, iter_BE3 = BE_logistic(p, 0.1, dt, N,
                                      'Picard', eps_r, omega)
        u_BE4, iter_BE4 = BE_logistic(p, 0.1, dt, N,
                                      'Newton', eps_r, omega)
        u_CN = CN_logistic(p, 0.1, dt, N)

        print u_FE[-1], u_BE31[-1], u_BE3[-1], u_CN[-1]
        for u_x in u_FE, u_BE31, u_BE3, u_CN:
            print u_x[-1]
            assert abs(u_x[-1] - 1) < tol, 'u=%.16f' % u_x[-1]

    """
    t = np.linspace(0, dt*N, N+1)
    plot(t, u_FE, t, u_BE3, t, u_BE31, t, u_BE4, t, u_CN,
         legend=['FE', 'BE Picard', 'BE Picard1', 'BE Newton', 'CN gm'],
         title='dt=%g, eps=%.0E' % (dt, eps_r), xlabel='t', ylabel='u',
         legend_loc='lower right')
    filestem = 'tmp_N%d_eps%03d' % (N, log10(eps_r))
    savefig(filestem + '_u.png')
    savefig(filestem + '_u.pdf')
    """

if __name__ == '__main__':
    #demo()
    #test_solvers()
    test_asymptotic_value()


import numpy as np

# Initial conditon

def u0(x): return (x*(1-x))

#Exact Solution

def u(x, t): return 8*np.sin(np.pi*x)*np.exp(-t*np.pi**2)/np.pi**3

# Discretization parameters

J = 24;  dx = 1.0 / J;  x = np.linspace(0, 1, J+1)
T = 0.1;  N = 24;  dt = T / N;  mu = dt / dx**2
theta =1./2

# Build the system matrix

a = (1-theta)*mu*np.ones(J-2);  b = (1-2*(1-theta)*mu)*np.ones(J-1); #theta=1/2 a = 1/2*np one
A = np.diag(a, -1) + np.diag(b, 0) + np.diag(a, 1)

c = -(theta*mu)*np.ones(J-2);  d = (1+2*theta*mu)*np.ones(J-1);
B = np.diag(c, -1) + np.diag(d, 0) + np.diag(c, 1)

# Initialize the solution vectors

Uold = u0(x[1:J]);  Unew = np.zeros(J-1)

# Time stepping
#B*Unew = A*Uold

for n in range(N):
    Unew = np.linalg.solve(B, A.dot(Uold))
    for j in range(J-1):
         Uold[j] = Unew[j]
    print(Unew)

Ex2-Finite Difference Methods for the heat equation-Theta Methods/Code+Report/theta.py


import numpy as np

# Create a 3D tensor from lists
tensor_from_lists = np.array([
    [[1, 2], [3, 4]],
    [[5, 6], [7, 8]],
    [[9, 10], [11, 12]],
])
print(f'\n3D tensor from list:\n{tensor_from_lists}')

# Create an array with 100 values between 6 and 9
array = np.linspace(start=6, stop=9, num=100)
print(f'\nArray with 100 values between 6 and 9:\n{array}')

# Reuse the previous array base with pi values
reused_array = np.full_like(a=array, fill_value=np.pi)
print(f'\nReusing previous array base with pi values:\n{reused_array}')

# Create 1D array with 10,000 random numbers
vector_with_10000_random_numbers = np.random.randn(10000)
print(f'\nVector with 10,000 random numbers:\n{vector_with_10000_random_numbers}')


# -*- coding: utf-8 -*-
"""
Created on Fri Sep 27 10:01:04 2019

@author: hamil
"""

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

#Define a function to calculate the integral by random sampling (pond idea)
def Probint(N, initial, final, limit):
    topx = []
    topy = []
    botx = []
    boty = []
    N_out = N
    #for each iteration, randomly generate the x and y values and calculate actual x**2 value
    for n in range(N):
        x = rand.uniform(initial,final)
        y = rand.uniform(initial,limit)
        y2 = x**2
        #determine which is greater and append to correct array
        if y > y2:
            N_out = N_out - 1
            topx.append(x)
            topy.append(y)
            #top_array = [x,y]
        elif y < y2:
            botx.append(x)
            boty.append(y)
            #bot_array = [x,y2]
    #calculate the total number of points and the results
    ratio = N_out/N
    area = final*limit
    results = area*ratio
    return results, topx,topy,botx,boty

test1, topx,topy,botx,boty = Probint(1000000, 0, 10, 100)
print("The estimated value for (x**2) is:", test1)
plt.scatter(topx, topy, s=2, color = 'green')
plt.scatter(botx, boty, s=2, color = 'blue')
plt.title("Distrubition of values for Integral of X**2")
plt.show()

#With 100,000 iterations, my function was able to get around a reasonable answer for
#for the integral of x**2 from 0 to 10. Even better result occurred with 1 million iterations.
#This is a reasonable value for the fact that it is
#calculated from randomly generated numbers. But it is interesting that you can use the distributation
#function to determine the integral of a function. Based on the fact that we have a correlation to
#area.

#Now use the function to calculate the integral for sin(x)
def Probint2(N, initial, final, up_limit, down_limit):
    topx = []
    topy = []
    botx = []
    boty = []
    N_out = N
    for n in range(N):
        x = rand.uniform(initial,final)
        y = rand.uniform(initial,up_limit)
        y2 = np.sin(x)
        if (y < y2) and (y >= 0) or (y > y2) and (y <= 0):
            topx.append(x)
            topy.append(y)
            N_out = N - 2
        else:
            botx.append(x)
            boty.append(y)
    tot_top = len(topy)
    tot_bot = len(boty)
    ratio = N/N_out
    lowx = np.min(botx)
    highx = np.max(botx)
    lowy = np.min(boty)
    highy = np.max(boty)
    xvalue = highx+lowx
    yvalue = highy+lowy
    area = xvalue*yvalue
    result = area*ratio
    return result, topx,topy,botx,boty

test2, toppx, toppy, bottx, botty = Probint2(1000000, -2*np.pi, 2*np.pi, 1, -1)
print("The estimated value for sin(x) is:", test2)
plt.scatter(toppx, toppy, s=2, color = 'purple')
plt.scatter(bottx, botty, s=2, color = 'pink')
plt.title("Distrubition of Values for Integral of sin(x)")
plt.ylim(-1,1)
plt.show()

#Here when looking at the calculated value from my function compared to the analytical value,
#my result is smaller by a couple orders of magnitude. It is close,but not quite there. I do not
#believe the function will be able to accurately calculate the integral of sin(x) from 0 to 10.
#With one million iterations alreasy, I do not know how feasible this method would be to precisely
#calculate the value. It is a good estimation though. But, the variation of the results for several runs,
#creates too much uncertainity. Some of the results are outside of pershaps two dtandard deviations.

#Now create a new function to calculate the integral of.
def Probint3(N, initial, final, up_limit):
    topx = []
    topy = []
    botx = []
    boty = []
    N_out = N
    for n in range(N):
        x = rand.uniform(initial,final)
        y = rand.uniform(initial,up_limit)
        y2 = np.exp(x**3)+ (2*x**2)+3
        if (y < y2) and (y >= 0) or (y > y2) and (y <= 0):
            topx.append(x)
            topy.append(y)
            N_out = N - 2
        else:
            botx.append(x)
            boty.append(y)
    tot_top = len(topy)
    tot_bot = len(botx)
    ratio = N/N_out
    area = up_limit*tot_bot
    #area = xvalue*yvalue
    result = area*ratio
    return result, topx,topy,botx,boty

test3, tx, ty, bx, by = Probint3(1000000, -10, 10, 500)
print("The estimated value of (e**(x**3)+ 2x**2 + 3) is:", test3)
plt.scatter(tx, ty, s=2, color = 'pink')
plt.scatter(bx, by, s=2, color = 'blue')
plt.title("Distrubition of Values for Integral of (e**(x**3)+2x**2+3)")
plt.show()


"""
Use Gaussian distributions to randomly generate two sets. Then use bhatta_dist() on the sets. Compare the results to the
 theoretical Bhattacharyya distance for the distributions.

The Bhattacharyya distance between two Gaussian distributions is given on this page:
  https://en.wikipedia.org/wiki/Bhattacharyya_distance

Created on 4/17/2018
Author: Eric Williamson (ericpaulwill@gmail.com)
"""

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde
from bhatta_dist import bhatta_dist

###We will generate our distributions from these parameters:
sigma1 = 0.5 #standard deviation
mu1 = 2.0    #mean
n1 = 5000    #population size
sigma2 = 1.5
mu2 = 3.1
n2 = 10000

###Calculate theoretical Bhattacharyya distance:
var1 = sigma1**2
var2 = sigma2**2
bdist_theory = np.log( (var1/var2 + var2/var1 + 2)/4 ) / 4  +  (mu1-mu2)**2 / (var1+var2) / 4

###Generate random data that follows our normal distributions:
X1 = np.random.normal(mu1,sigma1,n1)
X2 = np.random.normal(mu2,sigma2,n2)

###Plot distributions of X1 and X2 to verify that we generated the data we want:
def get_density(x,cov_factor=0.1):
    #Produces a continuous density function for the data in 'x'. Some benefit may be gained from adjusting the cov_factor.
    #Note that cov_factor is not related to scaling or bias.
    density = gaussian_kde(x)
    density.covariance_factor = lambda:cov_factor
    density._compute_covariance()
    return density
N_STEPS = 200
d1 = get_density(X1)
d2 = get_density(X2)
xs = np.linspace(0,10,N_STEPS)
fig, ax = plt.subplots()
p1 = np.exp(-((xs-mu1)**2) / (2*var1)) / np.sqrt(2*np.pi*var1)
p2 = np.exp(-((xs-mu2)**2) / (2*var2)) / np.sqrt(2*np.pi*var2)
ax.plot(xs,d1(xs))
ax.plot(xs,d2(xs))
ax.plot(xs,p1)
ax.plot(xs,p2)
ax.legend(['X1 density','X2 density','theoretical 1','theoretical 2'])
plt.show()

###Use bhatta_dist() function to calculate Bhattacharyya distance:
#Note that the 'noiseless' method is not tested here, since the feature we've generated is quantitative.
bdist_cont = bhatta_dist(X1,X2,method='continuous')
bdist_hist = bhatta_dist(X1,X2,method='hist')
bdist_ahist = bhatta_dist(X1,X2,method='autohist')
#Show results:
print("Theoretical:       {:.3f}".format(bdist_theory))
print("Test 'continuous': {:.3f}   Error: {:.6f}".format(bdist_cont, bdist_cont-bdist_theory))
print("Test 'hist':       {:.3f}   Error: {:.6f}".format(bdist_hist, bdist_hist-bdist_theory))
print("Test 'autohist':   {:.3f}   Error: {:.6f}".format(bdist_ahist, bdist_ahist-bdist_theory))

###Test 'noiseless' method by binning the values first (makes no sense for a real dataset, just for testing):
cX = np.concatenate((X1,X2))
N_BINS = 20
h1 = np.histogram(X1,bins=N_BINS,range=(min(cX),max(cX)), density=False)[0]
h2 = np.histogram(X2,bins=N_BINS,range=(min(cX),max(cX)), density=False)[0]
fakeX1 = []
fakeX2 = []
for i in range(N_BINS):
    fakeX1 += [i] * h1[i]
    fakeX2 += [i] * h2[i]
bdist_nl = bhatta_dist(fakeX1,fakeX2,method='noiseless')
print("Test 'noiseless':  {:.3f}   Error: {:.6f}".format(bdist_nl, bdist_nl-bdist_theory))


#!/usr/bin/env python3

import numpy as np
import sys,os,time
import math

def rand_double(N):
	return np.random.randint(0,N)/(N)

def random_walk_one_dimension(data, pleft, steps, wks):
	for wk in range(wks):
		x=0
		for ith in range(steps):
			rate=np.random.rand()
			if rate <= pleft:
				x=x+1
			else:
				x=x-1
			data[ith]+=x**2
	for ith in range(steps):
		data[ith]=data[ith]/wks

def random_walk_two_dimension(data, r1, r2, r3, steps, wks):
	for wk in range(wks):
		x=0
		y=0
		for ith in range(steps):
			rate=np.random.rand()
			if rate <= r1:
				x=x+1
			if r1< rate <= r2:
				x=x-1
			if r2<rate <= r3:
				y=y+1
			if rate > r3:
				y=y-1
			data[ith]+=x**2+y**2
	for ith in range(steps):
		data[ith]=data[ith]/wks

def random_walk_three_dimension(data, x1, x2, x3, x4, x5, steps, wks):
	for wk in range(wks):
		x=0
		y=0
		z=0
		for ith in range(steps):
			rate=np.random.rand()
			if 0<rate < x1:
				x=x+1
			if x1<=rate < x2:
				x=x-1
			if x2<=rate < x3:
				y=y+1
			if x3<=rate<x4:
				y=y-1
			if x4<=rate<x5:
				z=z+1
			if rate>=x5:
				z=z-1
			data[ith]+=x**2+y**2+z**2
	for ith in range(steps):
		data[ith]=data[ith]/wks

def random_walk_n_dimension(data, pleft, steps, wks, n):
	for wk in range(wks):
		x=0
		for ith in range(steps):
			rate=np.random.rand()
			if rate <= pleft:
				x=x+1
			else:
				x=x-1
			data[ith]+=x**2
	for ith in range(steps):
		data[ith]=data[ith]/wks

if __name__=="__main__":

	walkers=10000
	steps=100
	#  pleft=0.5
	pleft=float(sys.argv[1])
	#  steps=int(sys.argv[1])
	data=np.zeros(steps,float)
	data2=np.zeros(steps,float)
	data3=np.zeros(steps,float)
	random_walk_one_dimension(data, 0.5, steps, walkers)
	random_walk_two_dimension(data2, 0.25, 0.5, 0.75, steps, walkers)
	random_walk_three_dimension(data3, 1/6, 2/6, 3/6, 4/6, 5/6, steps, walkers)
	with open("rand.txt","w") as out:
		for i in range(steps):
			#  print("{}  {}".format(i, math.sqrt(data[i])))
			out.write("{}  {} {}  {}\n".format(i, data[i], data2[i], data3[i]))


import pandas as pd
import pandas
import numpy as np
#provide local path
testfile='../input/test.csv'
data = open(testfile).readlines()

sequences={}   #(key, value) = (id , sequence)
for i in range(1,len(data)):
    line=data[i]
    line =line.replace('"','')
    line = line[:-1].split(',')
    id = int(line[0])
    sequence=[int(x) for x in line[1:]];
    sequences[id]=sequence

# In[ ]:

def checkRecurrence(seq, order= 2, minlength = 7):
    """
    :type seq: List[int]
    :type order: int
    :type minlength: int
    :rtype: List[int]

    Check whether the input sequence is a recurrence sequence with given order.
    If it is, return the coefficients for the recurrenec relation.
    If not, return None.
    """
    if len(seq)< max((2*order+1), minlength):
        return None

    ################ Set up the system of equations
    A,b = [], []
    for i in range(order):
        A.append(seq[i:i+order])
        b.append(seq[i+order])
    A,b =np.array(A), np.array(b)
    try:
        if np.linalg.det(A)==0:
            return None
    except TypeError:
        return None

    #############  Solve for the coefficients (c0, c1, c2, ...)
    coeffs = np.linalg.inv(A).dot(b)

    ############  Check if the next terms satisfy recurrence relation
    for i in range(2*order, len(seq)):
        predict = np.sum(coeffs*np.array(seq[i-order:i]))
        if abs(predict-seq[i])>10**(-2):
            return None

    return list(coeffs)

def predictNextTerm(seq, coeffs):
    """
    :type seq: List[int]
    :type coeffs: List[int]
    :rtype: int

    Given a sequence and coefficienes, compute the next term for the sequence.
    """

    order = len(coeffs)
    predict = np.sum(coeffs*np.array(seq[-order:]))
    return int(round(predict))

# ## Example: ##
# * Given a sequence [1,5,11,21,39,73,139,269,527].
# * We verify if it's 3rd order recurrence sequence and find the coefficients (2,-5,4).
# * We then predict the next term using the last 3 terms and the relation $a_{n+3} = 2a_{n}-5a_{n+1}+4a_{n+2}$.

# In[ ]:

seq = [1,5,11,21,39,73,139,269,527]
print (checkRecurrence(seq,3))
print (predictNextTerm(seq, [2,-5,4]))

# # Find 2nd order sequeneces in the test set #

# In[ ]:

order2Seq={}   #(key, value) = (sequence id, [prediction, coefficients])
for id in sequences:
    seq = sequences[id]
    coeff = checkRecurrence(seq,2)
    if coeff!=None:
        predict = predictNextTerm(seq, coeff)
        order2Seq[id]=(predict,coeff)

print ("We found %d sequences\n" %len(order2Seq))

print  ("Some examples\n")
print ("ID,  Prediction,  Coefficients")
for key in sorted(order2Seq)[0:5]:
    value = order2Seq[key]
    print ("%s, %s, %s" %(key, value[0], [int(round(x)) for x in value[1]]))

# # Find 3rd order sequeneces in the test set #

# In[ ]:

order3Seq={}
for id in sequences:
    if id in order2Seq:
        continue
    seq = sequences[id]
    coeff = checkRecurrence(seq,3)
    if coeff!=None:
        predict = predictNextTerm(seq, coeff)
        order3Seq[id]=(predict,coeff)

print ("We found %d sequences\n" %len(order3Seq))

print  ("Some examples\n")
print ("ID,  Prediction,  Coefficients")
for key in sorted(order3Seq)[0:5]:
    value = order3Seq[key]
    print ("%s, %s, %s" %(key, value[0], [int(round(x)) for x in value[1]]))

# # Find 4th order sequeneces in the test set #

# In[ ]:

order4Seq={}
for id in sequences:
    if id in order2Seq or id in order3Seq:
        continue
    seq = sequences[id]
    coeff = checkRecurrence(seq,4)
    if coeff!=None:
        predict = predictNextTerm(seq, coeff)
        order4Seq[id]=(predict,coeff)

print ("We found %d sequences \n" %len(order4Seq))
print  ("Some examples\n")
print ("ID,  Prediction,  Coefficients")
for key in sorted(order4Seq)[4:5]:
    value = order4Seq[key]
    print ("%s, %s, %s" %(key, value[0], [int(round(x)) for x in value[1]]))

print (sequences[239][0:17])

# ## Recurrence relations not included in OEIS ##
# In the previous cells,
#     * We find that Sequence 239 is a 4th order sequence and predict the next term as 5662052980.
#     * We check OEIS https://oeis.org/A000773, which confirms the prediction is correct.
#     * We observe that this recurrence relation is not described in OEIS. (There are more such sequences.)

# In[ ]:

print("Conclusion:")
print("Number of sequences in the test set:", len(sequences))
print("Number of 2nd order sequences:", len(order2Seq))
print("Number of 3rd order sequences:", len(order3Seq))
print("Number of 4th order sequences:", len(order4Seq))


import numpy as np

import scipy
from scipy.stats import pearsonr
from scipy.spatial.distance import pdist, squareform

import sklearn
from sklearn.linear_model import LinearRegression

def pcorr(x1,x2,y):
    """
    Computes the (signed square-root of) proportion of variance (r^2) in y that is uniquely explained
    by x1, uniquely explained by x2, or simultaneously explained by x1 and x2
    (intersection). These signed r values are returned respectively in
    unique_x1_r, unique_x2_r and inter_r.
    In terms of a venn diagram with 3 circles representing x1, x2 and y, the 3
    outputs represent the 3 separate regions of overlap with y.
    """
    x1x2   = np.concatenate([x1, x2], axis=1)
    lm1    = LinearRegression().fit(x1, y)
    lm2    = LinearRegression().fit(x2, y)
    lmboth = LinearRegression().fit(x1x2, y)

    x1_r2    = lm1.score(x1,y)
    x2_r2    = lm2.score(x2,y)
    union_r2 = lmboth.score(x1x2,y)
    inter_r2 = max(x1_r2 + x2_r2 - union_r2, 0)

    unique_x1_r2 = x1_r2 - inter_r2
    unique_x2_r2 = x2_r2 - inter_r2

    inter_r     = np.sqrt(inter_r2)
    unique_x1_r = np.sqrt(np.maximum(0, unique_x1_r2)) * np.sign(lmboth.coef_[0])
    unique_x2_r = np.sqrt(np.maximum(0, unique_x2_r2)) * np.sign(lmboth.coef_[1])

    # if np.count_nonzero(np.sign(lmboth.coef_[0]) != np.sign(lmboth.coef_[1])) != 0:
    #     print("Unequal sign")
    #     raise Exception("Unequal sign")

    return unique_x1_r, unique_x2_r, inter_r

def get_rdm(vectors, distance='correlation'):
    """
    Computes the rdm of the given vectors using the specified distance.
    """
    rdm = pdist(vectors, distance)
    if not np.any(np.isnan(rdm)):
        return pdist(vectors, distance)
    else:
        raise ValueError('Found some NaNs in the RDM')

def calculate_noise_ceilings(all_rdms,corr_func=pearsonr):
    """
    Calcuilate the lower noise ceilings for each subject.
    """
    total_nums = len(all_rdsm)

    all_corrs = []
    for each_sub in range(1,total_nums+1):
        sub_rdm = all_rdms[each_sub-1]
        other_rdms = [all_rdms[x-1] for x in range(1,total_nums+1) if x!=each_sub]
        assert len(other_rdms)== (total_nums - 1)

        all_corrs.append(np.array([corr_func(x,sub_rdm)[0] for x in other_rdms]).mean())

    assert len(all_corrs) == total_nums
    upper_ceiling = np.array(all_corrs)

    # mean = upper_ceiling.mean()
    # sem = scipy.stats.sem(upper_ceiling)
    # return mean,sem

    return upper_ceiling


import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('messi5.jpg',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))

plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

img = cv2.imread('messi5.jpg',0)
rows, cols = img.shape
crow,ccol = rows/2 , cols/2
fshift[crow-30:crow+30, ccol-30:ccol+30] = 0
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)
img_back = np.abs(img_back)

plt.subplot(131),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(img_back, cmap = 'gray')
plt.title('Image after HPF'), plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(img_back)
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])

plt.show()

# Fourier Transform in OpenCV
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('messi5.jpg',0)

dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))

plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

rows, cols = img.shape
crow,ccol = rows/2 , cols/2

# create a mask first, center square is 1, remaining all zeros
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1

# apply mask and inverse DFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])

plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

OpenCV Python/4. Image Processing/11. Image Transforms/fourier-transform.py


import scipy
import numpy
import matplotlib.pyplot as plt
import sympy
#puntos a interpolar
A= numpy.array([-3, -1 , 2, 4])
B= numpy.array([0, 4, 3, 1])

#array de polinomios
#polinomio = numpy.array([0, 0])
x = sympy.symbols("x")
##### lagrange en x , y
def base_coef(j , pts, A ):
        alfa = 1
        for i in range(pts):
            if i is not j:
                alfa = alfa * ( (x- A[i]) / (A[j]-A[i])   )
        return alfa
def Lagrange():
    polinomio = 0
    for r in range(4):
        polinomio = polinomio + base_coef(r,4,A)*B[r]
    return polinomio

poly=Lagrange()
polisimple = sympy.expand(poly)
print(poly)
print(polisimple)
fx = sympy.lambdify(x,poly) # funcion
muestras = 100
a = numpy.min(A)
b = numpy.max(A)
p_xi = numpy.linspace(a,b,muestras)

pfi = fx(p_xi)
#grafica
plt.plot(A,B,'o')
plt.plot(p_xi,pfi)
plt.show()
"""

#funcion de mezcla
 i es el numero de  funcion de corte
    pts es la cantidad de puntos
def mezcla(i , pts ):
        t = sympy.symbols("t")
        alfa = 1
        for k in range(pts):
            if i is not k:
                alfa = alfa * (t-k)/(i-k)
        print(type(alfa))
        return alfa

#calcular el polinomio
for r in range(2):
    for j in range(tamaño_fila):
        alf = mezcla(j,tamaño_fila)  # alf es simbolo se puede
        polinomio[:,r] = alf* x[:,j] +  polinomio[]
print(polinomio[0])
"""


from pathlib import Path
from typing import List, Tuple

import numpy as np
import scipy.io
import tensorly as tl
from tensorly.decomposition import tucker

from tucker.tucker_als import TuckerALS

def compute_relative_error(X: np.ndarray, X_hat: np.ndarray) -> float:
    """Computes the relative Tucker error using the true and approximated tensor

    Parameters
    ----------
    X : np.ndarray
        True tensor
    X_hat : np.ndarray
        Approximated tensor from Tucker decomposition

    Returns
    -------
    float
        Relative error
    """
    signal = 0.0
    error = 0.0

    for k in range(X.shape[2]):
        signal += np.linalg.norm(X[..., k], ord="fro") ** 2
        error += np.linalg.norm(X[..., k] - X_hat[..., k], ord="fro") ** 2

    return error / signal

def compute_tensor_approximation(
    U: np.ndarray,
    V: np.ndarray,
    W: np.ndarray,
    G0: np.ndarray,
    orig_shape: Tuple[int, ...],
) -> np.ndarray:

    X0_hat = U @ G0 @ np.kron(V, W).T
    return tl.fold(X0_hat, 0, orig_shape)

def face_data_comparison(p: Path):
    X: np.ndarray = scipy.io.loadmat(p / "FERETC80A45.mat")["fea2D"] / 255.0

    # Get the Tucker approximation using my version of the ALS algorithm
    t_als = TuckerALS(X, (5, 5, 15))
    U, V, W, G0 = t_als.fit()
    X_hat = compute_tensor_approximation(U, V, W, G0, X.shape)
    relative_error = compute_relative_error(X, X_hat)
    print(f"Faces relative error (my implementation): {relative_error}")

    # Get the TensorLy Tucker approximation for comparison
    G, factors = tucker(X, rank=[5, 5, 15])
    G0 = tl.unfold(G, mode=0)
    X_hat = compute_tensor_approximation(
        factors[0], factors[1], factors[2], G0, X.shape
    )

    relative_error = compute_relative_error(X, X_hat)
    print(f"Faces relative error (TensorLy version): {relative_error}")

def generate_rank_options(num_choices: int, rng) -> List[Tuple[int, ...]]:
    # Assumes 3-way tensors
    r0 = rng.integers(low=1, high=15, size=num_choices)
    r1 = rng.integers(low=2, high=4, size=num_choices)
    r2 = rng.integers(low=2, high=4, size=num_choices)
    return list(zip(r0, r1, r2))

def compute_compression_ratio(
    tensor_shape: Tuple[int, ...], ranks: Tuple[int, ...]
) -> float:

    i, j, k = tensor_shape
    r0, r1, r2 = ranks
    return (i * j * k) / ((i * r0) + (j * r1) + (k * r2) + (r0 * r1 * r2))

def run_own_data_compression_experiment(X: np.ndarray, ranks: Tuple[int, ...]) -> None:
    t_als = TuckerALS(X, ranks, max_iter=200)
    U, V, W, G0 = t_als.fit()
    X_hat = compute_tensor_approximation(U, V, W, G0, X.shape)
    relative_error = compute_relative_error(X, X_hat)
    compression_ratio = compute_compression_ratio(X.shape, ranks)

    msg = f"Rank configuration: {ranks}; Relative Error: {relative_error}; Compression Ratio: {compression_ratio}"
    print(msg)

def compute_svd_approx_matrix_diff(X: np.ndarray, mode: int, rank: int) -> np.ndarray:
    X_mode = tl.unfold(X, mode)
    U, S, Vt = np.linalg.svd(X_mode)

    # Subset the factors based on the rank
    U = U[:, :rank]
    S = np.diag(S[:rank])
    Vt = Vt[:rank, :]

    X_hat = U @ S @ Vt
    return X_mode - X_hat

def compute_svd_error(X: np.ndarray, X_diff: np.ndarray) -> float:
    # First have to compute the "signal" for the original tensor
    signal = 0.0
    for k in range(X.shape[-1]):
        signal += np.linalg.norm(X[..., k], ord="fro") ** 2

    # Next compute the approximation error from the SVD for the unfolding
    error = np.linalg.norm(X_diff, ord="fro") ** 2
    return error / signal

def main():
    p = Path("data")

    face_data_comparison(p)

    # Personal data compression experiment; I'll try various random rank
    # tuples and log the results
    X: np.ndarray = np.load(p / "data.npy")
    run_own_data_compression_experiment(X, (5, 2, 3))

    """
    To now do the SVD approximation we have three unfoldings: X0 = (2000 x (4*10)),
    X1 = (4 x (2000*10)), and X2 = (10 x (2000*4)). Using the Tucker model,
    we're representing the tensor with
    (5 * 2000) + (1 * 4) + (2 * 10) + (5 * 1 * 2) = 10,068 floats.
    So for the three unfoldings we need, X0: 2,040 * r -> r = 5;
    X1: 20,004 * r -> r = 1; X2: 8,010 * r -> r = 2 as the closest approximations
    at the given compression ratio
    """
    # X0 SVD approximation
    X_diff = compute_svd_approx_matrix_diff(X, 0, rank=5)
    relative_error = compute_svd_error(X, X_diff)
    print(f"Mode 0 Relative Error {relative_error}")

    # X1 SVD approximation
    X_diff = compute_svd_approx_matrix_diff(X, 1, rank=1)
    relative_error = compute_svd_error(X, X_diff)
    print(f"Mode 1 Relative Error {relative_error}")

    # X2 SVD approximation
    X_diff = compute_svd_approx_matrix_diff(X, 2, rank=2)
    relative_error = compute_svd_error(X, X_diff)
    print(f"Mode 2 Relative Error: {relative_error}")

    return None

if __name__ == "__main__":
    main()


"""Constraints by half-spaces."""
import numpy as np

from optimus.types import Constraint

class HalfSpace(Constraint):
    """Constraint based on a linear inequality."""

    def __init__(self, vector: np.ndarray, threshold: float):
        """Create consrtaint from the defining vector and threshold.

        This defines the inequality vector.dot(point) <= threshold."""
        self.vector = vector
        self.threshold = threshold

    def project(self, point: np.ndarray) -> np.ndarray:
        dot_product_value = self.vector.dot(point)
        if dot_product_value <= self.threshold:
            return point
        return point - self.vector * (
            dot_product_value - self.threshold
        ) / np.linalg.norm(self.vector)


# SPDX-License-Identifier: MIT
# Copyright (c) 2021 ETH Zurich, Luc Grosheintz-Laval

import numpy as np
import scipy.integrate

from morinth.quadrature import GaussLegendre
from morinth.grid import Grid

def sinusoidal(x):
    x = (x - 10.0)/100.0
    fx = np.sin(2.0*np.pi*x) * np.cos(2.0*np.pi*x)**2
    return fx

def quadrature_error(n_cells, n_points):
    grid = Grid([10.0, 100.0], n_cells, 1)
    integrate = GaussLegendre(n_points)

    fbar = integrate(grid.edges, sinusoidal)
    fref = np.empty(n_cells)

    for i in range(n_cells):
        fref[i], err = scipy.integrate.quadrature(sinusoidal, grid.edges[i], grid.edges[i+1],
                                                  tol = 1e-10, rtol=1e-10)

    fref *= 1.0/grid.dx

    return np.max(np.abs(fbar - fref))

def quadrature_rate(n_points):
    resolutions = np.array([10, 20, 50, 100, 200, 500])
    errors = np.array([quadrature_error(res, n_points) for res in np.nditer(resolutions)])
    rate = np.max(np.abs(np.log(errors[1:]/errors[:-1])/np.log(resolutions[1:]/resolutions[:-1])))

    return rate

def test_quadrature_vs_scipy():
    for n_points in range(1,6):
        empirical = quadrature_rate(n_points)
        order = 2.0*n_points
        assert empirical > order - 0.1, "{:.1f} vs. {:.1f}".format(empirical, float(order))


import numpy as np
from numpy import ndarray

# Function to square an n-dimensional array
def square(x: ndarray) -> ndarray:
    '''
    Square each element in the input ndarray
    '''
    return np.power(x, 2)

def leaky_relu(x: ndarray) -> ndarray:
    '''
    Apply "Leaky Relu" funtion to each element in ndarray
    '''
    return np.maximum(0.2 * x, x)


import unittest
from assembler import GaussRule
from fem import  QuadFE
from mesh import Cell, QuadCell, HalfEdge, Vertex, convert_to_array
import numpy as np
class TestGaussRule(unittest.TestCase):
    """
    Test GaussRule class
    """
    def test_accuracy(self):
        """
        Test the Accuracy of the Gauss rule on the reference cell

        1D Rule: (Interval)
            Number of Nodes: 1,2,3,4,5,6
            Accuracy: 2N-1

        2D Rule (Quadrilateral):
            Number of Nodes: 1,4,9,16,25,36
            Accuracy: (2n-1, 2n-1), where n = sqrt(N)

        TODO: 2D Rule (Triangle)
        """
        #
        # 1D Polynomials and exact integrals
        #
        order_1d = [1,2,3,4,5,6]
        polynomials_1d = {1: lambda x: 2*np.ones(x.shape),
                          2: lambda x: x**3-2*x**2 + x + 1,
                          3: lambda x: x**5 - 2*x**2 + 2,
                          4: lambda x: x**7 + 2*x**6 + 3*x,
                          5: lambda x: x**9 + 3*x**4 + 1,
                          6: lambda x: x**11 - 3*x**8 + 1}

        integrals_1d = {1: 2,
                        2: 13/12,
                        3: 3/2,
                        4: 107/56,
                        5: 17/10,
                        6: 3/4}

        #
        # 2D Polynomials and exact integrals
        #
        order_2d = [1,4,9,16,25,36]

        polynomials_2d = {1: lambda x,y: np.ones(x.shape),
                          4: lambda x,y: x*y + x + y,
                          9: lambda x,y: (x**5 - 2*x**2 + 2)*(y**4- 2*y),
                          16: lambda x,y: (x**7 + 2*x**6 + 3*x)*(y**5 + 2*y**2) ,
                          25: lambda x,y: (x**9 + 3*x**4 + 1)*(y**9 + 3*y**4 + 1),
                          36: lambda x,y: (x**11 - 3*x**8 + 1)*(y**11 + 2*y)
                          }

        integrals_2d = {1: 1,
                        4: 5/4,
                        9: -6/5,
                        16: 535/336,
                        25: 289/100,
                        36: 13/16}

        # Combine information
        order = {1: order_1d, 2: order_2d}
        polynomials = {1: polynomials_1d, 2: polynomials_2d}
        integrals = {1: integrals_1d, 2: integrals_2d}

        #
        # Iterate over dimensions
        #
        for dim in [1,2]:
            element = QuadFE(dim, 'Q1')
            #
            # Iterate over orders
            #
            for n in order[dim]:

                # Define Gauss Rule
                rule = GaussRule(n, element)
                x = rule.nodes()
                w = rule.weights()

                # Compute approximate integral
                f = polynomials[dim][n]
                if dim==1:
                    Ia = np.dot(w, f(x))
                elif dim==2:
                    Ia = np.dot(w, f(x[:,0],x[:,1]))

                # Compute exact integral
                Ie = integrals[dim][n]

                # Compare
                self.assertAlmostEqual(Ia, Ie, 10)

    def test_nodes(self):
        pass

    def test_weights(self):
        pass

    def test_n_nodes(self):
        pass

    def test_map(self):
        pass

    def test_inverse_map(self):
        pass

    def test_jabobian(self):
        pass

    def test_line_integral(self):
        # Define quadrature rule
        rule = GaussRule(2, shape='interval')
        w = rule.weights()
        x_ref = rule.nodes()

        # function f to be integrated over edge e
        f = lambda x,y: x**2*y
        e = HalfEdge(Vertex((0,0)),Vertex((1,1)))

        # Map rule to physical entity
        x_phys, mg = e.reference_map(x_ref, jac_r2p=True)
        jacobian =  mg['jac_r2p']

        x_phys = convert_to_array(x_phys, dim=2)
        fvec = f(x_phys[:,0],x_phys[:,1])

        jac = np.linalg.norm(jacobian[0])
        self.assertAlmostEqual(np.dot(fvec,w)*jac,np.sqrt(2)/4,places=10,\
                               msg='Failed to integrate x^2y.')
        self.assertAlmostEqual(np.sum(w)*jac, np.sqrt(2), places=10,\
                               msg='Failed to integrate 1.')


import numpy as np
from plotData import *
from computeCost import *
from gradientDescent import *

# Test and Valiation data file
filename = './data1.txt'

# Load data from file into a 2-dimentional matrix
data = np.loadtxt(filename, delimiter=',')
m = len(data)

# Now set input and out put variables set as X and y respectively
X = data[:,0]
y = data[:,1]

# Now plot data
print('\nPloting data to view correlation between x and y values...\n')
#plotData(X, y)
plt.style.use('seaborn-whitegrid')
fig = plt.figure()
ax = plt.axes()
plt.scatter(X, y)
# display here as needed to get an idea of the pattern and help decide the ML algorithm to use
# plt.show()

input('Press ENTER to continue...')

# Calculate Cost Function
d = np.ones((m))
X = np.column_stack((d, X))
theta = np.array([0, 0])
# theta = np.zeros((2, 1))
# theta = [-1 , 2]
print('\nTesting the cost function ...\n')
J = computeCost(X, y, theta)  # compute and display initial cost
print('J= ', J)

input('Press ENTER to continue...')

# Some gradient descent settings
iterations = 1500
alpha = 0.01

# run gradient descent
print('\nRunning Gradient Descent ...\n')
theta = gradientDescent(X, y, theta, alpha, iterations)

print('Theta = ', theta)

input('Press ENTER to continue...')

# Plot the linear fit
#hold on; % keep previous plot visible
#plotData(X[:,1], X@theta)
lines = plt.scatter(X[:,1], X@theta)
plt.setp(lines, color='r', linewidth=2.0)
#legend('Training data', 'Linear regression')
#hold off % don't overlay any more plots on this figure

plt.show()


import numpy as np

# sigmoid function
def nonlin(x, deriv=False):
    if(deriv==True):
        return x*(1-x)
    return 1/(1+np.exp(-x))

# input dataset
X = np.array([  [0,0,1],
                [0,1,1],
                [1,0,1],
                [1,1,1] ])                  # 4x3

# output dataset
y = np.array([[0,0,1,1]]).T                 # 4x1

# seed random numbers to make calculation
# deterministic (just a good practice)
np.random.seed(1)

# initialize weights randomly with mean 0
syn0 = 2*np.random.random((3,1)) - 1        # 3x1 ranging [-1,1)

for iter in xrange(10000):

    # forward propagation
    l0 = X
    l1 = nonlin(np.dot(l0,syn0))            # 4x1

    # how much did we miss?
    l1_error = y - l1

    # element wise multiply how much we missed by the
    # slope of the sigmoid at the values in l1
    l1_delta = l1_error * nonlin(l1,True)   # 4x1

    # update weights with backpropagation
    syn0 += np.dot(l0.T,l1_delta)           # 3x1

print "Output After Training: \n", l1
print "Weight values: \n", syn0

'''
Output After Training:
[[0.00966449]
 [0.00786506]
 [0.99358898]
 [0.99211957]]
Weight values:
[[ 9.67299303]
 [-0.2078435 ]
 [-4.62963669]]
'''


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

# var.py

from __future__ import print_function

import datetime

import numpy as np
import pandas.io.data as web
from scipy.stats import norm

def var_cov_var(P, c, mu, sigma):
    """
    Variance-Covariance calculation of daily Value-at-Risk
    using confidence level c, with mean of returns mu
    and standard deviation of returns sigma, on a portfolio
    of value P.
    """
    alpha = norm.ppf(1-c, mu, sigma)
    return P - P*(alpha + 1)

if __name__ == "__main__":
    start = datetime.datetime(2010, 1, 1)
    end = datetime.datetime(2014, 1, 1)

    citi = web.DataReader("C", 'yahoo', start, end)
    citi["rets"] = citi["Adj Close"].pct_change()

    P = 1e6   # 1,000,000 USD
    c = 0.99  # 99% confidence interval
    mu = np.mean(citi["rets"])
    sigma = np.std(citi["rets"])

    var = var_cov_var(P, c, mu, sigma)
    print("Value-at-Risk: $%0.2f" % var)


# -*- coding: utf-8 -*-
"""
Python Script
Created on  Sunday August 2017 10:17:41
@author:  Mahmoud AbdelRahman

[desc]
The sklearn.linear_model module implements generalized linear models.
It includes Ridge regression, Bayesian Regression, Lasso and Elastic Net estimators
computed with Least Angle Regression and coordinate descent.
It also implements Stochastic Gradient Descent related algorithms.
[/desc]

ARGUMENTS:
----------
    <inp> _data :
        data </inp>
    <inp>_target :
        target </inp>
    <inp>_features :
        features </inp>
    <inp>_predict :
        predict </inp>
    <inp>_algorithm : [optional] - [int] - [12]

        Linear Model algorithm
        Default is 12 i.e. LinearRegression

            Options:

                1-> ARDRegression ---- Bayesian ARD regression.
                2-> BayesianRidge ---- Bayesian ridge regression
                3-> ElasticNet ---- Linear regression with combined L1 and L2 priors as regularizer.
                4-> ElasticNetCV ---- Elastic Net model with iterative fitting along a regularization path
                5-> Lars ---- Least Angle Regression model a.k.a.
                6-> LarsCV ---- Cross-validated Least Angle Regression model
                7-> Lasso ---- Linear Model trained with L1 prior as regularizer (aka the Lasso)
                8-> LassoCV ---- Lasso linear model with iterative fitting along a regularization path
                9-> LassoLars ---- Lasso model fit with Least Angle Regression a.k.a.
                10-> LassoLarsCV ---- Cross-validated Lasso, using the LARS algorithm
                11-> LassoLarsIC ---- Lasso model fit with Lars using BIC or AIC for model selection
                12-> LinearRegression ---- Ordinary least squares Linear Regression.
                13-> LogisticRegression ---- Logistic Regression (aka logit, MaxEnt) classifier.
                14-> LogisticRegressionCV ---- Logistic Regression CV (aka logit, MaxEnt) classifier.
                15-> MultiTaskLasso ---- Multi-task Lasso model trained with L1/L2 mixed-norm as regularizer
                16-> MultiTaskElasticNet ---- Multi-task ElasticNet model trained with L1/L2 mixed-norm as regularizer
                17-> MultiTaskLassoCV ---- Multi-task L1/L2 Lasso with built-in cross-validation.
                18-> MultiTaskElasticNetCV ---- Multi-task L1/L2 ElasticNet with built-in cross-validation.
                19-> OrthogonalMatchingPursuit ---- Orthogonal Matching Pursuit model (OMP)
                20-> OrthogonalMatchingPursuitCV ---- Cross-validated Orthogonal Matching Pursuit model (OMP)
                21-> PassiveAggressiveClassifier ---- Passive Aggressive Classifier
                22-> PassiveAggressiveRegressor ---- Passive Aggressive Regressor
                23-> Perceptron ---- Read more in the User Guide.
                24-> RandomizedLasso ---- Randomized Lasso.
                25-> RandomizedLogisticRegression ---- Randomized Logistic Regression
                26-> RANSACRegressor ---- RANSAC (RANdom SAmple Consensus) algorithm.
                27-> Ridge ---- Linear least squares with l2 regularization.
                28-> RidgeClassifier ---- Classifier using Ridge regression.
                29-> RidgeClassifierCV ---- Ridge classifier with built-in cross-validation.
                30-> RidgeCV ---- Ridge regression with built-in cross-validation.
                31-> SGDClassifier ---- Linear classifiers (SVM, logistic regression, a.o.) with SGD training.
                32-> SGDRegressor ---- Linear model fitted by minimizing a regularized empirical loss with SGD
                33-> TheilSenRegressor ---- Theil-Sen Estimator: robust multivariate regression model.
                34-> lars_path ---- Compute Least Angle Regression or Lasso path using LARS algorithm [1]
                35-> lasso_path ---- Compute Lasso path with coordinate descent
                36-> lasso_stability_path ---- Stability path based on randomized Lasso estimates
                37-> logistic_regression_path ---- Compute a Logistic Regression model for a list of regularization parameters.
                38-> orthogonal_mp ---- Orthogonal Matching Pursuit (OMP)
                39-> orthogonal_mp_gram ---- Gram Orthogonal Matching Pursuit (OMP)
    </inp>
    <inp>_parameters_ : [optional]
        Parameters of the Linear models - if omitted, it will be set to default values</inp>

RETURN:
    log_ = output log
    output_ = predict Data
    score_ score value
"""

import numpy as np
import pickle

_data = np.array(_data)
_target = np.array(_target)

def main( _data, _target, _features, _predict, _algorithm = 12):
    ''' This is the main function '''
    allModels = {1:"ARDRegression",                 2:"BayesianRidge",                  3:"ElasticNet",                     4:"ElasticNetCV",
                 5:"Lars",                          6:"LarsCV",                         7:"Lasso",                          8:"LassoCV",
                 9:"LassoLars",                     10:"LassoLarsCV",                   11:"LassoLarsIC",                   12:"LinearRegression",
                 13:"LogisticRegression",           14:"LogisticRegressionCV",          15:"MultiTaskLasso",                16:"MultiTaskElasticNet",
                 17:"MultiTaskLassoCV",             18:"MultiTaskElasticNetCV",         19:"OrthogonalMatchingPursuit",     20:"OrthogonalMatchingPursuitCV",
                 21:"PassiveAggressiveClassifier",  22:"PassiveAggressiveRegressor",    23:"Perceptron",                    24:"RandomizedLasso",
                 25:"RandomizedLogisticRegression", 26:"RANSACRegressor",               27:"Ridge",                         28:"RidgeClassifier",
                 29:"RidgeClassifierCV",            30:"RidgeCV",                       31:"SGDClassifier",                 32:"SGDRegressor",
                 33:"TheilSenRegressor",            34:"lars_path",                     35:"lasso_path",                    36:"lasso_stability_path",
                 37:"logistic_regression_path",     38:"orthogonal_mp",                 39:"orthogonal_mp_gram"}
    try:
        exec("from sklearn.linear_model import "+ allModels[_algorithm]+"\n"
             + "log = "+ allModels[_algorithm]+".__doc__")

        exec("model = "+allModels[_algorithm]+"()")
        try:
            model.fit(_data, _target)
            prediction = model.predict(_predict)
            score = model.score(_data, _target)
        except:
            f1 = open(_data, 'r')
            f2 = open(_target, 'r')
            data1 = f1.read()
            target1 = f2.read()
            f1.close()
            f2.close()
            model.fit(pickle.loads(data1), pickle.loads(target1))
            prediction = model.predict(_predict)
            score = model.score(pickle.loads(data1),pickle.loads(target1))

    except Exception as e:
        print str(e)

    return [log, prediction, score]

if(_data != None and _target!= None and _predict!=None):
    if (_algorithm == None):
        _algorithm = 12

    log_, output_, score_ = main( _data, _target, _features,_predict, _algorithm)
else:
    print "Please Complete all the required data"


import numpy as np
import matplotlib.pyplot as plt

#class Orthogonal_Polinomyals:

def Hermite(x2, n):

	if n==0:

		return np.ones(len(x2))

	elif n==1:

		return 2*x2

	else:

		return 2*x2*Hermite(x2,n-1)-2*(n-1)*Hermite(x2,n-2)

def Legendre(x, n):

	if n == 0:

		return np.ones(len(x))

	elif n == 1:

		return x

	else:

		return  (( x*(1+ 2*(n-1))*Legendre(x, n - 1) - (n-1)*Legendre(x, n - 2) )/(n))

x = np.linspace(-1,1,1001)

for i in range(6):

	plt.plot(x, Legendre(x, i), label = f"$P_{i}$")

plt.title("Polinomios de Legendre")
plt.grid() ; plt.legend()
plt.show()


from pyomo.environ import *

model = ConcreteModel()

model.y = Var([1,2,3], within=Binary)
model.z = Var([1,2,3], within=NonNegativeReals)

model.obj = Objective(expr=12*model.y[1]+20*model.y[2]+15*model.y[3]-8*model.z[1]-6*model.z[2]+2*model.z[3], sense=minimize)

model.constraint1 = Constraint(expr=10*model.y[1]+8*model.y[2]-2*model.z[1]-model.z[2]+model.z[3]>=4)
model.constraint2 = Constraint(expr=5*model.y[1]+8*model.y[3]-model.z[1]-model.z[2]-model.z[3]>=3)
model.constraint3 = Constraint(expr=model.y[1]+model.y[2]+model.y[3]>=1)

### SOLVE
solver_manager = SolverFactory('glpk')

results = solver_manager.solve(model)

print(model.display())