# some useful utilities

import numpy as np
from functools import reduce
from operator import add

def vec_norm_1(vec):
	return max(np.abs(elem) for elem in vec)

def vec_norm_2(vec):
	return sum(np.abs(elem) for elem in vec)

def vec_norm_3(vec):
	return np.sqrt(sum(elem ** 2 for elem in vec))

def mrx_norm_1(A):
	return max([vec_norm_2(row) for row in A])

def condition_number(A, mrx_norm=mrx_norm_1):
	return mrx_norm(A) * mrx_norm(np.linalg.inv(A))

# returns (signed) eigen value, which has the maximum abs value
def maxabs_eigen_value(A, niterations = 100):
	nrows, ncolumns =  A.shape
	assert nrows == ncolumns

	def next_iteration(A, u):
		Au = np.matmul(A, u)
		return Au / vec_norm_1(Au)

	u = np.ones(nrows)
	for i in range(niterations):
		u = next_iteration(A, u)
	return np.dot(np.matmul(A, u), u) / np.dot(u, u)

def minabs_eigen_value(A, niterations = 100):
	return 1 / maxabs_eigen_value(np.linalg.inv(A))


from sympy import Symbol, integrate, oo, simplify
import math
t = Symbol('t')

ex = integrate(t * 0.01 * math.e**(-0.01*t), (t, 0, oo))
ex.doit()

import scipy.integrate as si
import numpy as np

si.quad(lambda t: t * 0.01 * np.exp(-0.01*t), 0, np.inf)

# https://www.derivative-calculator.net/
# https://www.integral-calculator.com/
# Maxima


# -*- coding: utf-8 -*-
"""
Created on Mon Sep 17 16:00:20 2018

@author: Thiago, Renan
"""
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
import numpy as np
import math as m

### Funcao pra achar a raiz ###

def F(x):
    return m.exp(2.0*x) - 2.0 * m.exp(x) + 1

### Derivada da funcao

def dF(x):
    return 2 * (m.exp(x) - 1) * m.exp(x)

def insert_dash(string, index):
    return string[:index] + '|' + string[index:]

### Intervalo e chute inicial ###

a = np.dtype('f8')
b = np.dtype('f8')
xi_s = np.dtype('f8')
xi_n = np.dtype('f8')
E = np.dtype('f8')

a = -1.0
b = 1.0
xi_s = 0 #chute inicial (secante)
xi_n = 1 #chute inicial (Newton)

ordem = 5
E = 10**-ordem

### Metodos

def bissecao(_a, _b, Er):

    _x = np.dtype('f8')
    e = _b - _a
    mx = e / 2.0
    _x = mx + _a
    iteracoes = 0

    #checa se a raiz esta nos intervalos
    if(F(_a) == 0.0):
        return _a
    if(F(_b) == 0.0):
        return _b

    while(e > Er):

        #acha meio
        e = _b - _a
        mx = e / 2.0
        _x = mx + _a

        #determina valores
        fa = F(_a)
        fx = F(_x)

        #se a raiz estiver entre um dos intervalos formados, ajusta intervalo (_a, _b)
        if((fa >= 0 and fx < 0) or (fa < 0 and fx >= 0)):
            #intervalo a-x
            _b = _x
        else:
            #intervalo x-b
            _a = _x

        iteracoes += 1

        if(iteracoes > 10000):
            print("saiu no break da bissessao")
            break

    #atingiu condicao de parada
    return [_x, iteracoes]

def secante(x0, x1):
    iteracoes = 0
    x2 = np.dtype('f8')
    x2 = 0.0
    lista_iteracoes = []

    while(iteracoes < 10000):
        f0 = F(x0)
        f1 = F(x1)
        x2 = x2 - ((f1 * (x1 - x0)) / (f1 - f0))

        lista_iteracoes.append([iteracoes, x2, abs(x2 - x1)])

        if(abs(x2 - x1) < E):
            break

        x0 = x1
        x1 = x2
        iteracoes += 1

    return [x2, iteracoes, lista_iteracoes]

def newton(xi):
    iteracoes = 0
    lista_iteracoes = []
    x0 = xi

    while(iteracoes < 10000):
        x1 = x0 - (F(x0) / dF(x0))

        lista_iteracoes.append([iteracoes, x1, abs(x1 - x0)])

        if(abs(x1 - x0) < E):
            break

        x0 = x1
        iteracoes += 1

    return [x1, iteracoes, lista_iteracoes]

### Executa metodo da secante com primeiro chute

lista0 = []
lista1 = []
lista2 = []

#obtem primeiro chute
xi_b = bissecao(a, b, 0.1)

resultado_secante = secante(xi_s, xi_b[0])

raiz_funcao_sec = resultado_secante[0]
num_passos_sec = resultado_secante[1]
lista_iteracoes_sec = resultado_secante[2]

string_sec = repr(raiz_funcao_sec)

print("\nFuncao com chute inicial "+repr(xi_s)+" e metodo da Secante:\n")
print("Raiz:"+insert_dash(string_sec, ordem + string_sec.find('.') + 1)+"")
print("F(x):"+repr(F(raiz_funcao_sec)))
print("Precisao:"+str(E)+"")

print("Iteracoes")
print("#".ljust(5) + "|" + "valor de x".ljust(25) + "|" + "erro".ljust(25) )
for item in lista_iteracoes_sec:
    lista0.append(item[0])
    lista1.append(item[1])
    lista2.append(item[2])
    print(repr(item[0]).ljust(5) + "|" + repr(item[1]).ljust(25) + "|" + repr(item[2]).ljust(25) )

print("Num de Iteracoes:"+str(num_passos_sec)+"")

#plota grafico
plt.plot(
    lista0, lista1, 'b--',
    lista0, lista2, 'r--'
)

#legendas do grafico
se_line = mlines.Line2D([], [], color='blue', marker='', markersize=0, label=u'Solução')
ee_line = mlines.Line2D([], [], color='red', marker='', markersize=0, label=u'Erro')

plt.legend(handles=[se_line, ee_line])
plt.title("Metodo da Secante")
plt.show()

### Executa metodo de Newton com o segundo chute

lista0 = []
lista1 = []
lista2 = []

resultado_newton = newton(xi_n)

raiz_funcao_new = resultado_newton[0]
num_passos_new = resultado_newton[1]
lista_iteracoes_new = resultado_newton[2]

string_new = repr(raiz_funcao_new)

print("\nFuncao com chute inicial "+repr(xi_n)+" e metodo de Newton:\n")
print("Raiz:"+insert_dash(string_new, ordem + string_new.find('.') + 1)+"")
print("F(x):"+repr(F(raiz_funcao_new)))
print("Precisao:"+str(E)+"")

print("Iteracoes")
print("#".ljust(5) + "|" + "valor de x".ljust(25) + "|" + "erro".ljust(25) )
for item in lista_iteracoes_new:
    lista0.append(item[0])
    lista1.append(item[1])
    lista2.append(item[2])
    print(repr(item[0]).ljust(5) + "|" + repr(item[1]).ljust(25) + "|" + repr(item[2]).ljust(25) )

print("Num de Iteracoes:"+str(num_passos_new)+"")

#plota grafico
'''
plt.plot(
    lista0, lista1, 'b--',
    lista0, lista2, 'r--'
)

#legendas do grafico
se_line = mlines.Line2D([], [], color='blue', marker='', markersize=0, label=u'Solução')
ee_line = mlines.Line2D([], [], color='red', marker='', markersize=0, label=u'Erro')

plt.legend(handles=[se_line, ee_line])
plt.title("Metodo de Newton")
plt.show()
'''


from typing import List

import numpy as np

def interpolate(x1, y1, x2, y2, x):
    m = (y2 - y1) / (x2 - x1)
    b = y1 - m * x1
    return m * x + b

def precision_at(recall: float, results: List[int], relevant: List[int]) -> float:
    '''
    This function should compute the precision at the specified recall level.
    If the recall level is in between two points, you should do a linear interpolation
    between the two closest points. For example, if you have 4 results
    (recall 0.25, 0.5, 0.75, and 1.0), and you need to compute recall @ 0.6, then do something like

    interpolate(0.5, prec @ 0.5, 0.75, prec @ 0.75, 0.6)

    Note that there is implicitly a point (recall=0, precision=1).

    `results` is a sorted list of document ids
    `relevant` is a list of relevant documents
    '''
    ranks = list()
    for i, result in enumerate(results):
        if result in relevant:
            ranks.append(i+1)

    recalls = [0]
    precisions = [1]
    for i, rank in enumerate(ranks):
        recalls.append(float(i+1)/float(len(relevant)))
        precisions.append(float(i+1)/float(rank))

    if recall in recalls:
        return precisions[recalls.index(recall)]
    else:
        right_recall_id = np.searchsorted(recalls, recall, side='left', sorter=None)
        left_recall_id = right_recall_id - 1
        return interpolate(recalls[left_recall_id], precisions[left_recall_id],
                           recalls[right_recall_id], precisions[right_recall_id],
                           recall)

def mean_precision1(results, relevant):
    return (precision_at(0.25, results, relevant) +
            precision_at(0.5, results, relevant) +
            precision_at(0.75, results, relevant)) / 3.0

def mean_precision2(results, relevant):
    return sum([precision_at((i+1)/10, results, relevant) for i in range(10)]) / 10.0

def norm_recall(results, relevant):
    Rel = len(relevant)
    N = len(results)

    ranks = list()
    for i, result in enumerate(results):
        if result in relevant:
            ranks.append(i+1)

    rank_sum = sum(ranks)
    i_sum = sum(list(range(1, Rel+1)))

    return 1 - ((rank_sum - i_sum)/(Rel * (N - Rel)))

def norm_precision(results, relevant):
    Rel = len(relevant)
    N = len(results)

    ranks = list()
    for i, result in enumerate(results):
        if result in relevant:
            ranks.append(np.log(i+1))

    rank_sum = sum(ranks)
    i_sum = sum([np.log(i) for i in range(1, Rel+1)])

    return 1 - ((rank_sum - i_sum)/(N*np.log(N) - (N - Rel)*np.log(N - Rel) - Rel*np.log(Rel)))


from __future__ import absolute_import

import numpy as np
from chainer.backends import cuda
from chainer import initializer

def _kernel_center(ksize):

    center = [None] * len(ksize)
    factor = [None] * len(ksize)

    for i, s in enumerate(ksize):

        factor[i] = (s + 1) // 2
        if s % 2 == 1:
            center[i] = factor[i] - 1
        else:
            center[i] = factor[i] - 0.5

    return center, factor

def _bilinear_kernel_2d(ksize):
    """ Get a kernel upsampling by bilinear interpolation

    Args:
        ksize (list of int): Kernel size.

    Returns:
        numpy.ndarray: A kernel.

    See also:
        https://arxiv.org/pdf/1411.4038.pdf
        https://github.com/d2l-ai/d2l-en/blob/master/chapter_computer-vision/fcn.md#initialize-the-transposed-convolution-layer
    """

    assert len(ksize) == 2

    og = np.ogrid[:ksize[0], :ksize[1]]
    center, factor = _kernel_center(ksize)

    kernel = (1 - abs(og[0] - center[0]) / factor[0]) * \
             (1 - abs(og[1] - center[1]) / factor[1])

    return kernel

def _bilinear_kernel_3d(ksize):

    assert len(ksize) == 3

    og = np.ogrid[:ksize[0], :ksize[1], :ksize[2]]
    center, factor = _kernel_center(ksize)

    kernel = (1 - abs(og[0] - center[0]) / factor[0]) * \
             (1 - abs(og[1] - center[1]) / factor[1]) * \
             (1 - abs(og[2] - center[2]) / factor[2])

    return kernel

def _bilinear_kernel_nd(ksize, dtype=np.float32):

    if len(ksize) == 2:
        kernel = _bilinear_kernel_2d(ksize)
    elif len(ksize) == 3:
        kernel = _bilinear_kernel_3d(ksize)
    else:
        raise NotImplementedError()

    return kernel.astype(dtype)

class BilinearUpsample(initializer.Initializer):
    """ Initializer of Bilinear upsampling kernel for convolutional weights.
    See also: https://arxiv.org/pdf/1411.4038.pdf
    """

    def __init__(self, scale=1., dtype=None):
        self.scale = scale
        super(BilinearUpsample, self).__init__(dtype)

    def __call__(self, array):
        if self.dtype is None:
            dtype = array.dtype

        if array.shape[0] != array.shape[1]:
            raise ValueError(
                'The number of input and output channels are NOT same..')

        ksize = array.shape[2:]
        kernel = self.scale * _bilinear_kernel_nd(ksize, dtype)

        weight = np.zeros(array.shape, dtype=self.dtype)
        weight[range(array.shape[0]), range(array.shape[1]), ...] = kernel

        xp = cuda.get_array_module(array)
        array[...] = xp.asarray(weight)


import numpy as np
import math

def relu(z):
    '''This is the finction for ReLU'''
    return z * (z > 0)

def relu_backward(next_dz, z):
    '''This is the derivative of ReLU'''
    dz = np.where(np.greater(z,0), next_dz, 0)
    return dz

def tanh(z):
    '''This is the finction for tanh'''
    return np.tanh(z)

def tanh_backward(dz):
    '''This is the derivative of tanh'''
    return 1. - np.tanh(dz) * np.tanh(dz)

def sigmoid(z):
    '''This is the finction for sigmoid'''
    return 1/(1+np.exp(-z))

def sigmoid_backward(dz):
    '''This is the derivative of sigmoid'''
    return np.exp(-dz)/ ( (1 + np.exp(-dz)) * (1 + np.exp(-dz)) )

def softmax(z):
    exp_value = np.exp(z-np.max(z, axis = 1, keepdims=True)) # for stablility
    # keepdims = True means that the output's dimension is the same as of z
    softmax_scores = exp_value / np.sum(exp_value, axis = 1, keepdims=True)
    return softmax_scores


import numpy as np
from sklearn import linear_model
# from sklearn.linear_model
file1 = open('train.txt', 'r')
Lines = file1.readlines()
# Density determined from underwater weighing
# Percent body fat from Siri's (1956) equation
header = "Density , Percent , Age , Weight, Height, Neck circumference, Chest circumference, Abdomen 2 circumference, Hip circumference , Thigh circumference,  Knee circumference, Ankle circumference ,Biceps (extended) circumference, Forearm circumference ,Wrist circumference"
 # [
 # "Density underwater weighing", x
 # "Percent body fat",
 # "Age",
 # "Weight",
 # "Neck circumference",
 # "Chest circumference",
 # "Abdomen 2 circumference",
 # "Hip circumference",
 # "Thigh circumference",
 # "Knee circumference",
 # "Ankle circumference",
 # "Biceps (extended) circumference",
 # "Forearm circumference",
 # "Wrist circumference"]
data = []
# Strips the newline character
for line in Lines:
	# slpit list of string and remove the newline tag
	values = line.strip().split("  ")
	# removing empty values from list
	values = list(filter(None, values))
	# converting string to float values
	for i in range(0, len(values)):
		values[i] = float(values[i])
	# list of data
	data.append(values)
# convert data to numpy array
data = np.array(data)
# arr = np.array([14 ,21, 13, 56, 12])
# np.savetxt("foo.csv", np.dstack((np.arange(1, arr.size+1),arr))[0],"%d,%d",header="Id,Values")
# np.savetxt("foo.csv", np.dstack((np.arange(1, data.size+1),data))[0],"%d,%d",header=header)
# np.savetxt("foo.csv", data, delimiter=",")
#find the shape
# print (data)
y = data[:,1]
# print (y)
X = data[:,2:15]
# print (X)
# take the first row
# y = data[:,1]

# y=y.astype('int')
# clf = linear_model.LogisticRegression(C=1e40, solver='newton-cg')
# fitted_model = clf.fit(X, y)

fitted_model = linear_model.LinearRegression().fit(X, y)
print ("reg score ",fitted_model.score(X, y))
print ("coef ",fitted_model.coef_)
print ("intercept_ ",fitted_model.intercept_)
# example = [23,154.25,67.75,36.2,93.1,85.2,94.5,59.0,37.3,21.9,32.0,27.4,17.1]
example = [27,133.25,64.75,36.4,93.5,73.9,88.5,50.1,34.5,21.3,30.5,27.9,17.2]
print ("predict : ",fitted_model.predict(np.array([example])))

# import numpy as np
# from sklearn.linear_model import LinearRegression
# X = np.array([[1, 1],
# 	[1, 2],
# 	[2, 2],
# 	[2, 3]])
# print(X)
# # y = 1 * x_0 + 2 * x_1 + 3
# y = np.dot(X, np.array([1, 2])) + 3
# print("y",y)
# reg = LinearRegression().fit(X, y)
# print ("reg score ",reg.score(X, y))
# print ("coef ",reg.coef_)
# print ("intercept_ ",reg.intercept_)
# print ("predict 3,5 : ",reg.predict(np.array([[2, 3]])))

# In the case of Linear Regression, the outcome is continuous
# while in the case of Logistic Regression outcome is discrete (not continuous)

# Linear regression is used for regression or to predict continuous values
# whereas logistic regression can be used both in classification and regression problems
# but it is widely used as classification algorithm.
# Regression models aim to project value based on independent features.

# You can only multiply matrices if the number of columns of the first matrix is the same as the number of rows as the second matrix.
# For example, say you want to multiply A x B. If A is a 3x1 matrix, B has to be a 1xY matrix (Y can be any number), because A only has 1 column.

# import numpy as np
# data = [[1,2,3],[1,2,3]]
# d = np.array(data)

# print (d.shape)
# d = np.append(d, a, axis=1)
# print (d)


'''
This is the solutions file for the InteriorPointI lab in volume 2
'''
import numpy as np
from scipy import linalg as la
from matplotlib import pyplot as plt

def startingPoint(A, b, c):
    '''
    Calculate an initial guess to the solution of the
    linear program min c^T x, Ax = b, x>=0.
    Inputs:
        A -- array of shape (m,n) with linearly independent rows
        b -- array of length m
        c -- array of length n
    Returns:
        x -- array of length n
        lam -- array of length m
        s -- array of length n
    Ref: Nocedal and Wright, p. 410
    '''
    # first calculate x, lam, s of minimal norm satisfying the primal and dual constraints
    B = la.inv(A.dot(A.T))
    x = A.T.dot(B.dot(b))
    lam = B.dot(A.dot(c))
    s = c - A.T.dot(lam)

    # perturb x and s so they are nonnegative
    dx = max((-3./2)*x.min(), 0)
    ds = max((-3./2)*s.min(), 0)
    x += dx*np.ones(x.shape)
    s += ds*np.ones(s.shape)

    # perturb x and s so they are not too close to zero, not too dissimilar
    dx = .5*(x*s).sum()/s.sum()
    ds = .5*(x*s).sum()/x.sum()
    x += dx*np.ones(x.shape)
    s += ds*np.ones(s.shape)

    return x, lam, s

def interiorPoint(A, b, c, niter=20, verbose=False, starting_point=None, pts=False):
    '''
    Solve the linear programming problem min c^T x, Ax = b, x>=0
    using an Interior Point method. This code is not optimized, but
    forms the basis for a common practical approach known as the
    Predictor-Corrector Algorithm.
    Inputs:
        A -- array of shape (m,n) with linearly independent rows
        b -- array of length m
        c -- array of length n
        niter -- positive integer giving the number of iterations
        starting_point -- tuple of arrays giving the initial values for x, l, and s.
                          if unspecified, the function startingPoint is used.
    Returns:
        x -- the optimal point
        val -- the minimum value of the objective function
        (pts -- list of points traced by the algorithm, returned if pts=True)
    Ref: Nocedal and Wright, p. 411
    '''
    pts = []
    # initialize variables
    m,n = A.shape
    if starting_point:
        x, l, s = starting_point
    else:
        x,l,s = startingPoint(A,b,c)
    pts.append(x)
    N = np.zeros((n+m+n, n+m+n))
    N[:n, n:n+m] = A.T
    N[:n, n+m:] = np.eye(n)
    N[n:n+m, :n] = A
    sol = np.empty(n+m+n)
    for k in xrange(niter):
        # finish initializing parts of the step equation
        N[n+m:, :n] = np.diag(s)
        N[n+m:, n+m:] = np.diag(x)
        r_c = (A.T).dot(l)+s-c
        r_b = A.dot(x)-b
        rhs = np.hstack((-r_c.ravel(), -r_b.ravel(), -x*s))

        # solve dx_aff, dl_aff, ds_aff using LU decomposition
        lu_piv = la.lu_factor(N)
        sol[:] = la.lu_solve(lu_piv, rhs)
        dx_aff = sol[:n]
        dl_aff = sol[n:n+m]
        ds_aff = sol[n+m:]

        # calculate a_p, a_d, mu_aff
        mask1 = dx_aff < 0
        if mask1.sum() > 0:
            a_p = min(1, ((-x/dx_aff)[mask1]).min())
        else:
            a_p = 1
        mask2 = ds_aff < 0
        if mask2.sum() > 0:
            a_d = min(1, (-s/ds_aff)[mask2].min())
        else:
            a_d = 1
        mu_aff = ((x+a_p*dx_aff)*(s+a_d*ds_aff)).sum()/np.float(n)

        # calculate mu times the centering parameter sig
        mu = (x*s).sum()/n
        musig = mu_aff**3/mu**2

        # calculate dx, dl, ds
        rhs[n+m:] += - dx_aff*ds_aff + musig
        sol[:] = la.lu_solve(lu_piv, rhs)
        dx = sol[:n]
        dl = sol[n:n+m]
        ds = sol[n+m:]

        # calculate ap, ad
        nu = 1-.1/(k+1)
        mask3 = dx < 0
        if mask3.sum() > 0:
            ap_max = (-x/dx)[mask3].min()
            ap = min(1, nu*ap_max)
        else:
            ap = 1
        mask4 = ds < 0
        if mask4.sum() > 0:
            ad_max = (-s/ds)[mask4].min()
            ad = min(1, nu*ad_max)
        else:
            ad = 1

        # step to new point
        x = x + ap*dx
        l = l + ad*dl
        s = s + ad*ds
        pts.append(x)

        if verbose:
            print '{0:f} {1:f}'.format((c*x).sum(), mu)

    if pts:
        return pts
    else:
        return x, (c*x).sum()

def randomLP(m,n):
    '''
    Generate a linear program min c^T x s.t. Ax = b, x>=0.
    First generate m feasible constraints, then add
    slack variables to convert it into the above form.
    Inputs:
        m -- positive integer >= n, number of desired constraints
        n -- dimension of space in which to optimize
    Outputs:
        A -- array of shape (m,n+m)
        b -- array of shape (m,)
        c -- array of shape (n+m,), with m trailing 0s
        v -- the solution to the LP
    '''
    # generate random constraints (each row corresponds to the normal vector defining
    # a linear constraint)
    A = np.random.random((m,n))*20 - 10

    # adjust so that the normal vector of each constraint lies in the upper half-space.
    # this ensures that the constraints permit a feasible region
    A[A[:,-1]<0] *= -1

    # adjust so that the solution to the program is a prescribed point v in the first
    # quadrant.
    v = np.random.random(n)*10
    #k = np.random.randint(n,m+1)
    k = n
    b = np.zeros(m)
    b[:k] = A[:k,:].dot(v)
    b[k:] = A[k:,:].dot(v) + np.random.random(m-k)*10

    # now create the appropriate c vector, a weighted sum of the first k constraints
    c = np.zeros(n+m)
    c[:n] = A[:k,:].sum(axis=0)/k

    # at this point, we should have a program max c^T x s.t. Ax <= b, x >= 0
    # we need to convert it to standard equality form by adding slack variables
    A = np.hstack((A, np.eye(m)))

    # we now have the program min -c^T x s.t. Ax = b, x>=0.
    # the optimal solution has x[:n] = v

    return A, b, -c, v

def leastAbsoluteDeviations():
    """
    This code should be fairly close to what the students submit for the least absolute deviations
    problem.
    """
    data = np.loadtxt('simdata.txt')
    m = data.shape[0]
    n = data.shape[1] - 1
    c = np.zeros(3*m + 2*(n + 1))
    c[:m] = 1
    y = np.empty(2*m)
    y[::2] = -data[:, 0]
    y[1::2] = data[:, 0]
    x = data[:, 1:]
    A = np.ones((2*m, 3*m + 2*(n + 1)))
    A[::2, :m] = np.eye(m)
    A[1::2, :m] = np.eye(m)
    A[::2, m:m+n] = -x
    A[1::2, m:m+n] = x
    A[::2, m+n:m+2*n] = x
    A[1::2, m+n:m+2*n] = -x
    A[::2, m+2*n] = -1
    A[1::2, m+2*n+1] = -1
    A[:, m+2*n+2:] = -np.eye(2*m, 2*m)

    sol = interiorPoint(A, y, c, niter=10, verbose=True)[-1]
    beta = (sol[m:m+n] - sol[m+n:m+2*n])[0]
    b = sol[m+2*n] - sol[m+2*n+1]

    dom = np.linspace(0,10,2)
    plt.scatter(data[:,1], data[:,0])
    plt.plot(dom, beta*dom+b)
    plt.show()
    print 'Beta:', beta
    print 'b:', b


#DiamondSquare.py
#Written by Hailey K Buckingham
#On github, buckinha/DiamondSquare
#

import random
import math
import numpy as np

def diamond_square(shape: (int, int),
                   min_height: [float or int],
                   max_height: [float or int],
                   roughness: [float or int],
                   random_seed=None,
                   as_ndarray: bool = True):
    """Runs a diamond square algorithm and returns an array (or list) with the landscape

        An important difference (possibly) between this, and other implementations of the
    diamond square algorithm is how I use the roughness parameter. For each "perturbation"
    I pull a random number from a uniform distribution between min_height and max_height.
    I then take the weighted average between that value, and the average value of the
    "neighbors", whether those be in the diamond or in the square step, as normal. The
    weights used for the weighted sum are (roughness) and (1-roughness) for the random
    number and the average, respectively, where roughness is a float that always falls
    between 0 and 1.
        The roughness value used in each iteration is based on the roughness parameter
    passed in, and is computed as follows:

        this_iteration_roughness = roughness**iteration_number

    where the first iteration has iteration_number = 0. The first roughness value
    actually used (in the very first diamond and square step) is roughness**0 = 1. Thus,
    the values for those first diamond and square step entries will be entirely random.
    This effectively means that I am seeding with A 3x3 grid of random values, rather
    than with just the four corners.
        As the process continues, the weight placed on the random number draw falls from
    the original value of 1, to roughness**1, to roughness**2, and so on, ultimately
    approaching 0. This means that the values of new cells will slowly shift from being
    purely random, to pure averages.

    OTHER NOTES:
    Internally, all heights are between 0 and 1, and are rescaled at the end.

    PARAMETERS
    ----------
    :param shape
        tuple of ints, (int, int): the shape of the resulting landscape

    :param min_height
        Int or Float: The minimum height allowed on the landscape

    :param max_height
        Int or Float: The maximum height allowed on the landscape

    :param roughness
        Float with value between 0 and 1, reflecting how bumpy the landscape should be.
        Values near 1 will result in landscapes that are extremely rough, and have almost no
        cell-to-cell smoothness. Values near zero will result in landscapes that are almost
        perfectly smooth.

        Values above 1.0 will be interpreted as 1.0
        Values below 0.0 will be interpreted as 0.0

    :param random_seed
        Any value. Defaults to None. If a value is given, the algorithm will use it to seed the random
        number generator, ensuring replicability.

    :param as_ndarray
        Bool: whether the landscape should be returned as a numpy array. If set
        to False, the method will return list of lists.

    :returns [list] or nd_array
    """

    # sanitize inputs
    if roughness > 1:
        roughness = 1.0
    if roughness < 0:
        roughness = 0.0

    working_shape, iterations = _get_working_shape_and_iterations(shape)

    # create the array
    diamond_square_array = np.full(working_shape, -1, dtype='float')

    # seed the random number generator
    random.seed(random_seed)

    # seed the corners
    diamond_square_array[0, 0] = random.uniform(0, 1)
    diamond_square_array[working_shape[0] - 1, 0] = random.uniform(0, 1)
    diamond_square_array[0, working_shape[1]-1] = random.uniform(0, 1)
    diamond_square_array[working_shape[0]-1, working_shape[1]-1] = random.uniform(0, 1)

    # do the algorithm
    for i in range(iterations):
        r = math.pow(roughness, i)

        step_size = math.floor((working_shape[0]-1) / math.pow(2, i))

        _diamond_step(diamond_square_array, step_size, r)
        _square_step(diamond_square_array, step_size, r)

    # rescale the array to fit the min and max heights specified
    diamond_square_array = min_height + (diamond_square_array * (max_height - min_height))

    # trim array, if needed
    final_array = diamond_square_array[:shape[0], :shape[1]]

    if as_ndarray:
        return final_array
    else:
        return final_array.tolist()

def _get_working_shape_and_iterations(requested_shape, max_power_of_two=13):
    """Returns the necessary size for a square grid which is usable in a DS algorithm.

    The Diamond Square algorithm requires a grid of size n x n where n = 2**x + 1, for any
    integer value of x greater than two. To accomodate a requested map size other than these
    dimensions, we simply create the next largest n x n grid which can entirely contain the
    requested size, and return a subsection of it.

    This method computes that size.

    PARAMETERS
    ----------
    requested_shape
        A 2D list-like object reflecting the size of grid that is ultimately desired.

    max_power_of_two
        an integer greater than 2, reflecting the maximum size grid that the algorithm can EVER
        attempt to make, even if the requested size is too big. This limits the algorithm to
        sizes that are manageable, unless the user really REALLY wants to have a bigger one.
        The maximum grid size will have an edge of size  (2**max_power_of_two + 1)

    RETURNS
    -------
    An integer of value n, as described above.
    """
    if max_power_of_two < 3:
        max_power_of_two = 3

    largest_edge = max(requested_shape)

    for power in range(1, max_power_of_two+1):
        d = (2**power) + 1
        if largest_edge <= d:
            return (d, d), power

    #failsafe: no values in the dimensions array were allowed, so print a warning and return
    # the maximum size.
    d = 2**max_power_of_two + 1
    print("DiamondSquare Warning: Requested size was too large. Grid of size {0} returned""".format(d))
    return (d, d), max_power_of_two

def _diamond_step(DS_array, step_size, roughness):
    """Does the diamond step for a given iteration.

    During the diamond step, the diagonally adjacent cells are filled:

    Value   None   Value   None   Value  ...

    None   FILLING  None  FILLING  None  ...

    Value   None   Value   None   Value  ...

    ...     ...     ...     ...    ...   ...

    So we'll step with increment step_size over BOTH axes

    """
    # calculate where all the diamond corners are (the ones we'll be filling)
    half_step = math.floor(step_size/2)
    x_steps = range(half_step, DS_array.shape[0], step_size)
    y_steps = x_steps[:]

    for i in x_steps:
        for j in y_steps:
            if DS_array[i,j] == -1.0:
                DS_array[i,j] = _diamond_displace(DS_array, i, j, half_step, roughness)

def _square_step(DS_array, step_size, roughness):
    """Does the square step for a given iteration.

    During the diamond step, the diagonally adjacent cells are filled:

     Value    FILLING    Value    FILLING   Value   ...

    FILLING   DIAMOND   FILLING   DIAMOND  FILLING  ...

     Value    FILLING    Value    FILLING   Value   ...

      ...       ...       ...       ...      ...    ...

    So we'll step with increment step_size over BOTH axes

    """

    # doing this in two steps: the first, where the every other column is skipped
    # and the second, where every other row is skipped. For each, iterations along
    # the half-steps go vertically or horizontally, respectively.

    # set the half-step for the calls to square_displace
    half_step = math.floor(step_size/2)

    # vertical step
    steps_x_vert = range(half_step, DS_array.shape[0], step_size)
    steps_y_vert = range(0, DS_array.shape[1], step_size)

    # horizontal step
    steps_x_horiz = range(0, DS_array.shape[0],   step_size)
    steps_y_horiz = range(half_step, DS_array.shape[1],   step_size)

    for i in steps_x_horiz:
        for j in steps_y_horiz:
            DS_array[i,j] = _square_displace(DS_array, i, j, half_step, roughness)

    for i in steps_x_vert:
        for j in steps_y_vert:
            DS_array[i,j] = _square_displace(DS_array, i, j, half_step, roughness)

def _diamond_displace(DS_array, i, j, half_step, roughness):
    """
    defines the midpoint displacement for the diamond step
    :param DS_array:
    :param i:
    :param j:
    :param half_step:
    :param roughness:
    :return:
    """
    ul = DS_array[i-half_step, j-half_step]
    ur = DS_array[i-half_step, j+half_step]
    ll = DS_array[i+half_step, j-half_step]
    lr = DS_array[i+half_step, j+half_step]

    ave = (ul + ur + ll + lr)/4.0

    rand_val = random.uniform(0,1)

    return (roughness * rand_val) + (1.0 -roughness) * ave

def _square_displace(DS_array, i, j, half_step, roughness):
    """
    Defines the midpoint displacement for the square step

    :param DS_array:
    :param i:
    :param j:
    :param half_step:
    :param roughness:
    :return:
    """
    _sum = 0.0
    divide_by = 4

    # check cell "above"
    if i - half_step >= 0:
        _sum += DS_array[i-half_step, j]
    else:
        divide_by -= 1

    # check cell "below"
    if i + half_step < DS_array.shape[0]:
        _sum += DS_array[i+half_step, j]
    else:
        divide_by -= 1

    # check cell "left"
    if j - half_step >= 0:
        _sum += DS_array[i, j-half_step]
    else:
        divide_by -= 1

    # check cell "right"
    if j + half_step < DS_array.shape[0]:
        _sum += DS_array[i, j+half_step]
    else:
        divide_by -= 1

    ave = _sum / divide_by

    rand_val = random.uniform(0, 1)

    return (roughness * rand_val) + (1.0-roughness) * ave


import numpy as np

def iou_mask(mat_1, mat_2):
    # pass
    intersection = mat_1 * mat_2
    # return intersection
    union = np.clip(mat_1 + mat_2, 0, 1)
    return np.sum(intersection) / np.sum(union)

if __name__ == '__main__':
    mat_1 = np.array([
        [0, 0, 0, 0, 0, 0, 0],
        [0, 1, 1, 1, 0, 0, 0],
        [0, 1, 1, 1, 0, 0, 0],
        [0, 1, 1, 1, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0],
    ])

    mat_2 = np.array([
        [0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 1, 0, 0, 0],
        [0, 0, 1, 1, 1, 1, 0],
        [0, 0, 0, 1, 1, 1, 0],
        [0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0],
    ])

    print(iou_mask(mat_1, mat_2))


"""
 Function:  x, info = fistaR(fx, gradf, parameter)
 Purpose:   Implementation of fista.
 Parameter: x0         - Initial estimate.
            maxit      - Maximum number of iterations.
            tolx       - Error toleration for stopping condition.
            Lips       - Lipschitz constant for gradient.
            strcnvx    - Strong convexity parameter of f(x).

 Author: Cijo Jose.  [josevancijo@gmail.com]
"""
import time

import numpy as np

def fista(fx, gradf, gx, proxg, parameter, verbose=0):
    x = parameter["x0"]
    y = parameter["x0"]
    t = 1.0
    info = {"itertime": [], "fx": [], "iter": None, "time": None, "totaltime": "None"}
    # Set the clock.
    timestart = time.time()
    # Main loop.
    for iter in range(int(parameter["maxit"])):
        # Compute error and save data to be plotted later on.
        info["itertime"].append(time.time() - timestart)
        fs = fx(x) + gx(x)
        info["fx"].append(fs)
        # Print the information.
        if verbose:
            print("Iter = %4d, f(x) = %5.3e\n" % (iter, info["fx"][iter]))
        # Start the clock.
        fk = 0
        timestart = time.time()
        while True:
            x_next = proxg(y - gradf(y) / parameter["Lips"])
            if fs >= fx(x_next) + gx(x_next) or fk > 0:
                break
            t = 1.0
            y = x
            fk += 1
            # Update the next iteration.
        t_next = 0.5 * (1.0 + np.sqrt(4.0 * t * t + 1.0))
        y = x_next + (t - 1.0) * (x_next - x) / t_next
        # Check stopping criterion.
        if np.linalg.norm(x_next - x) <= parameter["tolx"]:
            break
        x = x_next
        t = t_next
    # Finalization.
    info["iter"] = iter
    info["time"] = np.cumsum(info["itertime"])
    info["totaltime"] = info["time"][iter]
    return x, info

if __name__ == "__main__":
    alpha = 10
    # Parameters for synthetic data.
    cfg = {}
    cfg["n"] = 50
    # number of features
    cfg["p"] = 15
    # number of dimensions
    cfg["noisestd"] = 1e-6
    # standard deviation of additive iid gaussian noise (0 for noiseless)
    # Methods to be checked.
    chk = {
        "GD": True,
        "AGD": True,
        "AGDR": True,
        "LSGD": True,
        "LSAGD": True,
        "LSAGDR": True,
        "CG": True,
    }
    # Generate synthetic data.
    A = np.random.random((cfg["n"], cfg["p"]))
    # Generate s-sparse vector.
    xtrue = np.random.randn(cfg["p"])
    # Take (noisy) samples.
    noise = cfg["noisestd"] * np.random.randn(cfg["n"])
    b = np.dot(A, xtrue) + noise

    fx = lambda x: np.linalg.norm(np.dot(A, x) - b)
    gradf = lambda x: 2 * np.dot(A.T, np.dot(A, x) - b)
    gx_l1 = lambda x: alpha * np.sum(np.abs(x))
    prox_l1 = lambda x: np.max(np.abs(x) - alpha, 0) * np.sign(x)

    parameter = dict()
    parameter["Lips"] = np.linalg.norm(np.dot(A.T, A))
    parameter["x0"] = np.zeros((cfg["p"]))
    parameter["tolx"] = 1e-10  # You can vary tolx and maxit
    parameter["maxit"] = 1e3  # to achieve the convergence.
    x, info = fista(fx, gradf, gx_l1, prox_l1, parameter)


# encoding=utf8

"""Implementations of Dixon Price function."""
import numpy as np

from niapy.problems.problem import Problem

__all__ = ['DixonPrice']

class DixonPrice(Problem):
    r"""Implementations of Dixon Price function.

    Date: 2018

    Author: Klemen Berkovič

    License: MIT

    Function:
    **Dixon Price Function**

        :math:`f(\textbf{x}) = (x_1 - 1)^2 + \sum_{i = 2}^D i (2x_i^2 - x_{i - 1})^2`

        **Input domain:**
        The function can be defined on any input domain but it is usually
        evaluated on the hypercube :math:`x_i ∈ [-10, 10]`, for all :math:`i = 1, 2,..., D`.

        **Global minimum:**
        :math:`f(\textbf{x}^*) = 0` at :math:`\textbf{x}^* = (2^{-\frac{2^1 - 2}{2^1}}, \cdots , 2^{-\frac{2^i - 2}{2^i}} , \cdots , 2^{-\frac{2^D - 2}{2^D}})`

    LaTeX formats:
        Inline:
            $f(\textbf{x}) = (x_1 - 1)^2 + \sum_{i = 2}^D i (2x_i^2 - x_{i - 1})^2$

        Equation:
            \begin{equation} f(\textbf{x}) = (x_1 - 1)^2 + \sum_{i = 2}^D i (2x_i^2 - x_{i - 1})^2 \end{equation}

        Domain:
            $-10 \leq x_i \leq 10$

    Reference:
        https://www.sfu.ca/~ssurjano/dixonpr.html

    """

    def __init__(self, dimension=4, lower=-10.0, upper=10.0, *args, **kwargs):
        r"""Initialize Dixon Price problem..

        Args:
            dimension (Optional[int]): Dimension of the problem.
            lower (Optional[Union[float, Iterable[float]]]): Lower bounds of the problem.
            upper (Optional[Union[float, Iterable[float]]]): Upper bounds of the problem.

        See Also:
            :func:`niapy.problems.Problem.__init__`

        """
        super().__init__(dimension, lower, upper, *args, **kwargs)

    @staticmethod
    def latex_code():
        r"""Return the latex code of the problem.

        Returns:
            str: Latex code.

        """
        return r'''$f(\textbf{x}) = (x_1 - 1)^2 + \sum_{i = 2}^D i (2x_i^2 - x_{i - 1})^2$'''

    def _evaluate(self, x):
        indices = np.arange(2, self.dimension)
        val = np.sum(indices * (2 * x[2:] ** 2 - x[1:self.dimension - 1]) ** 2)
        return (x[0] - 1) ** 2 + val

# vim: tabstop=3 noexpandtab shiftwidth=3 softtabstop=3


from scipy import stats
import numpy as np
import math
import sys
import json
from collections import OrderedDict
import time
import os

def assertation(lines0):
  run,components,paramdict = json.loads(lines0)
  assert len(run) == paramdict['REPRO_number_of_independent_runs']

def find_t(X1, X2, S1, S2, N1, N2):
  """X1 and X2 are means, S1 and S2 std devs, N1 and N2 are
     population sizes (and not degrees of freedom)
  """
  #with this, the result between scipy and manual is the same
  N1 = N1 - 1
  N2 = N2 - 1
  above = (X1 - X2)
  below = math.sqrt(  ((S1**2)/N1)  +  ((S2**2)/N2)  )
  return above/below

def find_v(S1, S2, N1, N2):
    vx1 = N1-1
    vx2 = N2-1
    above = (  ((S1**2)/N1)  +  ((S2**2)/N2)  )**2
    below = (S1**4)/((N1**2)*vx1)  +  (S2**4)/((N2**2)*vx2)
    return above/below

def scipy_t_test(X1, X2):
    """X1 and X2 are arrays of samples
       returns t,p
    """
    return stats.ttest_ind(X1, X2, equal_var=False)

def manual_t_test(paper_mean, this_mean, paper_std, this_std, paper_runs, this_runs, cmp_dataset_name="expected"):
    """prints stats and returns t,v,p
       The parameter cmp_dataset_name has no effect except label the expected result in the printed output
    """
    print("[manual ttest]")
    error_diff = abs(paper_mean - this_mean)
    insig = False
    if error_diff < 10**(-7):
        insig = True
        pprint = lambda s: print("*{:^72}*".format(s))
        print("*"*(72+2))
        pprint("Difference of error rates < 10^(-7)")
        pprint("the paper treats this as insignificant")
        pprint("(error difference was: {:1.2E})".format(error_diff))
        print("*"*(72+2))

    try:
        t = find_t(X1=paper_mean, X2=this_mean, S1=paper_std, S2=this_std, N1=paper_runs, N2=this_runs)
        v = find_v(S1=paper_std, S2=this_std, N1=paper_runs, N2=this_runs)
        p_value = stats.t.sf(np.abs(t), v)*2 #survival function
    except ZeroDivisionError:
        print("  ZeroDivisionError (paper: {}±{})".format(paper_mean, paper_std))
        print("")
        return -1, -1, -1
    else:
        print("  {tmean:1.4G} ± {tstd:1.4G}    [{pmean:1.4G} ± {pstd:1.4G} <-- {cmp_set}]".format(
                tmean=this_mean,
                tstd=this_std,
                pmean=paper_mean,
                pstd=paper_std,
                cmp_set=cmp_dataset_name))
        print("  t: {t:3.4f}  v: {v:3.4f}".format(t=t,v=v))
        print("  p-value: {p:1.4G}".format(p=p_value))
        print("")
        return t,v,p_value,insig

def write_file_jsonlines(L):
  s = '\n'.join(L)
  filename = str(time.time()).split('.')[0] + '.json_lines'

  path = os.path.join('RESULTS', 'output_json_list', filename)
  if os.path.exists(path):
    print("Filepath '{}' already exists, not overwriting; printing instead:".format(path))
    print(s)
  else:
    print("Writing final jsonlines-output to '{}'".format(path))
    with open(path,'w') as f:
      f.write(s)

def compare_with_paper(runfile):
  with open(runfile) as f:
    lines = [x.strip() for x in f.readlines()]

  json_lines_output = []

  for line in lines:
    assertation(line)
    runs,components,paramdict = json.loads(line)

    paper_mean = paramdict['PAPER_mean_error']
    paper_std = paramdict['PAPER_std_dev']
    this_mean = np.mean(runs)
    this_std = np.std(runs)

    paper_runs = paramdict['PAPER_number_of_independent_runs']
    this_runs = paramdict['REPRO_number_of_independent_runs']

    t,v,p,insig = manual_t_test(paper_mean=paper_mean,
                                paper_std=paper_std,
                                paper_runs=paper_runs,
                                this_mean=this_mean,
                                this_std=this_std,
                                this_runs=this_runs,
                                cmp_dataset_name="paper_results")
    print('\n')

    #dump the results to one final file
    newdict = OrderedDict()
    newdict['stat_runs'] = runs
    newdict['stat_components'] = components
    newdict['stat_t'] = t
    newdict['stat_v'] = v
    newdict['stat_p'] = p
    newdict['stat_insignificant_error_diff'] = insig
    newdict['REPRO_mean_error'] = this_mean
    newdict['REPRO_std_dev'] = this_std
    for key in sorted(paramdict):
      newdict[key] = paramdict[key]
    json_lines_output.append(json.dumps(newdict))
  write_file_jsonlines(json_lines_output)

def compare_two_runs(runfile1, runfile2):
  with open(runfile1) as f:
    lines1 = [x.strip() for x in f.readlines()]
  with open(runfile2) as f:
    lines2 = [x.strip() for x in f.readlines()]

  for line1,line2 in zip(lines1,lines2):
    assertation(line1)
    assertation(line2)
    run1,components1,paramdict1 = json.loads(line1)
    run2,components2,paramdict2 = json.loads(line2)

    print('Params1:', paramdict1)
    if paramdict2 != paramdict1:
      print('Params2:', paramdict2)
    else:
      print('Params2: <same as above>')

    t,p = scipy_t_test(run1, run2)
    print("[scipy ttest]\n  t: {t:3.4f}    p: {p:1.4G}".format(t=t,p=p))

    # treat run1 as the paper and run2 as the reproduction attempt
    # this is to investigate the implementation of the t-test and how
    # it performs on two populations generated the same way
    manual_t_test(paper_mean=np.mean(run1),
                  this_mean=np.mean(run2),
                  paper_std=np.std(run1),
                  this_std=np.std(run2),
                  paper_runs=len(run1),
                  this_runs=len(run2),
                  cmp_dataset_name=runfile1)

    print('\n\n\n')

if __name__ == '__main__':
  if len(sys.argv) == 2:
    runfile = sys.argv[1]
    print("Comparing a run to the results from the paper")
    print("File: {}\n".format(runfile))
    compare_with_paper(runfile)

  elif len(sys.argv) == 3:
    runfile1, runfile2 = sys.argv[1], sys.argv[2]
    print("Comparing two runs made using the same implementation")
    print("Files: {}  {}\n".format(runfile1, runfile2))
    compare_two_runs(runfile1, runfile2)
  else:
    print("Usage:")
    print("  Compare own run to paper results (and also write a final result-file):")
    print("    python3 t_test.py dumps/runfile_produced_by_main_invocation.run")
    print("")
    print("  Compare two own runs:")
    print("    python3 t_test.py dumps/runfile1_produced_by_1st_main_invocation.run dumps/runfile2_produced_by_2nd_main_invocation.run")


import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-3,3,1000)
print(x)

relu = lambda x: max(0.0,x)

y = np.zeros_like(x)
for i in range(len(x)):
    y[i] = relu(x[i])

sig = 1/(1 + np.exp(-x))

fig,ax = plt.subplots(1,2)

ax[0].plot(x,y)
ax[1].plot(x,sig)
plt.grid('on')
plt.show()

import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):
    return 1 / (1 + np.exp(-x))
sigmoid = np.vectorize(sigmoid) #vectorize function
values=np.linspace(-10, 10) #generate values between -10 and 10
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

#spine placement data centered
ax.spines['left'].set_position(('data', 0.0))
ax.spines['bottom'].set_position(('data', 0.0))
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

plt.plot(values, sigmoid(values), color=(1,0.25,0))
plt.show()

import numpy as np
import matplotlib.pyplot as plt
def relu(x):
    y = np.zeros_like(x)
    for i in range(len(x)):
        y[i] = max(0.0, x[i])
    return y

values=np.linspace(-10, 10, 1000) #generate values between -10 and 10
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

#spine placement data centered
ax.spines['left'].set_position(('data', 0.0))
ax.spines['bottom'].set_position(('data', 0.0))
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

plt.plot(values, relu(values), color=(1,0.25,0))
plt.show()


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

import numpy as np
import numpy.linalg as la
import numpy.polynomial.polynomial as poly
import matplotlib.pyplot as plt

data = np.loadtxt("whData.dat", dtype=np.object, comments='#',  delimiter=None)
#removing outliers or data with weight -1
data = data[ data[:,0] != '-1' , : ]

hgt = data[:,1].astype( np.float)
wgt = data[:,0].astype( np.float)

xmin = hgt.min()-15
xmax = hgt.max()+15
ymin = wgt.min()-15
ymax = wgt.max()+15

def plot_data_and_fit(h, w, x, y, figname):
    plt.plot(h, w, 'ko', x, y, 'r-')
    plt.xlabel('Height')
    plt.ylabel('Weight')
    plt.xlim(xmin,xmax)
    plt.ylim(ymin,ymax)
    plt.savefig("{}.pdf".format(figname), facecolor='w', edgecolor='w',
                 orientation='potrait', format='pdf', transparent=False)
    plt.show()
def trsf(x):
    return x / 100.

n = 10
x = np.linspace(xmin, xmax, 100)

# method 1:
# regression using polyfit
c = poly.polyfit(hgt, wgt, n)
y = poly.polyval(x, c)
plot_data_and_fit(hgt, wgt, x, y, "polyfit")

# method 2:
# regression using the Vandermonde matrix and pinv
X = poly.polyvander(hgt, n)
#Pattern Recognition (1) B-IT, Summer Term 2019
c = np.dot(la.pinv(X), wgt)
y = np.dot(poly.polyvander(x,n), c)
plot_data_and_fit(hgt, wgt, x, y, "method2")

# method 3:
# regression using the Vandermonde matrix and lstsq
X = poly.polyvander(hgt, n)
c = la.lstsq(X, wgt)[0]
y = np.dot(poly.polyvander(x,n), c)
plot_data_and_fit(hgt, wgt, x, y, "method3")

# method 4:
# regression on transformed data using the Vandermonde
# matrix and either pinv or lstsq
X = poly.polyvander(trsf(hgt), n)
c = np.dot(la.pinv(X), wgt)
y = np.dot(poly.polyvander(trsf(x),n), c)
plot_data_and_fit(hgt, wgt, x, y, "method4")


import numpy as np
import nanalysis as na
import support
from support import BaseFunction, get_base_args
import matplotlib.pyplot as plt

#m: Malthus 係数
class Exponential( BaseFunction ):
	def __init__( self, m = 3 ):
		self.m = m
		self.numberofvalues = 1
	def get_values( self, x, t ):
		return self.m * x

class Logistic( BaseFunction ):
	def __init__(self,  r = 1, K = 100 ):
			self.r = r
			self.K = K
			self.numberofvalues = 1
	def get_values( self, x, t ):
		return self.r * x * ( 1 - x / self.K )

	def get_linelist( self ):
		return [ [ 0, self.K ] ]

class Alley( BaseFunction ):
	def __init__( self, r = 0.03, K = 100, a = 20):
		self.r = r
		self.K = K
		self.a = a
		self.numberofvalues = 1

	def get_values( self, x, t ):
		return self.r * x * ( 1 - x / self.K ) * ( x - self.a )

	def get_linelist( self ):
		return [ [ 0, self.K ], [ 0, self.a ] ]

class Yamamura( BaseFunction ):

	def	__init__( P = 10 , r = 1.0, K = 100.0 ):
		self.P = P
		self.r = r
		self.K = K
		self.numberofvalues = 1
	def get_values( self, x, t ):
		return self.r * x *( 1 - x /self.K ) - self.P * x**2 / ( 1 + x**2 )

if __name__ == '__main__':

	ps = get_base_args()
	args = ps.parse_args()
	graph_n = args.equation_number
	ad = args.argdict
	sp   = args.spoint
	ep   = args.epoint
	hl   = args.hline
	vl   = args.vline
	llist  =  args.line
	pp   =  args.pointplot
	initial_value = args.initial_value
	saveoff = support.offsaving( args.savefigoff )

	graph = { 1: Exponential, 2: Logistic, 6: Alley, 4: Yamamura }

	if ad:
		function = graph[ graph_n ](**ad)
	else:
		function = graph[ graph_n ]()

	linelist =  function.get_linelist()

	if llist:
		linelist.append(llist)

	initial_value = np.array( initial_value ).reshape( -1, )

	t,xpoints, ypoints, zpoints = function.get_values_rungekutta( sp = sp, ep = ep, initial_value = initial_value, numberofvalues = function.numberofvalues )

	adplots = None

	if 'get_additionalplots' in dir(function ):
		adplots = function.get_additionalplots()

	na.graph_plot( t, xpoints = xpoints, ypoints = ypoints, zpoints = zpoints, chapter = 3 , function = function, hlines = hl, vlines = vl, linelist = linelist , savefigOn = saveoff, graph_n = graph_n, N = 1000, pointplot = pp, ntimegraphs = len( initial_value), additionalplots = adplots )


#codes are seperated by """ as multiline comments

"""
# Importing important libraries
import numpy as np
fromscipy.stats import norm

# Defining the methods required
def mean(n1, n2, n):
return ((2*n1*n2)/n)+1

def variance(n1,n2,n):
returnnp.sqrt((2*n1*n2*(2*n1*n2-n))/(n**2*(n-1)))

def statistic(r, mean, variance):
    return (r-mean)/variance

# Calculating Mean and Variance
m = mean(19,26,45)
print("Mean is: ", m)

v = variance(19,26,45)
print("Variance is: ", v)
"""

"""
z_statistic = statistic(19,m,v)
print("Z-Statistic is: ", z_statistic)

# define level of significance
a = 0.05

# Getting Critical Value
value = norm.ppf(1-a)

print("Z-Critical is: ", value)

if z_statistic>value:
print("Reject Null Hypothesis")
else:
print("Accept Null Hypothesis")
"""

"""
before = [18.5,21.5,21,20,15,19.75,15.75,18,22,15,20.5]
after = [19.25,21.75,20.25,22.25,16,19.5,17,19.25,19.5,16.5,20]

fromscipy.stats import wilcoxon

t, p = wilcoxon(after, before)

print("Test Statistic is: ", t)
print("p-value is: ", p)

level_of_significance = 0.05

if p>level_of_significance:
print("Accept Null Hypothesis")
else:
print("Reject Null Hypothesis")
"""

"""
Lincoln_Calcium = [0.11, 0.41, 0.19, 0.33, 0.09, 0.33, 0.67, 0.20, 0.21, 0.20, 0.75, 0.42, 0.09, 0.22,
                   0.19, 0.25, 0.07, 0.34, 0.30, 0.47, 0.30, 0.46]

Clarendon_Calcium = [0.06, 0.12, 0.14, 0.10,0.09, 0.29, 0.14, 0.21,0.14, 0.10, 0.12, 0.16,0.16, 0.41,
                     0.08, 0.13,0.03, 0.08, 0.09, 0.12]

fromscipy.stats import mannwhitneyu

t, p = mannwhitneyu(Lincoln_Calcium, Clarendon_Calcium,alternative='two-sided')

print("Test Statistic is: ", t)
print("p-value is: ", p)

level_of_significance = 0.05

if p>level_of_significance:
print("Accept Null Hypothesis")
else:
print("Reject Null Hypothesis")
"""

"""
personal_income = [48285,39817,66000,43874,32219,34453,31799,33786,37780]
birth_rate = [13.9,14.1,15.1,14.1,12.1,14.5,14.3,15.8,13.1]

fromscipy.stats import spearmanr

t, p = spearmanr(personal_income, birth_rate)

print("Test Statistic is: ", t)
print("p-value is: ", p)

level_of_significance = 0.05

if p>level_of_significance:
print("Accept Null Hypothesis")
else:
print("Reject Null Hypothesis")

"""

"""
period_A = [10456,11574,12321,11661,8521,11621,11321,7706,10872,10837]
period_B = [10799,11743,11657,11608,10982,9184,12357,12251,11916,11212]
period_C = [11465,12475,12454,12193,11244,12081,11387,9055,12319,12927]
period_D = [11261,11406,11627,8706,12022,11930,11054,11431,12618,10824]

fromscipy.stats import kruskal

t, p = kruskal(period_A,period_B,period_C,period_D)

print("Test Statistic is: ", t)
print("p-value is: ", p)

level_of_significance = 0.05

if p>level_of_significance:
print("Accept Null Hypothesis")
else:
print("Reject Null Hypothesis")
"""


'''
This fun project and playing with primes was insprired by 3Blue1Brown's video on youtube.

3Blue1Brown is a brilliant youtube channel on mathematics
Here is the link for the video: https://www.youtube.com/watch?v=EK32jo7i5LQ

This code replicates the distribution of prime numbers plot in a polar co-ordinate system seen in the video.
You can plot the first n prime numbers. Here there is only one input defined by the variable num.

'''

import math
import matplotlib.pyplot as plt
import numpy as np
from numba import jit
import time

@jit(nopython=True)
def is_prime(num):
    '''
    This function checks if any number is a prime number
    '''
    if num < 2:
        return False
    if num % 2 == 0 and num > 2:
        return False
    for i in range(3, int(math.sqrt(num)) + 1, 2):
        if num % i == 0:
            return False
    return True

@jit(nopython=True)
def nth_prime(n):
    '''
    This function generates the first n prime number where is defined by the user.
    n can change by assigning any positive integer to the variable num below
    '''
    i = 1
    j = 0
    list_of_primes = []
    while j < n:
        if is_prime(i):
            list_of_primes.append(i)
            j += 1
        i += 1
        #print(j, end='\r')
    return list_of_primes

## Running the functions here
num = 500000##-----> INPUT HERE

tic = time.perf_counter()
primes = nth_prime(num)
toc = time.perf_counter()

time = abs(toc - tic)

print('\n',time)
n = len(primes)

## Visualization
f = plt.figure(figsize=(10,10))
plt.subplot(111,polar = True)
ax1 = plt.scatter(primes,primes, s = 0.001)
plt.title(str(n)+' Primes', fontsize=36)
plt.axis('off')
plt.show()

f.savefig('{}_primes.png'.format(num),format='PNG',dpi=800)


import numpy as np
import matplotlib.pyplot as plt
from gradient_descent import gradient_descent
from examples import ex1, ex2, conditioned_quadratic
from plotutils import PlaneIterationPlotter
import seaborn as sns
sns.set_context("talk")

fun = conditioned_quadratic(cond=10)

starting_point = np.ones((2,1)) / np.sqrt(2)

condition_numbers = [1, 2, 4, 8, 16, 32, 64, 128]

for number in condition_numbers:
    fun = conditioned_quadratic(cond=number)

    plotter = PlaneIterationPlotter(fun, xlim=(-1,1), ylim=(-1,1))
    descents, _, _ = gradient_descent(fun, starting_point, tolerance=1e-10)

    plotter.plot_contours(colors=plt.cm.Greys(np.linspace(0,5)))
    plotter.plot_points(descents, 'ro')
    plotter.ax.set_title(f'Gradient Descent on Quadratic Form with $\kappa={number}$')
    plotter.save(f'figures/gd-condition-number-{number}.png', bbox_inches='tight')


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

# This script describes the interaction of economic growth rate, government budget
# deficit and the size of government debt. It is also described in the accompanying
# iPython Notebook and at
#
# http://misunderheard.org/blog/2015/07/14/what-is-a-sustainable-government-deficit/
#

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

#%% Create function which simulates economics scenario and plots course of government debt

def run_economy(time_steps, growth_rate, deficit_rate, start_income, start_debt):

    # Calculate the rate constant for economy growth based on passed in growth rate
    growth_rate_constant = (np.log(1 + growth_rate))

    # Initialize a list of timestep indices, e.g. 0, 1, 2, 3,...
    # This will be used to solve each of the equations through this number of timesteps
    # Since we're using the numpy library we can simply pass this vector of timesteps into
    # the equations and get a vector of solutions
    time_vector = np.linspace(0,time_steps-1,time_steps)

    # Calculate incomes (i.e. GDP with growth) across all timesteps
    income = start_income * np.exp(growth_rate_constant * time_vector)

    # Calculate debt across all timesteps
    debt   = start_debt + (deficit_rate * start_income / growth_rate_constant) * (np.exp(growth_rate_constant * time_vector) - 1)

    # Calculate the debt ratio across all timesteps
    # We could just divide the debt and income variables at this stage but lets use the elegant form!
    debt_ratio = (deficit_rate / growth_rate_constant) + ((start_debt / start_income) - (deficit_rate / growth_rate_constant))*np.exp(-(growth_rate_constant * time_vector))

    # Now plot all
    fig = plt.figure()

    gdp_plot = fig.add_subplot(311, xlim=(0, time_steps), ylim=(0, np.max(income)))
    gdp_plot.grid()
    gdp_plot.plot(range(time_steps),income)
    plt.ylabel('GDP')

    debt_plot = fig.add_subplot(312, xlim=(0, time_steps), ylim=(0, np.max(debt)))
    debt_plot.grid()
    debt_plot.plot(range(time_steps),debt)
    plt.ylabel('Debt')

    debt_ratio_plot = fig.add_subplot(313, xlim=(0, time_steps), ylim=(0, np.max(debt_ratio)))
    debt_ratio_plot.grid()
    debt_ratio_plot.plot(range(time_steps),debt_ratio)
    plt.ylabel('Debt/GDP')
    plt.xlabel('Time (arbitrary)')

    fig.show()

#%% Run some scenarios

run_economy(200, 0.02, 0.01, 500.0, 500.0)

run_economy(200, 0.02, 0.01, 500.0, 0.0)

run_economy(200, 0.02, 0.02, 500.0, 50.0)


import numpy as np
import pylab
import cv2
pylab.ion()

def kernal_convolution(image_path):

    '''
    *Performs a Sobel Kernal Conolution and Saves Output as jpg.

	Parameters
	----------

	image_path : <type 'str'>
		Path and file name of image (jpg or png)

	Returns
	-------
	y_copy :  <type 'ndarray'>
    '''

    #Sobel kernal
    kernal_x = [[-1,0,1],
               [-2,0,2],
               [-1,0,1]]

    kernal_y = [[-1,-2,-1],
               [0,0,0],
               [1,2,1]]

    #open image and make copy
    img = cv2.imread(image_path)
    y = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    xsize,ysize = y.shape
    y_copy = np.zeros((xsize,ysize))

    #loop through and calculate
    for i in range(1, xsize-1):

        for j in range(1, ysize - 1):

            xpix = (kernal_x[0][0] * y[i-1][j-1]) + (kernal_x[0][1] * y[i][j-1]) + (kernal_x[0][2] * y[i+1][j-1]) +\
                (kernal_x[1][0] * y[i-1][j])   + (kernal_x[1][1] * y[i][j])   + (kernal_x[1][2] * y[i+1][j]) +\
                (kernal_x[2][0] * y[i-1][j+1]) + (kernal_x[2][1] * y[i][j+1]) + (kernal_x[2][2] * y[i+1][j+1])

            ypix = (kernal_y[0][0] * y[i-1][j-1]) + (kernal_y[0][1] * y[i][j-1]) + (kernal_y[0][2] * y[i+1][j-1]) +\
                (kernal_y[1][0] * y[i-1][j])   + (kernal_y[1][1] * y[i][j])   + (kernal_y[1][2] * y[i+1][j]) +\
                (kernal_y[2][0] * y[i-1][j+1]) + (kernal_y[2][1] * y[i][j+1]) + (kernal_y[2][2] * y[i+1][j+1])

            mag = np.sqrt( (xpix * xpix) + (ypix * ypix) )
            mag = np.abs(mag)

            y_copy[i][j] = mag

    #normalise and save
    y_copy *= 255.0 / np.max(y_copy)
    pylab.imshow(y_copy, cmap = 'gray')
    pylab.savefig('output_' + image_path + '.jpg', dpi=200)

    return y_copy

if __name__ == '__main__':

    #example file 'corpus.jpg'
    arr = kernal_convolution('corpus.jpg')


"""
Ajay Kc
013213328
EE381
Project 6 Part 2
The experiment deals with five state Markov Chain where theoretical probability is plotted and the probability of each
page being visited is calculated.
"""
import numpy as np
import matplotlib.pyplot as plt

step = 20
transition_matrix = [[0,1,0,0,0],
                     [1/2,0,1/2,0,0],
                     [1/3,1/3,0,0,1/3],
                     [1,0,0,0,0],
                     [0,1/3,1/3,1/3,0]]
v1 = [1/5,1/5,1/5,1/5,1/5]
v2 = [0,0,0,0,1]
theoretical_probability_one = np.zeros((step+1,5))
theoretical_probability_two = np.zeros((step+1,5))
theoretical_probability_one[0,:]=v1
theoretical_probability_two[0,:]=v2

def calculate_theoretical_probabilities():
    for i in range(step):
        theoretical_probability_one[i+1,:]=np.matmul(theoretical_probability_one[i,:],transition_matrix)
        theoretical_probability_two[i + 1, :] = np.matmul(theoretical_probability_two[i, :], transition_matrix)

def plotGraph(state_one,state_two,state_three,state_four,state_five,xlabel,ylabel,title):

    plt.xlabel(xlabel, fontsize=20)
    plt.ylabel(ylabel, fontsize=20)
    plt.title(title, fontsize=20)

    plt.figure(1)
    plt.plot(range(0,step+1),state_one,color='b',marker='d',linestyle='--', label='State A')
    plt.plot(range(0, step + 1), state_two, color='r', marker='H', linestyle='--', label='State B')
    plt.plot(range(0, step + 1), state_three, color='g', marker='^', linestyle='--', label='State C')
    plt.plot(range(0, step + 1), state_four, color='m', marker='*', linestyle='--', label='State D')
    plt.plot(range(0, step + 1), state_five, color='y', marker='p', linestyle='--', label='State E')
    plt.legend(loc='best')

    plt.show()

calculate_theoretical_probabilities()

plotGraph(theoretical_probability_one[:,0],theoretical_probability_one[:,1],theoretical_probability_one[:,2],
          theoretical_probability_one[:, 3],theoretical_probability_one[:,4],"Step Number","Probability",
          "Five state Markov Chain - Calculated Using the State Transition Matrix where each state has equal initial probability")

plotGraph(theoretical_probability_two[:,0],theoretical_probability_two[:,1],theoretical_probability_two[:,2],
          theoretical_probability_two[:, 3],theoretical_probability_two[:,4],"Step Number","Probability",
          "Five state Markov Chain - Calculated Using the State Transition Matrix where one site is the home page")


# Libraries
import numpy as np
import matplotlib.pyplot as plt

# Coordinate matrix
# number of nodes
nnos = 11
# number of elements
nel  = nnos - 2

# coordinate matrix pre-allocation
coord = np.zeros((nnos, 3))
coord[0][0] = 1

# theta value
theta = (np.pi/2)/(nnos-2)

for i in range(0, nnos-1):
    coord[i + 1][0] = i + 2             # Node reference
    coord[i + 1][1] = np.cos(theta*i)   # X coordinate
    coord[i + 1][2] = np.sin(theta*i)   # Y coordinate

# Plot
fig = plt.figure()
plt.xlim([0,1])
plt.ylim([0,1])
plt.scatter(coord[:,1], coord[:,2], marker = '+', c = 'black', alpha = 0.85)
plt.xlabel('x', fontsize = 'xx-large')
plt.ylabel('y', fontsize = 'xx-large')

# Incidence matrix
# incidence matrix pre-allocation
inci = np.zeros((nel, 3))

for i in range(0,nel):
    # central node
    inci[i][0] = 1
    # first node
    inci[i][1] = i + 2
    # second node
    inci[i][2] = i + 3

fig, ax = plt.subplots()
plt.xlim([0,1])
plt.ylim([0,1])

for i in range(0,nel):
    node1 = inci[i][0]
    node2 = inci[i][1]
    node3 = inci[i][2]

    x1 = coord[int(node1) - 1][1]
    x2 = coord[int(node2) - 1][1]
    x3 = coord[int(node3) - 1][1]
    x  = np.array([x1, x2, x3])

    y1 = coord[int(node1) - 1][2]
    y2 = coord[int(node2) - 1][2]
    y3 = coord[int(node3) - 1][2]
    y  = np.array([y1, y2, y3])
    if i%2 == 0:
        ax.fill(x, y,'k',alpha=0.3)
    else:
        ax.fill(x, y,'b',alpha=0.3)

# Area
# somatory
A = 0

# central node coordinates
x1 = coord[int(inci[0,0] - 1), 1]
y1 = coord[int(inci[0,0] - 1), 2]

f = np.zeros(nnos-1)

for i in range(0,nel):
    #     second node coordinates
    x2 = coord[int(inci[i,1] - 1), 1]
    y2 = coord[int(inci[i,1] - 1), 2]

    #     third node coordinates
    x3 = coord[int(inci[i,2] - 1), 1]
    y3 = coord[int(inci[i,2] - 1), 2]

    a = 0.5*((x2 - x1)*(y3-y1) - (x3 - x1)*(y2 - y1))

    f[i] = a

    #     area summation
    A += a

# relative error
error_Area = (np.pi/4 - A)/(np.pi/4)*100
# display('Error = ',error_Area)

print('Error = ', error_Area,'%')

# Centroid
centx = 0
centy = 0

for i in range(0,nel):
    #     second node coordinates
    x2 = coord[int(inci[i,1] - 1), 1]
    y2 = coord[int(inci[i,1] - 1), 2]

    #     third node coordinates
    x3 = coord[int(inci[i,2] - 1), 1]
    y3 = coord[int(inci[i,2] - 1), 2]

    centx = centx + a*((x1+x2+x3)/3)
    centy = centy + a*((y1+y2+y3)/3)

# centroid X
X = centx/A

# centroid Y
Y = centy/A

# exact centroid
exact_cent = 4/(np.pi*3)

# error X
error_x = (exact_cent - X)/exact_cent*100
# error Y
error_y = (exact_cent - Y)/exact_cent*100

print('Error centroid X = ', error_x,'%')
print('Error centroid Y = ', error_y,'%')

# Inertia moment
Ix = 0
Iy = 0

# central node coordinates
x1 = coord[int(inci[0,0] - 1), 1]
y1 = coord[int(inci[0,0] - 1), 2]

for i in range(0,nel):
    #     second node coordinates
    x2 = coord[int(inci[i,1] - 1), 1]
    y2 = coord[int(inci[i,1] - 1), 2]

    #     third node coordinates
    x3 = coord[int(inci[i,2] - 1), 1]
    y3 = coord[int(inci[i,2] - 1), 2]

    Ix += 1/12*(y1**2+y2**2+y3**2+y1*y2+y1*y3+y2*y3)*(x2*y3-x3*y2) # momento de inércia em relação ao eixo x
    Iy += 1/12*(x1**2+x1*x2+x1*x3+x2**2+x2*x3+x3**2)*(x2*y3-x3*y2) # momento de inércia em relação ao eixo x

Iexato = np.pi/16 # valor exato do momento de inércia do quarto de círculo para R = 1

erro_Ix = (Iexato-Ix)/Iexato*100
erro_Iy = (Iexato-Iy)/Iexato*100

print('Error inertia X = ', erro_Ix,'%')
print('Error inertia Y = ', erro_Iy,'%')


import sympy
from sympy.plotting import plot_implicit
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

def mid_value(interval): return interval.mid

class Heart01:

    def __init__(self):
        self.x, self.y, self.a = sympy.symbols('x, y, a')
        self.eq = sympy.Eq((self.x**2 + self.y**2 - self.a)
                           ** 3 - self.x**2 * self.y**3, 0)
        self.fig, self.ax = self.plot_setup()

    def plot_setup(self):
        fig, ax = plt.subplots(figsize=(8, 8))
        ax.grid(False)
        ax.set_axis_off()
        return fig, ax

    def animate(self, constant):

        e = self.eq.subs({self.a: constant})
        p = plot_implicit(e, show=False)

        intervals = np.array(p[0].get_points()[0])
        px = tuple(map(mid_value, intervals[:, 0]))
        py = tuple(map(mid_value, intervals[:, 1]))
        points = np.array((px, py))

        heart = self.ax.scatter(*points)
        return heart,

    def show(self, frames=range(1, 6), interval=1, blit=True):
        ani = animation.FuncAnimation(self.fig, self.animate, frames=frames,
                                      interval=interval, blit=blit)
        plt.show()

class Heart02(Heart01):

    def show(self):
        super().show(blit=False)

class Heart03(Heart01):

    def __init__(self):
        super().__init__()
        self.eq = sympy.Eq(
            self.x**2 + (self.y - sympy.sqrt(sympy.Abs(self.x)))**2 - self.a, 0)

class Heart04(Heart03):

    def show(self):
        super().show(blit=False)

class Heart05(Heart01):

    def __init__(self):
        super().__init__()
        self.eq = sympy.Eq(self.x**2 + self.a*(sympy.Rational(3, 5)
                           * (self.x**2)**sympy.Rational(1, 3) - self.y)**2 - 1, 0)

class Heart06(Heart05):

    def show(self):
        super().show(blit=False)

class Heart07(Heart01):

    def __init__(self):
        super().__init__()
        self.eq = sympy.Eq(self.x**2 + 2*(sympy.Rational(3, 5) *
                           (self.x**2)**sympy.Rational(1, 3) - self.y)**2 - self.a, 0)

class Heart08(Heart07):

    def show(self):
        super().show(blit=False)

class Heart3d01:

    def __init__(self):
        self.fig, self.ax = self.plot_setup()

    def plot_setup(self):
        fig = plt.figure(figsize=(8, 8))
        fig.tight_layout(pad=0)
        ax = fig.add_subplot(111, projection='3d')
        return fig, ax

    def plot_implicit(self, fn, bbox=(-2.5, 2.5), resolution=100, slices=30,
                      colormap=plt.cm.Reds):
        """Create a plot of an implicit function fn
        Adapted from https://stackoverflow.com/a/4687582/8706250

        Parameters
        ----------
        fn : function
            implicit funcion with fn == 0
        bbox : tuple, optional
            x, y, z limits, by default (-2.5, 2.5)
        resolution : int, optional
            number of points, by default 100
        slices : int, optional
            number of countour planes, by default 30
        colormap : _type_, optional
            Matplotlib colormap to be used, by default plt.cm.Reds
        """

        xmin, xmax, ymin, ymax, zmin, zmax = bbox * 3
        A = np.linspace(xmin, xmax, resolution)
        B = np.linspace(xmin, xmax, slices)
        A1, A2 = np.meshgrid(A, A)
        colors = [colormap(i) for i in np.linspace(0.0, 1.0, slices)]

        for z, color in zip(B, colors):  # plot contours in the XY plane
            X, Y = A1, A2
            Z = fn(X, Y, z)
            self.ax.contour(X, Y, Z+z, [z], zdir='z',
                            colors=np.array(color).reshape(-1, 4))

        for y, color in zip(B, colors):  # plot contours in the XZ plane
            X, Z = A1, A2
            Y = fn(X, y, Z)
            self.ax.contour(X, Y+y, Z, [y], zdir='y',
                            colors=np.array(color).reshape(-1, 4))

        for x, color in zip(B, colors):  # plot contours in the YZ plane
            Y, Z = A1, A2
            X = fn(x, Y, Z)
            self.ax.contour(X+x, Y, Z, [x], zdir='x',
                            colors=np.array(color).reshape(-1, 4))

        self.ax.set_zlim3d(zmin, zmax)
        self.ax.set_xlim3d(xmin, xmax)
        self.ax.set_ylim3d(ymin, ymax)
        self.ax.grid(False)
        self.ax.set_axis_off()

    @staticmethod
    def heart3D(x, y, z, n=0):
        return (x**2 + (9/4) * y**2 + z**2 - 1)**3 - x**2 * z**3 - (9/80) * y**2 * z**3 < n

    def animate(self, i):
        self.ax.view_init(elev=30, azim=3.6*i)
        return self.fig,

    def show(self):
        self.plot_implicit(self.heart3D, bbox=(-1.3, 1.3),
                           colormap=plt.cm.PuRd, slices=50)
        ani = animation.FuncAnimation(self.fig, self.animate,
                                      frames=100, interval=10, blit=False)

        plt.tight_layout()
        plt.show()

class Heart3d02(Heart3d01):

    def __init__(self):
        super().__init__()
        self.ax.view_init(elev=30, azim=90)

    def animate(self, i):
        self.ax.dist = i
        return self.fig,

    def show(self):
        self.plot_implicit(self.heart3D, bbox=(-1.3, 1.3),
                           colormap=plt.cm.PuRd, slices=50)
        ani = animation.FuncAnimation(self.fig, self.animate, frames=(10, 20),
                                      interval=300, blit=False)

        plt.tight_layout()
        plt.show()

def cli():

    while True:
        try:
            print('\n\nWelcome to matplotlove!! By chicolucio', end='\n\n')
            print('Press 2 for 2D or 3 for 3D')
            choice_2d_3d = input('Do you want a 2D or a 3D heart? ')
        except KeyboardInterrupt:
            print('\nNo more love :-(')
            break
        else:
            if choice_2d_3d == '2':
                options_2d = input('Choose a number between 1 and 4: ')
                if int(options_2d) in range(1, 5):
                    eval(f'Heart0{options_2d}().show()')
                    break
                else:
                    print('Invalid number', end='\n\n')
            elif choice_2d_3d == '3':
                options_3d = input('Choose a number between 1 and 2: ')
                if int(options_3d) in range(1, 3):
                    eval(f'Heart3d0{options_3d}().show()')
                    break
                else:
                    print('Invalid number', end='\n\n')
            else:
                print('Invalid answer', end='\n\n')

if __name__ == "__main__":
    cli()


import numpy as np

def checkDiagonal(arr):
    for i in range(len(arr)):
        for j in range(len(arr[i])):
            if i == j:
                continue
            else:
                if abs(arr[i][j]) > 0.001:
                    return False
    return True

def qrFactorization(arr):
    temp = arr
    i = 0
    while (True):
        Q, R = np.linalg.qr(temp)
        temp = np.dot(R, Q)
        if (checkDiagonal(temp)):
            print("Number of Factorizations: " + str(i + 1))
            break
        else:
            i += 1
    return temp

def printLambda(arr):
    count = 1
    for i in range(len(arr)):
        for j in range(len(arr[i])):
            if (i == j):
                temp = arr[i][j]
                if (abs(temp) < 0.000000000001):
                    temp = 0
                print("Lamda" + str(count) + ": " + str(temp))
                count += 1

def read():
    f = open('matrix.txt', 'r')
    temp = f.read().split('\n')
    arr = []
    for i in temp:
        if i == '':
            continue
        arr.append(i.split(" "))
    for i in range(len(arr)):
        for j in range(len(arr[i])):
            arr[i][j] = int(arr[i][j])
    return arr

def main():
    arr = read()
    eigenvalues = np.linalg.eigvals(arr)
    matrix = np.array(arr)
    print(matrix)
    printLambda(qrFactorization(arr))

if __name__ == '__main__':
    main()


import numpy as np

def prox_l1(x, gamma):
    """
    The proximal operator for the l1_norm

    Parameters:
    -----------
    x : vector or matrix to calculate the norm from
    """
    sgn = np.sign(x)
    S = np.abs(x) - gamma
    S[S < 0.0] = 0.0
    return sgn * S

def prox_l1_01(x, gamma):
    """
    The proximal operator for the l1_norm with value constraint x in [0,1]

    Parameters:
    -----------
    x : vector or matrix to calculate the norm from
    """
    sgn = np.sign(x)
    S = np.abs(x) - gamma
    S[S < 0.0] = 0.0
    S = sgn * S
    S[S < 0.0] = 0
    S[S > 1.0] = 1
    return S

class ProximalGradSolver():
    def __init__(self, gamma, alpha, g, h, dg, prox_h):
        """
	Solves a problem of the form: min alpha*g(x) + h(x),
	where g(x) is smooth and differentiable and h(x) is non-differentiable (e.g. a regularization term or
        indicator function for a value constraint. Alpha is a trade-off variable and lambda is the step-size for
	the proximal gradient step.

	Parameters:
	-----------
	  lambda : step size for proximal gradient step
	  alpha : trade-off variable (problem dependent)
	  g : the differentiable function
          dg : the first derivative of g
	  prox_h : the proximal operator for h
	"""
        self.gamma = gamma
        self.alpha = alpha
        self.g = g
        self.h = h
        self.dg = dg
        self.prox_h = prox_h

    def proximal_step(self, x, gamma):
        """
        Proximal gradient update step

        Parameters:
        -----------
	  x : the current argument
	  gamma : the step size
        """
        x_new = self.prox_h(x - gamma * self.alpha * self.dg(x), gamma)
        return x_new

    def minimize(self, x0, n_iter=50):
        """
       Proximal gradient minimization

       Parameters:
       -----------
	 x0 : the initial argument
	 n_iter : number of steps
       """
        result = x0
        for n in np.arange(n_iter):
            result = self.proximal_step(result, self.gamma)
            costG = self.g(result)
            costH = self.h(result)
            print("Iteration :" + str(n) + " with g(x): " + str(costG) + " and h(x): " + str(costH))
        return result


import numpy as np

def planeRotation1(size,theta,j,k):
    """Compute the rotation matrix
       in the plane of columns j an k (j < k)
       by angle theta (in radians)."""

    protation = np.identity(size)
    protation[j,j] = np.cos(theta)
    protation[k,j] = np.sin(theta)
    protation[k,k] = np.cos(theta)
    protation[j,k] = -1*np.sin(theta)

    return protation

def planeRotation2(size,cos_theta,sin_theta,j,k):
    """Compute the rotation matrix
       in the plane of columns j an k (j < k)
       by cos_theta and sin_theta."""

    protation = np.identity(size)
    protation[j,j] = cos_theta
    protation[k,j] = sin_theta
    protation[k,k] = cos_theta
    protation[j,k] = -1*sin_theta

    return protation


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

import math
import numpy as np

def gen_gaussian_list(a, b, n=1000):

    dx = (b-a)/(n-1)                         # spacing between points
    x = [a + k*dx for k in range(n)]         # domain list

    # Local implementation of a Gaussian function
    def gauss(x):
        return (1/math.sqrt(2*math.pi))*math.exp(-x**2/2)

    g = [gauss(xk) for xk in x]                  # range list
    return (x, g)

def gen_gaussian_array(a, b, n=1000):

    x = np.linspace(a, b, endpoint=True, num=n)

    def gauss(x):
        return (1/np.sqrt(2*np.pi))*np.exp(-x**2/2)

    g = gauss(x)
    return (x, g)

def sinc_list(a, b, n=1000):

    dx = (b-a)/(n-1)                         # spacing between points
    x = [a + k*dx for k in range(n)]         # domain list
    x.remove(0)

    def sinc(x):
        return ((math.sin(x)/x))
    s = [sinc(xk) for xk in x]
    return (x,s)

def sinc_array(a, b, n=1000):

    x = np.linspace(a, b, endpoint=True, num=n)

    def sinc(x):
        ones = np.ones_like(x)
        return(np.divide(np.sin(x), x, out = ones, where=x!=0))

    s = sinc(x)
    return (x, s)

def sinf_list(a, b, n=1000):

    x = np.linspace(a, b, endpoint=True, num=n)

    def sinf(x):
        ones = np.ones_like(x)
        return(np.sin(np.divide(1, x, out = ones, where=x!=0)))

    s = sinf(x)
    return (x, s)

def main(a,b,n=1000):

    x, g = gen_gaussian_list(a,b,n)
    for (xk, gk) in zip(x, g):
        print("({}, {})".format(xk, gk))

# Protected main block for command line operation
if __name__ == "__main__":
    import sys

    if len(sys.argv) == 4:
        a = float(sys.argv[1])
        b = float(sys.argv[2])
        n = int(sys.argv[3])
        main(a,b,n)
    elif len(sys.argv) == 3:
        a = float(sys.argv[1])
        b = float(sys.argv[2])
        main(a,b)
    else:
        print("Usage: cw07.py a b [n]")
        print("  a : float, lower bound of domain")
        print("  b : float, upper bound of domain")
        print("  n : integer, number of points in domain")
        exit(1)


# This little solver is only good for *bounded* LPs of the form
# maximize cx
# subject to: Ax <= b

from sympy import *
from itertools import combinations

def enumeratevertices(A, b):
    '''enumerates all the vertices of {x | Ax <= b}'''
    m, n = A.rows, A.cols

    for rowlist in combinations(range(m), n):
        Ap = A.extract(rowlist, range(n))
        bp = b.extract(rowlist, [0])

        if Ap.det() != 0:
            xp = Ap.LUsolve(bp)

            d = A * xp - b
            feasible = True
            for i in range(m):
                if d[i] > 0:
                    feasible = False

            if feasible:
                yield xp

def findoptimum(A, b, c):
    '''finds the optimum using vertex enumeration'''
    m, n = A.rows, A.cols

    bestvalue, bestvertex = None, None
    for vertex in enumeratevertices(A, b):
        if not bestvalue or (vertex.T * c)[0] > bestvalue:
            bestvalue = (vertex.T * c)[0]
            bestvertex = vertex

    return bestvertex

def solve(A, b, c):
    x = findoptimum(A, b, c)

    if not x:
        print 'LP is infeasible'
    else:
        print 'Vertex', x.T, 'is optimal'
        print 'Optimal value is', (c.T * x)[0]

if __name__ == '__main__':

    # example
    A = Matrix([[50, 24],
         [30, 33],
         [-1, 0],
         [0, -1]])
    b = Matrix([2400, 2100, -45, -5])
    c = Matrix([1, 1])

    solve(A, b, c)


## This is based the work of Christopher Flynn fbm in
# https://github.com/crflynn/fbm and Davies, Robert B., and D. S. Harte. “Tests
# for Hurst effect.” Biometrika 74, no. 1 (1987): 95-101.

import numpy as np

def fgn(N: int, H: float) -> np.ndarray:
    """
    Generates fractional Gaussian noise with a Hurst index H in (0,1). If
    H = 1/2 this is simply Gaussian noise.
    The current method employed is the Davies–Harte method, which fails for
    H ≈ 0. A Cholesky decomposition method and the Hosking’s method will be
    implemented in later versions.

    Parameters
    ----------
    N: int
        Size of fractional Gaussian noise to generate.

    H: float
        Hurst exponent H in (0,1).

    Returns
    -------
    f: np.ndarray
        A array of size N of fractional Gaussian noise with a Hurst index H.
    """

    # Asserts
    assert isinstance(N, int), "Size must be an integer number"
    assert isinstance(H, float), "Hurst index must be a float in (0,1)"

    # Generate linspace
    k = np.linspace(0,N-1,N)

    # Correlation function
    cor = 0.5*(abs(k - 1)**(2*H) - 2*abs(k)**(2*H) + abs(k + 1)**(2*H))

    # Eigenvalues of the correlation function
    eigenvals = np.sqrt(
                  np.fft.fft(
                    np.concatenate([cor[:],0,cor[1:][::-1]],axis = None).real
                  )
                )

    # Two normal distributed noises to be convoluted
    gn = np.random.normal(0.0, 1.0, N)
    gn2 = np.random.normal(0.0, 1.0, N)

    # This is the Davies–Harte method
    w = np.concatenate(
        [(eigenvals[0]   / np.sqrt(2*N)) * gn[0],
         (eigenvals[1:N] / np.sqrt(4*N)) *(gn[1:] + 1j*gn2[1:]),
         (eigenvals[N]   / np.sqrt(2*N)) * gn2[0],
         (eigenvals[N+1:]/ np.sqrt(4*N)) *(gn[1:][::-1] - 1j*gn2[1:][::-1])
        ],
        axis = None)

    # Perform fft. Only first N entry are useful
    f = np.fft.fft(w).real[:N] * ( (1.0 / N) ** H )

    # TODO: Check for further speed-ups
    # TODO: Generalise for several outputs. Should be straightforward.
    # TODO: Implement the Cholesky decomposition method
    # TODO: Implement the Hosking’s method
    return f


import math
import random
from dataclasses import dataclass
from typing import ClassVar, Generator

from common import almost_equal

from scipy.spatial import distance

@dataclass
class Point:
    x: float
    y: float

def euclidean_distance(a: Point, b: Point) -> float:
    return distance.euclidean((a.x, a.y), (b.x, b.y))

class UnitCircle:
    center: ClassVar[Point] = Point(0.5, 0.5)
    radius: ClassVar[float] = 0.5

    def contains(self, point: Point) -> bool:
        return euclidean_distance(point, self.center) < self.radius

def simulate(n_iter: int) -> float:
    unit_circle = UnitCircle()
    random_points: Generator[Point] = (Point(x=random.random(), y=random.random()) for _ in range(n_iter))
    num_points_within_circle: int = sum(
        [1 if unit_circle.contains(point) else 0 for point in random_points]
    )

    return (float(num_points_within_circle) / n_iter) * 4

assert almost_equal(simulate(100000), math.pi)


from numba import autojit
from time import time

LIMIT = pow(10, 6)

def primes(limit):
    # Keep only odd numbers in sieve, mapping from index to number is
    # num = 2 * idx + 3
    # The square of the number corresponding to idx then corresponds to:
    # idx2 = 2*idx*idx + 6*idx + 3
    sieve = [True] * (limit // 2)
    prime_numbers = set([2])
    for j in range(len(sieve)):
        if sieve[j]:
            new_prime = 2 * j + 3
            prime_numbers.add(new_prime)
            for k in range((2 * j + 6) * j + 3, len(sieve), new_prime):
                sieve[k] = False
    return list(prime_numbers)

numba_primes = autojit(primes)

start = time()
numba_primes(LIMIT)
end = time()
print("Numba: Time Taken : ", end - start)

start = time()
primes(LIMIT)
end = time()
print("Python: Time Taken : ", end - start)


import numpy as np
import math as mth

#kernel density estimation method with a Gaussian kernel with standard deviation h (Seite 123 Bishop buch)
def kde(samples, h):
    # compute density estimation from samples with KDE
    # Input
    #  samples    : DxN matrix of data points
    #  h          : (half) window size/radius of kernel
    # Output
    #  estDensity : estimated density in the range of [-5,5]
    pos = np.arange(-5, 5.0, 0.1)  # Returns a 100 dimensional vector

    n = samples.shape[0]
    #d = pos.shape[0]
    d = 1

    temp_value = []
    for x in pos:
        summe = 0
        for j in range(0, n-1): # summe von 1 bis n
            diff_norm = np.linalg.norm(x - samples[j])
            summe += 1/(pow(2*mth.pi*pow(h,2),d/2))*mth.exp(-1*pow(diff_norm,2)/(2*pow(h,2)))
        p_x = 1/n * summe
        temp_value.append(p_x)

    value = np.array(temp_value)
    estDensity = np.column_stack((pos, value))

    return estDensity


import numpy as np

def multiDimensionalNormal(mean, covariance, value):
    D = len(value)

    normalizationFactor = 1/((2*np.pi)**(D/2)*np.linalg.det(covariance)**(0.5))

    distribution = np.exp(-0.5 * (np.transpose(value-mean) @ np.linalg.inv(covariance) @ (value-mean)))

    return normalizationFactor*distribution

def getLogEntry(means, weights, covariances, value):
    K = means.shape[0]

    innerSum = 0
    for k in range(K):
        innerSum += weights[k]*multiDimensionalNormal(means[k], covariances[:,:,k], value)

    return np.log(innerSum)

def getLogLikelihood(means, weights, covariances, X):
    # Log Likelihood estimation
    #
    # INPUT:
    # means          : Mean for each Gaussian KxD
    # weights        : Weight vector 1xK for K Gaussians
    # covariances    : Covariance matrices for each gaussian DxDxK
    # X              : Input data NxD
    # where N is number of data points
    # D is the dimension of the data points
    # K is number of gaussians
    #
    # OUTPUT:
    # logLikelihood  : log-likelihood

    means = np.array(means)
    weights = np.array(weights)

    sumOverDataPoints = 0
    for n in range(X.shape[0]):
        sumOverDataPoints += getLogEntry(means, weights, covariances, X[n])

    return sumOverDataPoints


import math
import numpy as np
import time

import matplotlib.pyplot as plt

#------------------------
#system configuration

num_of_classes = 2 #1 for regression, n for classification
epoch = 1000
learningRate = np.array([0.1])
hidden_layers = [5, 5]

print("system configuration: epoch=",epoch,", hidden layers=",hidden_layers)

optimization_algorithm = 'adam' #gradient-descent or adam

#------------------------
#trainset

x = np.array( #xor dataset
	[ #bias, #x1, #x2
		[[1],[0],[0]], #instance 1
		[[1],[0],[1]], #instance 2
		[[1],[1],[0]], #instance 3
		[[1],[1],[1]]  #instace 4
	]
)

if num_of_classes > 1: #classification
	y = np.array(
		[
			[[1],[0]],
			[[0],[1]],
			[[0],[1]],
			[[1],[0]],
		]
	)
else: #regression
	y = np.array(
		[
			[0], #instance 1
			[1], #instance 2
			[1], #instance 3
			[0]  #instace 4
		]
	)

"""
#suppose that traindata stored in this file. each line refers to an instance.
#final item of an instance is label (y) whereas the other ones are features  (x)
#now, loading trainset from external resource is available for regression problems
from numpy import genfromtxt
dataset = genfromtxt('../xor.csv', delimiter=',')
features = dataset[:,0:dataset.shape[1]-1]
labels = dataset[:,dataset.shape[1]-1:]
bias = np.array([1]);
x = [0 for i in range(features.shape[0])]
for i in range(features.shape[0]):
	x[i] = np.array([np.append([1], features[i])]).T
y = [0 for i in range(labels.shape[0])]
for i in range(labels.shape[0]):
	if num_of_classes == 1: #regression
		y[i] = np.array([labels[i]]).T
	else:
		encoded = [0 for i in range(num_of_classes)]
		encoded[int(labels[i])] = 1
		y[i] = np.array([encoded]).T
x = np.array(x)
y = np.array(y)
"""
#print("features: ",x)
#print("target: ",y)
#------------------------

num_of_features = x.shape[1]-1 #minus 1 refers to bias
num_of_instances = x.shape[0]
num_of_layers = len(hidden_layers) + 2 #plus input layer and output layer

#------------------------
def initialize_weights(rows, columns):
	#lecture: https://www.coursera.org/learn/deep-neural-network/lecture/RwqYe/weight-initialization-for-deep-networks
	weights = np.random.randn(rows+1, columns) #standard normal distribution, +1 refers to bias unit
	weights = weights * np.sqrt(1/rows) #xavier initialization. this is good for tanh (http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf)
	#weights = weights * np.sqrt(2/rows) #this is good for relu (https://www.cv-foundation.org/openaccess/content_iccv_2015/papers/He_Delving_Deep_into_ICCV_2015_paper.pdf)
	#weights = weights * np.sqrt(6/(rows + columns)) #normalized initialization (same ref with xavier initialization)
	return weights

#weight initialization
w = [0 for i in range(num_of_layers-1)]

w[0] = initialize_weights(num_of_features, hidden_layers[0])

if len(hidden_layers) > 1:
	for i in range(len(hidden_layers) - 1):
		w[i+1] = initialize_weights(hidden_layers[i], hidden_layers[i+1])

w[num_of_layers-2] = initialize_weights(hidden_layers[len(hidden_layers) - 1], num_of_classes)

#print("initial weights: ", w)
#------------------------

def sigmoid(netinput):
	netoutput = np.ones((netinput.shape[0] + 1, 1))
	#ones because init values are same as bias unit
	#size of output is 1 plus input because of bias

	for i in range(netinput.shape[0]):
		netoutput[i+1] = 1/(1 + math.exp(-netinput[i][0]))
	return netoutput

def applyFeedForward(x, w):

	netoutput = [i for i in range(num_of_layers)]
	netinput = [i for i in range(num_of_layers)]

	netoutput[0] = x
	for i in range(num_of_layers - 1):
		netinput[i+1] = np.matmul(np.transpose(w[i]), netoutput[i])
		netoutput[i+1] = sigmoid(netinput[i+1])

	netoutput[num_of_layers-1] = netoutput[num_of_layers-1][1:] #bias should not exist in output
	return netoutput

#------------------------

start_time = time.time()

def calculateCost():
	cost = 0
	for i in range(num_of_instances):
		nodes = applyFeedForward(x[i], w)
		predict = nodes[num_of_layers - 1]
		actual = y[i]

		cost = cost + sum(pow((actual - predict), 2)/2)

	cost = cost / num_of_instances
	return cost

#adam optimization parameters initialization
vdw = [0.0 for i in range(num_of_layers)]
sdw = [0.0 for i in range(num_of_layers)]
epsilon = np.array([pow(10, -8)])
beta1 = 0.9; beta2 = 0.999

J = [] #cost history
J.append(calculateCost()) #initial cost

for epoch in range(epoch):
	for i in range(num_of_instances):
		instance = x[i]
		nodes = applyFeedForward(instance, w)

		predict = nodes[num_of_layers - 1]
		actual = y[i]
		#print("predict: ",predict,", actual: ",actual)
		error = actual - predict
		#print("error: ",error)

		sigmas = [i for i in range(num_of_layers)] #error should not be reflected to input layer

		sigmas[num_of_layers - 1] = error
		for j in range(num_of_layers - 2, -1, -1):

			if sigmas[j + 1].shape[0] == 1:
				sigmas[j] = w[j] * sigmas[j + 1]
			else:
				if j == num_of_layers - 2: #output layer has no bias unit
					sigmas[j] = np.matmul(w[j], sigmas[j + 1])
				else: #otherwise remove bias unit from the following node because it is not connected from previous layer
					sigmas[j] = np.matmul(w[j], sigmas[j + 1][1:])

		#----------------------------------

		derivative_of_sigmoid = nodes * (np.array([1]) - nodes) #element wise multiplication and scalar multiplication
		sigmas = derivative_of_sigmoid * sigmas

		for j in range(num_of_layers - 1):

			if j == num_of_layers - 2: #outputlayer
				delta = nodes[j] * np.transpose(sigmas[j+1]) #no bias exist in output layer
			else:
				delta = nodes[j] * np.transpose(sigmas[j+1][1:])

			#-----------------------------------------------
			#optimization algorithm
			if optimization_algorithm == 'gradient-descent':
				w[j] = w[j] + learningRate * delta
			elif optimization_algorithm == 'adam':
				vdw[j] = beta1 * vdw[j] + (1 - beta1) * delta
				sdw[j] = beta2 * sdw[j] + (1 - beta2) * pow(delta, 2)

				vdw_corrected = vdw[j] / (1-pow(beta1, epoch+1))
				sdw_corrected = sdw[j] / (1-pow(beta2,epoch+1))

				w[j] = w[j] + learningRate * (vdw_corrected / (np.sqrt(sdw_corrected) + epsilon))
			##optimization algorithm end
	J.append(calculateCost())

#training end

x_axis = [i for i in range(len(J))]
plt.plot(x_axis, J, c='blue', label=optimization_algorithm)
plt.xlabel('epoch')
plt.ylabel('error')
plt.show()

#---------------------
print("--- execution for vectorization lasts %s seconds ---" % (time.time() - start_time))

#print("final weights: ",w)

for i in range(num_of_instances):
	nodes = applyFeedForward(x[i], w)
	predict = nodes[num_of_layers - 1]
	actual = y[i]
	print(np.transpose(x[i][1:])," -> actual: ", np.transpose(actual)[0],", predict: ", np.transpose(predict)[0])


import numpy as np

def mean_squared_error(y, t):
    return 0.5 * np.sum((y-t)**2)

t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0, 0.1, 0.0, 0.0]
print(mean_squared_error(np.array(y), np.array(t)))

y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0, 0.6, 0.0, 0.0]
print(mean_squared_error(np.array(y), np.array(t)))


import unittest
import pytest
import numpy as np

from autograd.tensor import Tensor

class TestTensorLog(unittest.TestCase):
    def test_simple_log(self):
        t1 = Tensor([1,2,3], requires_grad=True)
        t2 = t1.log()

        assert t2.data.tolist() == [np.log(a+1) for a in range(3)]

        t2.backward(Tensor([1,1,1]))

        assert t1.grad.data.tolist() == [1., 1/2, 1/3]


from collections import namedtuple
import sympy  # prime numbers manipulation
import random  # random integers generation

PUBLIC_KEY = namedtuple('Public_Key', ('enc_exponent', 'modulus'))
PRIVATE_KEY = namedtuple('Private_Key', ('dec_exponent', 'modulus'))

class Repository:
    """
    Public keys repository.
    """

    def __init__(self):
        self.public_keys = {}

    def add_key(self, name, key):
        """
        Adds a public key associated with a name to the repository.
        ---
        Args:
            - name(string): name of the key holder.
            - key(namedtuple): public key following the namedtuple convention above.
        Returns:
            - True if all goes well.
        """
        self.public_keys[name] = key

    def get_key(self, name):
        """
                Returns the public key from the holder's name.
                ---
                Args:
                        - name(String): key holder.
                Returns:
                        - public_key(NamedTuple): public key of the specified holder if it exists.
        """
        try:
            return self.public_keys[name]
        except Exception:
            print('Non-existing key. Check the key holder\'s name.')

    def get_all_keys(self):
        """
        Prints all existing keys.
        """
        for name in self.public_keys.keys():
            print(name + ': ', self.get_key(name))

class RSAInstance:
    """
    The RSA instance holding two keys: a public and a private key.
    It can send and receive messages from another RSA instance.
    """

    def __init__(self, name):
        self.name = name
        self.public_key = None
        self.private_key = None

        self._generate_keys()

    def _generate_keys(self):
        """
        function to generate the public and private key
        for the current instance.
        """
        # generate two prime numbers p and q in the interval [Lower, Upper]
        LOWER_BOUND = 0
        UPPER_BOUND = 10e2

        p = sympy.randprime(LOWER_BOUND, UPPER_BOUND)

        # generate q that is different from p
        q = p
        while q == p:
            q = sympy.randprime(LOWER_BOUND, UPPER_BOUND)

        # check whether p and q are both primes and are different numbers
        assert sympy.isprime(p)
        assert sympy.isprime(q)
        assert p != q

        # computing the modulus
        modulus = p * q

        # computing the totient of the modulus
        totient = (p - 1) * (q - 1)

        # selecting the encryption exponent in the interval ]1, totient[
        enc_exponent = 0
        while sympy.gcd(enc_exponent, totient) != 1:
            enc_exponent = random.randrange(2, totient)

        # create public key
        self.public_key = PUBLIC_KEY(enc_exponent, modulus)

        # decryption exponent
        dec_exponent = sympy.mod_inverse(enc_exponent, totient)

        # create private key
        self.private_key = PRIVATE_KEY(dec_exponent, modulus)

        # self.public_key = public_key(947, 8383)
        # self.private_key = private_key(7083, 8383)

    def encrypt(self, msg, to):
        """
        encrypting a message before sending it to another RSA instance.
        ---
        Args:
            - msg(String): message to be sent - Plaintext.
            - to(RSAInstance): receiver.
        Returns:
                - cipher(String): ciphered plaintext.
        """
        ascii_ = ""
        cipher = ""

        # convert string msg to ascii
        for character in msg:
            ascii_ += str(ord(character)) + " "

        # encrypt using public key of the receiver.
        for character in ascii_.strip().split(' '):
            cipher += str((int(character)**to.public_key.enc_exponent) %
                          to.public_key.modulus) + ' '

        return cipher

    def decrypt(self, cipher, from_, dig_sign=False):
        """
        decrypting a message encrypted by another RSA instance.
        ---
        Args:
            - msg(String): message to be sent - Plaintext.
            - to(RSAInstance): receiver.
        Returns:
            - cipher(String): ciphered plaintext.
        """
        # if dig_sign is true => decrypt using public key of from_
        ascii_ = ""
        res = ""

        # decryption using own private key
        for character in cipher.strip().split(' '):
            ascii_ += str((int(character)**self.private_key.dec_exponent) %
                          self.private_key.modulus) + ' '

        # convert ascii to char
        for character in ascii_.strip().split(' '):
            res += chr(int(character))

        return res


"""Auxiliary functions to generate Locally Differentially Private data."""

import numpy as np
import pandas as pd

def add_noise_laplace_mechanism(data_df: pd.DataFrame, epsilon: float,
                                sensitivity: float, seed: int) -> pd.DataFrame:
    """This function takes a (numerical) dataframe as input and yields a new
    dataframe as output where each element arises by adding noise to the
    corresponding element from the original dataframe. The Laplace mechanism,
    with scale = sensitivity / epsilon > 0, is used to generate the noise.
    A seed can be set for reproducubility."""
    output_df = data_df.copy()
    scale = sensitivity / epsilon
    noise = np.random.default_rng(seed).laplace(0, scale, output_df.shape)
    output_df = output_df + noise
    # for testing purposes: variance of Laplace(b) is 2b^2
    return output_df