# Machine Learning Online Class - Exercise 2: Logistic Regression
#
#  Instructions
#  ------------
#
#  This file contains code that helps you get started on the logistic
#  regression exercise. You will need to complete the following functions
#  in this exericse:
#
#     sigmoid.m
#     costFunction.m
#     predict.m
#     costFunctionReg.m
#
#  For this exercise, you will not need to change any code in this file,
#  or any other files other than those mentioned above.
#
import numpy
import scipy.optimize as optimization

import log_reg_funcs

import warnings
# invalid value encountered in multiply, divide by zero encountered in log
warnings.filterwarnings("ignore", category=RuntimeWarning)

# Load Data
#  The first two columns contains the exam scores and the third column
#  contains the label.

data = numpy.loadtxt('./ex2data1.txt', delimiter=',', dtype='float')
x_data = data[:, 0:2]
y_data = data[:, 2]

print("Few examples of the dataset:")
print(data[:4, :])

# ==================== Part 1: Plotting ====================
#  We start the exercise by first plotting the data to understand the
#  the problem we are working with.

print("\nPlotting data with + indicating (y = 1) examples and o indicating (y = 0) examples.\n")
log_reg_funcs.plot_data(x_data, y_data)

# ============ Part 2: Compute Cost and Gradient ============
#  In this part of the exercise, you will implement the cost and gradient
#  for logistic regression. You neeed to complete the code in
#  costFunction.m

num_examples, num_features = x_data.shape
x_data = numpy.c_[numpy.ones((num_examples, 1)), x_data]  # Add intercept term to x_data
initial_theta = numpy.zeros((num_features+1))  # Initialize fitting parameters

# Compute and display initial cost and gradient
cost_J = log_reg_funcs.cost_function(initial_theta, x_data, y_data)
gradient = log_reg_funcs.gradient_function(initial_theta, x_data, y_data)

print("Cost at initial theta (zeros):", cost_J)
print("Expected cost (approx): 0.693\n")
print("Gradient at initial theta (zeros):", gradient)
print("Expected gradients (approx): [-0.1000 -12.0092 -11.2628]")

# Compute and display cost and gradient with non-zero theta
test_theta = numpy.array([-24, 0.2, 0.2])
cost_J = log_reg_funcs.cost_function(test_theta, x_data, y_data)
gradient = log_reg_funcs.gradient_function(test_theta, x_data, y_data)
print("\nCost at test theta:", cost_J)
print("Expected cost (approx): 0.218\n")
print("Gradient at test theta:", gradient)
print("Expected gradients (approx): [0.043 2.566 2.647]")

# ============= Part 3: Optimizing using fminunc  =============
#  In this exercise, you will use a built-in function (fminunc) to find the
#  optimal parameters theta.

#  Set options for fminunc
results = optimization.fmin_bfgs(f=log_reg_funcs.cost_function, x0=initial_theta,
                                 fprime=log_reg_funcs.gradient_function, args=(x_data, y_data), maxiter=1000, full_output=True)

# Print theta to screen
print("Cost at theta found by fminunc equivalent fmin_bfgs:", results[1])
print("Expected cost (approx): 0.203\n")
print("theta:", results[0])
print("Expected theta (approx): [-25.161 0.206 0.201]\n")

# Plot decision boundary
log_reg_funcs.plot_decision_boundary(results[0], x_data, y_data)

# ============== Part 4: Predict and Accuracies ==============
#  After learning the parameters, you'll like to use it to predict the outcomes
#  on unseen data. In this part, you will use the logistic regression model
#  to predict the probability that a student with score 45 on exam 1 and
#  score 85 on exam 2 will be admitted.
#
#  Furthermore, you will compute the training and test set accuracies of
#  our model.
#
#  Your task is to complete the code in predict.m

#  Predict probability for a student with score 45 on exam 1
#  and score 85 on exam 2

test_observation = numpy.array([1.0, 45.0, 85.0])
test_probability = log_reg_funcs.sigmoid_function(numpy.dot(test_observation, results[0]))
print("For a student with scores 45 and 85, we predict an admission probability of ", test_probability)
print("Expected value: 0.775 +/- 0.002\n")

# Compute accuracy on our training set
train_predicted_labels = log_reg_funcs.predict(results[0], x_data)
correct = numpy.sum(train_predicted_labels.astype(int) == y_data)
train_accuracy = correct/num_examples

print("Train Accuracy:", train_accuracy*100)
print("Expected accuracy (approx): 89.0%\n")


# -*- coding: utf-8 -*-
from __future__ import print_function, division, absolute_import
import matplotlib
matplotlib.use('Agg')
from matplotlib import pyplot as plt
import seaborn as sns

import numpy as np

import tensorflow as tf
tf.enable_eager_execution()

import tensorflow_probability as tfp
from tensorflow_probability import edward2 as ed
tfd = tfp.distributions

# ===========================================================================
# Constant
# ===========================================================================
a = 8
b = 0.5
mu = 0
n_samples = 100000

# ===========================================================================
# Following the generative procedure
# ===========================================================================
# Step 1: generate the precision Beta
beta_dist = tfd.Gamma(concentration=a, rate=b)
beta = beta_dist.sample(n_samples)
# the prior probability
p_beta_given_a_and_b = beta_dist.prob(beta)

# Step 2: generate the data point
# scale is standard deviation
x_dist = tfd.Normal(loc=mu, scale=tf.sqrt(1 / beta))
x = x_dist.sample()
# the likelihood
p_x_given_mu_and_beta = x_dist.prob(x)

# ====== plotting the prior ====== #
plt.figure()
sns.distplot(beta.numpy(), bins=120, kde=True)
plt.title(r"Prior distribution: $p(\beta|a=%g, b=%g)$" % (a, b))

# ====== plotting the likelihood ====== #
plt.figure()
sns.distplot(x.numpy(), bins=120, kde=True)
plt.title(r"Likelihood distribution: $p(X|\mu=%g, \sigma=\sqrt{\beta^{-1}})$" % mu)

# ====== plotting the posterior ====== #
# the posterior probability, this is only
# proportionally, not exactly because we omit
# the evidence p(X)
# If we want to calculate p(X), we need to marginalize out
# beta using sum rule:
# p(X) = p(X, beta_1) +  p(X, beta_2) + ... +  p(X, beta_∞)
# This is not easy
p_beta_given_x = p_x_given_mu_and_beta * p_beta_given_a_and_b
p_beta_given_x = p_beta_given_x / tf.reduce_sum(p_beta_given_x)
posterior_dist = tfd.Categorical(probs=p_beta_given_x)

beta = beta.numpy()
posterior = []
for i in range(n_samples // 2000):
  idx = posterior_dist.sample(2000).numpy()
  posterior.append(beta[idx])
posterior = np.concatenate(posterior)

plt.figure()
sns.distplot(posterior, bins=120, kde=True)
plt.title(r"Sampled posterior distribution: $p(\beta|X)$")

# ====== plotting the close form solution ====== #
a0 = a + n_samples / 2
b0 = b + n_samples / 2 * np.var(x.numpy())
posterior_dist = tfd.Gamma(concentration=a0, rate=b0)
posterior = posterior_dist.sample(n_samples)

plt.figure()
sns.distplot(posterior, bins=120, kde=True)
plt.title(
    r"Closed form solution: $p(\beta|X) \sim Gamma(a=%g, b=%g)$"
    % (a0, b0))

from odin import visual as V
V.plot_save('/tmp/tmp.pdf', dpi=200)


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

import numpy as np

def isPositiveDefinite(matrix, debug=False):
    """
    Taken from: https://stackoverflow.com/a/44287862
    """

    # '\u2713' = ✓ (unicode tick character)
    if debug:
        print('Analysing symmetry of the matrix: \n', matrix)
        print()

    # Check if it is symmetric
    if isSymmetric(matrix, debug):
        # Using cholesky to check the check if it's positive deffinite
        try:
            np.linalg.cholesky(matrix)
            print(u'[\u2713] Matrix is positive definite.')
            return True
        except np.linalg.LinAlgError:
            print('[X] Matrix is not positive definite.')
            return False
    else:
        return False

def isSymmetric(matrix, debug=False):

    # '\u2713' = ✓ (unicode tick character)
    if debug:
        print('Analysing symmetry of the matrix: \n', matrix)
        print()

    if np.allclose(matrix, matrix.T):
        print(u'[\u2713] Matrix is symmetric.')
        return True
    else:
        print('[X] Matrix is NOT symmetric.')
        return False

def diagDominant(matrix, debug=False):
    """Print if a matrix is diagonal dominant

    Taken from: https://stackoverflow.com/a/43074838
    """

     # '\u2713' = ✓ (unicode tick character)

    if debug:
        print('Analysing matrix: \n', matrix)
        print()

    D = np.diag(np.abs(matrix)) # Find diagonal coefficients

    S = np.sum(np.abs(matrix), axis=1) - D # Find row sum without diagonal

    if np.all(D > S):
        print(u'[\u2713] Matrix is strictly diagonally dominant.')
        return True
    else:
        print('[X] Matrix is NOT strictly diagonally dominant')
        return False

def useJacobiGaussSeidel(matrix, debug=False):
    """Given an nxn matrix, tells if Gauss-Seidel or Jacobi could be used.

    Lineal system of equations: Ax = b

    Arguments:
        matrix: Should be matrix A of the system.

    Returns:
        True if either Jacobi or Gauss-Seidel could be used
    """
    matrixNumDim = np.ndim(matrix)
    if (matrixNumDim != 2):
        raise RuntimeError("I'm not prepared for this. </3")

    matrixShape = np.shape(matrix)
    if (matrixShape[0] != matrixShape[1]):
        print('[X] Matrix is not squared')
        return False

    jacobi = diagDominant(matrix, debug)
    posDef = isPositiveDefinite(matrix, debug)

    if posDef:
        print(u'[\u2713] Gauss-Seidel can be used.')
        print('[X] Jacobi can not be used')
        return True

    elif jacobi:
        print(u'[\u2713] Gauss-Seidel can be used.')
        print(u'[\u2713] Jacobi can be used')
        return True

    else:
        print('[X] Gauss-Seidel can not be used.')
        print('[X] Jacobi can not be used')
        return False

if __name__ == "__main__":
    # Strictly diagonally dominant
    I = np.array([[-4, 2, 1], [1, 6, 2], [1, -2, 5]])
    print('Testing: \n', I,'\n')
    diagDominant(I)

    # Diagonally dominant (not strictly)
    I = np.array([[3, -2, 1], [1, -3, 2], [-1, 2, 4]])
    print('Testing: \n', I,'\n')
    diagDominant(I)

    # Not diagonally dominant
    I = np.array([[-2, 2, 1], [1, 3, 2], [1, -2, 0]])
    print('Testing: \n', I,'\n')
    diagDominant(I)

    # Positive definite
    I = np.eye(4)
    print('Testing: \n', I,'\n')
    isPositiveDefinite(I)

    I = np.array([[2, -1, 0], [-1, 2, -1], [0, -1, 2]])
    print('Testing: \n', I,'\n')
    isPositiveDefinite(I)

    # NOT positive definite
    I = np.array([[1, 2], [2, 1]])
    print('Testing: \n', I,'\n')
    isPositiveDefinite(I)

    print('\nJacobi/Gauss-Seidel ?')

    # Strictly diagonally dominant and not definite positive.
    I = np.array([[-4, 2, 1], [1, 6, 2], [1, -2, 5]])
    print('Testing: \n', I,'\n')
    useJacobiGaussSeidel(I)

    # Positive definite and diagonally dominant
    I = np.eye(4)
    print('Testing: \n', I,'\n')
    useJacobiGaussSeidel(I)


from sympy import Rational as R
from sympy import E, Symbol, Abs, cos, sin, pi
from programa import integral, transformar

x = Symbol("x")
y = Symbol("y")
u = Symbol("u")
v = Symbol("v")
θ = Symbol("θ")
r = Symbol("r")

# Ejemplo 1
v1 = (x < 1)
v2 = (y > 0)
v3 = (y < x)
funcion = E**(-(x**2))

print(integral(funcion, v1, v2, v3))

# Ejemplo 2
list_rels = [x-2*y <= 0, x-2*y >= -4, x+y >= 1, x+y <= 4]
func = 3*x*y

vars_reem = [u, v]
dicc_reem = {x: R(1, 3)*(2*u + v),
             y: R(1, 3)*(u - v)}

det, func_reem, list_rels_reem = transformar(func, list_rels,
                                             vars_reem, dicc_reem)
print(integral(Abs(det)*func_reem, *list_rels_reem))

# Ejemplo 3
list_rels = [x**2 + y**2 >= 1, x**2 + y**2 <= 5]
func = x**2 + y

vars_reem = [r, θ]
dicc_reem = {x: r*cos(θ),
             y: r*sin(θ)}

det, func_reem, list_rels_reem = transformar(func, list_rels,
                                             vars_reem, dicc_reem)
list_rels_reem += [r >= 0, θ >= 0, θ <= 2*pi]
print(integral(det*func_reem, *list_rels_reem))


# -*- coding: utf-8 -*-
"""
Implementation of 4th order Runge - Kutta method for the ODE solving like y'(x) = f(x)
The implemented equation is analogue to the Simpon's integration rule
@author: ssklykov
"""
# %% Import section
import SampleF
import numpy as np
import matplotlib.pyplot as plt
from EulerSolver import predcorrEuler, numberOfSteps, checkInputs

# %% Implementation of the algorithm
def rungeCutta4(f,h:float,y0:float,xStart:float,xFinish:float) -> tuple:
    """Simple single step (~h*4) ODE Runge-Cutta solver. f - input function (y'(x) = f(x)),\
        h - step size, y0 - initial value, xStart - first value for solving an input ODE, xFinish - finishing value for \
        calculations. Returning a tuple that composes of xMesh values and yValues - the solution for an ODE"""
    # Checking input parameters for validity
    if (checkInputs(f, h, xStart, xFinish)):
        return None
    # Defying exact number of steps between interval points [xStart,xFinish] or number of points for modelling and returning
    n = numberOfSteps(xStart, xFinish, h); nEven = int((xFinish-xStart) / h) + 1
    # Values initialization
    yValues = np.zeros(n,dtype='float'); xMesh = np.zeros(n,dtype='float') # init mesh values
    yValues[0] = float(y0); xMesh[0] = float(xStart)
    # Calculations
    if (n == nEven):
        for i in range(1,n):
            xMesh[i] = xMesh[i-1] + h
            yValues[i] = yValues[i-1] + (h*(f(xMesh[i-1]) + f(xMesh[i]) + 4*f(xMesh[i-1]+0.5*h))/6) # like Simpson's rule
    else:
        for i in range(1,n-1):
            xMesh[i] = xMesh[i-1] + h
            yValues[i] = yValues[i-1] + (h*(f(xMesh[i-1]) + f(xMesh[i]) + 4*f(xMesh[i-1]+0.5*h))/6)
        hLastStep = xFinish - xMesh[n-2]; xMesh[n-1] = xFinish
        yValues[n-1] = yValues[n-2] + (hLastStep*(f(xMesh[n-2]) + f(xMesh[n-1]) + 4*f(xMesh[n-2]+0.5*h))/6)
    return (xMesh,yValues)

# %% Testing parameters
h = 0.25; y0 = 0.0; xStart = 0.0; xFinish = 4.0; nDigits = 2
#%% Testing
f1 = SampleF.SampleFunctions(1,nDigits); y1 = f1.getValue # For referring to a function it can be called without () notation
(x,y) = predcorrEuler(y1,h,y0,xStart,xFinish)
(x2,y2) = rungeCutta4(y1,h,y0,xStart,xFinish)

# %% Theoretical values calculation
yTh = np.zeros(len(x),dtype='float')
for i in range(len(x)):
    yTh[i] = f1.getTheoreticalValue(x[i])
yTh2 = np.zeros(len(x2),dtype='float')
for i in range(len(x2)):
    yTh2[i] = f1.getTheoreticalValue(x2[i])
# %% Comparison results on grahps
# x.round(nDigits); y.round(nDigits)
# plt.figure(); plt.xlabel("x"); plt.ylabel("y(x) solution"); plt.plot(x,y,label='numerical solution',linewidth=3)
# plt.plot(x,yTh,label='theoretical function',linewidth=2); plt.legend(); plt.title("Euler solver with prediction / correction")

# %% 2nd Comparison results on graphs
x2.round(nDigits); y2.round(nDigits)
plt.figure(); plt.xlabel("x"); plt.ylabel("y(x) solution"); plt.plot(x2,y2,'bo',label='numerical solution',linewidth=4)
plt.plot(x2,yTh2,'r',label='theoretical function',linewidth=2); plt.legend(); plt.title("Runge-Cutta 4th order solver")


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

from numpy import linspace, logspace, diff, zeros
from numpy import cos, sin, exp, log, pi
import matplotlib.pyplot as plt
from scipy.integrate import solve_ivp

####################################
# Implementación genérica de Taylor 2
# f(t,x): primera derivada de x respecto al tiempo
# g(t,x): segunda derivada de x respecto al tiempo
# x0: condición inicial
# t0, tf: tiempo inicial y final
# h: paso de integración
####################################
def taylor2(f,g,x0,t0,tf,h):
    N = int((tf-t0)/h)           #número de puntos
    t = linspace(t0,tf,N+1)
    n = x0.shape[0]         #dimensión del problema
    x = zeros((n,N+1))
    x[:,0] = x0
    i = h*h/2.0
    for k in range(N):
        x[:,k+1] = x[:,k]+h*f(t[k],x[:,k])+i*g(t[k],x[:,k])

    return t,x

####################################
# Implementación genérica de Heun
# f(t,x): derivada de x respecto al tiempo
# x0: condición inicial
# t0, tf: tiempo inicial y final
# h: paso de integración
####################################
def heun(f,x0,t0,tf,h):
    N = int((tf-t0)/h)          #número de puntos
    t = linspace(t0,tf,N+1)
    n = x0.shape[0]             #dimensión del problema
    x = zeros((n,N+1))
    x[:,0] = x0
    for k in range(N):
        f1 = h*f(t[k],x[:,k])
        f2 = h*f(t[k]+h,x[:,k]+f1)
        x[:,k+1] = x[:,k]+(f1+f2)/2.0

    return t,x

####################################
# Implementación genérica de Cauchy
# f(t,x): derivada de x respecto al tiempo
# x0: condición inicial
# t0, tf: tiempo inicial y final
# h: paso de integración
####################################
def cauchy(f,x0,t0,tf,h):
    N = int((tf-t0)/h)          #número de puntos
    t = linspace(t0,tf,N+1)
    n = x0.shape[0]             #dimensión del problema
    x = zeros((n,N+1))
    x[:,0] = x0
    h2 = h/2.0
    for k in range(N):
        x[:,k+1] = x[:,k]+h*f(t[k]+h2,x[:,k]+h2*f(t[k],x[:,k]))

    return t,x

########################
# EJEMPLO
########################
R = 1e3	            #Valor de la resistencia
C = 1e-6	        #Valor de la capacidad
w = 2.0*pi*1000     #frecuencia angular de la señal de entrada
A = 1.0		        #amplitud de la señal de entrada
T = 5*2*pi/w	    #simulo cinco ciclos

####################################
# Solución
def xsol(t):
    x = -exp(-t/(R*C))+cos(w*t)+w*R*C*sin(w*t)
    x = (A/(1+(w*R*C)**2))*x
    return x

####################################
# Derivada primera de x
def dx(t,x):
    return ((A*cos(w*t)-x)/(R*C))

####################################
# Derivada segunda de x
def d2x(t,x):
    return ((-A*w*sin(w*t)-((A*cos(w*t)-x)/(R*C)))/(R*C))

####################################
# Plot ejemplo
def plotejemplo(h):
    x0 = zeros(1)
    t,xh = heun(dx,x0,0,T,h)
    t,xc = cauchy(dx,x0,0,T,h)
    t,xt = taylor2(dx,d2x,x0,0,T,h)
    x = xsol(t)
    fig, ax = plt.subplots()
    ax.plot(t, x, label='Solución')
    ax.plot(t, xh[0,:], label='Heun')
    ax.plot(t, xc[0,:], label='Cauchy')
    ax.plot(t, xt[0,:], label='Taylor 2')
    ax.legend()
    plt.title('Ejemplo')
    fig, ax = plt.subplots()
    ax.plot(t, xh[0,:]-x, label='Heun')
    ax.plot(t, xc[0,:]-x, label='Cauchy')
    ax.plot(t, xt[0,:]-x, label='Taylor 2')
    ax.legend()
    plt.title('Error')

####################################
# Errores ejemplo
def errorejemplo():
    n = 5
    N = logspace(1,5,n)
    h = T/N
    eh = zeros(n)
    ec = zeros(n)
    et = zeros(n)
    x0 = zeros(1)
    x = xsol(T)
    for k in range(n):
        t,xh = heun(dx,x0,0,T,h[k])
        t,xc = cauchy(dx,x0,0,T,h[k])
        t,xt = taylor2(dx,d2x,x0,0,T,h[k])
        eh[k] = abs(xh[0,-1]-x)
        ec[k] = abs(xc[0,-1]-x)
        et[k] = abs(xt[0,-1]-x)
    fig, ax = plt.subplots()
    ax.loglog(h, eh, label='Heun')
    ax.loglog(h, ec, label='Cauchy')
    ax.loglog(h, et, label='Taylor 2')
    # ax.loglog(h, (h/h[0])**2*eh[0], 'b--')
    # ax.loglog(h, (h/h[0])**2*ec[0], 'r--')
    # ax.loglog(h, (h/h[0])**2*et[0], 'g--')
    ax.legend()
    plt.xlabel('h')
    plt.ylabel('error')
    plt.title('Error')
    print(diff(log(eh))/diff(log(h)))
    print(diff(log(ec))/diff(log(h)))
    print(diff(log(et))/diff(log(h)))

####################################
# Estimación error ejemplo
def esterrorejemplo(h):
    x0 = zeros(1)
    x = xsol(T)
    t,xh1 = heun(dx,x0,0,T,h)
    t,xc1 = cauchy(dx,x0,0,T,h)
    t,xt1 = taylor2(dx,d2x,x0,0,T,h)
    t,xh2 = heun(dx,x0,0,T,h/2)
    t,xc2 = cauchy(dx,x0,0,T,h/2)
    t,xt2 = taylor2(dx,d2x,x0,0,T,h/2)

    eh = abs(xh2[0,-1]-x)
    ec = abs(xc2[0,-1]-x)
    et = abs(xt2[0,-1]-x)
    eeh= abs(xh1[0,-1]-xh2[0,-1])/3.0
    eec= abs(xc1[0,-1]-xc2[0,-1])/3.0
    eet= abs(xt1[0,-1]-xt2[0,-1])/3.0
    print(abs(eh-eeh)/eh*100)
    print(abs(ec-eec)/ec*100)
    print(abs(et-eet)/et*100)
    return eh,eeh,ec,eec,et,eet

####################################
# Comparación con RK45
def comp45(h):
    x0 = zeros(1)
    t,xh = heun(dx,x0,0,T,h)
    # s45 = solve_ivp(dx,[0,T],x0,method='RK45', t_eval=None,
    #                 rtol = 1e-6, atol = 1e-8)
    # s45 = solve_ivp(dx,[0,T],x0,method='RK45', t_eval=None,
    #                 rtol = 1e-13, atol = 1e-14)
    s45 = solve_ivp(dx,[0,T],x0,method='RK45', t_eval=t,
                    rtol = 1e-13, atol = 1e-14)
    x = xsol(t)
    x1 = xsol(s45.t)

    fig, ax = plt.subplots()
    ax.plot(t, x, label='Solución')
    ax.plot(t, xh[0,:], label='Heun')
    ax.plot(s45.t, s45.y[0,:], label='RK45')
    ax.legend()
    plt.title('Ejemplo')
    fig, ax = plt.subplots()
    ax.plot(t[:-1],diff(t), label='Heun')
    ax.plot(s45.t[:-1],diff(s45.t), label='RK45')
    ax.legend()
    plt.title('Paso de integración')

    fig, ax = plt.subplots()
    ax.semilogy(t,abs(xh[0,:]-x), label='Heun')
    ax.semilogy(s45.t,abs(s45.y[0,:]-x1), label='RK45')
    ax.legend()
    plt.title('Error')

    print(s45.t.shape)
    print(t.shape)

####################################
# Plot ejemplo
def plotejemplo_ruku4(h, fruku4):
    x0 = zeros(1)
    t, xrk4 = fruku4(dx,x0,0,T,h)

    t,xt = taylor2(dx,d2x,x0,0,T,h)

    print("Calculating solution...")
    x = xsol(t)

    print("Plotting solution and RuKu 4.")
    fig, ax = plt.subplots()
    ax.plot(t, x, label='Solución')
    print(f"t: {t}\nxrk4: {xrk4}\nxrk4[0,:]: {xrk4[0:1]}")
    ax.plot(t, xrk4[:], label='RuKu 4')
    ax.legend()
    plt.title('Ejemplo')

    print("Plotting error.")
    fig, ax = plt.subplots()
    ax.plot(t, xrk4[:]-x, label='RuKu 4')
    #plt.axis("off")
    #ax.legend()
    #plt.title('Error')

    print("Showing plots.")
    plt.show()

# plotejemplo(T/10000)
# plt.close('all')
# errorejemplo()
# esterrorejemplo(T/1e4)
#comp45(T/1000)


import numpy as np
import numpy.linalg as la
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.cm as cm
#from tqdm import tqdm
import sys
from matplotlib.animation import FuncAnimation

def gershgorin_bound(A):
    '''
        return geshgorin bound on spectral radius of A
    '''
    N,M = A.shape
    assert(N==M, 'matrix not square')
    specrad = 0
    for i in range(0, N):
        diag_elem = A[i,i]
        sum_non_diag = 0.0
        for j in range(0, M):
            if j != i:
                sum_non_diag += abs(A[i,j])
        cur_specrad = diag_elem + abs(sum_non_diag)
        if cur_specrad>= specrad:
            specrad = cur_specrad
    return specrad

def specrad(A):
    eigs = la.eigvals(A)
    return np.max(eigs)

def track_specrad(A, tstep, title):
    dat = specrad(A)
    if tstep==1:
        open("{0}.txt".format(title), 'w').close()
    f = open("{0}.txt".format(title), "a")
    f.write('{0}: {1}\n'.format(tstep, dat))
    f.close()
    return dat

def color_grads(steps):
    blue_max = np.array([0.2, 0.2, 0.99])
    red_max = np.array([0.99, 0.2, 0.2])
    green_max = np.array([0.2, 0.99, 0.2])
    blue_min = np.array([0.09, 0.09, 0.4])
    red_min = np.array([0.3, 0.09, 0.09])
    green_min = np.array([0.09, 0.3, 0.09])
    B = []
    R = []
    G = []
    for n in np.linspace(0.0, 1.0, steps):
        B += [blue_max*n+(1-n)*blue_min]
        G += [green_max*n+(1-n)*green_min]
        R += [red_max*n+(1-n)*red_min]

    return R, G, B


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

import numpy as np

class Normalizer:
    """
    MLP 相关的数据标准化器(归一化)

    标准化处理对于计算距离的机器学习方法是非常重要的，因为特征的尺度不同会导致计算出来的距离倾向于尺度大的特征，
    为保证距离对每一列特征都是公平的，必须将所有特征缩放到同一尺度范围内

    Author: xrh
    Date: 2021-07-10

    """

    @staticmethod
    def tow_norm_normalize(X):
        """
        对所有样本进行二范数归一化

        ref:
        https://blog.csdn.net/hqh131360239/article/details/79061535

        :param X: shape(N,m)
                  N - 样本的个数
                  m - 样本的维度
        :return:
        """

        X_norm_2 = np.linalg.norm(X, ord=2, axis=1, keepdims=True)  # 每一个样本的模(二范数) shape(N,1)

        # X_norm_2 = X_norm_2.reshape(-1,1)

        X = X / X_norm_2

        return X

    @staticmethod
    def Z_Score_normalize(X):
        """
        0均值归一化( Z-Score Normalization)

        对所有特征进行 0均值归一化, 将特征归一化为均值为0 方差为1

        :param X: shape(N,m)
                  N - 样本的个数
                  m - 样本的维度
        :return:
        """

        # N, m = np.shape(X)  # N 个样本, m 个特征

        mu = np.mean(X, axis=0)  # 每一个特征的均值 shape:(m,)

        s = np.std(X, axis=0)  # 每一个特征的标准差 shape:(m,)

        X = (X - mu) / s

        return X

    @staticmethod
    def min_max_normalize(Xarray):
        """
        对特征进行 min-max 标准化，将数据缩放到0-1之间

        :param Xarray:
        :return:
        """

        for f in range(Xarray.shape[1]):
            maxf = np.max(Xarray[:, f])
            minf = np.min(Xarray[:, f])
            for n in range(Xarray.shape[0]):
                Xarray[n][f] = (Xarray[n][f] - minf) / (maxf - minf)
        return Xarray


import numpy as np
import math

# Compute the intersection distance between histograms x and y
# Return 1 - hist_intersection, so smaller values correspond to more similar histograms
# Check that the distance range in [0,1]

def dist_intersect(x, y):
    s = 0
    for q, v in zip(x, y):
        s = s + min(q, v)

    s = s / np.sum(x) + s / np.sum(y)
    s = s / 2

    return 1 - s

# Compute the L2 distance between x and y histograms
# Check that the distance range in [0,sqrt(2)]

def dist_l2(x, y):
    s = 0
    for q, v in zip(x, y):
        s = s + pow(q - v, 2)

    return s

# Compute chi2 distance between x and y
# Check that the distance range in [0,Inf]
# Add a minimum score to each cell of the histograms (e.g. 1) to avoid division by 0

def dist_chi2(x, y):
    s = 0
    for q, v in zip(x, y):
        if q + v != 0:
            s = s + pow(q - v, 2) / (q + v)
        else:
            s = s + pow(q - v, 2)

    return s

def get_dist_by_name(x, y, dist_name):
    if dist_name == 'chi2':
        return dist_chi2(x, y)
    elif dist_name == 'intersect':
        return dist_intersect(x, y)
    elif dist_name == 'l2':
        return dist_l2(x, y)
    else:
        assert False, 'unknown distance: %s' % dist_name


import matplotlib.pyplot as plt
import numpy as np
import math
g = 9.8
m = 0.3
k = 0.1
def f1 (v) :
    return v
def f2x (vx,vy,m):
    return - (k * (vx*vx + vy*vy) * vx) / (m * math.sqrt(vx*vx + vy*vy))
def f2y (vx,vy,m):
    return - g - (k * (vx*vx + vy*vy) * vy) / (m * math.sqrt(vx*vx + vy*vy))
def runge_kutta (x,y,vx,vy,f1,f2x,f2y,filename):
    alpha = 1
    beta = 1/2
    h = 0.01
    x_list = []
    vx_list = []
    y_list = []
    vy_list = []
    x_list.append(x)
    vx_list.append(vx)
    y_list.append(y)
    vy_list.append(vy)
    for i in range (200):
        x_new = x + h * ( (1-beta) * f1(vx) + beta * f1(vx + alpha * h * f1(vx)))
        vx_new = vx + h * ( (1-beta) * f2x(vx,vy,m) + beta * f2x(vx+alpha*h*f2x(vx,vy,m),vy+alpha*h*f2y(vx,vy,m),m))
        y_new = y + h * ( (1-beta) * f1(vy) + beta * f1(vy + alpha * h * f1(vy)))
        vy_new = vy + h * ( (1-beta) * f2y(vx,vy,m) + beta * f2y(vx+alpha*h*f2x(vx,vy,m),vy+alpha*h*f2y(vx,vy,m),m))
        x_list.append(x_new)
        vx_list.append(vx_new)
        y_list.append(y_new)
        vy_list.append(vy_new)
        x = x_new
        vx = vx_new
        y = y_new
        vy = vy_new
        if y < 0 :
            break
    fig = plt.figure(figsize=(12, 8))
    plt.xlim(0,13.411)
    plt.ylim(0,5)
    plt.plot([6.767, 6.767], [0, 1.554], 'k-', lw=2)
    plt.plot(x_list, y_list)
    plt.savefig(filename)
if __name__ == '__main__' :
    runge_kutta (1,2,100,30,f1,f2x,f2y,"high_clear.png")
    runge_kutta (1,2,130,10,f1,f2x,f2y,"driven_clear.png")
    runge_kutta (3,3.5,80,-30,f1,f2x,f2y,"smash.png")


"""
相似度计算
"""
import math
import numpy as np
from numpy.linalg import norm

def cosineSim(a, b, dtype=np.ndarray):
    """
    余弦相似度。如果是集合,公式为：a与b的交集的长度/根号(a的长度*b的长度);
    如果是向量，公式为a与b的点积/a的范数*b的范数
    :param dtype: set或np.ndarray
    :param a: 集合或向量a
    :param b: 集合或向量b
    :return: a与b的余弦相似度
    """
    if dtype == set:
        return len(a & b) / math.sqrt(len(a) * len(b))
    elif dtype == np.ndarray:
        return np.dot(a, b) / (norm(a) * norm(b))
    else:
        return None

def jaccardSim(a: set, b: set) -> float:
    """
    Jaccard相似度，公式为：a与b的交集的长度/a与b的并集的长度
    :param a:
    :param b:
    :return: a与b的Jaccard相似度
    """
    return len(a & b) / len(a | b)

if __name__ == '__main__':
    a = np.array([1, 0, 0])
    b = np.array([1, 1, 0])
    print(cosineSim(a,b))


import numpy as np
import random as rm
states = ["Sleep","Icecream","Run"]

# Possible sequences of events
transitionName = [["SS","SR","SI"],["RS","RR","RI"],["IS","IR","II"]]

# Probabilities matrix (transition matrix)
transitionMatrix = np.array([[0.2,0.6,0.2],[0.1,0.6,0.3],[0.2,0.7,0.1]])
# A function that implements the Markov model to forecast the state/mood.
def Markov_forecast(initial_state, steps, transitionMatrix):
    """
    Do Markov chain forecasting
    INPUTS
    initial_state    : The initial state
    steps            : number of predictions
    transitionMatrix : Array of states conditional probability

    OUTPUTS
    states : array of forecasting states
    """
    states = np.zeros((steps), dtype=int)
    n = transitionMatrix.shape[0]
    s = np.arange(1,n+1)

    states[0] = initial_state
    for i in range(steps-1):
        states[i+1] = np.random.choice(s,p=transitionMatrix[states[i]-1])

    return states

# Function that forecasts the possible state for the next 2 days
activity_forecast(2)

def activity_forecast(days):
    # Choose the starting state
    activityToday = "Sleep"
    activityList = [activityToday]
    i = 0
    prob = 1
    while i != days:
        if activityToday == "Sleep":
            change = np.random.choice(transitionName[0],replace=True,p=transitionMatrix[0])
            if change == "SS":
                prob = prob * 0.2
                activityList.append("Sleep")
                pass
            elif change == "SR":
                prob = prob * 0.6
                activityToday = "Run"
                activityList.append("Run")
            else:
                prob = prob * 0.2
                activityToday = "Icecream"
                activityList.append("Icecream")
        elif activityToday == "Run":
            change = np.random.choice(transitionName[1],replace=True,p=transitionMatrix[1])
            if change == "RR":
                prob = prob * 0.5
                activityList.append("Run")
                pass
            elif change == "RS":
                prob = prob * 0.2
                activityToday = "Sleep"
                activityList.append("Sleep")
            else:
                prob = prob * 0.3
                activityToday = "Icecream"
                activityList.append("Icecream")
        elif activityToday == "Icecream":
            change = np.random.choice(transitionName[2],replace=True,p=transitionMatrix[2])
            if change == "II":
                prob = prob * 0.1
                activityList.append("Icecream")
                pass
            elif change == "IS":
                prob = prob * 0.2
                activityToday = "Sleep"
                activityList.append("Sleep")
            else:
                prob = prob * 0.7
                activityToday = "Run"
                activityList.append("Run")
        i += 1
    return activityList

# To save every activityList
list_activity = []
count = 0

# `Range` starts from the first count up until but excluding the last count
for iterations in range(1,10000):
        list_activity.append(activity_forecast(2))

# Check out all the `activityList` we collected
#print(list_activity)

# Iterate through the list to get a count of all activities ending in state:'Run'
for smaller_list in list_activity:
    if(smaller_list[2] == "Run"):
        count += 1

# Calculate the probability of starting from state:'Sleep' and ending at state:'Run'
percentage = (count/10000) * 100
print("The probability of starting at state:'Sleep' and ending at state:'Run'= " + str(percentage) + "%")


from cmath import pi
import numpy as np
from pyparsing import col
from .utils import check_2D, check_dimension

def _calc_gaussian_value(i,j,sigma,half_size):
    return 1/(2*np.pi * sigma**2)* np.exp( -1* ( ( i-(half_size+1) )**2 + (j-(half_size+1))**2  ) /(2*sigma**2)  )

def create_gaussian_filter(size,sigma):
    if(size%2 ==0):
        raise ValueError()

    filter= np.zeros((size,size))
    half_size=size//2

    for i in range(size):
        for j in range(size):
            filter[i][j]= _calc_gaussian_value(i,j,sigma,half_size)
    return filter

def is_in_edge_range(image_shape, coords, filter_size):
    y,x= coords
    filter_size =filter_size//2

    print(x,y,filter_size)
    return (x-filter_size)<-1 or (x+filter_size) > image_shape[1] or (y-filter_size)<-1 or (y+filter_size) > image_shape[0]

def convolve(arr1, arr2):
    return np.sum(np.multiply(arr1,arr2))

def filter_image(image,filter, egde=""): # 3x3 5x5 array
    check_2D(image)

    filter_row_size, filter_col_size =filter.shape
    row_n = image.shape[0] - filter_row_size-1
    col_n = image.shape[1] - filter_col_size-1

    filtered=np.zeros((row_n, col_n) )

    for row_i in range(row_n):
        for col_i in range(col_n):
            current_arr= image[row_i:row_i+filter_row_size,col_i:col_i+filter_col_size]
            filtered[row_i][col_i]= convolve(current_arr,filter)

    return filtered

def _median(arr):
    return int(np.median(arr))

def _min(arr):
    return np.min(arr)
def _max(arr):
    return np.max(arr)

def _mean(arr):
    return np.mean(arr)

def _diff(arr):
    return _max(arr) - _min(arr)

def _filter_nonlinear(image, shape,function):

    check_2D(image)
    filter_row_size, filter_col_size =shape
    row_n = image.shape[0] - filter_row_size-1
    col_n = image.shape[1] - filter_col_size-1

    filtered=np.zeros((row_n, col_n) )

    for row_i in range(row_n):
        for col_i in range(col_n):
            current_arr= image[row_i:row_i+filter_row_size,col_i:col_i+filter_col_size]
            filtered[row_i][col_i]= function(current_arr)

    return filtered

def medfilt(image,shape):
    return _filter_nonlinear(image,shape,_median)

def minfilt(image,shape):
    return _filter_nonlinear(image,shape, _min)

def maxfilt(image,shape):
    return _filter_nonlinear(image,shape,_max)

def rangefilt(image,shape):
    return _filter_nonlinear(image,shape,_diff)

def meanfilt(image,shape):
    return _filter_nonlinear(image,shape,_mean)


#IIR Analog and Digital Butterworth HPF filter design
from scipy import signal
import numpy as np
import matplotlib.pyplot as plt
from pylab import clf
#Analog High pass butterworth filter, order =3, fc=100Hz
#b = numerator coefficients, a = denominator coefficients
#w = frequency variable, h= frequency response
b,a = signal.iirfilter(3,100,btype ='high',analog=True, ftype ='butter')
w,h = signal.freqs(b,a,1000)

fig1 = plt.figure(1)
ax = fig1.add_subplot(1,1,1)
ax.semilogx(w,20*np.log10(np.maximum(abs(h),1e-5)))
ax.set_title('Butterworth IIR Analog HPF frequency response')
ax.set_xlabel('Frequency in Hz---->')
ax.set_ylabel('Amplitude in dB----->')
#ax.axis((10,1000,-100,10))
ax.grid(which='both',axis='both')
plt.show()

#Digital High pass butterworth filter, order =3, fc=100Hz
fs =1000
sos = signal.iirfilter(3,100/fs,btype ='high',analog=False, ftype ='butter',output='sos')
w,h = signal.sosfreqz(sos,1000)

fig2 = plt.figure(2)
clf()
ax = fig2.add_subplot(1,1,1)
ax.plot(w/np.pi,20*np.log10(np.maximum(abs(h),1e-5)))
ax.set_title('Butterworth IIR Digital HPF frequency response')
ax.set_xlabel('Normalized Digital Frequency ---->')
ax.set_ylabel('Amplitude in dB----->')
#ax.axis((10,1000,-100,10))
ax.grid(which='both',axis='both')
plt.show()

#Result
##>>> b
##array([1., 0., 0., 0.])
##>>> a
##array([1.e+00, 2.e+02, 2.e+04, 1.e+06])
##>>> sos
##array([[ 0.72944072, -0.72944072,  0.        ,  1.        , -0.72654253,
##         0.        ],
##       [ 1.        , -2.        ,  1.        ,  1.        , -1.64755222,
##         0.73233892]])
##>>>


"""Is channel Hermiticity-preserving."""
from typing import List, Union

import numpy as np

from toqito.channel_ops import kraus_to_choi
from toqito.matrix_props import is_hermitian

def is_herm_preserving(
    phi: Union[np.ndarray, List[List[np.ndarray]]],
    rtol: float = 1e-05,
    atol: float = 1e-08,
) -> bool:
    r"""
    Determine whether the given channel is Hermitian-preserving [WatH18]_.

    A map :math:`\Phi \in \text{T} \left(\mathcal{X}, \mathcal{Y} \right)` is
    *Hermitian-preserving* if it holds that

    .. math::
        \Phi(H) \in \text{Herm}(\mathcal{Y})

    for every Hermitian operator :math:`H \in \text{Herm}(\mathcal{X})`.

    Examples
    ==========

    The map :math:`\Phi` defined as

    .. math::
        \Phi(X) = X - U X U^*

    is Hermitian-preserving, where

    .. math::
        U = \frac{1}{\sqrt{2}}
        \begin{pmatrix}
            1 & 1 \\
            -1 & 1
        \end{pmatrix}.

    >>> import numpy as np
    >>> from toqito.channel_props import is_herm_preserving
    >>> unitary_mat = np.array([[1, 1], [-1, 1]]) / np.sqrt(2)
    >>> kraus_ops = [[np.identity(2), np.identity(2)], [unitary_mat, -unitary_mat]]
    >>> is_herm_preserving(kraus_ops)
    True

    We may also verify whether the corresponding Choi matrix of a given map is
    Hermitian-preserving. The swap operator is the Choi matrix of the transpose map, which is
    Hermitian-preserving as can be seen as follows:

    >>> import numpy as np
    >>> from toqito.perms import swap_operator
    >>> from toqito.channel_props import is_herm_preserving
    >>> unitary_mat = np.array([[1, 1], [-1, 1]]) / np.sqrt(2)
    >>> choi_mat = swap_operator(3)
    >>> is_herm_preserving(choi_mat)
    True

    References
    ==========
    .. [WatH18] Watrous, John.
        "The theory of quantum information."
        Section: "Linear maps of square operators".
        Cambridge University Press, 2018.

    :param phi: The channel provided as either a Choi matrix or a list of Kraus operators.
    :param rtol: The relative tolerance parameter (default 1e-05).
    :param atol: The absolute tolerance parameter (default 1e-08).
    :return: True if the channel is Hermitian-preserving, and False otherwise.
    """
    # If the variable `phi` is provided as a list, we assume this is a list
    # of Kraus operators.
    if isinstance(phi, list):
        phi = kraus_to_choi(phi)

    # Phi is Hermiticity-preserving if and only if its Choi matrix is Hermitian.
    if phi.shape[0] != phi.shape[1]:
        return False
    return is_hermitian(phi, rtol=rtol, atol=atol)


# LUPPFactors.py
#
# Daniel R. Reynolds
# SMU Mathematics
# Math 4315

# imports
import numpy

def LUPPFactors(A):
    """
    usage: [L,U,P1,P2] = LUPPFactors(A)

    Row-oriented LU factorization with complete pivoting; constructs the factorization
          P1 A P2 = LU  <=>  A = P1^T L U P2^T
    This function checks that A is square, and attempts to catch the case where A
    is singular.

    Inputs:
      A - square n-by-n matrix

    Outputs:
      L  - unit-lower-triangular matrix (n-by-n)
      U  - upper-triangular matrix (n-by-n)
      P1 - permutation matrix (n-by-n)
      P2 - permutation matrix (n-by-n)
    """

    # check input
    m, n = numpy.shape(A)
    if (m != n):
        raise ValueError("LUPPFactors error: matrix must be square")

    # set singularity tolerance
    tol = 1000*numpy.finfo(float).eps

    # create output matrices
    U = A.copy()
    L = numpy.eye(n)
    P1 = numpy.eye(n)
    P2 = numpy.eye(n)
    for k in range(n-1):               # loop over pivots
      si = k                           # determine pivot position
      sj = k
      for i in range(k,n):
        for j in range(k,n):
          if (numpy.abs(U[i,j]) > numpy.abs(U[si,sj])):
            si = i
            sj = j
      if (numpy.abs(U[si,sj]) < tol):  # check for singularity
        raise ValueError("LUPPFactors error: matrix is [close to] singular")
      for j in range(k,n):             # swap rows in U
        tmp = U[k,j]
        U[k,j] = U[si,j]
        U[si,j] = tmp
      for j in range(k):               # swap rows in L
        tmp = L[k,j]
        L[k,j] = L[si,j]
        L[si,j] = tmp
      for j in range(n):               # swap rows in P1
        tmp = P1[k,j]
        P1[k,j] = P1[si,j]
        P1[si,j] = tmp
      for i in range(n):               # swap columns in U
        tmp = U[i,k]
        U[i,k] = U[i,sj]
        U[i,sj] = tmp
      for i in range(n):               # swap columns in P2
        tmp = P2[i,k]
        P2[i,k] = P2[i,sj]
        P2[i,sj] = tmp
      for i in range(k+1,n):           # loop over remaining rows
        L[i,k] = U[i,k]/U[k,k]         # compute multiplier
        for j in range(k,n):           # update remainder of matrix row
          U[i,j] -= L[i,k]*U[k,j]

    return [L, U, P1, P2]

# end function


from scipy.stats import beta

np.random.seed(42)
theta_real = 0.35
ntrials = 100
data = stats.bernoulli.rvs(p=theta_real, size=ntrials)

N = ntrials; N1 = sum(data); N0 = N-N1; # Sufficient statistics
aprior = 1; bprior = 1; # prior
apost = aprior + N1; bpost = bprior + N0 # posterior

# Interval function
alpha = 0.05
CI1 = beta.interval(1-alpha, apost, bpost)
print('{:0.2f}--{:0.2f}'.format(CI1[0], CI1[1])) # (0.06:0.52)

# Use the inverse CDF (percent point function)
l  = beta.ppf(alpha/2, apost, bpost)
u  = beta.ppf(1-alpha/2, apost, bpost)
CI2 = (l,u)
print('{:0.2f}--{:0.2f}'.format(CI2[0], CI2[1])) # (0.06:0.52)

# Use Monte Carlo sampling
samples = beta.rvs(apost, bpost, size=10000)
samples = np.sort(samples)
CI3 = np.percentile(samples, 100*np.array([alpha/2, 1-alpha/2]))
print('{:0.2f}--{:0.2f}'.format(CI3[0], CI3[1])) # (0.06:0.51)
print(np.mean(samples))


# --------------
#Header files
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

#Reading of the file
data=pd.read_csv(path)
data['Gender'].replace('-','Agender',inplace=True)
gender_count = data['Gender'].value_counts()
plt.bar(gender_count.index, gender_count)
plt.show()

alignment = data['Alignment'].value_counts()
plt.figure(figsize=(6,6))
plt.bar(alignment.index, alignment)
plt.title('Character alignment')
plt.show()

scdf = data[['Strength','Combat']].copy()
sc_covariance = scdf.cov().iloc[0,1]
sc_strength = scdf['Strength'].std()
sc_combat = scdf['Combat'].std()

icdf = data[['Intelligence','Combat']].copy()
ic_covariance = icdf.cov().iloc[0,1]
ic_intelligence = icdf['Intelligence'].std()
ic_combat = icdf['Combat'].std()

sc_pearson = round(sc_covariance/(sc_strength*sc_combat), 2)
print("Pearson's Correlation Coefficient between Strength and Combat : ",sc_pearson)

ic_pearson = round(ic_covariance/(ic_intelligence*ic_combat), 2)
print("Pearson's Correlation Coefficient between Intelligence and Combat : ", ic_pearson)

#Find out who are the best of the best in this superhero universe by finding the value of quantile =0.99 for the Total colum and subset the df whose Total is higher than this quantile.
total_high = data['Total'].quantile(q=0.99)

super_best = data[data['Total'] > total_high]
super_best_names = list(super_best['Name'])
print(super_best_names)
# Code starts here


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

def func(x):
    return -0.5 * x + 0

def error():
    return 2 * rd.uniform(-0.5, 0.5)

def noise(x_list):
    rd.seed(12)
    y_list = [func(x_i) + error() for x_i in x_list]
    return y_list

def get():
    x_list = np.linspace(-2, 2, 16)
    y_list = noise(x_list)
    return x_list, y_list

def show_noise_data(x_noise, y_noise):
    fig, ax = plt.subplots()
    ax.scatter(x_noise, y_noise)
    ax.set_title('Noise data')  # заголовок для Axes
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.grid()
    fig.set_figwidth(7)  # ширина и
    fig.set_figheight(7)  # высота "Figure"
    plt.savefig("images/Noise data.png")
    plt.show()

def mse(y_actual, y_pred):
    mse_error = 0
    for y, y_prime in zip(y_actual, y_pred):
        mse_error += (y - y_prime) ** 2
    return mse_error

def neuron(x_list, w1, w0):
    return [w1 * x + w0 for x in x_list]

def find_optimal_d(c_m, x_noise, y_noise):
    d_cur = rd.uniform(-1, 1)
    min_mse = mse(y_noise, neuron(x_noise, c_m, d_cur))
    d_min = d_cur
    for i in range(1, 1000):
        d_cur = rd.uniform(-1, 1)
        new_mse = mse(y_noise, neuron(x_noise, c_m, d_cur))
        if new_mse < min_mse:
            min_mse = new_mse
            d_min = d_cur
    return d_min

def find_optimal(x_noise, y_noise, data_=None):
    if data_ is None:
        data_ = []
    c_m = np.linspace(-1.5, 0.5, 1000)
    c_opt = c_m[0]
    d_opt = find_optimal_d(c_opt, x_noise, y_noise)
    min_mse = mse(y_noise, neuron(x_noise, c_opt, d_opt))
    data_.append([d_opt, c_opt, min_mse])
    for i in range(1, 1000):
        d_new = find_optimal_d(c_m[i], x_noise, y_noise)
        new_mse = mse(y_noise, neuron(x_noise, c_m[i], d_new))

        if new_mse < min_mse:
            d_opt = d_new
            c_opt = c_m[i]
            min_mse = new_mse
            data_.append([d_new, c_m[i], new_mse])
    return c_opt, d_opt, min_mse, data

def show_regression(x_noise, y_noise, c_opt, d_opt):
    fig, ax = plt.subplots()
    ax.scatter(x_noise, y_noise)
    ax.set_title('Found function')  # заголовок для Axes
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    fig.set_figwidth(7)  # ширина и
    fig.set_figheight(7)  # высота "Figure"
    ax.plot(x_noise, neuron(x_noise, c_opt, d_opt), color='red', linewidth=2)
    ax.grid()
    plt.legend(["regression", "data"])
    plt.savefig("images/Regression.png")
    plt.show()

if __name__ == '__main__':
    X, Y = get()
    show_noise_data(X, Y)
    data = []
    c, d, mse_min, data = find_optimal(X, Y, data)
    show_regression(X, Y, c, d)
    df = pd.DataFrame(data, columns=["w0", "w1", "error"])
    df.to_csv("results/data.csv")
    print(df)
    print("Optimal weights:")
    print(f"w0 = {d}")
    print(f"w1 = {c}")
    print(f"MSE = {mse_min}")
    print("Linear regression:")
    print(f"y = {c}x + {d}")


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

class KMean:
    ## Class Variables ##
    X = n_k = _tolerance = _max_itr = cluster = None
    centroids = []

    ## Constructors ##
    def __init__(self, n_k, tolerance=0.0001, max_itr=1000):
        self.n_k = n_k
        self._tolerance = tolerance
        self._max_itr = max_itr

    ## Methods ##
    def parse_data(self, file_path, sep):
        df = pd.read_csv(file_path, sep=sep)
        self.X = df.values

    def clusterify(self):
        for i in range(self._max_itr):
            self._init_cluster_classes()
            self._classify_points_to_cluster()

            new_centroid = self._update_centroid()

            if self._has_converged(new_centroid):
                self.centroids = new_centroid
                break
            else:
                self.centroids = new_centroid

    def _classify_points_to_cluster(self):
        if len(self.centroids) == 0:  # RANDOM init centroid
            for point in self.X:
                self.cluster[np.random.randint(0, len(self.cluster))].append(point)
        else:
            for point in self.X:
                dist = [self.euclidean_dist(point, centroid) for centroid in self.centroids]
                classified_index = dist.index(min(dist))
                self.cluster[classified_index].append(point)

    def _update_centroid(self):
        new_centroid = []

        for i, cluster in enumerate(self.cluster):
            new_centroid.append(np.average(cluster, axis=0))

        return new_centroid

    def _has_converged(self, new_centroid):
        if len(self.centroids) == 0:
            return False
        else:
            for i, centroid in enumerate(self.centroids):
                old_centroid = centroid
                curr_centroid = new_centroid[i]

                if np.sum((curr_centroid - old_centroid) / old_centroid * 100.0) > self._tolerance:
                    return False
                else:
                    return True

    def _init_cluster_classes(self):
        self.cluster = []

        for i in range(self.n_k):
            self.cluster.append([])

    def init_cluster_center(self, method="FORGY"):
        if method == "FIRST_K":
            for i in range(self.n_k):
                self.centroids.append(self.X[i])
        elif method == "FORGY":
            index_list = np.random.choice(len(self.X), self.n_k)
            for index in index_list:
                self.centroids.append(self.X[index])
        elif method == "RANDOM":
            return
        else:
            raise NotImplementedError

    @staticmethod
    def euclidean_dist(p1, p2):
        sqr_dist = 0
        for i in range(len(p1)):
            sqr_dist += (p1[i] - p2[i]) ** 2

        return np.sqrt(sqr_dist)

def main():
    k_mean = KMean(3)
    k_mean.parse_data("heightWeight.csv")
    k_mean.init_cluster_center("FORGY")
    k_mean.clusterify()

    colors = 10 * ['r', 'g', 'c', 'b', 'k']

    for i, cluster in enumerate(k_mean.cluster):
        color = colors[i]
        plt.scatter(k_mean.centroids[i][0], k_mean.centroids[i][1], s=130, color=color, marker='x')

        for points in cluster:
            plt.scatter(points[0], points[1], color=color, s=30)

    plt.show()

if __name__ == "__main__":
    main()


import numpy as np

from si.supervised.supervised_model import SupervisedModel

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

class LogisticRegression(SupervisedModel):
    # https://datascience-enthusiast.com/R/logistic_regression.html

    def __init__(self, epochs=1000, lr=0.001):
        super(LogisticRegression, self).__init__()
        self.theta = None
        self.epochs = epochs
        self.lr = lr
        self.history = None
        self.X, self.y = None, None
        self.is_fitted = False

    def fit(self, dataset):
        if not dataset.hasLabel():
            raise Exception("Data has no labels.")
        X, self.y = dataset.getXy()
        self.X = np.hstack((np.ones((X.shape[0], 1)), X))
        self.is_fitted = True
        self.train(self.X, self.y)
        return self.X, self.y

    def train(self, X, y):
        m, n = X.shape
        self.history = {}
        self.theta = np.zeros(n)
        for epoch in range(self.epochs):
            z = np.dot(X, self.theta)
            h = sigmoid(z)
            # grad = 1 / m * np.dot(X.T, (h - y))
            grad = np.dot(X.T, (h - y))
            self.theta -= self.lr * grad
            self.history[epoch] = [self.theta[:], self.cost()]
        return self.theta

    def predict(self, x):
        if not self.is_fitted:
            raise Exception("The model hasn't been fitted yet.")
        _x = np.hstack(([1], x))
        return np.round(sigmoid(np.dot(self.theta, _x)))

    def cost(self, X=None, y=None):
        if not self.is_fitted:
            raise Exception("The model hasn't been fitted yet.")

        X = np.hstack((np.ones((X.shape[0], 1)), X)) if X is not None else self.X
        y = y if y is not None else self.y

        y_pred = sigmoid(np.dot(self.theta, X.T))
        epsilon = 1e-5
        return (((-y).dot(np.log(y_pred + epsilon))) - ((1 - y).dot(np.log(1 - y_pred + epsilon)))) / y.size
        # change this

# Implement Regularização L1 / L2

class LogisticRegressionReg(LogisticRegression):
    def __init__(self, epochs=1000, lr=0.001, lbd=1):
        super().__init__(epochs, lr)
        self.lbd = lbd

    def train(self, X, y):
        m, n = X.shape
        self.history = {}
        self.theta = np.zeros(n)
        for epoch in range(self.epochs):
            z = np.dot(X, self.theta)
            h = sigmoid(z)
            grad = np.dot(X.T, (h - y))
            # grad = 1 / m * np.dot(X.T, (h - y))
            reg = self.lbd / m * np.hstack(([0], self.theta[1:]))
            self.theta -= self.lr * (grad + reg)
            self.history[epoch] = [self.theta[:], self.cost()]
        return self.theta

    def cost(self, X=None, y=None):
        if not self.is_fitted:
            raise Exception("The model hasn't been fitted yet.")
        X = np.hstack((np.ones((X.shape[0], 1)), X)) if X is not None else self.X
        y = y if y is not None else self.y

        y_pred = sigmoid(np.dot(self.theta, X.T))
        m = y.size
        epsilon = 1e-5
        reg = self.lbd / (2 * m) * np.sum(np.square(self.theta))
        return (((-y).dot(np.log(y_pred + epsilon))) - ((1 - y).dot(np.log(1 - y_pred + epsilon)))) / m + reg


import math

import numpy as np
import pytest

from skspatial.objects import Vector, Line, Plane, Circle, Sphere

@pytest.mark.parametrize(
    "point, point_line, vector_line, point_expected, dist_expected",
    [
        ([0, 5], [0, 0], [0, 1], [0, 5], 0),
        ([0, 5], [0, 0], [0, 100], [0, 5], 0),
        ([1, 5], [0, 0], [0, 100], [0, 5], 1),
        ([0, 1], [0, 0], [1, 1], [0.5, 0.5], math.sqrt(2) / 2),
        ([1, 0], [0, 0], [1, 1], [0.5, 0.5], math.sqrt(2) / 2),
        ([0, 2], [0, 0], [1, 1], [1, 1], math.sqrt(2)),
        ([-15, 5], [0, 0], [0, 100], [0, 5], 15),
        ([50, 10], [1, -5], [0, 3], [1, 10], 49),
    ],
)
def test_project_point_line(point, point_line, vector_line, point_expected, dist_expected):
    line = Line(point_line, vector_line)

    point_projected = line.project_point(point)
    distance = line.distance_point(point)

    assert point_projected.is_close(point_expected)
    assert math.isclose(distance, dist_expected)

@pytest.mark.parametrize(
    "point, point_plane, normal_plane, point_expected, dist_expected",
    [
        ([0, 0, 0], [0, 0, 0], [0, 0, 1], [0, 0, 0], 0),
        ([0, 0, 0], [0, 0, 0], [0, 0, -1], [0, 0, 0], 0),
        ([0, 0, 1], [0, 0, 0], [0, 0, 1], [0, 0, 0], 1),
        ([0, 0, 1], [0, 0, 0], [0, 0, -1], [0, 0, 0], -1),
        ([0, 0, 1], [0, 0, 0], [0, 0, 50], [0, 0, 0], 1),
        ([0, 0, 1], [0, 0, 0], [0, 0, -50], [0, 0, 0], -1),
        ([0, 0, 5], [0, 0, 0], [0, 0, 50], [0, 0, 0], 5),
        ([0, 0, 5], [0, 0, 0], [0, 0, -50], [0, 0, 0], -5),
        ([5, -4, 1], [0, 0, 0], [0, 0, 1], [5, -4, 0], 1),
    ],
)
def test_project_point_plane(point, point_plane, normal_plane, point_expected, dist_expected):
    plane = Plane(point_plane, normal_plane)

    point_projected = plane.project_point(point)
    distance_signed = plane.distance_point_signed(point)

    assert point_projected.is_close(point_expected)
    assert math.isclose(distance_signed, dist_expected)

@pytest.mark.parametrize(
    "vector_u, vector_v, vector_expected",
    [
        ([1, 1], [1, 0], [1, 0]),
        ([1, 5], [1, 0], [1, 0]),
        ([5, 5], [1, 0], [5, 0]),
        # Scaling v by a non-zero scalar doesn't change the projection.
        ([0, 1], [0, 1], [0, 1]),
        ([0, 1], [0, -5], [0, 1]),
        ([0, 1], [0, 15], [0, 1]),
        # The projection is the zero vector if u and v are perpendicular.
        ([1, 0], [0, 1], [0, 0]),
        ([5, 0], [0, 9], [0, 0]),
        # The projection of the zero vector onto v is the zero vector.
        ([0, 0], [0, 1], [0, 0]),
    ],
)
def test_project_vector(vector_u, vector_v, vector_expected):
    """Test projecting vector u onto vector v."""

    vector_u_projected = Vector(vector_v).project_vector(vector_u)

    assert vector_u_projected.is_close(vector_expected)

@pytest.mark.parametrize(
    "line, vector, vector_expected",
    [
        (Line([0, 0], [1, 0]), [1, 1], [1, 0]),
        (Line([-56, 72], [1, 0]), [1, 1], [1, 0]),
        (Line([-56, 72], [200, 0]), [5, 9], [5, 0]),
        (Line([-56, 72], [200, 0]), [-5, 9], [-5, 0]),
    ],
)
def test_project_vector_line(line, vector, vector_expected):

    vector_projected = line.project_vector(vector)
    assert vector_projected.is_close(vector_expected)

@pytest.mark.parametrize(
    "plane, vector, vector_expected",
    [
        (Plane([0, 0, 0], [0, 0, 1]), [1, 1, 0], [1, 1, 0]),
        (Plane([0, 0, 0], [0, 0, 1]), [1, 1, 1], [1, 1, 0]),
        (Plane([0, 0, 0], [0, 0, 1]), [7, -5, 20], [7, -5, 0]),
        (Plane([0, 0, 0], [0, 0, -10]), [7, -5, 20], [7, -5, 0]),
    ],
)
def test_project_vector_plane(plane, vector, vector_expected):

    vector_projected = plane.project_vector(vector)
    assert vector_projected.is_close(vector_expected)

@pytest.mark.parametrize(
    "circle, point, point_expected",
    [
        (Circle([0, 0], 1), [1, 0], [1, 0]),
        (Circle([0, 0], 1), [2, 0], [1, 0]),
        (Circle([0, 0], 1), [-2, 0], [-1, 0]),
        (Circle([0, 0], 1), [0, 2], [0, 1]),
        (Circle([0, 0], 1), [0, -2], [0, -1]),
        (Circle([0, 0], 5), [0, -2], [0, -5]),
        (Circle([0, 1], 5), [0, -2], [0, -4]),
        (Circle([0, 0], 1), [1, 1], math.sqrt(2) / 2 * np.ones(2)),
        (Circle([0, 0], 2), [1, 1], math.sqrt(2) * np.ones(2)),
    ],
)
def test_project_point_circle(circle, point, point_expected):

    point_projected = circle.project_point(point)
    assert point_projected.is_close(point_expected)

@pytest.mark.parametrize(
    "sphere, point, point_expected",
    [
        (Sphere([0, 0, 0], 1), [1, 0, 0], [1, 0, 0]),
        (Sphere([0, 0, 0], 2), [1, 0, 0], [2, 0, 0]),
        (Sphere([0, 0, 0], 0.1), [1, 0, 0], [0.1, 0, 0]),
        (Sphere([-1, 0, 0], 1), [1, 0, 0], [0, 0, 0]),
        (Sphere([0, 0, 0], 1), [1, 1, 1], math.sqrt(3) / 3 * np.ones(3)),
        (Sphere([0, 0, 0], 3), [1, 1, 1], math.sqrt(3) * np.ones(3)),
    ],
)
def test_project_point_sphere(sphere, point, point_expected):

    point_projected = sphere.project_point(point)
    assert point_projected.is_close(point_expected)

@pytest.mark.parametrize(
    "circle_or_sphere, point",
    [
        # The point to project cannot be the center of the circle/sphere.
        (Circle([0, 0], 1), [0, 0]),
        (Circle([0, 0], 5), [0, 0]),
        (Circle([7, -1], 5), [7, -1]),
        (Sphere([0, 0, 0], 1), [0, 0, 0]),
        (Sphere([0, 0, 0], 5), [0, 0, 0]),
        (Sphere([5, 2, -6], 5), [5, 2, -6]),
    ],
)
def test_project_point_circle_sphere_failure(circle_or_sphere, point):

    with pytest.raises(Exception):
        circle_or_sphere.project_point(point)


"""
Functions related to Fractal Algorithms

Public Methods :
  * get_fibonocci_number - Returns the Fibonnoci Number for the requested index
  * multibrot_algorithm - Performs a single interation of the Multibrot Formula
  * newton_method_algorithm - Performs a single iteration of the Newton Method Formula
  * evaluate_polynomial_1d - Performs a single iteration of a Polynomial Formula
"""

import numpy

_PHI = (1 + 5**0.5) / 2.0

def get_fibonocci_number(index):
    """
    Returns the Fibonocci Number for the requested index

    Parameters :
      * index - Index of the requested Fibonocci Number
          (indexes 2 and below will simply return the requested index value)
    """
    if index < 2:
        return index

    return int(round((_PHI**index - (1 - _PHI)**index) / 5**0.5))

def multibrot_algorithm(z_values, c_values, power):
    """
    Perform an iteration of the Multibrot Polynomial Formula (z = z^power + c) and return the
    resulting values

    Parameters :
      * z_values - Input z values for the Polynomial Formula
      * c_values - Input c values for the Polynomial Formula
      * power - Exponential power to use in the Polynomial Formula
    """
    z_values_new = numpy.copy(z_values)
    exponent_value = numpy.copy(z_values)
    for exponent_counter in range(0, power - 1):
        z_values_new = numpy.multiply(exponent_value, z_values_new)

    z_values_new = numpy.add(z_values_new, c_values)
    return z_values_new

def newton_method_algorithm(coefficient_array, coefficient_array_derivative, z_values, c_values):
    """
    Perform an iteration of the Newton Method Algorithm (z = z - (f(z) / f_deriv(z))) and return
    the difference in iteration values and the resulting values

    Parameters :
      * coefficient_array - An array describing a Polynomial Formula in exponential order
          (ie. [ 1, 2, 3 ] = c + 2z + 3z**2 ; [ 4, 0, 1, 0, 5 ] = 4c + z**2 + 5z**4)
      * coefficient_array_derivative - An array describing the Derivative Polynomial Formula
          of coefficient_array in exponential order
          (ie. [ 1, 2, 3 ] = c + 2z + 3z**2 ; [ 4, 0, 1, 0, 5 ] = 4c + z**2 + 5z**4)
      * z_values - Input z values for the Polynomial Formula
      * c_values - Input c values for the Polynomial Formula
    """
    coefficient_func_values = evaluate_polynomial_1d(coefficient_array, z_values, c_values)
    coefficient_deriv_func_values = evaluate_polynomial_1d(coefficient_array_derivative,
                                                           z_values, c_values)
    func_values = numpy.divide(coefficient_func_values, coefficient_deriv_func_values)

    z_values_new = numpy.add(z_values, -func_values)
    iteration_diff = numpy.add(z_values, -z_values_new)

    return [iteration_diff, z_values_new]

def evaluate_polynomial_1d(coefficient_array, z_values, c_values):
    """
    Perform an iteration of the Polynomial Formula provided and return the resulting values

    Parameters :
      * coefficient_array - An array describing a Polynomial Formula in exponential order
          (ie. [ 1, 2, 3 ] = c + 2z + 3z**2 ; [ 4, 0, 1, 0, 5 ] = 4c + z**2 + 5z**4)
      * z_values - Input z values for the Polynomial Formula
      * c_values - Input c values for the Polynomial Formula
    """
    # Calculate Polynomial Constant Expression
    constant_coefficient = coefficient_array[0]
    constant_values = c_values * constant_coefficient

    # Calculate Polynomial Exponential Expressions
    exponent_accumulator = numpy.ones(z_values.shape, dtype=z_values.dtype)
    exponent_values = numpy.empty(z_values.shape, dtype=z_values.dtype)
    z_values_new = numpy.zeros(z_values.shape, dtype=z_values.dtype)
    for exponent_counter in range(1, len(coefficient_array)):
        exponent_accumulator = numpy.multiply(exponent_accumulator, z_values)
        exponent_coefficient = coefficient_array[exponent_counter]

        exponent_values = numpy.multiply(exponent_accumulator, exponent_coefficient)
        z_values_new = numpy.add(z_values_new, exponent_values)

    # Add Constant and Exponential Expressions
    z_values_new = z_values_new + constant_values

    return z_values_new


"""Link functions related to power function."""

# author: Benjamin Cross
# email: btcross26@yahoo.com
# created: 2019-08-26

from typing import Union

import numpy as np

from .base_class import BaseLink

class PowerLink(BaseLink):
    """Implementation of power link functions."""

    def __init__(self, power: Union[float, int], summand: float = 0.0):
        """
        Initialize a power link instance - i.e., link = (y + summand) ** power.

        Extends BaseLink class intializer.

        Parameters
        ----------
        power: float or int
            Exponent of the link function.

        summand: float or int
            Summand of the link function.
        """
        super().__init__()
        self.power_ = power
        self.summand_ = summand

    def _link(self, y: np.ndarray) -> np.ndarray:
        """
        Get the link, eta, as a function of y.

        Overrides BaseLink._link.
        """
        return (y + self.summand_) ** self.power_

    def _inverse_link(self, eta: np.ndarray) -> np.ndarray:
        """
        Get the target, y, as a function of the link, `eta`.

        Overrides BaseLink._inverse_link.
        """
        return eta ** (1.0 / self.power_) - self.summand_

    def dydeta(self, y: np.ndarray) -> np.ndarray:
        """
        Get the derivative of `y` with respect to the link as a function of y.

        Overrides BaseLink.dydeta.
        """
        return (1.0 / self.power_) * (y + self.summand_) ** (1.0 - self.power_)

    def d2ydeta2(self, y: np.ndarray) -> np.ndarray:
        """
        Get the second derivative of `y` with respect to the link as a function of y.

        Overrides BaseLink.d2ydeta2.
        """
        return self.dydeta(y) * (1.0 / self.power_ - 1.0) / self._link(y)

class SqrtLink(PowerLink):
    """Square root link function implementation."""

    def __init__(self) -> None:
        """
        Class initializer.

        Extends PowerLink class intializer by specifying power=0.5 and summand=0.0.
        """
        super().__init__(power=0.5)

class CubeRootLink(PowerLink):
    """Cube root link function implementation."""

    def __init__(self) -> None:
        """
        Class initializer.

        Extends PowerLink class initializer by specifying power=1/3 and summand=0.0.
        """
        super().__init__(power=(1.0 / 3.0))

class ReciprocalLink(PowerLink):
    """Inverse link function implementation."""

    def __init__(self, summand: float = 0.0):
        """
        Class initializer.

        Extends PowerLink class initializer by specifying power=-1 and summand=0.0.
        """
        super().__init__(power=-1.0, summand=summand)


import random
import itertools
import numpy as np
from sklearn.datasets import make_blobs

class KMeans:
	def __init__(self,k):
		self.k = k
		self.means = None

	def form_clusters(self,data,indexes):
		#assigning clusters to points

		clusters = [[] for i in range(self.k)]
		means = []
		for point,index in zip(data,indexes):
			clusters[index].append(point)
		for cluster in clusters:
			if cluster:
				means.append(np.mean(cluster,axis=0).tolist())
			else:
				means.append(random.choice(data))
		return means

	def classify(self,vector):

		diff = []
		#calculating euclidean distance for each point from each center
		for mean in self.means:
			diff.append(np.linalg.norm(mean - vector))
		return np.argmin(diff)

	@property
	def centers(self):
		return self.means

	def fit(self,data):

		#random initialization of means
		cluster_index = [random.randrange(self.k) for _ in data]
		for i in itertools.count():
			#computing means and reassigning centers
			self.means = self.form_clusters(data,cluster_index)
			new_cluster_index = [self.classify(val) for val in data]

			#if difference between old centers and new centers is 0 then break the loop
			differences = 0
			for ind,new_ind in zip(cluster_index,new_cluster_index):
				if ind != new_ind:
					differences = differences + 1

			if differences == 0:
			 	return

			#calculating means for new cluster centers
			cluster_index = new_cluster_index
			self.means = self.form_clusters(data,cluster_index)

#generating random dataset
X,y= make_blobs(n_samples=150,n_features=2,centers=3)
clustering = KMeans(k=3)
clustering.fit(X)
print(clustering.centers)


### import libraries ###
import numpy as np
from mpmath import *
import matplotlib.pyplot as plt
### make MATLAB-like commands for use in Python ###
fft, fftshift, ifft = np.fft.fft, np.fft.fftshift, np.fft.ifft
abs, rndm, exp = np.abs, np.random.normal, np.exp
def sech(x) :  return 1/np.cosh(x)
np.set_printoptions(precision=3)

L,n,pi = 10,64,np.pi
t2 = np.linspace(-L,L,n+1)
t = t2[0:n]
k = (2*pi/(2*L)) * np.append(np.arange(0,n/2),np.arange(-n/2,0))

u=sech(t)
ut = fft(u)
noise = 0.5
rn = rndm(0,noise,[n]) + 1j*rndm(0,noise,[n])
utn = ut + rn
un = ifft(utn)
filter = exp(-0.2*k**2)

ks = fftshift(k)
fs = fftshift(filter)
utns = fftshift(utn)

### PLOTS ###
fig, (ax1, ax2) = plt.subplots(2)
ax1.plot(t,u, label='signal, real space')
ax1.plot(t,un, label='noisy signal, real space (transformed back)')
ax1.plot(t,filter)
ax2.plot(ks, utns/np.max(utns))
ax2.plot(ks, abs(utns)/np.max(utns))
ax2.plot(ks, fs)
plt.savefig('fftNoisySignal.png')

### NOTES ###
'''
u = sech(t) : a simple signal (hyperbolic secant)
ut :
ks : shifted frequencies for k-space plots
noise : magnitude of noise
rn : COMPLEX noise
'''

### QUESTIONS ###
'''
1) when plot in k space, what part of complex plane are we plotting?
'''


from typing import Tuple

import numpy as np

from . import modulus, inverse

def gcd_poly(poly1: np.poly1d, poly2: np.poly1d, p: int) -> np.poly1d:
    """Seek the gcd of two polynomials over Fp.

    Args:
        poly1 (np.poly1d): A polynomial.
        poly2 (np.poly1d): A polynomial.
        p (int): A prime number.

    Returns:
        np.poly1d: gcd(poly1, poly2) over Fp.
    """
    def poly2monic(poly: np.poly1d)\
            -> Tuple[np.poly1d, Tuple[np.poly1d, np.poly1d]]:
        highest_degree_coeff = poly.coeffs[0]
        if highest_degree_coeff == 1:
            return poly, (np.poly1d([1]), np.poly1d([1]))

        inv_hdc = inverse.inverse_el(highest_degree_coeff, p)
        coeffs = poly.coeffs * inv_hdc
        return np.poly1d(modulus.modulus_coeffs(coeffs, p)),\
            (np.poly1d([highest_degree_coeff]), np.poly1d([inv_hdc]))

    if len(poly1.coeffs) < len(poly2.coeffs):
        poly1, poly2 = poly2, poly1

    poly2_monic, hdc = poly2monic(poly2)
    _, r = np.polydiv(poly1 * hdc[1], poly2_monic)
    r = np.poly1d(modulus.modulus_coeffs(r.coeffs, p)) * hdc[0]
    r = modulus.modulus_poly_over_fp(r, p)

    if r.coeffs[0] == 0:
        return poly2

    return gcd_poly(poly2, r, p)


'''
    Problem 77 : Prime summations

    Desc :
        It is possible to write ten as the sum of primes in exactly five different ways:

        7 + 3
        5 + 5
        5 + 3 + 2
        3 + 3 + 2 + 2
        2 + 2 + 2 + 2 + 2

        What is the first value which can be written as the sum of primes in over five thousand different ways?
'''
import numpy as np
from numba import jit

@jit
def getPrimes(n):
    arr = np.ones(n + 1, dtype=bool)
    arr[0], arr[1] = 0, 0
    for i in range(2, n + 1):
        if arr[i]:
            arr[i * i:n + 1:i] = False
    return arr.nonzero()[0]

def compute_sum_matrix(n, primes):
    arr = np.zeros((len(primes), n + 1))
    p = primes[0]
    arr[0, p:n + 1:p] = 1

    for i in range(1, len(primes)):
        p = primes[i]
        arr[i, 0] = 1
        for j in range(1, n + 1):
            if j < p:
                arr[i, j] = arr[i - 1, j]
            else:
                arr[i, j] = arr[i - 1, j] + arr[i, j - p]

    return arr

if __name__ == "__main__":
    n = 100
    primes = getPrimes(n)
    print("Number of primes : ", len(primes))
    sum_matrix = compute_sum_matrix(n, primes)
    # print(sum_matrix)
    res = n
    for i, row in enumerate(sum_matrix):
        for j, value in enumerate(row):
            if value > 5000:
                if j < res:
                    res = j
    print(res)


import math
import numpy as np

def lb_to_kg(x):
	return .45 * x

def kg_to_lb(x):
	return x / .45

def force(m, a):
	return m * a

def rad_to_deg(rad):
	return rad * 180. / np.pi

def deg_to_rad(deg):
	return deg * np.pi / 180.

def mi_to_m(mi):
	return mi / 1609.34

def cm_to_m(m):
	return m / 100.

def radius_to_circum(r):
	return np.pi * (r**2.)

def hours_to_sec(h):
	return h * 3600.

def rev_to_rad(rev):
	return 2. * np.pi * rev

def rad_to_rev(rad):
	return rad / (2. * np.pi)

def mi_ph_to_me_ps(mi_ph):
	me_ph = mi_to_m(mi_ph)
	me_ps = me_ph * hours_to_sec(1.)
	return me_ps

def ang_vel_rad_ps_to_lin_vel_me_ps(ang_vel, wheel_diam):
	wheel_radius = wheel_diam / 2. # cm
	cm_ps = rad_to_rev(ang_vel) * radius_to_circum(wheel_radius)
	return cm_ps / 100.

def hypotenuse(x, y):
	return math.sqrt(x**2. + y**2)

def circum_ratio_to_angle_rad(ratio):
	return ratio * 2. * np.pi

def circum_ratio_to_angle_deg(ratio):
	return ratio * 360.

def arc_cm_angle_rad_to_radius_cm(arc, theta):
	return arc / theta

def chord_from_radius_cm_and_angle_rad(r, theta):
	return 2. * r * math.sin(theta/2.)

def vec_2D_to_components(vec, theta):
	return vec * math.cos(theta), vec * math.sin(theta)

def base_angles_of_isosceles_triangle_rad(theta):
	return (np.pi - theta)/2.

# target_ang_vel = me_ps
def wheel_diam_cm_to_rad_ps(d, target_ang_vel):
	me_per_rev = cm_to_m(radius_to_circum(d/2))
	rev_ps = target_ang_vel / me_per_rev
	return rev_to_rad(rev_ps)

#rotate x,y around xo,yo by theta (rad)
def rotate(x,y,xo,yo,theta):
	xr=math.cos(theta)*(x-xo)-math.sin(theta)*(y-yo)   + xo
	yr=math.sin(theta)*(x-xo)+math.cos(theta)*(y-yo)  + yo
	return [xr,yr]


# binomial distribution describes outcome of binary scenarios,
# e.g. toss of a coin, it will either be head or tails.
# it has three parameters:
# n - number of trails
# p - probability of occurrence of each trial (e.g. for toss of a coin 0.5 each).
# size - Shape of returned array.

from numpy import random
import matplotlib.pyplot as plt
import seaborn as sns

arr1 = random.binomial(n=3, p=0.5, size=10)        # n = how many times probability will use
print(arr1)                                        # p = probability of getting excepted value in returned array

sns.distplot(random.binomial(n=3, p=0.8, size=10), hist=True, kde=False)     # kde is use for line graph
plt.show()

omk = random.normal(loc=50, scale=5, size=10)
# mean = 50 with standard deviation = 5 i.e. 68% chances are there for getting number between 45 - 55
# and 95% chances are there for getting number between 40 to 60
# and 99.7% chances are there for getting number between 35 to 65
print(omk)
sns.distplot(omk, hist=False, label='normal')         # label for graph values

sut = random.binomial(n=100, p=0.5, size=10)
# Here n = 100 and probability = 0.5 i.e. 50% chance are there to get value around 100/0.5 = 50 number
print(sut)
sns.distplot(sut, hist=False, label='binomial')        # specify various label for each graph line

plt.show()

Python/Numpy/numpy 21 - binomial distribution.py


"""

"""

from numpy import mean, median, abs, sum, cumsum, histogram, sqrt
from sklearn.metrics import mean_squared_error, r2_score

def rmse(y_true, y_pred):
    """
rmse
    description:
        computes RMSE
"""
    return sqrt(mean_squared_error(y_true, y_pred))

def all_metrics(y_true, y_pred):
    """
metrics
    description:
        computes a standard set of performance metrics using true and predicted values
            * training and test set R-squared (R2)
            * training and test set root mean squared error (RMSE)
            * training and test set mean absolute error (MAE)
            * cumulative error distribution at the <1, <3, <5, and <10% levels
              for training and test set (CE135A)
"""
    # compute metrics
    abs_y_err = abs(y_pred - y_true)
    r2 = r2_score(y_true, y_pred)
    mae = mean(abs_y_err)
    mdae = median(abs_y_err)
    rmse_ = rmse(y_true, y_pred)
    y_err_percent = 100. * abs_y_err / y_true
    mre = mean(y_err_percent)
    mdre = median(y_err_percent)
    cum_err = cumsum(histogram(y_err_percent, [_ for _ in range(101)])[0])
    cum_err = 100. * cum_err / sum(cum_err)
    ce1, ce3, ce5, ceA = cum_err[0], cum_err[2], cum_err[4], cum_err[9]
    summary = {'R2': r2, 'MAE': mae, 'MDAE': mdae, 'MRE': mre, 'MDRE': mdre, 'RMSE': rmse_, 'CE135A': [ce1, ce3, ce5, ceA]}
    return summary


# Import
import numpy as np

# Global Variables

# Classes

# Functions
def multiply_ex1():
	print("--------------------------");
	print("Example 1. [2x3] x [3x2] = [2x2]")
	A = np.array([[1,2,3], [4,5,6]])
	print(A)
	print("shape: " + str(A.shape))

	B = np.array([[1,2], [3,4], [5,6]])
	print(B)
	print("shape: " + str(B.shape))

	Y = np.dot(A, B)
	print(Y)
	print("shape: " + str(Y.shape))

def multiply_ex2():
	print("--------------------------");
	print("Example 2. [3x2] x [2x1] = [3x1]")
	A = np.array([[1,2], [3,4], [5,6]])
	print(A)
	print("shape: " + str(A.shape))

	B = np.array([7,8])
	print(B)
	print("shape: " + str(B.shape))

	Y = np.dot(A, B)
	print(Y)
	print("shape: " + str(Y.shape))

def multiply_ex3():
	print("--------------------------");
	print("Example 3. [1x2] x [2x3] = [1x3]")
	A = np.array([1,2])
	print(A)
	print("shape: " + str(A.shape))

	B = np.array([[1,3,5], [2,4,6]])
	print(B)
	print("shape: " + str(B.shape))

	Y = np.dot(A, B)
	print(Y)
	print("shape: " + str(Y.shape))

def main():
	print("--------------------------");
	print("multiplication of matrices")
	multiply_ex1()
	multiply_ex2()
	multiply_ex3()

if __name__ == '__main__':
	main()


import numpy as np
import matplotlib.pyplot as plt
from .integrate import Integrate

class Riemann(Integrate):
    """
    Compute the Riemann sum of f(x) over the interval [a,b].

    Parameters
    ----------
    f : function
    A single variable function f(x), ex: lambda x:np.exp(x**2)
    """
    def __init__(self, f):
        Integrate.__init__(self, f)
        self.N = 25

    def compute_integral(self, a, b, N = 25, method='midpoint'):
        """
        Approximate the value of the integral of f(x) dx from a to b with N sub-intervals using left, right or midpoint method

        Parameters
        ----------
        a , b : any numbers
        Endpoints of the interval [a,b]

        N : integer
        Number of subintervals of equal length in the partition of [a,b]

        method : string
        Determines the kind of Riemann sum:\n
        right : Riemann sum using right endpoints\n
        left : Riemann sum using left endpoints\n
        midpoint (default) : Riemann sum using midpoints

        Returns
        -------
        float
            Approximation of the integral given by the Riemann sum.

        Examples
        --------
        >>> compute_integral(0,np.pi/2,1000), f = lambda x:1 / (1 + x**2)
        approx = 1.3731040812301096
        actual = 1.373400766945016
        """
        self.a = a
        self.b = b
        self.N = N

        dx = (self.b - self.a) / self.N
        x = np.linspace(self.a, self.b, self.N+1)

        if method == 'left':
            x_left = x[:-1] # from 0 to N-1
            return np.sum(self.f(x_left)*dx)
        elif method == 'right':
            x_right = x[1:] # from 1 to N
            return np.sum(self.f(x_right)*dx)
        elif method == 'midpoint':
            x_mid = (x[:-1] + x[1:])/2  # all N but averaged
            return np.sum(self.f(x_mid)*dx)
        else:
            raise ValueError("Method must be 'left', 'right' or 'midpoint'.")

    def plot_function(self):

        x = np.linspace(self.a, self.b, self.N+1)
        y = self.f(x)

        X = np.linspace(self.a, self.b, 5*self.N+1)
        Y = self.f(X)

        plt.figure(figsize=(15,5))

        plt.subplot(1,3,1)
        plt.plot(X,Y,'b')
        x_left = x[:-1] # Left endpoints
        y_left = y[:-1]
        plt.plot(x_left,y_left,'b.',markersize=10)
        plt.bar(x_left, y_left,width=(self.b - self.a) / self.N, alpha=0.2, align='edge', edgecolor='b')
        plt.title('Left Riemann Sum, N = {}'.format(self.N))

        plt.subplot(1,3,2)
        plt.plot(X,Y,'b')
        x_mid = (x[:-1] + x[1:])/2 # Midpoints
        y_mid = self.f(x_mid)
        plt.plot(x_mid, y_mid, 'b.', markersize=10)
        plt.bar(x_mid, y_mid,width=(self.b - self.a) / self.N, alpha=0.2, edgecolor='b')
        plt.title('Midpoint Riemann Sum, N = {}'.format(self.N))

        plt.subplot(1, 3, 3)
        plt.plot(X, Y, 'b')
        x_right = x[1:] # Right endpoints
        y_right = y[1:]
        plt.plot(x_right, y_right,'b.', markersize=10)
        plt.bar(x_right, y_right,width=-(self.b - self.a) / self.N, alpha=0.2, align='edge', edgecolor='b')
        plt.title('Right Riemann Sum, N = {}'.format(self.N))

        plt.show()


import numpy as np
import scipy

from ... import operators
#------------------------------------------
def ar_levenson_durbin(x, order,mode='same',unbias = False):
    '''
    The autoregressive model approximation,
        based on the Levenson-Dubrin itterative method
        for solution toeplitz matrix equations.

    Parameters
    -------------------
    * x: is 1-d input ndarray.
    * order: int,
        is the order of the desired model.
    * mode: string,
        mode of correlation function,
        mode = {full, same, straight}.
    * unbias: bool,
        if True, the unbiased autocorrleation
         function will be taken.

    Returns
    ---------------------
    * a: 1d ndarray,
        autoregression coefficients,
    * noise_variace: float or complex,
        variance of model residulas.

    See also
    ------------
    yule_walker,
    lsar,
    covar,
    burg.

    Examples
    -----------

    References
    --------------------
    [1a] Stoica, Petre, and Randolph L. Moses.
            "Spectral analysis of signals." (2005).
    [1b] http://www2.ece.ohio-state.edu/~randy/SAtext/
    - Dr.Moses Spectral Analysis of Signals: Resource Page
    [2a] M.H. Hayes. Statistical Digital Signal Processing
                        and Modeling, John Wiley & Sons, 1996.
    [2b] https://www.mathworks.com/matlabcentral/fileexchange/
        2183-statistical-digital-signal-processing-and-modeling
    [3]  S.L. Marple, Digital spectral analysis with applications.
                                    – New-York: Present-Hall, 1986.

    '''
    x = np.asarray(x)
    N = x.shape[0]

    r  = operators.correlation(x,y=None,mode=mode,
                        take_mean=False,unbias=unbias)

    a = np.zeros((order,), x.dtype)
    var  = r[0] - (r[1] *np.conj(r[1]))/r[0]
    a[0] = -r[1] / r[0]

    for i in np.arange(1,order):
        k   = -(r[i+1] + np.sum(a[:i]*r[i:0:-1]))/var #r[i:0:-1]=np.flipud(r[1:i+1])
        var = var*(1-(k *np.conj(k)))

        # same as a[:i+1] = [a,0] + k[a~,1] in Stoic
        a[:i] = a[:i] + k*np.conj(a[i-1::-1])
        a[i]  = k

    # here is sign "-" is already taken
    a = np.append(1,a)

    return a, var


# Load dash components
import dash
import dash_html_components as html
import dash_core_components as dcc
import dash_daq as daq
from dash.dependencies import Input, Output

# Loading numpy and pandas libraries
import numpy as np
import pandas as pd

# Model deployment
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA

# Data Visualization with plotly
import plotly.graph_objs as go
import plotly.figure_factory as ff

# Read data
df = pd.read_csv('heart.csv')
# Separating out the features
features = ['age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg', 'thalach', 'exang', 'oldpeak', 'slope', 'ca', 'thal']
# Get the correlation heatmap
corr = df.drop(["target"], axis = 1).corr()
heatmap_corr = np.array(corr.values)
corr_text = np.around(heatmap_corr, decimals=2)
heatmap_labels = list(corr.columns.values)
# Separating out the data without label(target)
x = df.loc[:, features].values
# Separating out the label(target)
y = df.loc[:,['target']].values
# Standardizing the features
x = StandardScaler().fit_transform(x)

# PCA model building
pca = PCA(random_state=222)
principalComponents = pca.fit_transform(x)
principalDf = pd.DataFrame(data = principalComponents
             , columns = ['principal component 1',
                          'principal component 2',
                          'principal component 3',
                          'principal component 4',
                          'principal component 5',
                          'principal component 6',
                          'principal component 7',
                          'principal component 8',
                          'principal component 9',
                          'principal component 10',
                          'principal component 11',
                          'principal component 12',
                          'principal component 13',
                          ])

# The final model which will be used in next plottngs
finalDf = pd.concat([principalDf, df[['target']]], axis = 1)

# Keep eigan values for cumulative explained variance plot
eig_vals = pca.explained_variance_ratio_

# Used Functions
def pca_components_scatter_plot(dim_value):
	'''
	Plot the appropriate scatter plot depends on input value

	Parameters:
	dim_value (int): If 2 then plto will be 2 dimensional and will contain first 2 components of pca
					 and if 3 then first 3 components of pca

	Returns:
	figure(graph_obj) 2 or 3 dimensional scatter plot
	'''

	if dim_value == 3:
		data = []
		for i in [0, 1]:
		    trace = go.Scatter3d(x = finalDf[finalDf["target"] == i].iloc[:, 0],
		                         y = finalDf[finalDf["target"] == i].iloc[:, 1],
		                         z = finalDf[finalDf["target"] == i].iloc[:, 2],
		                         mode = 'markers',
		                         name = "class_{}".format(i),
		                         marker = dict(size = 3))
		    data.append(trace)
		    layout=dict(
		        title='Scatter plot between principal components',
		        xaxis=dict(
		            title='Principal component 1'
		        ),
		        yaxis=dict(
		            title='Principal component 2'
		        ),
		        zaxis=dict(
		            title='Principal component 3'
		        )
		    )

		figure = dict(data=data, layout=layout)
	else:
		data = []
		for i in [0, 1]:
		    trace = go.Scatter(x = finalDf[finalDf["target"] == i].iloc[:, 0],
		                         y = finalDf[finalDf["target"] == i].iloc[:, 1],
		                         mode = 'markers',
		                         name = "class_{}".format(i),
		                         marker = dict(size = 7))
		    data.append(trace)
		    layout=dict(
		        title='Scatter plot between principal components',
		        xaxis=dict(
		            title='Principal component 1'
		        ),
		        yaxis=dict(
		            title='Principal component 2'
		        )
		    )

		figure = dict(data=data, layout=layout)

	return figure

def cumulative_explained_variance_plot(eig_vals = eig_vals):
	# Plot the cumulative explained variance of pca components

	# Parameters:
	# eig_vals (array): eigan values of pca components (eigan vectors)

	# Returns:
	# figure(graph_obj): histogram and line graph on one plot

    tot = sum(eig_vals)
    var_exp = [(i / tot)*100 for i in sorted(eig_vals, reverse=True)]
    cum_var_exp = np.cumsum(var_exp)

    trace1 = dict(
        type='bar',
        x=['PC %s' %i for i in range(1,14)],
        y=var_exp,
        name='Individual'
    )

    trace2 = dict(
        type='scatter',
        x=['PC %s' %i for i in range(1,14)],
        y=cum_var_exp,
        name='Cumulative'
    )

    data = [trace1, trace2]

    layout=dict(
        title='Explained variance by different principal components',
        yaxis=dict(
            title='Explained variance in percent'
        ),
    )

    figure = dict(data=data, layout=layout)
    return figure

def corr_heatmap_plot():
	# Plot the correlation matrix between initial variables

	# Returns:
	# figure(graph_obj): plotly heatmap

	fig = ff.create_annotated_heatmap(heatmap_corr, x=heatmap_labels, y=heatmap_labels, annotation_text=corr_text, hoverinfo='z')

	for i in range(len(fig.layout.annotations)):
	    fig.layout.annotations[i].font.size = 8

	return fig

# Dash app declaration
app = dash.Dash()
app.css.append_css({'external_url': 'https://codepen.io/chriddyp/pen/bWLwgP.css'})

heatmap_plot = corr_heatmap_plot()
scatter_plot = pca_components_scatter_plot(dim_value = 2)
explained_variance_plot = cumulative_explained_variance_plot(eig_vals = eig_vals)

app.layout = html.Div([
	html.H1(
        children='Heart Disease Dataset Analysys',
        style={
            'textAlign': 'center'
        }
    ),

	html.Div([
			html.Div([dcc.Markdown('''
							This dataset gives a number of variables along with a target condition of having or not having heart disease.

							The features are the following:

							age: The person's age in years
							sex: The person's sex (1 = male, 0 = female)
							cp: The chest pain experienced
								Value 1: typical angina,
								Value 2: atypical angina,
								Value 3: non-anginal pain,
								Value 4: asymptomatic
							trestbps: The person's resting blood pressure ,mm Hg on admission to the hospital
							chol: The person's cholesterol measurement in mg/dl
							fbs: The person's fasting blood sugar (> 120 mg/dl, 1 = true; 0 = false)
							restecg: Resting electrocardiographic measurement
								0 = normal,
								1 = having ST-T wave abnormality,
								2 = showing probable or definite left ventricular hypertrophy by Estes'
							thalach: The person's maximum heart rate achieved
							exang: Exercise induced angina (1 = yes; 0 = no)
							oldpeak: ST depression induced by exercise relative to rest
							slope: the slope of the peak exercise ST segment
								Value 1: upsloping,
								Value 2: flat,
								Value 3: downsloping
							ca: The number of major vessels (0-3)
							thal: A blood disorder called thalassemia
								3 = normal,
								6 = fixed defect
								7 = reversable defect
							target: Heart disease (0 = no, 1 = yes)
				''')], className = "row"),

			html.Div([dcc.Markdown('''
							The task of this project is to use some techniques such as
							visualizing correlation and pca analysis to find some basic knowledge about dataset.
							So first we will plot correlation heatmap to see linear correlation between features.
							Then by using pca analysis, visualize dependency between 2 or 3 (depending on toggle switch ) principal components.

							''')], className = "row"),

			html.Div([dcc.Graph(id='heatmap_plot_id', figure = heatmap_plot)], className = "row"),
			html.Div([
				    daq.ToggleSwitch(
				    	id='graph-switch',
					    label='Switch 2D or 3D',
					    labelPosition='bottom'
					)
				], className = "ten columns"),
			html.Div([dcc.Graph(id='explained_variance_plot_id', figure = explained_variance_plot)], className = "five columns"),
			html.Div([dcc.Graph(id='scatter_plot_id', figure = scatter_plot)], className = "five columns"),

			html.H3(
			        children='Conclusion',
			        style={
			            'textAlign': 'center'
			        }, className = "ten columns"
			    ),
			html.Div([dcc.Markdown('''
								According to above plotted graphs we can make some decisions about data set.
							At first let's look at the correlation between the features.
							Actually there is no perfect (strong) linear relationship between them but comparing with others,
							some of them have in some sence good correlation , for example the following features have
							negative correlation lesser than -0.3 (as a threshold I chose -0.3)
							"age" and "thalach": -0.4,
							"exang" and "cp: -.39
							"thalach" and "oldpeack": -0.34
							"thalach" and "exang": -0.38

							Also let;s notice that some of them have positive correlation greather than 0.3
							"thalach" and "slope" have positive correlation: 0.39
							"thalach" and "cp": 0.31

							The rest of them have correlation lesser (in case of positive correlation) and greather (in case of negative correlation)
							than +- 0.3.

							And the second point that I would like to take into consideration is principal components visualization.
							As the result of non perfect correlation between initial features, only first component has a significant explained variance which is 21.23 %,
							all the other 12 components have from 11.8 to 2.8 explained variance. PCA helps us to notice that in some sense there is a
							possibility to cluster our data into 2 parts.

				 ''')], className = "twenty columns"),
		], className = "row")

	], style={
			'width': '90%',
            # 'flex-flow': 'row wrap',
            'padding': '5px',
           })
@app.callback(
    Output(component_id='scatter_plot_id', component_property='figure'),
    [Input(component_id='graph-switch', component_property='value')]
)
def update_text_output(value_):
	if value_:
		return pca_components_scatter_plot(3)
	return pca_components_scatter_plot(2)

if __name__ == '__main__':
    app.run_server(debug=True, host='0.0.0.0', port='8080')


"""
Newton (Polynomial Interpolation)
"""

import numpy as np

def newton(X, Y):
    """
    Polynomial Interpolation using Newton's method

    Parameters
    ------------
        X : list
            list of x values
        Y : list
            list of y values
    Returns
    -------
        function
            function of polynomial interpolation (using  newton's method)
    """
    n = len(X)
    K = np.zeros((n, n))
    K[:, 0] = Y

    for k in range(1, n):
        K[k:, k] = [(K[i, k - 1] - K[i - 1, k - 1]) / (X[i] - X[i - k]) for i in range(k, K.shape[0])]
    D = np.ndarray.tolist(np.diag(K))

    def f(x):
        A = np.ones((n))
        A[1: n] = [(x - X[k]) for k in range(n - 1)]
        return sum(D[i] * np.prod(A[: i + 1]) for i in range(n))

    return f


"""
This example produces a sequence of samples for the uniform distribution
U([0,1]) using a linear congruential generator (LCG). A description of
the method can be found at
https://en.wikipedia.org/wiki/Linear_congruential_generator.
"""
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
from matplotlib.ticker import MaxNLocator

rc('font', **{'size':12, 'family':'serif', 'serif':['Computer Modern Roman']})
rc('text', usetex=True)

# Parameters for LCG https://en.wikipedia.org/wiki/Linear_congruential_generator
X_0 = 0
M = np.power(2, 32)
A = 1664525
C = 1013904223

NUM_DRAWS = 1000000
NUM_BINS = 100

PATH = 'uniform_samples.pdf'

def compute_uniform_samples():
	"""
	Random numbers are computed according to the formula X_{n+1} = (A*X_{N} + C) mod M.
	Uniform Samples U_{i} are then computed as U_{i} = X_{i} / M for i = [1, NUM_DRAWS]
	"""
	X_values = np.zeros(NUM_DRAWS)
	X_values[0] = X_0

	for i in range(0, (NUM_DRAWS-1)):
		X_values[i+1] = (A*X_values[i] + C) % M

	return (X_values/M)

def visualization(samples):
	"""
	Plotting the draws in form of a histogram clusterd in NUM_BINS bins and saving figure.
	"""
	n, bins, patches = plt.hist(samples, NUM_BINS, color='white', histtype='bar', ec='black')

	ax = plt.gca()
	ax.set_xlim([0,1])

	ax.yaxis.set_major_locator(MaxNLocator(integer=True, prune='lower'))

	plt.xlabel(r'Drawn values')
	plt.ylabel(r'Frequency')

	plt.savefig(PATH, bbox_inches='tight')
	plt.show()

def main():
	samples = compute_uniform_samples()
	visualization(samples)

if __name__ == "__main__":
	main()


"""
 __  __             _          ____           _
|  \/  | ___  _ __ | |_ ___   / ___|__ _ _ __| | ___
| |\/| |/ _ \| '_ \| __/ _ \ | |   / _` | '__| |/ _ \
| |  | | (_) | | | | ||  __/ | |__| (_| | |  | | (_) |
|_|  |_|\___/|_| |_|\__\___|  \____\__,_|_|  |_|\___/

@author: Jonathan Wang
@coding: utf-8
@environment: Manjaro 18.1.5 Juhraya
@date: 15th Jan., 2020

"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.patches import Circle

n = 100000
r = 1.0
a, b = 0.0, 0.0

y_max, y_min, x_max, x_min = b + r, b - r, a + r, a - r

x = np.random.uniform(x_min, x_max, n)
y = np.random.uniform(y_min, y_max, n)

distance = np.sqrt((x - a)**2 + (y - b)**2)
cnt = np.sum(np.where(distance <= r, 1, 0))

pi = 4 * cnt / n
print("Pi = ", pi)

fig = plt.figure(figsize=(12, 12))
ax = fig.add_subplot(1, 1, 1)
plt.scatter(x, y, marker='.', s=10, alpha=0.5)
circle = Circle(xy=(a, b), radius=r, alpha=0.5, color='green')
ax.add_patch(circle)
ax.grid(color='k', linestyle='--', alpha=0.2, linewidth=2)

plt.show()


# Marsaglia and Bray method
import matplotlib.pyplot as plt #pip install matplotlib
import numpy as np #pip install numpy
import random
import math
import statistics
import time

#each of this corresponds to a list where nxy_z is z values of N(x,y) distribution
n01_100=[]
n01_10000=[]
n05_100=[]
n05_10000=[]
n55_100=[]
n55_10000=[]
def find_values_N01(): #this function uses the Marsaglia and Bray algorithm and generates 100 and 10000 values of N(0,1)
    count_acc=0
    count_rej=0
    while(1):
        u1=random.uniform(0,1)
        u2=random.uniform(0,1)
        u1=2*u1-1
        u2=2*u2-1
        x=u1**2+u2**2
        if(x>1):
            count_rej=count_rej+1
            continue
        else:
            count_acc=count_acc+1
            y=math.sqrt(-2*math.log(x)/x)
            z1=u1*y
            z2=u2*y
            if(count_acc%2==0):
                n01_100.append(z1)
            else:
                n01_100.append(z2)
            if(count_acc==100):
                break
    print('For 100 values the rejected proportion is ',count_rej/(count_rej+count_acc))
    count_acc=0
    count_rej=0
    while(1):
        u1=random.uniform(0,1)
        u2=random.uniform(0,1)
        u1=2*u1-1
        u2=2*u2-1
        x=u1**2+u2**2
        if(x>1):
            count_rej=count_rej+1
            continue
        else:
            count_acc=count_acc+1
            y=math.sqrt(-2*math.log(x)/x)
            z1=u1*y
            z2=u2*y
            if(count_acc%2==0):
                n01_10000.append(z1)
            else:
                n01_10000.append(z2)
            if(count_acc==10000):
                break
    print('For 10000 values the rejected proportion is ',count_rej/(count_rej+count_acc))
    print('The value of 1-pi/4 is ',1-(math.pi/4))
    print('\n')

def q1a_sample_meanvar(): #this function calculates and prints the sample mean and variance
    print('For 100 values')
    print('Sample mean=',statistics.mean(n01_100))
    print('Sample variance= {}\n'.format(statistics.variance(n01_100)))
    print('For 10000 values')
    print('Sample mean=',statistics.mean(n01_10000))
    print('Sample variance=',statistics.variance(n01_10000))

def q1b_plot_freqvsval(l): #this function prints the freq vs x histograms for N(0,1)
    l.sort()
    plt.title('Frequency vs sample values for N(0,1) for {} values'.format(len(l)))
    plt.xlabel('Sample values')
    plt.ylabel('Frequency')
    plt.hist(l,bins=50,rwidth=0.8)
    plt.show()

def q1c_find_n05_and_n55(): #this function finds the values of N(0,5) and N(5,5)
    for i in range(0,100):
        n05_100.append(n01_100[i]*math.sqrt(5))
        n55_100.append(n01_100[i]*math.sqrt(5)+5)
    for i in range(0,10000):
        n05_10000.append(n01_10000[i]*math.sqrt(5))
        n55_10000.append(n01_10000[i]*math.sqrt(5)+5)

def return_pdf_normal(x,neu,sigmasq,bw,lenl): #f(x)=(1/(sigma*sqrt(2*pi))*e^(-1/2*((x-neu)/sigma)^2))
    fx=[]
    for i in range(0,len(x)):
        power_term=-(((x[i]-neu)**2)/sigmasq)/2
        num=math.exp(power_term)
        den=math.sqrt(2*math.pi*sigmasq)
        fx.append(num*bw*lenl/den)
    return fx

def plotandcompare(l,typ): #this function plots the N(0,5) and N(5,5) and compares with the drawn histograms
    l.sort()
    distri=''
    _,bins,_=plt.hist(l,bins=50,rwidth=0.8,label='Observed')
    bw=bins[1]-bins[0]
    x=np.arange(bins[0]-0.5,bins[-1]+0.5,0.1)
    if(typ==0):
        distri='N(0,5)'
        y=return_pdf_normal(x,0,5,len(l),bw)
    else:
        distri='N(5,5)'
        y=return_pdf_normal(x,5,5,len(l),bw)
    plt.plot(x,y,label='Expected-'+distri)
    plt.title('Observed and Expected values for {} vs Sample values'.format(distri))
    plt.xlabel('Sample values')
    plt.ylabel('Frequency')
    plt.legend()
    plt.show()

start=time.time() #start keeping a track of time

print('Marsaglia and Bray method')
#call all functions
find_values_N01()
q1a_sample_meanvar()
q1b_plot_freqvsval(n01_100)
q1b_plot_freqvsval(n01_10000)
q1c_find_n05_and_n55()
plotandcompare(n05_100,0)
plotandcompare(n05_10000,0)
plotandcompare(n55_100,5)
plotandcompare(n55_10000,5)

end=time.time() #end keeping track of time
print(f"Runtime of the program is {end - start}") #print the overall runtime

Semester 5/MA 323 (Monte Carlo)/Lab Submissions/Lab 5/Marsaglia_and_Bray_ABSatyaprakash_180123062.py