""""
Author : Aditya Jain
Contact : https://adityajain.me
"""
import numpy as np
import matplotlib.pyplot as plt

class SGDRegressor():
	"""
	SGD regressor model, that optimizes using gradient descent

	Parameters
	----------
	lr : float, learning rate (Default 0.01)

	tol : float, tolerance as stopping criteria for gradient descent (Default : 0.01)

	seed : integer, random seed

	normalize : boolean, normalize X in fit method

	Attributes
	----------
	coef_ : Estimated coefficients for the linear regression problem

	intercept_ : integer, bias for the linear regression problem

	"""
	def __init__(self, learning_rate=0.01, tol=0.01, seed=None,normalize=False):
		self.W = None
		self.b = None
		self.__lr = learning_rate
		self.__tol = tol
		self.__length = None
		self.__normalize = normalize
		self.__m = None
		self.__costs = []
		self.__iterations = []
		np.random.seed(seed if seed is not None else np.random.randint(100))

	def __initialize_weights_and_bais(self):
		self.W = np.random.randn(self.__length) #(n,1)
		self.b = 0

	def __computeCost(self,h,Y):
		loss = np.square(h-Y)
		cost = np.sum(loss)/(2*self.__m)
		return cost

	def __optimize(self,X,Y):
		h = np.dot(X,self.W)+self.b
		dW = np.dot( X.T, (h-Y) ) / self.__m
		db = np.sum( h-Y )  / self.__m
		self.W = self.W - self.__lr*dW
		self.b = self.b - self.__lr*db

	def __normalizeX(self,X): return (X-self.__mean) / (self.__std)

	def fit(self, X, y, verbose=False):
		"""
		Fit X using y by optimizing weights and bias

		Parameters
		----------
		X : 2D numpy array, independent variables

		y : 1D numpy array, dependent variable

		verbose : boolean, print out details while optimizing (Default : False)

		"""
		if self.__normalize:
			self.__mean, self.__std = X.mean(axis=0), X.std(axis=0)
			X = self.__normalizeX(X)
		self.__m,self.__length = X.shape
		self.__initialize_weights_and_bais()
		last_cost,i = float('inf'),0
		while True:
			h = np.dot(X,self.W)+self.b
			cost = self.__computeCost(h,y)
			if verbose: print(f"Iteration: {i}, Cost: {cost:.3f}")
			self.__optimize(X,y)
			if last_cost-cost < self.__tol: break
			else: last_cost,i = cost,i+1
			self.__costs.append(cost)
			self.__iterations.append(i)

	def predict(self,X):
		"""
		Predict dependent variable

		Parameters
		----------
		X : numpy array, independent variables

		Returns
		-------
		predicted values

		"""
		if self.__normalize: X = self.__normalizeX(X)
		return np.dot(X,self.W)+self.b

	def plot(self,figsize=(7,5)):
		"""
		Plot a optimization graph
		"""
		plt.figure(figsize=figsize)
		plt.plot(self.__iterations,self.__costs)
		plt.xlabel('Iterations')
		plt.ylabel('Cost')
		plt.title("Iterations vs Cost")
		plt.show()

	def score(self,X,y):
		"""
		Computer Coefficient of Determination (rsquare)

		Parameters
		----------
		X : 2D numpy array, independent variables

		y : numpy array, dependent variables

		Returns
		-------
		r2 values

		"""
		return 1-(np.sum(((y-self.predict(X))**2))/np.sum((y-np.mean(y))**2))

	@property
	def coef_(self): return self.W

	@property
	def intercept_(self): return self.b

class LinearRegression():
	"""
	An implementation of OLS regression

	Parameters
	----------
	normalize : boolean, normalize data use standardscaler before fitting

	Attributes
	----------
	coef_ : coefficients for each of the feature

	intercept_ : y intercept

	"""
	def __init__(self, normalize=False):
		self.__bias = None
		self.__normalize = normalize
		self.__weights = None
		self.__std = None
		self.__mean = None

	def __normalizeX(X):
		return (X-self.__mean)/self.__std

	def fit(self,X,y):
		"""
		Fit X,y into the model

		Parameters
		----------
		X : numpy array, array of independent variables
		y : numpy array, dependent variable

		"""
		if self.__normalize:
			self.__mean, self.__std = X.mean(axis=0), X.std(axis=0)
			X = self.__normalizeX(X)

		#weights = (X'X)^-1 X'Y
		self.__weights = np.dot( np.linalg.inv(np.dot(X.T, X)), np.dot( X.T, y ))
		self.__bias = y.mean() - np.sum(b * X.mean(axis=0))

	def predict(self,X):
		"""
		Predict dependent variable

		Parameters
		----------
		X : numpy array, independent variables

		Returns
		-------
		predicted values

		"""
		if self.__normalize:
			X = self.__normalizeX(X)
		return np.dot(X, self.__weights )+ self.__bias

	def score(self,X,y):
		"""
		Computer Coefficient of Determination (rsquare)

		Parameters
		----------
		X : 2D numpy array, independent variables

		y : numpy array, dependent variables

		Returns
		-------
		r2 values

		"""
		return 1-(np.sum(((y-self.predict(X))**2))/np.sum((y-np.mean(y))**2))

	@property
	def coef_(self): return self.__weights

	@property
	def intercept_(self): return self.__bias


"""
In this challenge, we're reinforcing what we've learned today.

Task
A bag contains 3 red marbles and 4 blue marbles. Then, 2 marbles are drawn from the bag, at random, without replacement.
If the first marble drawn is red, what is the probability that the second marble is blue?
"""

import numpy as np

def second_blue(N=10000):
    num_1red = 0
    num_1red_2blue = 0
    for i in range(N):
        # suppose 0-2 are red, 3-6 are blue
        # draw the first marble
        marble1 = np.random.randint(0, 7)

        # draw the second marble
        marble2 = np.random.randint(0, 7)
        # if the same, then redraw
        while marble2 == marble1:
            marble2 = np.random.randint(0, 7)

        if marble1<= 2:
            num_1red += 1
            if marble2 in range(3, 7):
                num_1red_2blue += 1

    # conditional probability
    return num_1red_2blue / num_1red


#!/usr/bin/env python

import numpy as np
from scipy.spatial.distance import pdist, squareform

### For matlab interface
# scipy.io.loadmat and scipy.io.savemat

# Create the following array where each row is a point in 2D space:
# [[0 1]
#  [1 0]
#  [2 0]]
x = np.array([[0, 1], [1, 0], [2, 0]])
print x

# Compute the Euclidean distance between all rows of x.
# d[i, j] is the Euclidean distance between x[i, :] and x[j, :],
# and d is the following array:
# [[ 0.          1.41421356  2.23606798]
#  [ 1.41421356  0.          1.        ]
#  [ 2.23606798  1.          0.        ]]
d = squareform(pdist(x, 'euclidean'))
print d


import numpy as np
from simple_markov_chain_lib import markov_chain

## Build Markov Chain
markov_table = {
    1: {2: 0.5, 3: 0.5},
    2: {1: 1/3, 4: 2/3},
    3: {3: 0.8, 4: 0.2},
    4: {1: 0.6, 4: 0.4}
}

for starting in [1,2,3,4]:
    init_dist = {starting: 1.0} #the chain starts from state 1 since we are interested in excursions around state 1.

    mc = markov_chain(markov_table, init_dist)

    N = 100_000

    ##Initialize the dictionary "visits". Every state is a key of this dictionary, with value 0
    visits = {state: 0 for state in (1, 2, 3, 4)}

    mc.start()
    completed = 0
    stoppingTimeCounter = 0
    stoppingTimes = []
    ##Simulate N excursions. Every time we complete an excursion we increase completed by 1.
    while completed < N:
        visits[mc.running_state] += 1
        mc.move()
        stoppingTimeCounter += 1
        if mc.running_state == starting:
            stoppingTimes.append(stoppingTimeCounter)
            stoppingTimeCounter = 0
            completed +=1

    print("Invariant Distribution starting from {}:".format(starting))
    for x, y in visits.items():
        print("%d: %.3f" % (x, (y / N)/np.mean(stoppingTimes)))


from scipy.stats import multivariate_normal
import numpy as np

def classification(X, mu, sigma, weight):
    k = len(weight)
    n = X.shape[0]
    X_pdf = np.zeros([k, n])
    for i in range(k):
        mu_k = mu[i]
        sigma_k = sigma[i]
        X_pdf[i] = weight[i] * multivariate_normal(mu_k, sigma_k).pdf(X)

    gamma = X_pdf / X_pdf.sum(axis=0)
    return np.argmax(gamma, axis=0)

def step_E(X, mu, sigma, weight):
    k = len(weight)
    n = X.shape[0]
    X_pdf = np.zeros([k, n])
    for i in range(k):
        mu_k = mu[i]
        sigma_k = sigma[i]
        X_pdf[i] = weight[i] * multivariate_normal(mu_k, sigma_k).pdf(X)
    return X_pdf

def step_M(X, X_pdf, mu, sigma, weight, t):
    k = len(weight)
    n = X.shape[0]
    verosimilitud = 0
    gamma = X_pdf / X_pdf.sum(axis=0)
    for i in range(k):
        sum_gamma_k = np.sum(gamma[i])
        weight[i] = sum_gamma_k / n

        mu[i] = np.sum(np.multiply(X.T, gamma[i]).T, axis=0) / sum_gamma_k

        sigma[i] = np.dot((X - mu[i]).T, np.multiply((X - mu[i]).T, gamma[i]).T) / sum_gamma_k
        verosimilitud += np.sum(np.log(weight[i] * np.sum(X_pdf[i])))
    return mu, sigma, weight, verosimilitud

def EM_algoritmo(X, mu, sigma, weight, t, t_max, epsilon, k, verosimilitud):
    n = X.shape[1]
    n_samples = X.shape[0]
    if t == 0:
        weight = np.repeat(1 / k, k)
        index = np.random.choice(np.linspace(0, n_samples, n_samples + 1), k, False)
        index = [int(i) for i in index]
        mu = X[index]
        sigma = np.full([k, n, n], np.cov(X, rowvar=False))

    X_pdf = step_E(X, mu, sigma, weight)
    mu, sigma, weight, verosimilitud_new = step_M(X, X_pdf, mu, sigma, weight, t)
    if (np.abs(verosimilitud_new - verosimilitud) > epsilon) & (t < t_max):
        t += 1
        return EM_algoritmo(X, mu, sigma, weight, t, t_max, epsilon, k, verosimilitud_new)
    else:
        print("Converge in iterations", t)
        return mu, sigma, weight, verosimilitud


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

#----------------------------------------------------------------------------
#   MÉTRICAS
#----------------------------------------------------------------------------

def AutoCov(X, k):
  n = len(X)
  mx = np.mean(X)
  c = np.zeros(n-k)
  for i in range(n - k):
    c[i] = (X[i] - mx)*(X[i+k] - mx)
  c = c.mean()

  return c

def CrossCov(X, Y, k):
  n = len(X)
  mx = np.mean(X)
  my = np.mean(Y)
  c = np.zeros(n-k)
  for i in range(n - k):
    c[i] = (X[i] - mx)*(Y[i+k] - my)
  c = c.mean()

  return c

def CCF(X, Y, k):
  gamma_xy = CrossCov(X, Y, k)
  gamma_x = Var(X)
  gamma_y = Var(Y)
  return gamma_xy / np.sqrt(gamma_x * gamma_y)

def plot_ccf(X, Y, k, **kwargs):
  ccf = []
  for i in range(k):
    ccf.append(CCF(X, Y,  i))

  ax = kwargs.get("axis", None)
  if ax is None:
    fig, ax = plt.subplots(nrows=1, ncols=1,figsize=[10,5])

  ax.hlines([0],[0],[k], color="black")
  ax.vlines([i for i in range(k)], [0 for i in range(k)], ccf, color="red")
  ax.scatter([i for i in range(k)], ccf, marker="*")
  ax.set_xlabel("k")
  ax.set_ylabel("CCF(k)")

#----------------------------------------------------------------------------
#   MODELOS COM VARIÁVEIS EXÓGENAS
#----------------------------------------------------------------------------

def lags_x(endog, exog, k):
  t = len(endog)
  n = len(exog)
  X = np.zeros((t-k, (n+1)*k))
  Y = endog[k:]
  for i in range(k, t):
    X[i-k,0:k] = endog[i-k:i]
    for e in range(n):
      X[i-k,(e+1)*k:(e+2)*k] = exog[e][i-k:i]
  return X,Y

def ajustar_arx(endog, exog, parametros):
  p = parametros[0]
  X,Y = lags_x(endog, exog, p)

  coef = np.linalg.inv(X.T @ X) @ (X.T @ Y )

  previsoes = arx(endog, exog, [coef, None])

  residuos = endog[p:] - previsoes

  sigma2 = np.std(residuos)

  return coef, sigma2

def arx(endog, exog, parametros):
  coef, _ = parametros
  t = len(endog)
  n = len(exog)
  p = int(len(coef) / (n+1))
  ret = np.zeros(t-p)
  X, _ = lags_x(endog, exog, p)
  for i in range(p,t):
    ret[i-p] = X[i-p].dot(coef)

  return ret

#----------------------------------------------------------------------------
#   MODELOS COM MULTIVARIADOS / VETORIAIS
#----------------------------------------------------------------------------

def lags_v(dados, p):
  T, n = dados.shape
  X = np.zeros((T-p, n*p))
  Y = dados[p:, :]
  for i in range(p, T):
    for j in range(p):
      X[i - p, j*n:(j*n)+n] = dados[i-(p-j), : ]
  return X, Y

def var(dados, parametros):
  T, n = dados.shape
  coef, _ = parametros
  p = int(coef.shape[0]/n)
  X,_ = lags_v(dados, p)
  ret = np.zeros((T-p, n))
  for i in range(T-p):
    ret[i, :] = coef.T @ X[i, :]
  return ret

def ajustar_var(dados, p):
  X,Y = lags_v(dados, p)

  coef = np.linalg.inv(X.T @ X) @ ( X.T @ Y )

  previsoes = var(dados, [coef, None])

  residuos = dados[p:, :] - previsoes

  Sigma = np.sqrt(np.cov(residuos, rowvar=False))

  return coef, Sigma


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize

# exponential fn to fit to curves
def expfun(t, c1, a, T_inf):
    return - c1 * np.exp(-a * t) + T_inf

rawdata = pd.read_csv('lab2_home_raw_data.csv')

fig1, ax1 = plt.subplots(figsize=(7,3), tight_layout=True)
fig2, ax2 = plt.subplots(figsize=(7,3), tight_layout=True)

# we iterate through each type, of which
# there are two: (uninsulated, insulated)
curve_parameters = dict()
for runtype, d1 in rawdata.groupby('type'):
    xs = d1['time'][d1['time'] <= 50]
    ys = d1['tempK'][d1['time'] <= 50] - 273.15
    '''
    fit to our model of the system. For a body for which LC assumption is true, the governing
    equation is given by:

    dTs/dt = - (h As) / (m Cv) * ( T_s(t) - T_inf )

    We can group parameters:
    dTs/dt = - a * (Ts(t) - Tinf)

    This 1st order ode has solution of the form:
    where c1, a, and T_inf are free parameters

    T_s(t) = - c1 e^( -a t ) + T_inf

    So we fit the exp curve to those parameters
    '''
    params, _ = scipy.optimize.curve_fit(expfun, xs, ys, p0=(1, 1e-2, 1))
    xxs = np.linspace(np.min(xs), np.max(xs), 900)
    yys = expfun(xxs, *params)
    curve_parameters[runtype] = {
        'c1' : params[0],
        'hAs/mCv' : params[1],
        'T_inf' : params[2]
    }

    # we iterate through each run
    if runtype == 'uninsulated':
        for run, d2 in d1.groupby('video_fname'):
            ax1.scatter(d2['time'][d2['time'] <= 50], d2['tempK'][d2['time'] <= 50]- 273.15, marker='+', label=runtype)
        ax1.plot(xxs, yys, 'k', label='exp fitted - {}'.format(runtype))
        ax1.set_ylabel('Temperature (C)')
        ax1.set_xlabel('Time (s)')
        ax1.legend()

    elif runtype == 'insulated':
        for run, d2 in d1.groupby('video_fname'):
            ax2.scatter(d2['time'][d2['time'] <= 50], d2['tempK'][d2['time'] <= 50]- 273.15, marker='+', label=runtype)
        ax2.plot(xxs, yys, 'k', label='exp fitted - {}'.format(runtype))
        ax2.set_ylabel('Temperature (C)')
        ax2.set_xlabel('Time (s)')
        ax2.legend()

pd.DataFrame(curve_parameters).to_csv('table1.csv')
plt.show()


import numpy as np
from numpy import random
from collections import deque

def forward(A,B,pi,sequence,scale=False):
    N=A.shape[0]
    M=B.shape[1]
    T=len(sequence)
    alpha=np.zeros([T,N])
    alpha[0]=pi*B[:,sequence[0]]
    t=1
    while True:
        if t==T:
            break
        alpha[t]=alpha[t-1]@A*B[:,sequence[t]]
        if scale:
            alpha[t]/=np.sum(alpha[t])
        t+=1
    return(np.sum(alpha[T-1]),alpha)

def backward(A,B,pi,sequence,scale=False):
    N=A.shape[0]
    M=B.shape[1]
    T=len(sequence)
    beta=np.zeros([T,N])
    beta[T-1]=1
    t=T-2
    while True:
        if t<0:
            break
        beta[t]=A@(B[:,sequence[t+1]]*beta[t+1])
        if scale:
            beta[t]/=np.sum(beta[t])
        t-=1
    return(np.sum(pi*B[:,sequence[0]]*beta[0]),beta)

def Viterbi(A,B,pi,sequence):
    N=A.shape[0]
    M=B.shape[1]
    T=len(sequence)
    delta=np.zeros([T,N])
    psi=np.zeros([T,N])
    delta[0]=pi*B[:,sequence[0]]
    t=1
    while True:
        if t==T:
            break
        delta_A=delta[t-1,np.newaxis].T*A
        delta[t]=np.max(delta_A,axis=0)*B[:,sequence[t]]
        psi[t]=np.argmax(delta_A,axis=0)
        t+=1
    psi=psi.astype(int)
    q=np.zeros(T).astype(int)
    q[T-1]=np.argmax(delta[T-1])
    t=T-2
    while True:
        if t<0:
            break
        q[t]=psi[t+1,q[t+1]]
        t-=1
    return(q)

def Baum_Welch(A,B,pi,sequence,max_iter,threshold=1e-15,scale=False):
    N=A.shape[0]
    M=B.shape[1]
    T=len(sequence)
    likelihood,alpha=forward(A,B,pi,sequence,scale)
    for i in range(max_iter):
        beta=backward(A,B,pi,sequence,scale)[1]
        #temporary variables
        gamma=alpha*beta/np.sum(alpha*beta,axis=1).reshape((T,1))
        xi=np.zeros([N,N,T-1])
        for t in range(T-1):
            xi[:,:,t]=alpha[t].reshape((N,1))*A*beta[t+1]*B[:,sequence[t+1]]
            xi[:,:,t]=xi[:,:,t]/np.sum(xi[:,:,t])
        pi=gamma[0]
        A=np.sum(xi,axis=2)/np.sum(gamma[:-1],axis=0).reshape([N,1])
        B=np.zeros([N,M])
        for t in range(T):
            B[:,sequence[t]]+=gamma[t]
        B=B/np.sum(gamma,axis=0).reshape([N,1])
        likelihood_new,alpha=forward(A,B,pi,sequence,scale)
        if abs(likelihood-likelihood_new)<threshold:
            break
        likelihood=likelihood_new
    return(A,B,pi)

def Baum_Welch_linear_memory(A,B,pi,sequence,max_iter,threshold=1e-15):
    N=A.shape[0]
    M=B.shape[1]
    T=len(sequence)
    ###########################
    for z in range(max_iter):
        ##Beta_t+1
        beta_tilt_old=np.zeros(N)
        ##Beta_t
        beta_tilt_new=np.zeros(N)
        #T_t+1
        T_tilt_old=np.zeros([N,N,N])
        #T_t
        T_tilt_new=np.zeros([N,N,N])
        #E_t+1
        E_tilt_old=np.zeros([N,M,N])
        #E_t
        E_tilt_new=np.zeros([N,M,N])
        beta_tilt_old+=1
        d=1/np.sum(beta_tilt_old)
        beta_tilt_old=d*beta_tilt_old
        for m in range(N):
            for i in range(N):
                for gamma in range(M):
                    E_tilt_old[m,gamma,m]=beta_tilt_old[i]*int(sequence[T-1]==gamma)
        for t in range(T-2,-1,-1):
            beta_tilt_new=A@(B[:,sequence[t+1]]*beta_tilt_old)
            dt=1/np.sum(beta_tilt_new)
            for m in range(N):
                for i in range(N):
                    for j in range(N):
                        partial=0
                        for n in range(N):
                            partial+=A[m,n]*T_tilt_old[i,j,n]*B[n,sequence[t+1]]
                        T_tilt_new[i,j,m]=dt*(beta_tilt_old[j]*A[m,j]*B[j,sequence[t+1]]*int(i==m)+partial)
                    for gamma in range(M):
                        partial=0
                        for n in range(N):
                            partial+=B[n,sequence[t+1]]*A[m,n]*E_tilt_old[i,gamma,n]
                        E_tilt_new[i,gamma,m]=dt*(partial+beta_tilt_new[m]*int(sequence[t]==gamma)*int(m==i))
            beta_tilt_new=dt*beta_tilt_new
            beta_tilt_old=beta_tilt_new
            T_tilt_old=T_tilt_new
            E_tilt_old=E_tilt_new
        E_end=np.zeros([N,M])
        T_end=np.zeros([N,N])
        for m in range(N):
            E_end+=E_tilt_old[:,:,m]*pi[m]*B[m,sequence[0]]
            T_end+=T_tilt_old[:,:,m]*pi[m]*B[m,sequence[0]]
        alpha=pi*B[:,sequence[0]]
        pi=alpha*beta_tilt_old
        pi=pi/np.sum(pi)
        B=E_end/np.sum(E_end,axis=1).reshape((N,1))
        A=T_end/np.sum(T_end,axis=1).reshape((N,1))
    return(A,B,pi)

def Viterbi_linear_memory(A,B,pi,sequence):
    N=A.shape[0]
    M=B.shape[1]
    T=len(sequence)
    delta=np.zeros([T,N])
    psi=np.zeros([T,N])
    d = deque([], maxlen=T)
    delta[0]=pi*B[:,sequence[0]]
    t=1
    while True:
        if t==T:
            break
        delta_A=delta[t-1,np.newaxis].T*A
        delta[t]=np.max(delta_A,axis=0)*B[:,sequence[t]]
        d.append(np.argmax(delta_A,axis=0).astype(int))
        t+=1

    q=np.zeros(T).astype(int)
    q[T-1]=np.argmax(delta[T-1])

    t=T-2
    while d:
        q[t]=d.pop().reshape([N,1])[q[t+1]]
        t-=1
    return q

def sim_HMM(A,B,pi,length):
    states=np.arange(A.shape[0])
    outcomes=np.arange(B.shape[1])
    out_states=np.zeros(length)
    out_emission=np.zeros(length)
    out_states=np.zeros(length).astype(int)
    out_emission=np.zeros(length).astype(int)
    out_states[0]=random.choice(states,size=1,p=pi)
    out_emission[0]=random.choice(outcomes,size=1,p=B[out_states[0]])
    for i in range(1,length):
        out_states[i]=random.choice(states,size=1,p=A[out_states[i-1]])
        out_emission[i]=random.choice(outcomes,size=1,p=B[out_states[i]])
    return(out_states,out_emission)


import math
import numpy as np
import plotly.express as px
import plotly.graph_objects as go

# Relationship between power (kW) and Torque (Nm) with Motor Speed 2000 rpm
x = np.array([1.1, 1.5, 2.2, 3.7, 5.6])
y = np.array([5.3, 7.1, 10.7, 18, 27])

def gradient_descent(epochs, alpha):
    m = 0
    c = 0
    n = len(x)

    for _ in range(epochs):
        Y_pred = m*x + c

        D_m = (-2/n)*sum(x*(y - Y_pred))
        D_c = (-2/n)*sum(y - Y_pred)

        m = m - alpha * D_m
        c = c - alpha * D_c

    return [m, c]

def predict(x_train):
    [m, c] = gradient_descent(1000, 0.01)
    print('m = %.5f c = %.5f\n' % (m, c))
    Y_predict = m*x_train + c

    return Y_predict

def rmse(Y_predict):
    n = len(x)
    substract = []
    squared_error = []

    for i in range(n):
        subs = Y_predict[i] - y[i]
        substract.append(subs)
        square = pow(substract[i], 2)
        squared_error.append(square)

    rmse = math.sqrt(sum(squared_error) / n)

    return rmse

y_prediction = predict(x)
y_prediction = np.round(y_prediction, 3)

print('Prediction = %s\n' % (y_prediction))
print('RMSE = %s' % (rmse(y_prediction)))

fig1 = px.scatter(x=x, y=y, color_discrete_sequence=['green'])
fig = go.Figure(data=fig1.data)
fig.add_trace(go.Scatter(x=x, y=y_prediction, name='Linear Regression'))
fig.show()


import numpy as np
from math import sqrt

def distance(x1, y1, x2, y2):
    '''
    Distance between two points (x1, y1), (x2, y2).
    '''
    return pow((pow(x1 - x2, 2) + pow(y1 - y2, 2)), 0.5)

def node_dist(node1, node2):
    '''
    Distance between two nodes.
    '''
    return distance(node1.x, node1.y, node2.x, node2.y)

def edge_dist(A, B, E):
    '''
    Distance from Node E to edge A->B. Adapted from GeeksforGeeks.
    '''
    A = [A.x, A.y]
    B = [B.x, B.y]
    E = [E.x, E.y]
    # vector AB
    AB = [None, None];
    AB[0] = B[0] - A[0];
    AB[1] = B[1] - A[1];

    # vector BP
    BE = [None, None];
    BE[0] = E[0] - B[0];
    BE[1] = E[1] - B[1];

    # vector AP
    AE = [None, None];
    AE[0] = E[0] - A[0];
    AE[1] = E[1] - A[1];

    # Variables to store dot product

    # Calculating the dot product
    AB_BE = AB[0] * BE[0] + AB[1] * BE[1];
    AB_AE = AB[0] * AE[0] + AB[1] * AE[1];

    # Minimum distance from
    # point E to the line segment
    reqAns = 0;

    # Case 1
    if (AB_BE > 0) :

        # Finding the magnitude
        y = E[1] - B[1];
        x = E[0] - B[0];
        reqAns = sqrt(x * x + y * y);

    # Case 2
    elif (AB_AE < 0) :
        y = E[1] - A[1];
        x = E[0] - A[0];
        reqAns = sqrt(x * x + y * y);

    # Case 3
    else:

        # Finding the perpendicular distance
        x1 = AB[0];
        y1 = AB[1];
        x2 = AE[0];
        y2 = AE[1];
        mod = sqrt(x1 * x1 + y1 * y1);
        reqAns = abs(x1 * y2 - y1 * x2) / mod;

    return reqAns


import numpy as np

def mdape(y_actual, y_pred):
    # median absolute percentage error
    return np.median(np.abs((y_actual - y_pred) / y_actual)) * 100


# Native

# Site-packages
import numpy as np

# Locals

def MSE(y_true: np.array, y_pred: np.array) -> float:
    return np.round(((y_true - y_pred)**2).mean(), 5)

def MAE(y_true: np.array, y_pred: np.array) -> float:
    return np.round((np.abs(y_true - y_pred)).mean(), 5)

def RMSE(y_true: np.array, y_pred: np.array) -> float:
    return np.round(MSE(y_true, y_pred)**0.5, 5)

def logLoss(y_true: np.array, y_pred: np.array) -> float:
    pred = (y_pred * (1 - 2 * 1e-15)) + 1e-15
    return np.round(-((y_true * np.log(pred)) + ((1 - y_true) * np.log(1 - pred))).mean(axis=0), 5)

def hingeLoss(y_true, y_pred):
    return np.round(np.clip(1 - y_true * y_pred, 0, float('inf')).mean(axis=0), 5)


import numpy as np
from scipy import constants
import matplotlib as mpl
import matplotlib.ticker
import matplotlib.pyplot as plt
import sys

re = 6371E3;

def distance(phi_l_deg, h):
    phi_l_rad = phi_l_deg * np.pi / 180.0;
    return np.sqrt((re * np.sin(phi_l_rad))**2 + 2 * re * h + h**2) - re * np.sin(phi_l_rad)

def fsl(d, f):
    c = constants.speed_of_light
    return 20.0 * np.log10( 4 * np.pi * f * d / c )

def elevation_angle_to_earth_angle(elevation_angle: float, orbit_height: float):
    elevation_angle = elevation_angle * np.pi / 180
    return 180 / np.pi * (np.arccos(re / (re + orbit_height) * np.cos(elevation_angle)) - elevation_angle)

if __name__ == "__main__":

    plt.close()

    h = 650E3;
    a = np.linspace(90, 0, 19);
    z = distance(a, h);

    if(len(sys.argv) >= 3):
        elevation_angle = int(sys.argv[1])
        f               = int(sys.argv[2])
        print(fsl(10**3 * distance(elevation_angle, h), 10**9 * f))
        exit()

    fig, ax = plt.subplots(1)
    ax.plot(a, z / 1e3, 'rx')
    ax.invert_xaxis()
    ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(base = 10.0))

    ax.grid(True, which = 'major')
    ax.grid(True, which = 'minor', axis = 'y')
    ax.minorticks_on()

    plt.title   ("Distance between satellite and base station")
    plt.xlabel  ("Elevation angle $\phi_l$ [deg]")
    plt.ylabel  ("Distance [km]")

    plt.savefig ("../output/distance.svg")
    plt.savefig ("../output/distance.png")

    plt.show()

    fig, ax = plt.subplots(1)
    losses = fsl(z, 7.8E9)
    ax.plot(a, losses, 'rx')
    ax.invert_xaxis()
    ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(base = 10.0))

    ax.grid(True, which = 'major')
    ax.grid(True, which = 'minor', axis = 'y')
    ax.minorticks_on()

    plt.title   ("Free space losses")
    plt.xlabel  ("Elevation angle $\phi_l$ [deg]")
    plt.ylabel  ("FSL [dB]")

    plt.savefig ("../output/fsl.svg")
    plt.savefig ("../output/fsl.png")

    plt.show()


# -*- coding: utf-8 -*-
"""
Created on Mon Feb 15 11:37:30 2021
Simulate SIR Model:
    Where
    S — The number of people who are susceptible to the disease
    I — The number of people infected with the disease
    R — Those incapable of infecting others; either recovered or diseased
@author: ROY.ZHOU
"""

import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt

# Total population, N.
N = 1000
# Initial number of infected and recovered individuals, I0 and R0.
I0, R0 = 1, 0
# Everyone else, S0, is susceptible to infection initially.
S0 = N - I0 - R0
# Contact rate, beta, and mean recovery rate, gamma, (in 1/days).
beta, gamma = 0.2, 1./10
# A grid of time points (in days)
t = np.linspace(0, 160, 160)

# The SIR model differential equations
def deriv(y, t, N, beta, gamma):
    S, I, R = y
    dSdt = -beta * S * I / N
    dIdt = beta * S * I / N - gamma * I
    dRdt = gamma * I
    return dSdt, dIdt, dRdt

# Initial conditions vector
y0 = S0, I0, R0
# Integrate the SIR equations over the time grid, t.
ret = odeint(deriv, y0, t, args=(N, beta, gamma))
S, I, R = ret.T

# Plot the data on three separate curves for S(t), I(t) and R(t)
fig = plt.figure(facecolor='w')
ax = fig.add_subplot(111, facecolor='#dddddd', axisbelow=True)
ax.plot(t, S/1000, 'b', alpha=0.5, lw=2, label='S')
ax.plot(t, I/1000, 'r', alpha=0.5, lw=2, label='I')
ax.plot(t, R/1000, 'g', alpha=0.5, lw=2, label='R')
ax.set_xlabel('Time / days')
ax.set_ylabel('Number (1000s)')
ax.set_ylim(0,1.2)
ax.yaxis.set_tick_params(length=0)
ax.xaxis.set_tick_params(length=0)
legend = ax.legend()
legend.get_frame().set_alpha(0.6)
for spine in ('top', 'right', 'bottom', 'left'):
    ax.spines[spine].set_visible(False)
plt.show()


import numpy as np
import sympy as sp
from scipy.misc import derivative
from scipy import stats

def errorprop(f, variables, values, errors):
    """Propagate errors"""
    returnvals = f.subs([(var, val) for var, val in zip(variables, values)])
    derivsum = sum([sp.Derivative(f, var)**2 * err**2 for var, err in zip(variables, errors)])
    prop = sp.sqrt(derivsum).doit().subs([(var, val) for var, val in zip(variables, values)])
    return np.float64(sp.N(returnvals)), np.float64(sp.N(prop))

def errorprop2(f, values, errors):
    value = f(*values)
    som = 0
    for i in range(0, len(values)):
        deriv = derivative(lambda x: f(*values[0:i], x, *values[i+1:len(values)]), values[i])
        som += (deriv**2 * errors[i]**2)
    error = np.sqrt(som)
    return (value, error)

def chi2(x, y, dy, model, parameters):
    """Geeft least-squares waarde terug"""
    errors = ((y - model(x, *parameters))**2) / dy**2
    return np.sum(errors)

def weighted_average(waardenlijst, foutenlijst):
    """Geeft gewogen gemiddelde en de bijhorende fout"""
    gewichtenlijst = []
    for fout in foutenlijst:
        gewichtenlijst.append(1 / (fout**2))
    fout_op_gemiddelde = 1 / np.sqrt(sum(gewichtenlijst))

    tellerlijst = []
    for i in range(len(waardenlijst)):
        tellerlijst.append(gewichtenlijst[i]*waardenlijst[i])

    teller = sum (tellerlijst)
    noemer = sum (gewichtenlijst)

    gewogen_gemiddelde = teller / noemer
    # print("Het gewogen gemiddelde is ", gewogen_gemiddelde, "+-", fout_op_gemiddelde)
    return gewogen_gemiddelde, fout_op_gemiddelde

def test_compatibiliteit(x, sx, y, sy, alpha=None):
    """Test compatibiliteit van twee waarden"""
    fout = np.sqrt(sx**2 + sy**2)
    z = np.abs(x-y) / fout
    p = 2*(1 - stats.norm.cdf(z))
    print("z-value is:  ", str(round(z, 3)))
    print("p-value is:  ", str(round(p, 3)), " = ", str(round(p*100,1)),"%")
    if alpha:
        if p < alpha:
            print("REJECT at alpha = {}".format(alpha))
        else:
            print("NOT REJECTED at alpha = {}".format(alpha))
    else:
        if p < 0.05:
            print("REJECT at alpha = 0.05")
        if p < 0.01:
            print("REJECT at alpha = 0.01")

    return z, p


#!/usr/bin/env python
# Demonstrate criterion of Chauvenet to exclude poor data
# Use data example from Bevington & Robinson

from numpy.random import normal
from scipy.special import erf, erfc
import numpy
from kapteyn import kmpfit
from matplotlib.pyplot import figure, show, rc

def chauvenet(x, y, mean=None, stdv=None):
   #-----------------------------------------------------------
   # Input:  NumPy arrays x, y that represent measured data
   #         A single value of a mean can be entered or a
   #         sequence of means with the same length as
   #         the arrays x and y. In the latter case, the
   #         mean could be a model with best-fit parameters.
   # Output: It returns a boolean array as filter.
   #         The False values correspond to the array elements
   #         that should be excluded
   #
   # First standardize the distances to the mean value
   # d = abs(y-mean)/stdv so that this distance is in terms
   # of the standard deviation.
   # Then the  CDF of the normal distr. is given by
   # phi = 1/2+1/2*erf(d/sqrt(2))
   # Note that we want the CDF from -inf to -d and from d to +inf.
   # Note also erf(-d) = -erf(d).
   # Then the threshold probability = 1-erf(d/sqrt(2))
   # Note, the complementary error function erfc(d) = 1-erf(d)
   # So the threshold probability pt = erfc(d/sqrt(2))
   # If d becomes bigger, this probability becomes smaller.
   # If this probability (to obtain a deviation from the mean)
   # becomes smaller than 1/(2N) than we reject the data point
   # as valid. In this function we return an array with booleans
   # to set the accepted values.
   #
   # use of filter:
   # xf = x[filter]; yf = y[filter]
   # xr = x[~filter]; yr = y[~filter]
   # xf, yf are cleaned versions of x and y and with the valid entries
   # xr, yr are the rejected values from array x and y
   #-----------------------------------------------------------
   if mean is None:
      mean = y.mean()           # Mean of incoming array y
   if stdv is None:
      stdv = y.std()            # Its standard deviation
   N = len(y)                   # Lenght of incoming arrays
   criterion = 1.0/(2*N)        # Chauvenet's criterion
   d = abs(y-mean)/stdv         # Distance of a value to mean in stdv's
   d /= 2.0**0.5                # The left and right tail threshold values
   prob = erfc(d)               # Area normal dist.
   filter = prob >= criterion   # The 'accept' filter array with booleans
   return filter                # Use boolean array outside this function

def residuals(p, data):
   a, b = p
   x, y, err = data
   return (y-a-b*x)/err

def prob( Xlo, Xhi ):
   sq2 = numpy.sqrt(2.0)
   # Left tail and right tail area
   return 1.0 - 0.5 * (erf(Xhi/sq2) - erf(Xlo/sq2))

# Artificial data
x = numpy.array([2, 4, 6, 8, 10, 12])
y = numpy.array([3.5, 7.2, 9.5, 17.1, 20.0, 25.5])
err = numpy.array([0.55, 0.65, 0.74, 0.5, 0.85, 0.6])

# Prepare plot
fig = figure()
rc('legend', fontsize=8)
frame = fig.add_subplot(1,1,1)
frame.plot(x, y, 'go', label="data")
frame.set_xlabel("x")
frame.set_ylabel("y")
frame.set_title("Exclude poor data with criterion of Chauvenet")

params0 = (1,1)
fitter = kmpfit.Fitter(residuals=residuals, data=(x,y,err))
fitter.fit(params0=params0)

print("======== Fit results all data included ==========")
print("Params:                      ", fitter.params)
print("Uncertainties:               ", fitter.xerror)
print("Errors assuming red.chi^2=1: ", fitter.stderr)
print("Iterations:                  ", fitter.niter)
print("Function ev:                 ", fitter.nfev)
print("dof:                         ", fitter.dof)
print("chi^2, rchi2:                ", fitter.chi2_min, fitter.rchi2_min)
print("Status:                      ", fitter.status)

from scipy.stats import chi2
rv = chi2(fitter.dof)
print("If H0 was correct, then")
print("the probability to find a chi-squared higher than this:  ", 1-rv.cdf(fitter.chi2_min))
print("If we set the threshold to alpha=0.05, we REJECT H0.")

a, b = fitter.params
N = len(y)
mean = a + b*x
stdv = err
criterion = 1.0/(2*N)
print("\nExclude loop:")
for xf, yf, m, std in zip(x, y, mean, stdv):
   d = abs(yf-m)/std
   P = prob(-d, d)
   if P < criterion:
      print("Data y=%f has distance %fsigma to mean (%f), prob.=%f" %(yf,d,m,P))
      print("Based on Chauvenet's criterion (prob=%g), we reject data point y=%g"\
      %(criterion,yf))
      frame.plot((xf,), (yf,), 'rx', ms=20)

# The function chauvenet() does it the NumPy way
filter = chauvenet(x, y, mean, stdv)
xf = x[filter]; yf = y[filter]; errf = err[filter]
xe = x[~filter]; ye = y[~filter]; erre = err[~filter]
print("Excluded by function chauvenet() are:")
print(list(zip(xe, ye)))
fitter = kmpfit.Fitter(residuals=residuals, data=(xf,yf,errf))
fitter.fit(params0=params0)

print("\n======== Fit results with filtered data ==========")
print("Params:                      ", fitter.params)
print("Uncertainties:               ", fitter.xerror)
print("Errors assuming red.chi^2=1: ", fitter.stderr)
print("Iterations:                  ", fitter.niter)
print("Function ev:                 ", fitter.nfev)
print("dof:                         ", fitter.dof)
print("chi^2, rchi2:                ", fitter.chi2_min, fitter.rchi2_min)
print("Status:                      ", fitter.status)

rv = chi2(fitter.dof)
print("If H0 was correct, then")
print("the probability to find a chi-squared higher than this:  ", 1-rv.cdf(fitter.chi2_min))
print("If we set the threshold to alpha=0.05, we ACCEPT H0.")

frame.set_ylim(0, 1.1*y.max())
frame.errorbar(xf, yf, errf, fmt='go')
frame.errorbar(xe, ye, erre, fmt='ro')
frame.plot(x, a+b*x, 'g', label="Fit unfilterd data")
a, b = fitter.params
frame.plot(x, a+b*x, 'b', label="Fit filterd data")
leg = frame.legend(loc=2)
show()


# -*- coding: utf-8 -*-
"""2D functions."""
import numpy as np

def angle(origin, pt):
    """
    compute angle between the vector from origin to pt and the x-direction vector.

    For example:

    .. doctest::

        >>> angle((0,0), (1,1)) # should return pi/4
        0.7853981633974484
    """
    x1, y1 = (1, 0)
    x2, y2 = (pt[0] - origin[0], pt[1] - origin[1])
    inner_product = x1 * x2 + y1 * y2
    len1 = np.hypot(x1, y1)
    len2 = np.hypot(x2, y2)
    if y2 < 0:
        return 2 * np.pi - np.arccos(inner_product / (len1 * len2))
    else:
        return np.arccos(inner_product / (len1 * len2))

if __name__ == "__main__":
    import doctest
    doctest.testmod()


import numpy as np

def softmax(predictions):
    """
    Computes probabilities from scores

    Arguments:
      predictions, np array, shape is either (N) or (batch_size, N) -
        classifier output

    Returns:
      probs, np array of the same shape as predictions -
        probability for every class, 0..1
    """
    axis = predictions.ndim - 1
    stab = (predictions.T - np.max(predictions, axis=axis)).T
    exps = np.exp(stab)
    return (exps.T / exps.sum(axis=axis)).T

def cross_entropy_loss(probs, target_index):
    """
    Computes cross-entropy loss

    Arguments:
      probs, np array, shape is either (N) or (batch_size, N) -
        probabilities for every class
      target_index: np array of int, shape is (1) or (batch_size) -
        index of the true class for given sample(s)

    Returns:
      loss: single value
    """
    if probs.ndim == 1:
        idx = target_index
    else:
        idx = (np.arange(probs.shape[0]), target_index)
    return -np.mean(np.log(probs[idx]))

def softmax_with_cross_entropy(predictions, target_index):
    """
    Computes softmax and cross-entropy loss for model predictions,
    including the gradient

    Arguments:
      predictions, np array, shape is either (N) or (batch_size, N) -
        classifier output
      target_index: np array of int, shape is (1) or (batch_size) -
        index of the true class for given sample(s)

    Returns:
      loss, single value - cross-entropy loss
      dprediction, np array same shape as predictions - gradient of predictions by loss value
    """
    probs = softmax(predictions)
    loss = cross_entropy_loss(probs, target_index)

    if probs.ndim == 1:
        n_batches = 1
        idx = target_index
    else:
        n_batches = probs.shape[0]
        idx = (np.arange(n_batches), target_index)

    dprediction = probs
    dprediction[idx] -= 1
    dprediction /= n_batches

    return loss, dprediction

def l2_regularization(W, reg_strength):
    """
    Computes L2 regularization loss on weights and its gradient

    Arguments:
      W, np array - weights
      reg_strength - float value

    Returns:
      loss, single value - l2 regularization loss
      gradient, np.array same shape as W - gradient of weight by l2 loss
    """
    loss = reg_strength * (W ** 2).sum()
    grad = 2 * reg_strength * W
    return loss, grad

def linear_softmax(X, W, target_index):
    """
    Performs linear classification and returns loss and gradient over W

    Arguments:
      X, np array, shape (num_batch, num_features) - batch of images
      W, np array, shape (num_features, classes) - weights
      target_index, np array, shape (num_batch) - index of target classes

    Returns:
      loss, single value - cross-entropy loss
      gradient, np.array same shape as W - gradient of weight by loss

    """
    predictions = X.dot(W)
    loss, dprediction = softmax_with_cross_entropy(predictions, target_index)
    dW = X.T.dot(dprediction)
    return loss, dW

class LinearSoftmaxClassifier:
    def __init__(self):
        self.W = None

    def fit(self, X, y, batch_size=100, learning_rate=1e-7, reg=1e-5,
            epochs=1):
        """
        Trains linear classifier

        Arguments:
          X, np array (num_samples, num_features) - training data
          y, np array of int (num_samples) - labels
          batch_size, int - batch size to use
          learning_rate, float - learning rate for gradient descent
          reg, float - L2 regularization strength
          epochs, int - number of epochs
        """

        num_train = X.shape[0]
        num_features = X.shape[1]
        num_classes = np.max(y) + 1
        if self.W is None:
            self.W = 0.001 * np.random.randn(num_features, num_classes)

        loss_history = []
        for epoch in range(epochs):
            loss = None
            shuffled_indices = np.arange(num_train)
            np.random.shuffle(shuffled_indices)
            sections = np.arange(batch_size, num_train, batch_size)
            batches_indices = np.array_split(shuffled_indices, sections)

            for batch in batches_indices:
                ce_loss, ce_grad = linear_softmax(X[batch], self.W, y[batch])
                reg_loss, reg_grad = l2_regularization(self.W, reg)
                loss, grad = ce_loss + reg_loss, ce_grad + reg_grad
                self.W -= learning_rate * grad
                loss_history.append(loss)

            print("Epoch %i, loss: %f" % (epoch, loss))

        return loss_history

    def predict(self, X):
        """
        Produces classifier predictions on the set

        Arguments:
          X, np array (test_samples, num_features)

        Returns:
          y_pred, np.array of int (test_samples)
        """
        return X.dot(self.W).argmax(axis=1)


"""
Copyright 2013 Steven Diamond

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

# for decimal division
from __future__ import division

import cvxopt
import numpy as np
from pylab import *
import math

from cvxpy import *

# Taken from CVX website http://cvxr.com/cvx/examples/
# Example: CVX Textbook exercise 4.3: Solve a simple QP with inequality constraints
# Ported from cvx matlab to cvxpy by Misrab Faizullah-Khan
# Original comments below

# From Boyd & Vandenberghe, "Convex Optimization"
# Joelle Skaf - 09/26/05
#
# Solves the following QP with inequality constraints:
#           minimize    1/2x'*P*x + q'*x + r
#               s.t.    -1 <= x_i <= 1      for i = 1,2,3
# Also shows that the given x_star is indeed optimal

# Generate data
n = 3
P = cvxopt.matrix([	13, 12, -2,
					12, 17, 6,
					-2, 6, 12], (n,n))
q = cvxopt.matrix([-22, -14.5, 13], (n,1))
r = 1
x_star = cvxopt.matrix([1, 1/2, -1], (n,1))

# Frame and solve the problem

x = Variable(n)
objective = Minimize(  0.5 * quad_form(x, P)  + q.T * x + r )
constraints = [ x >= -1, x <= 1]

p = Problem(objective, constraints)
# The optimal objective is returned by p.solve().
result = p.solve()


import numpy as np

def calculate_q(p_seq):
  """
  Benjamini-Hochberg method
  """
  p_arr          = np.array(p_seq)
  n_genes        = len(p_arr)
  sort_index_arr = np.argsort(p_arr)
  p_sorted_arr   = p_arr[sort_index_arr]
  q_arr          = p_sorted_arr * n_genes / (np.arange(n_genes) + 1)
  q_min          = q_arr[-1]
  q_list         = [q_min]
  for q in q_arr[-2::-1]:
    if q < q_min:
      q_min = q
    q_list.append(q_min)
  q_arr = np.array(q_list)[::-1]
  q_arr[sort_index_arr] = q_arr.copy()
  return q_arr

if __name__ == '__main__':
  p_arr = np.random.rand(5)
  q_arr = calculate_q(p_arr)
  print('p-values', p_arr)
  print('q-values', q_arr)


from __future__ import division
from sympy import *
from timeit import Timer
import mpmath
import math
import matplotlib.pyplot as plt

x, y, z, t = symbols('x y z t')
COEF_ADAMS_BASH = [
    [1],
    [1],
    [3/2, -1/2],
    [23/12, -4/3, 5/12],
    [55/24, -59/24, 37/24, -3/8],
    [1901/720, -1387/360, 109/30, -637/360, 251/720],
    [4277/1440, -2641/480, 4991/720, -3649/720, 959/480, -95/288],
    [198721/60480, -18637/2520, 235183/20160, -10754/945, 135713/20160, -5603/2520, 19087/60480],
    [16083/4480, -1152169/120960, 242653/13440, -296053/13440, 2102243/120960, -115747/13440, 32863/13440, -5257/17280]
]
COEF_ADAM_MOULTON = [
    [1],
    [1],
    [1/2, 1/2],
    [5/12, 2/3, -1/12],
    [3/8, 19/24, -5/24, 1/24],
    [251/720, 323/360, -11/30, 53/360, -19/720],
    [95/288, 1427/1440, -133/240, 241/720, -173/1440, 3/160],
    [19087/60480, 2713/2520, -15487/20160, 586/945, -6737/20160, 263/2520, -863/60480],
    [5257/17280, 139849/120960, -4511/4480, 123133/120960, -88547/120960, 1537/4480, -11351/120960, 275/24192]
]
COEF_FORM_INV = [
    [1],
    [1, 1],
    [2/3, 4/3, -1/3],
    [6/11, 18/11, -9/11, 2/11],
    [12/25, 48/25, -36/25, 16/25, -3/25],
    [60/137, 300/137, -300/137, 200/137, -75/137, 12/137],
    [60/147, 360/147, -450/147, 400/147, -225/147, 72/147, -10/147]
]

SHOW_GRAPHS = True ## MUDAR PARA TRUE CASO DESEJE VER OS GRAFICOS!
BY_LISTA_VALORES = 0
BY_EULER = 1
BY_EULER_INVERSO = 2
BY_EULER_APRIMORADO = 3
BY_RUNGE_KUTTA = 4

def F(f, t0, y0):
    return f.subs({t : t0, y : y0})

def f_bashforth(funcao, valores_iniciais, passo_atual, h, t0, ordem):
    retorno = valores_iniciais[passo_atual - 1]
    k = int(0)

    for i in range(passo_atual - 1, passo_atual - ordem - 1, -1):
        fn = F(funcao, t0 + i * h, valores_iniciais[i])
        retorno += h * (fn * COEF_ADAMS_BASH[ordem][k])
        k += 1

    return retorno

def f_moulton(funcao, valores_iniciais, passo_atual, h, t0, ordem):
    retorno = valores_iniciais[passo_atual - 1]
    k = int(0)

    for i in range(passo_atual, passo_atual - ordem, -1):
        fn = F(funcao, t0 + i * h, valores_iniciais[i])
        retorno += h * (fn * COEF_ADAM_MOULTON[ordem][k])
        k += 1

    return retorno

def f_inversa(funcao, valores_iniciais, passo_atual, h, t0, ordem):
    y1 = valores_iniciais[passo_atual]
    t1 = t0 + (passo_atual) * h
    retorno = COEF_FORM_INV[ordem][0] * h * F(funcao, t1, y1)
    k = 1

    for i in range(passo_atual - 1, passo_atual - ordem - 1, -1):
        yn = valores_iniciais[i]
        retorno += (yn * COEF_FORM_INV[ordem][k])
        k += 1

    return retorno

def print_header(nome_metodo, y0, t0, h):
    print('Metodo de ' + nome_metodo)
    print('y(' + str(t0) + ') = ' + str(y0))
    print('h = ' + str(h))

def mostra_grafico(nome_metodo, tempos, resultados):
    if (SHOW_GRAPHS == 0):
        return

    plt.title('Metodo ' + nome_metodo)
    plt.plot(tempos, resultados)
    plt.show()

def euler_simples(y0, t0, h, qtd_passos, funcao, flag):
    if (flag == 0):
        print_header('Euler Simples', y0, t0, h)

    qtd_passos = int(qtd_passos)
    y0 = float(y0)
    t0 = float(t0)
    h = float(h)
    f = sympify(funcao)

    resultados = []
    tempos = []

    if (flag == 0):
        print('0 ' + str(y0))

    resultados.append(y0)
    tempos.append(t0)

    for passo_atual in range(1, qtd_passos + 1):
        ft0y0 = F(f, t0, y0)
        y1 = y0 + ft0y0 * h
        t1 = t0 + h
        if (flag == 0):
            print(str(passo_atual) + ' ' + str(y1))
        y0 = y1
        t0 = t1
        resultados.append(y0)
        tempos.append(t0)

    if (flag == 0):
        mostra_grafico('Euler Simples', tempos, resultados)

    return resultados

def euler_inverso(y0, t0, h, qtd_passos, funcao, flag):
    if (flag == 0):
        print_header('Euler Inverso', y0, t0, h)

    qtd_passos = int(qtd_passos)
    y0 = float(y0)
    t0 = float(t0)
    h = float(h)
    f = sympify(funcao)

    resultados = []
    tempos = []

    if (flag == 0):
        print('0 ' + str(y0))

    resultados.append(y0)
    tempos.append(t0)

    for passo_atual in range(1, qtd_passos + 1):
        y1 = y0 + F(f, t0, y0) * h
        t1 = t0 + h
        y1 = y0 + (h * F(f, t1, y1))
        # eq = y0 + (h * F(f, t0 + h, y)) (resolucao implicita)
        # eq = y - eq
        # y1 = solve(eq, y).pop()
        if (flag == 0):
            print(str(passo_atual) + ' ' + str(y1))
        y0 = y1
        t0 = t1
        resultados.append(y0)
        tempos.append(t0)

    if (flag == 0):
        mostra_grafico('Euler Inverso', tempos, resultados)

    return resultados

def euler_aprimorado(y0, t0, h, qtd_passos, funcao, flag):
    if (flag == 0):
        print_header('Euler Aprimorado', y0, t0, h)

    resultados = []
    tempos = []

    qtd_passos = int(qtd_passos)
    y0 = float(y0)
    t0 = float(t0)
    h = float(h)
    f = sympify(funcao)

    if (flag == 0):
        print('0 ' + str(y0))

    resultados.append(y0)
    tempos.append(t0)

    for passo_atual in range(1, qtd_passos + 1):
        ft0y0 = F(f, t0, y0)
        y1 = y0 + ft0y0 * h
        t1 = t0 + h
        ft1y1 = F(f, t1, y1)

        y1 = y0 + ((ft0y0 + ft1y1) * (h)) / 2.0

        if (flag == 0):
            print(str(passo_atual) + ' ' + str(y1))

        y0 = y1
        t0 = t1
        resultados.append(y0)
        tempos.append(t0)

    if (flag == 0):
        mostra_grafico('Euler Aprimorado', tempos, resultados)

    return resultados

def runge_kutta(y0, t0, h, qtd_passos, funcao, flag):
    if (flag == 0):
        print_header('Runge-Kutta', y0, t0, h)

    resultados = []
    tempos = []

    qtd_passos = int(qtd_passos)
    y0 = float(y0)
    t0 = float(t0)
    h = float(h)
    f = sympify(funcao)

    if (flag == 0):
        print('0 ' + str(y0))

    resultados.append(y0)
    tempos.append(t0)

    for passo_atual in range (1, qtd_passos + 1):
        k1 = F(f, t0, y0)
        k2 = F(f, t0 + h / 2.0, y0 + (h * k1) / 2.0)
        k3 = F(f, t0 + h / 2.0, y0 + (h * k2) / 2.0)
        k4 = F(f, t0 + h, y0 + h * k3)

        y1 = y0 + (h / 6.0) * (k1 + 2 * k2 + 2.0 * k3 + k4)

        if (flag == 0):
            print(str(passo_atual) + ' ' + str(y1))

        y0 = y1
        t0 = t0 + h
        resultados.append(y0)
        tempos.append(t0)

    if (flag == 0):
        mostra_grafico('Runge-Kutta', tempos, resultados)

    return resultados

def adams_bashforth(entrada, t0, h, qtd_passos, funcao, ordem, origem):
    resultados = []
    tempos = []

    qtd_passos = int(qtd_passos)
    t0 = float(t0)
    h = float(h)
    f = sympify(funcao)
    ordem = int(ordem)
    origem = int(origem)

    valores_iniciais = []
    nome_metodo = ""

    if (origem == BY_LISTA_VALORES):
        valores_iniciais = entrada
        nome_metodo = 'Adams-Bashforth'
    elif (origem == BY_EULER):
        valores_iniciais = euler_simples(entrada, t0, h, ordem - 1, funcao, 1)
        nome_metodo = 'Adams-Bashforth por Euler Simples'
    elif (origem == BY_EULER_INVERSO):
        valores_iniciais = euler_inverso(entrada, t0, h, ordem - 1, funcao, 1)
        nome_metodo = 'Adams-Bashforth por Euler Inverso'
    elif (origem == BY_EULER_APRIMORADO):
        valores_iniciais = euler_aprimorado(entrada, t0, h, ordem - 1, funcao, 1)
        nome_metodo = 'Adams-Bashforth por Euler Aprimorado'
    elif (origem == BY_RUNGE_KUTTA):
        valores_iniciais = runge_kutta(entrada, t0, h, ordem - 1, funcao, 1)
        nome_metodo = 'Adams-Bashforth por Runge-Kutta (ordem = ' + str(ordem) + ')'

    print_header(nome_metodo, valores_iniciais[0], t0, h)

    for i in range(ordem):
        valores_iniciais[i] = float(valores_iniciais[i])
        print(str(i) + ' ' + str(valores_iniciais[i]))
        resultados.append(valores_iniciais[i])
        tempos.append(float(t0 + i * h))

    for passo_atual in range(ordem, qtd_passos + 1):
        y1 = f_bashforth(f, valores_iniciais, passo_atual, h, t0, ordem)
        print(str(passo_atual) + ' ' + str(y1))
        valores_iniciais.append(y1)
        resultados.append(y1)
        tempos.append(t0 + passo_atual * h)

    mostra_grafico(nome_metodo, tempos, resultados)

    return resultados

def adam_moulton(y0, t0, h, qtd_passos, funcao, ordem, origem):
    resultados = []
    tempos = []

    qtd_passos = int(qtd_passos)
    t0 = float(t0)
    h = float(h)
    f = sympify(funcao)
    ordem = int(ordem)

    valores_iniciais = []
    nome_metodo = ""

    if (origem == BY_LISTA_VALORES):
        valores_iniciais = y0
        nome_metodo = 'Adam-Moulton'
    elif (origem == BY_EULER):
        valores_iniciais = euler_simples(y0, t0, h, ordem - 2, funcao, 1)
        nome_metodo = 'Adam-Moulton por Euler Simples'
    elif (origem == BY_EULER_INVERSO):
        valores_iniciais = euler_inverso(y0, t0, h, ordem - 2, funcao, 1)
        nome_metodo = 'Adam-Moulton por Euler Inverso'
    elif (origem == BY_EULER_APRIMORADO):
        valores_iniciais = euler_aprimorado(y0, t0, h, ordem - 2, funcao, 1)
        nome_metodo = 'Adam-Moulton por Euler Aprimorado'
    elif (origem == BY_RUNGE_KUTTA):
        valores_iniciais = runge_kutta(y0, t0, h, ordem - 2, funcao, 1)
        nome_metodo = 'Adam-Moulton por Runge-Kutta (ordem = ' + str(ordem) + ')'

    print_header(nome_metodo, valores_iniciais[0], t0, h)

    for i in range(ordem - 1):
        valores_iniciais[i] = float(valores_iniciais[i])
        print(str(i) + ' ' + str(valores_iniciais[i]))
        resultados.append(valores_iniciais[i])
        tempos.append(t0 + i * h)

    for passo_atual in range(ordem - 1, qtd_passos + 1):
        y1 = f_bashforth(f, valores_iniciais, passo_atual, h, t0, ordem - 1) #previsao a partir de a. bash.
        valores_iniciais.append(y1)
        y1 = f_moulton(f, valores_iniciais, passo_atual, h, t0, ordem)
        valores_iniciais.pop()
        print(str(passo_atual) + ' ' + str(y1))
        valores_iniciais.append(float(y1))
        resultados.append(y1)
        tempos.append(t0 + passo_atual * h)

    mostra_grafico(nome_metodo, tempos, resultados)

    return resultados

def formula_inversa(y0, t0, h, qtd_passos, funcao, ordem, origem):
    resultados = []
    tempos = []

    qtd_passos = int(qtd_passos)
    t0 = float(t0)
    h = float(h)
    f = sympify(funcao)
    ordem = int(ordem)

    valores_iniciais = []
    nome_metodo = ""

    if (origem == BY_LISTA_VALORES):
        valores_iniciais = y0
        nome_metodo = 'Formula Inversa de Dif.'
    elif (origem == BY_EULER):
        valores_iniciais = euler_simples(y0, t0, h, ordem - 2, funcao, 1)
        nome_metodo = 'Formula Inversa de Dif. por Euler Simples'
    elif (origem == BY_EULER_INVERSO):
        valores_iniciais = euler_inverso(y0, t0, h, ordem - 2, funcao, 1)
        nome_metodo = 'Formula Inversa de Dif. por Euler Inverso'
    elif (origem == BY_EULER_APRIMORADO):
        valores_iniciais = euler_aprimorado(y0, t0, h, ordem - 2, funcao, 1)
        nome_metodo = 'Formula Inversa de Dif. por Euler Aprimorado'
    elif (origem == BY_RUNGE_KUTTA):
        valores_iniciais = runge_kutta(y0, t0, h, ordem - 2, funcao, 1)
        nome_metodo = 'Formula Inversa de Dif. por Runge-Kutta (ordem = ' + str(ordem) + ')'

    print_header(nome_metodo, valores_iniciais[0], t0, h)

    for i in range(ordem - 1):
        valores_iniciais[i] = float(valores_iniciais[i])
        print(str(i) + ' ' + str(valores_iniciais[i]))
        resultados.append(valores_iniciais[i])
        tempos.append(t0 + i * h)

    for passo_atual in range(ordem - 1, qtd_passos + 1):
        y1 = f_bashforth(f, valores_iniciais, passo_atual, h, t0, ordem - 1) #previsao a partir de a. bash.
        valores_iniciais.append(y1)
        y1 = f_inversa(f, valores_iniciais, passo_atual, h, t0, ordem - 1)
        valores_iniciais.pop()
        print(str(passo_atual) + ' ' + str(y1))
        valores_iniciais.append(float(y1))
        resultados.append(y1)
        tempos.append(t0 + passo_atual * h)

    mostra_grafico(nome_metodo, tempos, resultados)

    return resultados

def filtra_entrada(data):
    metodo = data[0]
    euler = metodo.find('euler') != -1
    rk = metodo.find('runge_kutta') != -1
    bashforth = metodo.find('bashforth') != -1
    multon = metodo.find('multon') != -1
    by = metodo.find('by') != -1
    inversa = metodo.find('formula') != -1

    valores_iniciais = []
    ordem = -1

    if (not by and not euler and not rk):
        if (multon or inversa):
            ordem = int(data[len(data) - 1])
            valores_iniciais = []
            for valor in range(1, ordem):
                valores_iniciais.append(data[valor])
        else:
            ordem = int(data[len(data) - 1])
            valores_iniciais = []
            for valor in range(1, ordem + 1):
                valores_iniciais.append(data[valor])

    if (bashforth):
        if (not by):
            return (valores_iniciais, data[ordem + 1], data[ordem + 2], data[ordem + 3], data[ordem + 4], ordem)
        else:
            return (data[1], data[2], data[3], data[4], data[5], data[6])
    elif (multon):
        if (not by):
            return (valores_iniciais, data[ordem], data[ordem + 1], data[ordem + 2], data[ordem + 3], ordem)
        else:
            return (data[1], data[2], data[3], data[4], data[5], data[6])
    elif (inversa):
        if (not by):
            return (valores_iniciais, data[ordem], data[ordem + 1], data[ordem + 2], data[ordem + 3], ordem)
        else:
            return (data[1], data[2], data[3], data[4], data[5], data[6])
    elif (euler):
        return (data[1], data[2], data[3], data[4], data[5], -1)
    elif (rk):
        return (data[1], data[2], data[3], data[4], data[5], -1)
    else:
        print('Metodo nao existente.')

    return (-1, -1, -1, -1, -1, -1)

def calcula_origem(nome_metodo):
    euler_inv = nome_metodo.find('by_euler_inverso')
    euler_apr = nome_metodo.find('by_euler_aprimorado')
    euler_simp = nome_metodo.find('by_euler')
    rk = nome_metodo.find('by_runge_kutta')

    if (euler_inv != -1):
        return BY_EULER_INVERSO
    elif (euler_apr != -1):
        return BY_EULER_APRIMORADO
    elif (euler_simp != -1):
        return BY_EULER
    elif (rk != -1):
        return BY_RUNGE_KUTTA
    else:
        return BY_LISTA_VALORES

def main():
    input_file = open('entrada.txt', 'r')

    tempos_metodos = []

    for line in input_file:
        data = line.split(' ')

        y0, t0, h, qtd_passos, funcao, ordem = filtra_entrada(data)

        metodo = data[0]
        tempo = 0

        if (metodo == "euler"):
            t = Timer(lambda : euler_simples(y0, t0, h, qtd_passos, funcao, 0))
            tempo = t.timeit(number=1)
        elif (metodo == "euler_inverso"):
            t = Timer(lambda : euler_inverso(y0, t0, h, qtd_passos, funcao, 0))
            tempo = t.timeit(number=1)
        elif (metodo == "euler_aprimorado"):
            t = Timer(lambda : euler_aprimorado(y0, t0, h, qtd_passos, funcao, 0))
            tempo = t.timeit(number=1)
        elif (metodo == "runge_kutta"):
            t = Timer(lambda : runge_kutta(y0, t0, h, qtd_passos, funcao, 0))
            tempo = t.timeit(number=1)
        elif (metodo.find('bashforth') != -1):
            origem = calcula_origem(metodo)
            t = Timer(lambda : adams_bashforth(y0, t0, h, qtd_passos, funcao, ordem, origem))
            tempo = t.timeit(number=1)
        elif (metodo.find('multon') != -1):
            origem = calcula_origem(metodo)
            t = Timer(lambda : adam_moulton(y0, t0, h, qtd_passos, funcao, ordem, origem))
            tempo = t.timeit(number=1)
        else:
            origem = calcula_origem(metodo)
            t = Timer(lambda : formula_inversa(y0, t0, h, qtd_passos, funcao, ordem, origem))
            tempo = t.timeit(number=1)

        print('')
        tempos_metodos.append((metodo, tempo))

    # DESCOMENTAR P/ MOSTRAR O TEMPO DE EXECUÇÃO DE CADA MÉTODO
    # for tempo in tempos_metodos:
    #     print(tempo)
    #     print('---')

if __name__ == "__main__":
    main()


# Refer: https://en.wikipedia.org/wiki/Test_functions_for_optimization

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

pso_solver.setSeed(1)

lower = xlower = ylower = -4
upper = xupper = yupper = 4
particleList = pso_solver.createRandomParticleList(2, numParticles=10, lower=lower, upper=upper)

# Testing on Himmelblau's function
# This function has 4 global minima, which minimum is computed by PSO depends on the initialization.
# seed = 1 gives minimum (-2.81, 3.13)
# seed = 2 gives minimum (-3, 2)
# seed = 3 gives mimimum (3.58, -1.85)
# seed = 4 gives mimimum (3, 2)
f = lambda x, y: (x**2 + y - 11)**2 + (x + y**2 - 7)**2

pso_solver.psoVisualizeBivariate(particleList, f, xlower, xupper, ylower, yupper, c1=1, c2=1, W=0.5, numIters=50, maxFlag=False, sleepTime=0.1, density=1000, accuracy=2, verbose=False)


# -*- coding: utf-8 -*-
"""
Created on Sat Jan  6 06:17:43 2018

@author: Alankar
"""

import numpy as np

M_sun = 1.989e30 #in kg
G = 6.67e-11

def ecc(vmax,rmin):
    e = (vmax**2*rmin)/(G*M_sun)-1
    return e

def apph(e,vmax,rmin):
    c = (vmax*rmin)**2/(G*M_sun)
    rmax = c/(1-e)
    return rmax

def v_app(vmax,rmin,rmax):
    vmin = (vmax*rmin)/rmax
    return vmin

def time_p(vmax,rmin,e):
    c = (vmax*rmin)**2/(G*M_sun)
    a = c/(1-e**2)
    T = np.sqrt((((2*np.pi)**2)/(G*M_sun))*a**3)
    return T/(365*24*60**2) #in yr

print('-----------------------------------------------------------')
print('Demo Output:\n\nEarth')
vmax, rmin = 3.0287e4, 1.4710e11
e = ecc(vmax,rmin)
rmax = apph(e,vmax,rmin)
vmin = v_app(vmax,rmin,rmax)
T = time_p(vmax,rmin,e)
#1 m = 6.685e-12 AU
print('\nOrbital Eccentricity: %.4f\nAphelion Distance(m): %.3e\nAphelion Velocity(m/s): %.3e\nOrbital period(yr): %.2f'%(e,rmax,vmin,T))
print('\nHalley\'s Comet')
vmax, rmin = 5.4529e4, 8.7830e10
e = ecc(vmax,rmin)
rmax = apph(e,vmax,rmin)
vmin = v_app(vmax,rmin,rmax)
T = time_p(vmax,rmin,e)
print('\nOrbital Eccentricity: %.4f\nAphelion Distance(m): %.3e\nAphelion Velocity(m/s): %.3e\nOrbital period(yr): %.2f'%(e,rmax,vmin,T))
print('-----------------------------------------------------------')

vmax = float(input('Enter velocity at perihelion(m/s): '))
rmin = float(input('Enter distance from Sun at perihelion(m): '))
e = ecc(vmax,rmin)
rmax = apph(e,vmax,rmin)
vmin = v_app(vmax,rmin,rmax)
T = time_p(vmax,rmin,e)
print('\nOrbital Eccentricity: %.4f\nAphelion Distance(m): %.3e\nAphelion Velocity(m/s): %.3e\nOrbital period(yrs): %.2f'%(e,rmax,vmin,T))


from src.si.supervised.Model import Model
from ..util.metrics import mse
from ..util.util import add_intersect
import numpy as np

class LinearRegression(Model):

    def __init__(self, gd=False, epochs=1000, lr=0.001):
        super(LinearRegression, self).__init__()
        self.gd = gd
        self.theta = None
        self.epochs = epochs
        self.lr = lr

    def fit(self, dataset):
        X, Y = dataset.getXy()#vai buscar X e y do dataset
        X = np.hstack((np.ones((X.shape[0], 1)), X))
        self.X = X
        self.Y = Y

        # closed form of GD
        self.train_gd(X, Y) if self.gd else self.train_closed(X, Y)
        self.is_fitted = True

    def train_closed(self, x, y):
        self.theta = np.linalg.inv(x.T.dot(x)).dot(x.T).dot(y)

    def train_gd(self, x, y):
        m = x.shape[0]
        n = x.shape[1]

        self.history = {}  # criar um historico dos thetas e custo por epoch
        self.theta = np.zeros(n)

        for epoch in range(self.epochs):
            grad = 1/m * (x.dot(self.theta) - y).dot(x)
            self.theta -= self.lr * grad

            self.history[epoch] = [self.theta[:], self.cost()]

    def predict(self, x):
        assert self.is_fitted, 'Model must be fitted before predicting'
        x = np.array(x)
        if x.ndim > 1:#ndim: numero de dimensoes
            res = []
            for i in x:
                _x = np.hstack(([1], i))
                res.append(np.dot(self.theta, _x))
        else:
            _x = np.hstack(([1], x))
            res = np.dot(self.theta, _x)
        return res

    def cost(self, X=None, Y=None, theta=None):
        X = add_intersect(X) if X is not None else self.X
        Y = Y if Y is not None else self.Y
        theta = theta if theta is not None else self.theta

        y_pred = np.dot(X, theta)
        return mse(Y, y_pred) / 2

class LinearRegressionReg(LinearRegression):

    def __init__(self, gd=False, epochs=1000, lr=0.001, lbd=1):
        super(LinearRegressionReg, self).__init__(gd=gd, epochs=epochs, lr=lr)
        self.lbd = lbd

    def train_closed(self, x, y):
        n = x.shape[1]
        identity = np.eye(n)
        identity[0, 0] = 0
        self.theta = np.linalg.inv(x.T.dot(x) + self.lbd * identity).dot(x.T).dot(y)
        self.is_fitted = True

    def train_gd(self, x, y):
        m = x.shape[0]
        n = x.shape[1]

        self.history = {}  # criar um historico dos thetas por epoch
        self.theta = np.zeros(n)
        lbds = np.full(m, self.lbd)
        lbds[0] = 0

        for epoch in range(self.epochs):
            grad = 1 / m * (x.dot(self.theta) - y).dot(x)
            self.theta -= (self.lr/m) * (lbds+grad)

            self.history[epoch] = [self.theta[:], self.cost()]


import numpy as np

# Part 1-2

number_of_samples = np.int(1e6)
gauss_data = np.random.normal(0,1,number_of_samples)
samples_greater_than_three = 0
for i in gauss_data:
    if i>3:
        samples_greater_than_three+=1
fraction_of_samples = samples_greater_than_three/number_of_samples

print('\nPart 1,2 x~G(0,1)\nnumber of x>3 samples: %i\nfraction of samples: %f\nhypothesis rejected %i times' \
      %(samples_greater_than_three,fraction_of_samples, samples_greater_than_three))

# Part 3

# (1)
number_of_samples = np.int(1e6)
gauss_data = np.random.normal(0,np.sqrt(2),number_of_samples)
samples_greater_than_three = 0
for i in gauss_data:
    if i>3:
        samples_greater_than_three+=1
fraction_of_samples = samples_greater_than_three/number_of_samples

print('\nPart 3.1 x~G(0,2)\nnumber of x>3 samples: %i\nfraction of samples: %f\nhypothesis rejected %i times' \
      %(samples_greater_than_three,fraction_of_samples, samples_greater_than_three))

# (2)
gauss_data_m_equals_two = np.random.normal(-0.5,1,number_of_samples)
samples_greater_than_three = 0
for i in gauss_data_m_equals_two:
    if i>3:
        samples_greater_than_three+=1
fraction_of_samples = samples_greater_than_three/number_of_samples

print('\nPart 3.2 x~G(-0.5,1)\nnumber of x>3 samples: %i\nfraction of samples: %f\nhypothesis rejected %i times' \
      %(samples_greater_than_three,fraction_of_samples, samples_greater_than_three))


#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
       _
      /  |     | __  _ __  _
     /   |    /  |_||_|| ||
    /    |   /   |  |\ | ||_
   /____ |__/\ . |  | \|_|\_|
   __________________________ .

Created on Tue Jun 12 10:18:09 2018

@author: chrisunderwood
"""

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

class select_Gaus_fit():
    def __init__(self, x, y, plottingOnOff, guess):
        self.x = x
        self.y = y
        self.plotting = plottingOnOff
        self.guess = guess
        if self.plotting:
            self.plotInput()

        self.fit_gaus_2_to_8()

    def gaus2(self, x, *params):
        #Gaussian function
        A = params[0]
        x0 = params[1]
        c = params[2]
        return A*np.exp(-((x-x0)/(c**2))**2)

    def gaus4(self, x, *params):
        #Gaussian function
        A = params[0]
        x0 = params[1]
        c = params[2]
        return A*np.exp(-((self.x-x0)/(c**2))**4)

    def gaus6(self, x, *params):
        #Gaussian function
        A = params[0]
        x0 = params[1]
        c = params[2]
        return A*np.exp(-((self.x-x0)/(c**2))**6)

    def gaus8(self, x, *params):
        #Gaussian function
        A = params[0]
        x0 = params[1]
        c = params[2]
        return A*np.exp(-((self.x-x0)/(c**2))**8)

    def plotInput(self):
        plt.plot(self.x,self.y)

    def fitGaus2(self):
        self.popt_G2, self.pcov_G2 = curve_fit(self.gaus2, self.x, self.y ,
                                               p0=self.guess)
        self.fitG2 = self.gaus2(self.x, *self.popt_G2)

        if self.plotting:
            print 'Fitting SG2: '
            print self.guess
            print self.popt_G2
            print
            plt.plot(self.x, self.fitG2)

    def fitGaus4(self):
        self.popt_G4, self.pcov_G4 = curve_fit(self.gaus4, self.x, self.y ,
                                               p0=self.guess)
        self.fitG4 = self.gaus4(self.x, *self.popt_G4)
        if self.plotting:
            print 'Fitting SG4: '
            print self.guess
            print self.popt_G4
            print
            plt.plot(self.x, self.fitG4)

    def fitGaus6(self):
        self.popt_G6, self.pcov_G6 = curve_fit(self.gaus6, self.x, self.y ,
                                               p0=self.guess)
        self.fitG6 = self.gaus6(self.x, *self.popt_G6)
        if self.plotting:
            print 'Fitting SG6: '
            print self.guess
            print self.popt_G6
            print
            plt.plot(self.x, self.fitG6)

    def fitGaus8(self):

        self.popt_G8, self.pcov_G8 = curve_fit(self.gaus8, self.x, self.y ,
                                               p0=self.guess)
        self.fitG8 = self.gaus8(self.x, *self.popt_G8)
        if self.plotting:
            print 'Fitting SG8: '
            print self.guess
            print self.popt_G8
            print
            plt.plot(self.x, self.fitG8)

    def fit_gaus_2_to_8(self):
        self.fitOptions = ['SG2', 'SG4', 'SG6', 'SG8']
        self.fitPowers = [2, 4, 6, 8]

        self.fitGaus2()
        self.fitGaus4()
        self.fitGaus6()
        self.fitGaus8()
        self.fitParams = [self.popt_G2, self.popt_G4, self.popt_G6, self.popt_G8]
        self.CalcR_2_value()

    def nearposn(self, array,value):
        posn = (abs(array-value)).argmin()
        return posn

    def CalcR_2_value(self):
        self.rrValues = []
        for fit in [self.fitG2, self.fitG4, self.fitG6, self.fitG8]:

            residuals = self.y - fit
            ss_res = np.sum(residuals**2)
            ss_tot = np.sum((self.y-np.mean(self.y))**2)
            self.rrValues.append( 1 - (ss_res / ss_tot) )
        maxRR = max(self.rrValues)
        self.bestFit = self.nearposn(self.rrValues, maxRR)
        outStr = ''
        CSI="\x1B[31;40m"
        CEND = '\x1B[0m'
        for i in self.rrValues:
            if i == self.rrValues[self.bestFit]:
                outStr += CSI + str(i) + ' ' + CEND
            else:
                outStr += str(i) + ' '
        if self.plotting: print outStr

    def output(self):
        if self.plotting:
            print self.fitOptions[self.bestFit]
            print self.fitParams[self.bestFit]
            print self.fitPowers[self.bestFit]
        return self.fitPowers[self.bestFit] , self.fitParams[self.bestFit]


"""
Collection of functions to compute various performance measures from a 2x2 confusion matrix.
As an introduction to evaluating classificators, we recommend reading this `paper`_ about ROC analysis.

TP = true positive

FP = false positive

TN = true negative

FN = false negative

.. _paper: http://dx.doi.org/10.1016/j.patrec.2005.10.010.
"""

import numpy as np
from math import sqrt

def mcc(TP, FN, FP, TN):
    """Matthews Correlation Coefficient"""
    return np.divide(
        TP * TN + FP * FN, sqrt((TP + FP) * (TP + FN) * (TN + FP) * (TN + FN))
    )

def sens(TP, FN, FP, TN):
    """Sensitivity"""
    return np.divide(TP, (TP + FN))

def spec(TP, FN, FP, TN):
    """Specificity"""
    return np.divide(TN, (TN + FP))

def prec_pos(TP, FN, FP, TN):
    """Posivitve Precision"""
    return np.divide(TP, (TP + FP))

def recall_pos(TP, FN, FP, TN):
    """Positive recall"""
    return np.divide(TP, (TP + FN))

def prec_neg(TP, FN, FP, TN):
    """Negative Precision"""
    return np.divide(TN, (TN + FN))

def recall_neg(TP, FN, FP, TN):
    """Negative recall"""
    return np.divide(TN, (TN + FP))

def f1_pos(TP, FN, FP, TN):
    """f1-measure on positive instances"""
    return np.divide(
        2 * prec_pos(TP, FN, FP, TN) * recall_pos(TP, FN, FP, TN),
        (prec_pos(TP, FN, FP, TN) + recall_pos(TP, FN, FP, TN)),
    )

def f1_neg(TP, FN, FP, TN):
    """f1-measure on negative instances."""
    return np.divide(
        2 * prec_neg(TP, FN, FP, TN) * recall_neg(TP, FN, FP, TN),
        (prec_neg(TP, FN, FP, TN) + recall_neg(TP, FN, FP, TN)),
    )


from __future__ import annotations

from typing import Generator
from sympy import I, Basic
from sympy.core.backend import zeros, sqrt

from ._base import LieGroup
from ..algebras import A

def generalized_gell_mann(dimension: int) -> Generator:
    """Generator of generalized Gell-Mann Matrices. Note order may
    be different than usual because we generate symmetric, then antisymmetric,
    then diagonal.

    Args:
        dimension (int): Dimension of group

    Yields:
        Generator[Matrix]: Python Generator of (mathematical) generators

    Sources:
        - https://mathworld.wolfram.com/GeneralizedGell-MannMatrix.html

    """
    def eij(dim):
        def _(i, j):
            mat = zeros(dim)
            mat[i, j] = 1
            return mat
        return _
    E = eij(dimension)

    # Symmetric
    for k in range(dimension):
        for j in range(k):
            yield E(k, j) + E(j, k)

    # AntiSymmetric
    for k in range(dimension):
        for j in range(k):
            yield I * (E(k, j) - E(j, k))

    # Diagonal
    for l in range(dimension - 1):
        coeff = sqrt(2) / sqrt((l+1) * (l + 2))
        sum_term = sum([E(j, j) for j in range(l+1)], zeros(dimension))
        yield coeff * (sum_term - (l+1) * E(l+1, l+1))

class SU(LieGroup):
    """The Special Unitary Group
    """

    def __new__(cls, dim: int):
        if dim < 2:
            raise NotImplementedError("SU(1)==U(1) is not implemented yet.")
        return super().__new__(cls, "SU", dim)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._algebra = A(self.dimension - 1)
        self._generators = None

    def generators(self):
        r"""Generators for SU(N).  Based off the generalized Gell-Mann matrices $\lambda_a$
        the generators, $T_a$ are

        .. math::

            T_a = \frac{\lambda_a}{2}
        """
        if self._generators is None:
            # typical normalization
            self._generators = [
                x / 2 for x in generalized_gell_mann(self.dimension)]
        return self._generators


# -*- coding: utf-8 -*-
"""
helper function: convert Hz to Bark scale

  Args:
    fInHz: The frequency to be converted, can be scalar or vector
    cModel: The name of the model ('Schroeder' [default], 'Terhardt', 'Zwicker', 'Traunmuller')

  Returns:
    Bark values of the input dimension
"""

import numpy as np
import math

def ToolFreq2Bark(fInHz, cModel = 'Schroeder'):
    def acaSchroeder_scalar(f):
        return 7 * math.asinh(f/650)
    def acaTerhardt_scalar(f):
        return 13.3 * math.atan(0.75 * f/1000)
    def acaZwicker_scalar(f):
        return 13 * math.atan(0.76 * f/1000) + 3.5 * math.atan(f/7500)
    def acaTraunmuller_scalar(f):
        return 26.81/(1+1960./f) - 0.53

    f = np.asarray(fInHz)
    if f.ndim == 0:
        if cModel == 'Terhardt':
            return acaTerhardt_scalar(f)
        elif cModel == 'Zwicker':
            return acaZwicker_scalar(f)
        elif cModel == 'Traunmuller':
            return acaTraunmuller_scalar(f)
        else:
            return acaSchroeder_scalar(f)

    fBark = np.zeros(f.shape)
    if cModel == 'Terhardt':
        for k,fi in enumerate(f):
            fBark[k] =  acaTerhardt_scalar(fi)
    elif cModel == 'Zwicker':
        for k,fi in enumerate(f):
            fBark[k] =  acaZwicker_scalar(fi)
    elif cModel == 'Traunmuller':
        for k,fi in enumerate(f):
            fBark[k] =  acaTraunmuller_scalar(fi)
    else:
        for k,fi in enumerate(f):
            fBark[k] =  acaSchroeder_scalar(fi)

    return (fBark)


""" Util Functions """
import math
import numpy as np
import random

def addition(first: int, second: int) -> int:
    """
    Returns sum of two integers.

    Parameters:
        first (int) : First Integer
        second (int) : Second Integer
    """
    return first + second

def subtraction(first: int, second: int) -> int:
    """
    Returns subtraction of two integers.

    Parameters:
        first (int) : First Integer
        second (int) : Second Integer
    """
    return first - second

def multiplication(first: int, second: int) -> int:
    """
    Returns multiplication of two integers.

    Parameters:
        first (int) : First Integer
        second (int) : Second Integer
    """
    return first * second

def division(first: int, second: int) -> float:
    """
    Returns float division of two integers.

    Parameters:
        first (int) : First Integer
        second (int) : Second Integer
    """
    return first / second

def integer_division(first: int, second: int) -> int:
    """
    Returns integer division of two integers.

    Parameters:
        first (int) : First Integer
        second (int) : Second Integer
    """
    return first // second

def power(base_int: int, power_int: int) -> int:
    """
    Returns base raised to the power.

    Parameters:
        first (int) : First Integer
        second (int) : Second Integer
    """
    return base_int ** power_int

def modulo(dividend: int, divisor: int) -> int:
    """
    Returns remainder of dividend // divisor.

    Parameters:
        first (int) : First Integer
        second (int) : Second Integer
    """
    return dividend % divisor

def log(first: int, base: int) -> float:
    """
    Returns sum of two integers.

    Parameters:
        first (int) : Value to calculate base for. Should be > 0.
        second (int) : Logarithmic base to use.
    """
    return math.log(first, base)

def sigmoid(z):
    """
    Compute the sigmoid of z

    Arguments:
    x -- A scalar or numpy array of any size.

    Return:
    s -- sigmoid(z)
    """

    ### START CODE HERE ### (≈ 1 line of code)
    s = 1 / (1 + np.exp(-z))
    ### END CODE HERE ###

    return s

def rand_between(start: int, stop: int) -> int:
    """
    Returns a random number between two integers.
    Parameters:
        start (int) : Lower limit of Random Number
        stop (int) : Upper Limit of Random Number
    """
    return random.randint(start, stop)

def mean(numbers: list) -> float:
    """
    Returns an float of the mean of numbers provided in mean 64 for more accuracy.
    Parameters:
        numbers (list) : A list of numbers
    """
    return np.mean(np.array(numbers), dtype=np.float64)

def range(first: int, second: int) -> float:
    """
    Returns the range between 2 numbers.
    Parameters:
        start (int) : First number
        end (int) : Second number
    """

    biggest = 0
    smallest = 0

    if (first < second):
        biggest = second
        return biggest - first

    return first - second

def median(numbers: list) -> float:
    """
    Returns the median of a list of numbers.
    Parameters:
         numbers (list) : A list of numbers
    """
	list_size = len(numbers)
	numbers.sort()

	if list_size % 2 == 0:
		median1 = numbers[list_size//2]
		median2 = numbers[list_size//2 - 1]
		median = (median1 + median2)/2
	else:
		median = numbers[list_size//2]

	return median

def mode(numbers: list) -> dict:
    """
    Returns the mode of a list of numbers as a dictionary.
    Parameters:
         numbers (list) : A list of numbers
    """
    numbers.sort()
    ordered_list = []

    i = 0
    while i < len(numbers):
        ordered_list.append(numbers.count(numbers[i]))
        i += 1

    count_num_dict = dict(zip(numbers, ordered_list))
    filter_dict = {k for (k, v) in count_num_dict.items() if v == max(ordered_list)}

    return int(str(filter_dict).replace("{","").replace("}",""))


#!/usr/bin/env python

"""fit_2dgaussian.py -- given

Usage: fit_2dgaussian [-h] [-v] [-s STRING] [-o] <fitsfile> <init_params>

Arguments:
    fitsfile STRING
        Containing the Gaussian you want to fit
    init_params STRING
        amplitude,x0,y0,sigma_x,sigma_y,theta (from +y axis, clockwise),offset.

Options:
    -h, --help                                  Show this screen
    -v, --verbose                               Show extra information (including fitted parameters) [default: False]
    -s STRING, --saveloc STRING                 Save model as fits file, e.g. ./model.fits
    -o, --overwrite                             Overwrite if saveloc exists.

Examples:
    python fit_2dgaussian.py gaussian2fit.fits 3,100,100,20,40,0,10
"""

import docopt
import astropy.io.fits as fits

import numpy as np
from scipy.optimize import curve_fit

def twoD_Gaussian(xytuple, amplitude, xo, yo, sigma_x, sigma_y, theta, offset):
    (x,y) = xytuple
    xo    = float(xo)
    yo    = float(yo)
    a     = (np.cos(theta)**2)/(2*sigma_x**2) + (np.sin(theta)**2)/(2*sigma_y**2)
    b     = -(np.sin(2*theta))/(4*sigma_x**2) + (np.sin(2*theta))/(4*sigma_y**2)
    c     = (np.sin(theta)**2)/(2*sigma_x**2) + (np.cos(theta)**2)/(2*sigma_y**2)
    g     = offset + amplitude*np.exp( - (a*((x-xo)**2) + 2*b*(x-xo)*(y-yo)
                            + c*((y-yo)**2)))
    return g.ravel()

def fit_2dgaussian(z,parameters_initial_guess,verbose=False):
    '''Fit 2D gaussian to z (lenx by leny array).
    The parameters_initial_guess should include:
    amplitude,
    x0,
    y0,
    sigma_x,
    sigma_y,
    theta (from +y axis, clockwise),
    offset.'''

    # Create x and y indices
    lenx,leny = np.shape(z)
    x         = np.linspace(0, lenx-1, lenx)
    y         = np.linspace(0, leny-1, leny)
    x, y      = np.meshgrid(x, y)
    xytuple   = tuple((x,y))

    # Unwrap z
    z=z.ravel()

    # Do fit
    popt, pcov = curve_fit(twoD_Gaussian, xytuple, z, p0=parameters_initial_guess)

    # Print parameters
    if verbose:
        print('The model parameters are: ',popt)
        print('amplitude: ',popt[0])
        print('x0: ',popt[1])
        print('y0: ',popt[2])
        print('sigma_x: ',popt[3])
        print('sigma_y: ',popt[4])
        print('theta (clockwise from y-axis: ',popt[5])
        print('offset: ',popt[6])

    # Calculate model (i.e. create gaussian with fitted params)
    model            = twoD_Gaussian(xytuple, *popt)
    model            = model.reshape(lenx,leny)
    model_parameters = popt

    return model, model_parameters, x, y

def fit_2dgaussian_fitsinput(fitsfile,init_params,save=False,overwrite=False,verbose=False):
    # Read in fits file
    z                 = fits.getdata(fitsfile)
    # Unwrap initial parameters and make floats, then wrap it up
    [amplitude,x0,y0,sigma_x,sigma_y,theta,offset] = [float(x) for x in init_params.split(',')]
    initial_guess     = (amplitude,x0,y0,sigma_x,sigma_y,theta,offset)
    # Do fit
    data_fitted, popt = fit_2dgaussian(z,initial_guess,verbose=verbose)
    hduP=fits.PrimaryHDU(im)
    hdulist=fits.HDUList(hduP)
    keynames = ['amplitude','x0','y0','sigma_x','sigma_y','theta','offset']
    for name, value in zip(keynames,popt):
        hdulist[0].header.update(name,value)
    if overwrite:
        hdulist.writeto(saveloc,overwrite=True)
        print('File saved (overwrite=True) ',saveloc)
    else:
        hdulist.writeto(saveloc)
        print('File saved (overwrite=False) ',saveloc)
    return

####################### BODY OF PROGRAM STARTS HERE ########################

if __name__ == "__main__":

    arguments = docopt.docopt(__doc__)

    # Mandatory argument
    fitsfile    = arguments['<fitsfile>']
    init_params = argumetns['<init_params>']

    # Non-mandatory options without arguments
    verbose     = arguments['--verbose']
    save        = arguments['--saveloc']
    overwrite   = arguments['--overwrite']

    # Perform fit
    fit_2dgaussian_fitsinput(fitsfile,init_params,save=save,overwrite=overwrite,verbose=verbose)


import sys
import numpy as np
from scipy.integrate import odeint
import csv

#based on https://scipython.com/blog/the-double-pendulum/

# The gravitational acceleration (m.s-2).
g = 9.81

def deriv(y, t, L1, L2, m1, m2):
    """Return the first derivatives of y = theta1, z1, theta2, z2."""
    theta1, z1, theta2, z2 = y

    c, s = np.cos(theta1-theta2), np.sin(theta1-theta2)

    theta1dot = z1
    z1dot = (m2*g*np.sin(theta2)*c - m2*s*(L1*z1**2*c + L2*z2**2) -
             (m1+m2)*g*np.sin(theta1)) / L1 / (m1 + m2*s**2)
    theta2dot = z2
    z2dot = ((m1+m2)*(L1*z1**2*s - g*np.sin(theta2) + g*np.sin(theta1)*c) +
             m2*L2*z2**2*s*c) / L2 / (m1 + m2*s**2)
    return theta1dot, z1dot, theta2dot, z2dot

def solve(L1, L2, m1, m2, tmax, dt, y0):
    t = np.arange(0, tmax+dt, dt)

    # Do the numerical integration of the equations of motion
    y = odeint(deriv, y0, t, args=(L1, L2, m1, m2))
    theta1, theta2 = y[:,0], y[:,2]

    # Convert to Cartesian coordinates of the two bob positions.
    x1 = L1 * np.sin(theta1)
    y1 = -L1 * np.cos(theta1)
    x2 = x1 + L2 * np.sin(theta2)
    y2 = y1 - L2 * np.cos(theta2)

    return theta1, theta2, x1, y1, x2, y2

def mappableSolve(args):
	L1, L2, m1, m2, tmax, dt, theta1_init, theta2_init = args
	y0 = np.array([
		theta1_init,
		0.0,
		theta2_init,
		0.0
	])
    #vracam i thete da znam za cega su ovi rezultati (da ih posle mogu
    #pisati u fajl)
	return theta1_init, theta2_init, solve(L1, L2, m1, m2, tmax, dt, y0)

def simulate_pendulum(theta_resolution, tmax, dt, filename, parallel):
    # Pendulum rod lengths (m), bob masses (kg).
    L1, L2 = 1.0, 1.0
    m1, m2 = 1.0, 1.0

    # Maximum time, time point spacings (all in s).
    #tmax, dt = 30.0, 0.01

    theta1_inits = np.linspace(0, 2*np.pi, theta_resolution)
    theta2_inits = np.linspace(0, 2*np.pi, theta_resolution)

    import itertools
    t1t2_inits = itertools.product(theta1_inits, theta2_inits)
    params = ((L1, L2, m1, m2, tmax, dt, t1t2_i[0], t1t2_i[1]) for t1t2_i in t1t2_inits)

    if parallel:
        from multiprocessing import Pool
        pool = Pool()
        solutions = pool.imap(mappableSolve, params)
    else:
        solutions = itertools.imap(mappableSolve, params)

    with open(filename, 'wb') as csvfile:
	    csvwriter = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL)
	    csvwriter.writerow(["theta1_init", "theta2_init", "theta1_last", "theta2_last", "x1_last", "y1_last", "x2_last", "y2_last"])
	    for t1i, t2i, results in solutions:
	       theta1, theta2, x1, y1, x2, y2 = results #to je ono sto je solve izracunao
	       csvwriter.writerow([t1i, t2i, theta1[-1], theta2[-1], x1[-1], y1[-1], x2[-1], y2[-1]])

def plot_the_thing(filename):

	rows = []
	with open(filename, 'rb') as csvfile:
		csvreader = csv.reader(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL)
		next(csvreader, None)	#skip header
		for row in csvreader:
			rows.append(row)

	x1_lasts = [float(row[4]) for row in rows]
	y1_lasts = [float(row[5]) for row in rows]
	x2_lasts = [float(row[6]) for row in rows]
	y2_lasts = [float(row[7]) for row in rows]

	from matplotlib import pyplot as plt
	#t = range(0, len(rows[0]))
	#plt.plot(t, rows[0], label="theta 1")
	plt.plot(x1_lasts, y1_lasts, 'ro', label='1')
	plt.plot(x2_lasts, y2_lasts, 'go', label='2')
	#plt.axis([-1, 1, -1, 1])
	plt.legend()
	plt.savefig("points.png")

def do_the_thing(theta_resolution, tmax, dt, filename, graph, parallel):
    simulate_pendulum(theta_resolution, tmax, dt, filename, parallel)
    if graph:
        plot_the_thing(filename)


import numpy as np
from numpy.linalg import norm

def myCG(A, b, tol, maxiter):
    """
    Conjugate gradient mathods. Solve Ax=b for PD matrices.
    INPUT:
        A: Positive definite matrix
        b: column vector
        tol: inexactness tolerance
        maxiter: maximum iterations
    OUTPUT:
        x: best solution x
        rel_res: relative residual
        T: iterations
    """
    b = b.reshape(len(b), 1)
    x = np.zeros((len(b),1))
    r = b
    T = 0
    rel_res_best = np.inf
    rel_res = 1

    delta = r.T.dot(r)
    p = np.copy(r)
    x = np.zeros((len(b), 1))

    while T < maxiter and rel_res > tol:
        T += 1
        Ap = Ax(A, p)
        pAp = p.T.dot(Ap)
#        if pAp < 0:
#            print('pAp =', pAp)
#            raise ValueError('pAp < 0 in myCG')
        alpha = delta/pAp
        x = x + alpha*p
        r = r - alpha*Ap
        rel_res = norm(r)/norm(b)
        if rel_res_best > rel_res:
            rel_res_best = rel_res
        prev_delta = delta
        delta = r.T.dot(r)
        p = r + (delta/prev_delta)*p
    return x, rel_res, T

def Ax(A, x):
    if callable(A):
        Ax = A(x)
    else:
        Ax = A.dot(x)
    return Ax


# 10.008 Hands-on Activity 3 Verifier Script
# Check validity of inverse-square relationship between intensity and height
# Also check validity of black-body radiation relationship between spectral irradiance and wavelength
# Created by James Raphael Tiovalen (2020)

# Import scientific libraries
import numpy as np
from scipy.optimize import curve_fit
from sklearn import metrics

# Define inverse-square law function
def inverse_square(h, k):
    return k / (h ** 2)

if __name__ == "__main__":
    heights = np.array([6.5, 9.0, 12.0, 17.0]).astype(np.float64)

    red_intensities = np.array(
        [0.8319219036, 0.4896690263, 0.249988924, 0.1288602701]
    ).astype(np.float64) # λ = 633 nm
    green_intensities = np.array(
        [0.410783097, 0.2675019527, 0.1692426359, 0.0913581608]
    ).astype(np.float64) # λ = 524 nm
    blue_intensities = np.array(
        [1.002523336, 0.5135877745, 0.398544113, 0.1931090032]
    ).astype(np.float64) # λ = 460 nm

    for intensity in [red_intensities, green_intensities, blue_intensities]:
        popt, pcov = curve_fit(inverse_square, heights, intensity, method="lm")
        r_squared = round(
            metrics.r2_score(inverse_square(heights, *popt), intensity), 3
        )

        print(f"Equation: I = {popt[0]} / h^2")
        print(f"R^2 = {r_squared}")


from numpy import pi, cos, exp, array
from NIM.benchmarks.benchmark import Benchmark

class Easom(Benchmark):
    """dim: 2"""
    def __init__(self, lower=-100, upper=100, dimension=2):
        super(Easom, self).__init__(lower, upper, dimension)

    def get_optimum(self):
        return array([[pi, pi]]), -1

    @staticmethod
    def eval(sol):
        term1 = -cos(sol[0]) * cos(sol[1])
        term2 = exp(-(sol[0] - pi) ** 2 - (sol[1] - pi) ** 2)

        return term1 * term2


from sympy import symbols, integrate, Rational, lambdify
import matplotlib.pyplot as plt
import numpy as np

# Pollution from a factory is entering a lake. The rate of concentration of the pollutant at time t is given by
t = symbols( 't', positive = True )
dP = 91*t ** Rational( 5, 2 )

# where t is the number of years since the factory started introducing pollutants into the lake.

#  Ecologists estimate that the lake can accept a total level of pollution of 7600 units before all the fish life in the lake ends.
#  Can the factory operate for 5 years without killing all the fish in the lake?

# Yes, because:
P = integrate( dP, ( t, 0, 5 ) ).evalf()
round( P )
# is less than 7600.

# What is the polution doing?
g_xlim = [ 1, 10 ]
g_ylim = [ -5, 15 ]

lam_p = lambdify( t, integrate( dP, t ), np )

x_vals = np.linspace( g_xlim[0], g_xlim[1], 1000, endpoint=True )
y_vals = lam_p( x_vals )
plt.plot( x_vals, y_vals )
plt.show()


import math
import numpy as np

## 1a
a=123
b=321
print (a*b)

## 1b
print ("\nvec1:")
vec1 = [3, 8, 9, 10, 12]
print (vec1)

print ("\nvec2:")
vec2 = [8, 7, 7, 5, 6]
print (vec2)

print ("\nsuma wektorow:")
print ([x+y for x,y in zip (vec1, vec2)])

print ("\niloczyn wektorow (po wspolrzednych):")
vec3 = [x*y for x,y in zip (vec1, vec2)]
print (vec3)

## 1c
print ("\niloczyn skalarny:")
sum = 0
for x in vec3:
    sum = sum + x
print (sum)

print ("\ndlugosc vec1:")
vec1_len = 0
for x in vec1:
    vec1_len = x * x + vec1_len
vec1_len = math.sqrt (vec1_len)
print (vec1_len)

print ("\ndlugosc vec2:")
vec2_len = 0
for x in vec2:
    vec2_len = x * x + vec2_len
vec2_len = math.sqrt (vec2_len)
print (vec2_len)

## 1d

mat1 = np.matrix ('1 2 3; 2 2 2; 4 1 7')
print ("\nmat1:")
print (mat1)
mat2 = np.matrix ('4 5 6; 4 5 6; 4 5 6')
print ("\nmat2:")
print (mat2)

mat3 = np.multiply (mat1, mat2)
print ("\nmnozenie po wspolrzednych:")
print (mat3)

mat3 = np.dot(mat1, mat2)
print ("\nmnozenie wektorowe")
print (mat3)

## 1e
vec4 = np.random.randint(low=1, high=100, size=50)
print ("\n50 losowych liczb (vec4):")
print (vec4)

## 1f
min_vec4 = np.min (vec4)
max_vec4 = np.max (vec4)

print ("\nmin(vec4):")
print (min_vec4)
print ("\nmax(vec4):")
print (max_vec4)
print ("\nmean(vec4):")
print (np.mean(vec4))
print ("\nstd(vec4):")
print (np.std(vec4))

for i, x in np.ndenumerate(vec4):
    if vec4[i] == max_vec4:
        print ("\nindex for max in vec4: " + str(i))
        ind_max_vec4 = i

    if vec4[i] == min_vec4:
        print ("\nindex for min in vec4: " + str(i))
        ind_min_vec4 = i
## 1g
vec5 = np.zeros (shape=50)
for i, x in np.ndenumerate(vec4):
    vec5[i] = (vec4[i] - min_vec4) / (max_vec4 - min_vec4)

print ("\n vec5:")
print (vec5)

print ("\n under the max_index in new vector: " + str(vec5[ind_max_vec4[0]]))


from scipy.fft import fft, fftfreq
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
from scipy.signal import hann

# Number of sample points
N1 = 256
N2 = 512
N3 = 4096
# sample spacing
Fs = 48000
T = 1.0 / Fs
#X axis
x1 = np.linspace(0.0, N1*T, N1, endpoint=False)
x2 = np.linspace(0.0, N2*T, N2, endpoint=False)
x3 = np.linspace(0.0, N3*T, N3, endpoint=False)
#Signal
y1 = np.cos(2.0*np.pi*x1*5000)
y2 = np.cos(2.0*np.pi*x2*5000)
y3 = np.cos(2.0*np.pi*x3*5000)
#Window
w1 = hann(N1)
w2 = hann(N2)
w3 = hann(N3)
#FFT of signal with window
ywf1 = fft(y1*w1)
ywf2 = fft(y2*w2)
ywf3 = fft(y3*w3)
# Used to calculate bins
# We only grab the first half of the bins
# because we don't need the negative frequencies
xf1 = np.arange(0,Fs/2,Fs/N1)
xf2 = np.arange(0,Fs/2,Fs/N2)
xf3 = np.arange(0,Fs/2,Fs/N3)

plt.semilogy(xf1[0:int(N1/2)], 2.0/N1 * np.abs(ywf1[0:int(N1/2)]), '-r')
plt.semilogy(xf2[0:int(N2/2)], 2.0/N2 * np.abs(ywf2[0:int(N2/2)]), '-g')
plt.semilogy(xf3[0:int(N3/2)], 2.0/N3 * np.abs(ywf3[0:int(N3/2)]), '-b')

plt.legend([f'FFT size: {N1}', f'FFT size: {N2}', f'FFT size: {N3}'])

plt.grid()
plt.show()


def Poisson(lambd, N):
    """ Devuelve una lista con elementos que siguen la distribución de Poisson

    Parameters
    ----------
    lambd : int
        Es la tasa de la distribución
    N : int
        Número de puntos, tiempo trancurrido

    Returns
    -------
    list
        Lista de valores "k" para una distribución de Poisson que siga los parámetros
    """
    import numpy as np
    from math import factorial
    # Creo la distribución acumulada de Poisson, la muestreo hasta un k igual a 3 sigma de
    # Poisson
    maxk = 3*lambd
    Poisson = np.empty(maxk)
    for ij in range(maxk):
        Numerador = (lambd**(ij))*np.exp(-lambd)
        Poisson[ij] = Numerador/factorial(ij)
        ij = ij + 1
    Acum = np.cumsum(Poisson) # Distribución de probabilidad acumulada

    # Creo la distribución K que sigue la distribución de Poisson mediante "Acum"
    Nums = np.random.random(N) # Números aleatorios en [0,1]
    K = []
    ij = 0 # Recorre el arreglo Nums
    while ij<len(Nums):
        ik = 0 # Recorre el arreglo Acum
        while ik<maxk:
            if ik==0 and Nums[ij]<Acum[0]: # Caso cero
                K.append(ik)
            if ik>0 and Nums[ij]<Acum[ik] and Nums[ij]>Acum[ik-1]:
                K.append(ik)
            ik = ik + 1
        ij = ij + 1
    return K


from sympy import *

x = symbols('x[0]')
y = symbols('x[1]')
uu = cos(x)*exp(x+y)
u = diff(uu,y)
v = -diff(uu,x)
p = sin(2*pi*y)*sin(2*pi*x)
print "u:    ",u
print "\n"
print "v:    ",v
print "\n"
print "p:    ",p
print "\n"
L1 = diff(v,x,y) - diff(u,y,y)
L2 = diff(u,x,y) - diff(v,x,x)
print "Curl 1:    ",L1
print "\n"
print "Curl 2:    ",L2
print "\n"

print "\n"
P1 = diff(p,x)
P2 = diff(p,y)
print "Pressure 1:    ",P1
print "\n"
print "Pressure 2:    ",P2

 # (exp(x + y)*sin(y) + exp(x + y)*cos(y))**2 - 2*exp(2*x + 2*y)*sin(y)*cos(y)


import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab

def updateParams(k, alpha, N,sum_log_di, x, h):

    div_xByAlpha = np.divide(x,alpha)
    powK_div_xByAlpha = np.power(div_xByAlpha, k)
    log_div_xByAlpha = np.log(div_xByAlpha)

    sum_powK_div_diByAlpha = np.sum(np.multiply(powK_div_xByAlpha, h))
    sum_prod_OF_powK_div_diByAlpha_AND_log_div_diByAlpha = np.sum(np.multiply(np.multiply(powK_div_xByAlpha,log_div_xByAlpha),h))
    sum_prod_OF_powK_div_diByAlpha_AND_logP2_div_diByAlpha = np.sum(np.multiply(np.multiply(powK_div_xByAlpha,np.power(log_div_xByAlpha,2)),h))

    #N = d.shape[0]

    hessian = np.zeros((2,2))
    hessian[0,0] = -1.0 * ((N/(k*k)) + sum_prod_OF_powK_div_diByAlpha_AND_logP2_div_diByAlpha)
    hessian[1,1] = (k/(alpha*alpha)) * (N-(k+1)*sum_powK_div_diByAlpha)
    hessian[0,1] = hessian[1,0] = (1.0/alpha)*sum_powK_div_diByAlpha + (k/alpha)*sum_prod_OF_powK_div_diByAlpha_AND_log_div_diByAlpha - N/alpha

    vec = np.zeros((2,1))
    vec[0] = -1.0 *( N/k - N*np.log(alpha) + sum_log_di - sum_prod_OF_powK_div_diByAlpha_AND_log_div_diByAlpha)
    vec[1] = -1.0 *(k/alpha * (sum_powK_div_diByAlpha - N))

    param = np.linalg.inv(hessian).dot(vec)
    return k+param[0], alpha+param[1]

if __name__ == "__main__":
    #loading histograms
    data = np.loadtxt('myspace.csv',dtype=np.object,comments='#',delimiter=',')
    h = data[:,1].astype(np.int)
    h = np.array([x for x in h if x>0])
    x = np.array([num for num in range(1, h.shape[0]+1)])

    k = 1.0
    alpha = 1.0

    N = np.sum(h)
    sum_log_di = np.sum(np.multiply(np.log(x), h))
    for i in range(0,20):
        k,alpha = updateParams(k, alpha, N, sum_log_di, x, h)
        print i
        print k
        print alpha
        print "________"

    x_1 = np.linspace(1,500,2500)
    fig = plt.figure()
    axs = fig.add_subplot(111)
    y = N * (k/alpha) * np.multiply(np.power(np.divide(x_1,alpha), k-1), np.exp(-1.0* np.power(np.divide(x_1,alpha), k)))
    axs.plot(x_1,y, 'b')
    axs.plot(x, h, 'g')
    plt.show()


import numpy as np

data_points = np.array([[0.11, 1.24],
                        [0.20, 1.40],
                        [0.49, 2.00],
                        [0.65, 2.27],
                        [0.67, 2.41],
                        [0.83, 2.52]])

a =np.random.randn(1)
b =np.random.randn(1)
print(a,b)

"""Step 2: repeatedly visit entire dataset for N epochs"""

n_epoch =1000
batch_size =2
eta =0.01  # learning rate

for epoch in range(n_epoch):
  # Step 2.1: shuffle the data point
  np.random.shuffle(data_points)

  # Step 2.2:
  for i in range(0,len(data_points),batch_size):
    points =data_points[i:i+batch_size]

    x =points[:,0]
    y =points[:,1]

    # compute MSE loss
    y_pred = a *x +b
    y_err =y - y_pred
    mse_loss = (y_err**2).mean()

    # compute the gradients w.r.t a and b
    a_grad =-2.0*((y_err *x).mean())
    b_grad =-2.0*(y_err.mean())

    # update a and b (model parameter)
    a =a -eta *a_grad
    b =b -eta *b_grad

    print('grad:{} {} {}'.format(a,b,mse_loss))