import numpy as np
from sklearn.linear_model import Lasso, Ridge, ElasticNet, LinearRegression

def mean_return_historic(r: np.array):
    '''
    Computes mean historical expected returns

    r: t x n np.array of returns

    out: 1 x n np.array of expected returns
    '''
    comp = np.prod(1 + r, axis = 0)
    nPer = r.shape[0]
    annr = comp ** (252 / nPer) - 1
    return annr

def ema_return_historic(r, window=22):
    '''
    Computes exponentially weighted historical returns

    r: t x n pd.DataFrame of returns
    window: window for calculating exponential moving average

    out: 1 x n np.array of expected returns
    '''
    ema = np.mean((1 + _ewma_vectorized_2d(r, window = window, axis = 1)) ,axis=0)
    annr = ema ** 252 - 1
    return annr

def sample_cov(r):
    '''
    Sample empirical covariance estimator

    r: t x n pd.DataFrame of returns

    out: n x n np.array of covariances
    '''
    return np.cov(r, rowvar=False) * 252

def elton_gruber_cov(r):
    '''
    Constant correlation model of Elton and Gruber

    r: t x n pd.DataFrame of returns

    out: n x n np.array of covariances
    '''
    rho = np.corrcoef(r, rowvar= False)
    n_ = rho.shape[0]

    rho_bar = (rho.sum() - n_) / (n_ * (n_ - 1))
    ccor = np.full_like(rho, rho_bar)
    np.fill_diagonal(ccor, 1.)
    sig = r.std()
    ccov = ccor * np.outer(sig, sig)
    return ccov

def shrinkage_cov(r, delta=0.5, prior_model=elton_gruber_cov, *args, **kwargs):
    '''
    Shrinks the sample covariance towards a specified model such as Elton/Gruber

    r: n x 1 returns
    delta: shrinkage parameter [0,1] #0.5 is standard
    prior_model: prior_model function that we shrink towards

    out: n x n shrunk covariance matrix
    '''

    prior = prior_model(r, *args, **kwargs)
    sig_hat = sample_cov(r)

    # https://jpm.pm-research.com/content/30/4/110
    honey = delta * prior + (1 - delta) * sig_hat
    return honey

def linear_factor_model(Y, X, kernel = None, regularize = None):
    t_, n_ = Y.shape

    #setting weights
    if kernel is None:
        kernel = np.ones(t_) / t_

    m_Y = kernel @ Y
    m_X = kernel @ X

    Y_p = ((Y - m_Y).T * np.sqrt(kernel)).T
    X_p = ((X - m_X).T * np.sqrt(kernel)).T

    #model fit
    if regularize == 'L1':
        mod = Lasso(alpha = 0.01/(2.*t_), fit_intercept = True)
    if regularize == 'L2':
        mod = Ridge(alpha = 0.01/(2.*t_), fit_intercept = True)
    if regularize == 'net':
        mod = ElasticNet(alpha = 0.01/(2.*t_), fit_intercept = True)
    else:
        mod = LinearRegression()

    mod.fit(X_p, Y_p)

    alpha = mod.intercept_
    beta = mod.coef_
    residuals = np.subtract(Y - alpha, X @ np.atleast_2d(beta.T))

    return alpha, beta, residuals

def _ewma_vectorized(data, alpha, offset=None, dtype=None, order='C', out=None):
    """
    Calculates the exponential moving average over a vector.
    Will fail for large inputs.
    :param data: Input data
    :param alpha: scalar float in range (0,1)
        The alpha parameter for the moving average.
    :param offset: optional
        The offset for the moving average, scalar. Defaults to data[0].
    :param dtype: optional
        Data type used for calculations. Defaults to float64 unless
        data.dtype is float32, then it will use float32.
    :param order: {'C', 'F', 'A'}, optional
        Order to use when flattening the data. Defaults to 'C'.
    :param out: ndarray, or None, optional
        A location into which the result is stored. If provided, it must have
        the same shape as the input. If not provided or `None`,
        a freshly-allocated array is returned.
    """
    data = np.array(data, copy=False)

    if dtype is None:
        if data.dtype == np.float32:
            dtype = np.float32
        else:
            dtype = np.float64
    else:
        dtype = np.dtype(dtype)

    if data.ndim > 1:
        # flatten input
        data = data.reshape(-1, order)

    if out is None:
        out = np.empty_like(data, dtype=dtype)
    else:
        assert out.shape == data.shape
        assert out.dtype == dtype

    if data.size < 1:
        # empty input, return empty array
        return out

    if offset is None:
        offset = data[0]

    alpha = np.array(alpha, copy=False).astype(dtype, copy=False)

    # scaling_factors -> 0 as len(data) gets large
    # this leads to divide-by-zeros below
    scaling_factors = np.power(1. - alpha, np.arange(data.size + 1, dtype=dtype),
                               dtype=dtype)
    # create cumulative sum array
    np.multiply(data, (alpha * scaling_factors[-2]) / scaling_factors[:-1],
                dtype=dtype, out=out)
    np.cumsum(out, dtype=dtype, out=out)

    # cumsums / scaling
    out /= scaling_factors[-2::-1]

    if offset != 0:
        offset = np.array(offset, copy=False).astype(dtype, copy=False)
        # add offsets
        out += offset * scaling_factors[1:]

    return out

def _ewma_vectorized_2d(data, window, axis=None, offset=None, dtype=None, order='C', out=None):
    """
    Calculates the exponential moving average over a given axis.
    Credit to Jake Walden: https://stackoverflow.com/questions/42869495/
    :param data: Input data, must be 1D or 2D array.
    :param alpha: scalar float in range (0,1)
        The alpha parameter for the moving average.
    :param axis: The axis to apply the moving average on.
        If axis==None, the data is flattened.
    :param offset: optional
        The offset for the moving average. Must be scalar or a
        vector with one element for each row of data. If set to None,
        defaults to the first value of each row.
    :param dtype: optional
        Data type used for calculations. Defaults to float64 unless
        data.dtype is float32, then it will use float32.
    :param order: {'C', 'F', 'A'}, optional
        Order to use when flattening the data. Ignored if axis is not None.
    :param out: ndarray, or None, optional
        A location into which the result is stored. If provided, it must have
        the same shape as the desired output. If not provided or `None`,
        a freshly-allocated array is returned.
    """
    data = np.array(data, copy=False)

    assert data.ndim <= 2

    #calculate the window
    sum_proportion = 0.99 #proportion of the window to be summed upon
    alpha = 1 - np.exp(np.log(1 - sum_proportion) / window)

    if dtype is None:
        if data.dtype == np.float32:
            dtype = np.float32
        else:
            dtype = np.float64
    else:
        dtype = np.dtype(dtype)

    if out is None:
        out = np.empty_like(data, dtype=dtype)
    else:
        assert out.shape == data.shape
        assert out.dtype == dtype

    if data.size < 1:
        # empty input, return empty array
        return out

    if axis is None or data.ndim < 2:
        # use 1D version
        if isinstance(offset, np.ndarray):
            offset = offset[0]
        return _ewma_vectorized(data, alpha, offset, dtype=dtype, order=order,
                               out=out)

    assert -data.ndim <= axis < data.ndim

    # create reshaped data views
    out_view = out
    if axis < 0:
        axis = data.ndim - int(axis)

    if axis == 0:
        # transpose data views so columns are treated as rows
        data = data.T
        out_view = out_view.T

    if offset is None:
        # use the first element of each row as the offset
        offset = np.copy(data[:, 0])
    elif np.size(offset) == 1:
        offset = np.reshape(offset, (1,))

    alpha = np.array(alpha, copy=False).astype(dtype, copy=False)

    # calculate the moving average
    row_size = data.shape[1]
    row_n = data.shape[0]
    scaling_factors = np.power(1. - alpha, np.arange(row_size + 1, dtype=dtype),
                               dtype=dtype)
    # create a scaled cumulative sum array
    np.multiply(
        data,
        np.multiply(alpha * scaling_factors[-2], np.ones((row_n, 1), dtype=dtype),
                    dtype=dtype)
        / scaling_factors[np.newaxis, :-1],
        dtype=dtype, out=out_view
    )
    np.cumsum(out_view, axis=1, dtype=dtype, out=out_view)
    out_view /= scaling_factors[np.newaxis, -2::-1]

    if not (np.size(offset) == 1 and offset == 0):
        offset = offset.astype(dtype, copy=False)
        # add the offsets to the scaled cumulative sums
        out_view += offset[:, np.newaxis] * scaling_factors[np.newaxis, 1:]

    return out


"""
A Pythagorean triplet is a set of three natural numbers, a < b < c, for which,

a2 + b2 = c2
For example, 32 + 42 = 9 + 16 = 25 = 52.

There exists exactly one Pythagorean triplet for which a + b + c = 1000.
Find the product abc.
"""

import numpy

def find_triplet(rangenum: int, thousand: int):
    """
    get summary
    >>> find_triplet(500, 1000)
    31875000
    """
    for a in range(1, rangenum):
        for b in range(1, rangenum):
            c = numpy.sqrt(a ** 2 + b ** 2)

            if a + b + c == thousand:
                return int(a * b * c)

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


r"""
Solve Poisson equation in 1D with homogeneous Neumann bcs

    \nabla^2 u = f

Use Shen's Neumann basis

The equation to solve is

     (\nabla^2 u, v) = (f, v)

"""
import sys
import os
import importlib
from sympy import symbols, sin, cos, pi, chebyshevt
import numpy as np
from shenfun import inner, div, grad, TestFunction, TrialFunction, FunctionSpace, \
    Array, Function, legendre, chebyshev, extract_bc_matrices, la, SpectralMatrix

# Collect basis from either Chebyshev or Legendre submodules
assert len(sys.argv) == 3, "Call with two command-line arguments"
assert sys.argv[-1].lower() in ('legendre', 'chebyshev')
assert isinstance(int(sys.argv[-2]), int)
family = sys.argv[-1].lower()

# Use sympy to compute a rhs, given an analytical solution
x = symbols("x", real=True)
alpha = 0
ue = sin(pi*x)*(1-x**2)
fe = -ue.diff(x, 2)+alpha*ue

# Size of discretization
N = int(sys.argv[-2])

# alpha=0 requires a fixed gauge, but not alpha!=0 -> mean
SD = FunctionSpace(N, family=family, bc={'left': ('N', 0), 'right': ('N', 0)},
                   mean=0 if alpha==0 else None, basis='ShenNeumann')
u = TrialFunction(SD)
v = TestFunction(SD)

# Get f on quad points
fj = Array(SD, buffer=fe)

# Compute right hand side of Poisson equation
f_hat = inner(v, fj)

# Get left hand side of Poisson equation
A0 = inner(v, div(grad(u)))
B0 = inner(v, u)

# Solve
u_hat = Function(SD)
M = alpha*B0-A0
sol = la.Solve(M, SD)
u_hat = sol(f_hat, u_hat)

# Transform to real space
uj = u_hat.backward()

# Compare with analytical solution
ua = Array(SD, buffer=ue)
print(abs(uj-ua).max())
assert np.allclose(uj, ua)

if 'pytest' not in os.environ:
    import matplotlib.pyplot as plt
    plt.figure()
    X = SD.mesh()
    plt.plot(X, uj)

    plt.figure()
    plt.plot(X, ua)

    plt.figure()
    plt.plot(X, ua-uj)
    plt.title('Error')
    #plt.show()


# -*- coding: utf-8 -*-
"""
Spyder Editor

This is a temporary script file.
"""
import time as tm
import math as ma
#import random as rd
import numpy as np
import matplotlib.pyplot as mp
import funfit as f1

xnum=10
t0=np.linspace(0,1,1000)
x=np.random.random(xnum)
y=np.zeros(xnum,)

for ind in range(0,xnum,):
    y[ind]=ma.sin(x[ind]*ma.pi*2)

mp.plot(x,y,'b*')

#==============================================================================
# Fitting with y=w0+w1*x
#==============================================================================
w0=0
w1=0
lb=.1

for iter in range(1,10000):
    yfit=f1.gs1order(w0,w1,x)
    cf1=f1.cf(y,yfit)
#    print '# Iter',str(iter),': ',str(cf1)

    w0=w0-lb*np.sum(yfit-y)
    w1=w1-lb*np.sum((yfit-y)*x)

t1=w0+w1*t0
mp.plot(x,y,'rx')
mp.plot(t0,t1)

#==============================================================================
# Fitting with y=w0+w1*x+w2*x^2
#==============================================================================
w0=0
w1=0
w2=0
lb=.1

for iter in range(1,5000):
    yfit=f1.gs2order(w0,w1,w2,x)
    cf2=f1.cf(y,yfit)
#    print '# Iter',str(iter),': ',str(cf2)

    w0=w0-lb*np.sum(yfit-y)
    w1=w1-lb*np.sum((yfit-y)*x)
    w2=w2-lb*np.sum((yfit-y)*x**2)

t2=w0+w1*t0+w2*t0**2
mp.plot(x,y,'rx')
mp.plot(t0,t2)

#==============================================================================
# Fitting with 5 degree polynomial
#==============================================================================
w0=0
w1=0
w2=0
w3=0
w4=0
w5=0
lb=.1

for iter in range(1,10000):
    yfit=f1.gs5order(w0,w1,w2,w3,w4,w5,x)
    cf5=f1.cf(y,yfit)
#    print '# Iter',str(iter),': ',str(cf5)

    w0=w0-lb*np.sum(yfit-y)
    w1=w1-lb*np.sum((yfit-y)*x)
    w2=w2-lb*np.sum((yfit-y)*x**2)
    w3=w3-lb*np.sum((yfit-y)*x**3)
    w4=w4-lb*np.sum((yfit-y)*x**4)
    w5=w5-lb*np.sum((yfit-y)*x**5)

t5=f1.gs5order(w0,w1,w2,w3,w4,w5,t0)
mp.plot(x,y,'rx')
mp.plot(t0,t5)

#==============================================================================
# Fitting with n degree polynomial
#==============================================================================
n=5
w=np.zeros([1,n+1])
lb=.05
xext=f1.gsnxext(x,n)
cfprev=f1.cf(y,f1.gsnorder(w.T,n,x))
gdsucc=1

start=tm.clock()
for iter in range(1,90000):
    yfit=f1.gsnorder(w.T,n,x)
    cf=f1.cf(y,yfit)

    if (cf-cfprev)<1e-2:
#        print '# Iter',str(iter),': ',str(cf)
        w=w-lb*np.dot((yfit-y),xext)
        cfprev=cf
    else:
        print 'Parameter is too large! Please choose a smaller one.'
        gdsucc=0
        break

end=tm.clock()

if gdsucc==1:
    t1=np.dot(f1.gsnxext(t0,n),w.T)
    mp.plot(x,y,'ro')
    mp.plot(t0,t1)
    leg='M='+str(n)
    mp.legend(('Xn',leg))
    mp.title('Fitting with polynomial')
    print "Successful! Running time: %f s" % (end-start)
    print "> Cost Value: %f" % cf
    print "> Fitting with %d degree polynomial" % n
    print "> Parameter of the polynomial:",w
    print "> Absolute value of (y-yfit):",abs(y-yfit)

#==============================================================================
# Regularized fitting with n degree polynomial
#==============================================================================
n=12
w=np.zeros([1,n+1])
lb=.01
regpar=1
xext=f1.gsnxext(x,n)
cfprev=f1.cf(y,f1.gsnorder(w.T,n,x))
gdsucc=1

start=tm.clock()
for iter in range(1,90000):
    yfit=f1.gsnorder(w.T,n,x)
    cf=f1.cf(y,yfit)

    if (cf-cfprev)<1e-4:
#        print '# Iter',str(iter),': ',str(cf)
        w=w-lb*(np.dot((yfit-y),xext)+regpar*w)
        w[0]=w[0]-lb*(np.dot((yfit-y),xext)[0])
        cfprev=cf
    else:
        print 'Parameter is too large! Please choose a smaller one.'
        gdsucc=0
        break

end=tm.clock()

if gdsucc==1:
    t1=np.dot(f1.gsnxext(t0,n),w.T)
    mp.plot(x,y,'ro')
    mp.plot(t0,t1)
    leg='M='+str(n)
    mp.legend(('Xn',leg))
    mp.title('Regularized fitting with polynomial (lambda=%0.4f)'%lb)
    print "Successful! Running time: %f s" % (end-start)
    print "> Cost Value: %f" % cf
    print "> Fitting with %d degree polynomial" % n
    print "> Parameter of the polynomial:",w
    print "> Absolute value of (y-yfit):",abs(y-yfit)


from __future__ import annotations
import numpy as np
import numpy.random
from numpy.linalg import inv, det, slogdet
from matplotlib import pyplot as plt

class UnivariateGaussian:
    """
    Class for univariate Gaussian Distribution Estimator
    """

    def __init__(self, biased_var: bool = False) -> UnivariateGaussian:
        """
        Estimator for univariate Gaussian mean and variance parameters

        Parameters
        ----------
        biased_var : bool, default=False
            Should fitted estimator of variance be a biased or unbiased estimator

        Attributes
        ----------
        fitted_ : bool
            Initialized as false indicating current estimator instance has not been fitted.
            To be set as True in `UnivariateGaussian.fit` function.

        mu_: float
            Estimated expectation initialized as None. To be set in `UnivariateGaussian.fit`
            function.

        var_: float
            Estimated variance initialized as None. To be set in `UnivariateGaussian.fit`
            function.
        """
        self.biased_ = biased_var
        self.fitted_, self.mu_, self.var_ = False, None, None

    def fit(self, X: np.ndarray) -> UnivariateGaussian:
        """
        Estimate Gaussian expectation and variance from given samples

        Parameters
        ----------
        X: ndarray of shape (n_samples, )
            Training data

        Returns
        -------
        self : returns an instance of self.

        Notes
        -----
        Sets `self.mu_`, `self.var_` attributes according to calculated estimation (where
        estimator is either biased or unbiased). Then sets `self.fitted_` attribute to `True`
        """
        self.mu_ = np.average(X)
        self.var_ = np.var(X)
        self.fitted_ = True
        return self

    def pdf(self, X: np.ndarray) -> np.ndarray:
        """
        Calculate PDF of observations under Gaussian model with fitted estimators

        Parameters
        ----------
        X: ndarray of shape (n_samples, )
            Samples to calculate PDF for

        Returns
        -------
        pdfs: ndarray of shape (n_samples, )
            Calculated values of given samples for PDF function of N(mu_, var_)

        Raises
        ------
        ValueError: In case function was called prior fitting the model
        """
        if not self.fitted_:
            raise ValueError("Estimator must first be fitted before calling `pdf` function")
        exponent = np.exp(-1 * np.divide(np.power(X - self.mu_, 2), (2 * self.var_)))
        return np.multiply((1 / np.sqrt(2 * np.pi * self.var_)), exponent)

    @staticmethod
    def log_likelihood(mu: float, sigma: float, X: np.ndarray) -> float:
        """
        Calculate the log-likelihood of the data under a specified Gaussian model

        Parameters
        ----------
        mu : float
            Expectation of Gaussian
        sigma : float
            Variance of Gaussian
        X : ndarray of shape (n_samples, )
            Samples to calculate log-likelihood with

        Returns
        -------
        log_likelihood: float
            log-likelihood calculated
        """
        var = sigma ** 2
        exponent = np.exp(-1 * np.divide(np.power(X - mu, 2), (2 * var)))
        y = np.multiply((1 / np.sqrt(2 * np.pi * var)), exponent)
        summery = 0
        for elem in y:
            summery +=np.log2(elem)
        return summery

class MultivariateGaussian:
    """
    Class for multivariate Gaussian Distribution Estimator
    """

    def __init__(self):
        """
        Initialize an instance of multivariate Gaussian estimator

        Attributes
        ----------
        fitted_ : bool
            Initialized as false indicating current estimator instance has not been fitted.
            To be set as True in `MultivariateGaussian.fit` function.

        mu_: ndarray of shape (n_features,)
            Estimated expectation initialized as None. To be set in `MultivariateGaussian.fit`
            function.

        cov_: ndarray of shape (n_features, n_features)
            Estimated covariance initialized as None. To be set in `MultivariateGaussian.fit`
            function.
        """
        self.mu_, self.cov_ = None, None
        self.fitted_ = False

    def fit(self, X: np.ndarray) -> MultivariateGaussian:
        """
        Estimate Gaussian expectation and covariance from given samples

        Parameters
        ----------
        X: ndarray of shape (n_samples, n_features)
            Training data

        Returns
        -------
        self : returns an instance of self

        Notes
        -----
        Sets `self.mu_`, `self.cov_` attributes according to calculated estimation.
        Then sets `self.fitted_` attribute to `True`
        """
        self.mu_ = np.mean(X, axis=0)
        self.cov_ = np.cov(X.T)
        self.fitted_ = True
        return self

    def pdf(self, X: np.ndarray):
        """
        Calculate PDF of observations under Gaussian model with fitted estimators

        Parameters
        ----------
        X: ndarray of shape (n_samples, n_features)
            Samples to calculate PDF for

        Returns
        -------
        pdfs: ndarray of shape (n_samples, )
            Calculated values of given samples for PDF function of N(mu_, cov_)

        Raises
        ------
        ValueError: In case function was called prior fitting the model
        """
        if not self.fitted_:
            raise ValueError("Estimator must first be fitted before calling `pdf` function")
        d = len(self.mu_)
        divider = 1 / (((2 * np.pi) ** d) * det(self.cov_))
        f_arr = []
        for x in X:
            power = -0.5 * np.matmul(np.matmul((x - self.mu_).T, self.cov_.T), (x - self.mu_))
            f_arr.append(divider * np.exp(power.item()))
        return f_arr

    @staticmethod
    def log_likelihood(mu: np.ndarray, cov: np.ndarray, X: np.ndarray) -> float:
        """
        Calculate the log-likelihood of the data under a specified Gaussian model

        Parameters
        ----------
        mu : ndarray of shape (n_features,)
            Expectation of Gaussian
        cov : ndarray of shape (n_features, n_features)
            covariance matrix of Gaussian
        X : ndarray of shape (n_samples, n_features)
            Samples to calculate log-likelihood with

        Returns
        -------
        log_likelihood: float
            log-likelihood calculated over all input data and under given parameters of Gaussian
        """
        d = len(mu)
        divider = 1 / (((2 * np.pi) ** d) * det(cov))
        f_arr = []
        for x in X:
            power = -0.5 * np.matmul(np.matmul((x - mu).T, cov.T), (x - mu))
            f_arr.append(+divider * np.exp(power.item()))
        summery =0
        for i in range(len (f_arr)):
            summery += np.log2(f_arr[i])
        # if prod == 0:
        #     return 0
        # return prod
        return summery

if __name__ == "__main__":
    Q_3_array = np.array([1, 5, 2, 3, 8, -4, -2, 5, 1, 10, -10, 4, 5, 2, 7, 1, 1, 3, 2, -1, -3, 1, -4, 1, 2, 1,
                          -4, -4, 1, 3, 2, 6, -6, 8, 3, -6, 4, 1, -2, 3, 1, 4, 1, 4, -2, 3, -1, 0, 3, 5, 0, -2])
    print("mu=1 : {}".format(UnivariateGaussian.log_likelihood(1, 1, Q_3_array)))
    print("mu=10 : {}".format(UnivariateGaussian.log_likelihood(10, 1, Q_3_array)))


#Activation function

import numpy as np
import nnfs
from nnfs.datasets import spiral_data

nnfs.init()

X = [[1, 2, 3, 2.5],
		[2.0, 5.0, -1.0, 2.0],
		[-1.5, 2.7, 3.3, -0.8]]

X, y = spiral_data(100, 3)
# inputs = [0, 2, -1, 3.3, -2.7, 1.1, 2.2, -100]
# output = []

'''
for i in inputs:
	output.append(max(0, i))
	# if i>0:
	# 	output.append(i)
	# elif i<=0:
	# 	output.append(0)

print(output)
'''

class Layer_Dense:
	def __init__(self, n_inputs, n_neurons):
		self.weights = 0.10 * np.random.randn(n_inputs, n_neurons)
		self.biases = np.zeros((1, n_neurons))
	def forward(self, inputs):
		self.output = np.dot(inputs, self.weights) + self.biases

class Activation_ReLU:
	def forward(self, inputs):
		self.output = np.maximum(0, inputs)

layer1 = Layer_Dense(2, 5)
# layer2 = Layer_Dense(5, 2)

activation1 = Activation_ReLU()

layer1.forward(X)
activation1.forward(layer1.output)

print(activation1.output)
# print(layer1.output)
# activation1.forward(layer1.output)
#print(layer1.output)
# layer2.forward(layer1.output)
# print(layer2.output)


# USEFUL METHODS OF THE NUMPY ARRAYS
# Santiago Garcia Arango, June 2020
# -------------------------------------------------------------------------
import numpy as np

array_1 = np.arange(25)  # Equivalent to: [0,1,2,3, ...,22, 23, 24]
array_2 = np.random.randint(0, 50, 10)  # Vector of 5 random integers(0,50)

print("array_1:\n", array_1, "\n")
print("array_2:\n", array_2, "\n")

# ----------------------RESHAPE METHOD--------------------------------------
# This method allows us to reshape an array into a given shape (must match)
# Remark: the product of dimensions N*M must be equal to the size of vector
new_array_1 = array_1.reshape(5, 5)
print("array_1 (reshaped):\n", new_array_1, "\n")

# -------------------------GET SHAPE OF ARRAY------------------------------
print("SHAPE(array_1) -->", array_1.shape)
print("SHAPE(array_1 (reshaped) ) -->", new_array_1.shape)
print("SHAPE(array_2) -->", array_2.shape, "\n")

# -------------------MAXIMUM AND MINIMUM OF ARRAY---------------------------
# array.max(): returns the max VALUE of a given array
# array.min(): returns the min VALUE of a given array
# array.argmax(): returns INDEX location of the max VALUE of given array
# array.argmin(): returns INDEX location of the min VALUE of given array
print("MAX(array_2) =", array_2.max(), " (at index", array_2.argmax(), ")\n")
print("MIN(array_2) =", array_2.min(), " (at index", array_2.argmin(), ")\n")

# ------------------------DATATYPE OF ARRAY----------------------------------
print("DATATYPE(array_1) -->", array_1.dtype)
print("DATATYPE(array_2) -->", array_2.dtype)


import numpy as np

from optimizer import Optimizer

class Bfgs(Optimizer):
    """
    Broyden–Fletcher–Goldfarb–Shanno algorithm.

    Arguments:
        L (float, optional): an upper bound on the smoothness constant
            to initialize the Hessian estimate
        hess_estim (float array of shape (dim, dim)): initial Hessian estimate
        lr (float, optional): stepsize (default: 1)
    """
    def __init__(self, L=None, hess_estim=None, lr=1, line_search=False, ls_backtrack=0.5, ls_it_max=100, *args, **kwargs):
        super(Bfgs, self).__init__(*args, **kwargs)
        if L is None and hess_estim is None:
            L = self.loss.smoothness()
            if L is None:
                raise ValueError("Either smoothness constant L or Hessian estimate must be provided")
        self.lr = lr
        self.L = L
        self.B = hess_estim
        self.line_search = line_search
        self.ls_backtrack = ls_backtrack
        self.ls_it_max = ls_it_max

    def step(self):
        self.grad = self.loss.gradient(self.x)
        x_new = self.x - self.B_inv @ self.grad
        if self.line_search:
            lr = min(1., self.lrs[-1] / self.ls_backtrack if len(self.lrs) > 0 else .1)
            for i in range(self.ls_it_max):
                f_new = self.loss.value(self.x + lr * (x_new - self.x))
                if f_new < self.f:
                    break
                lr *= self.ls_backtrack
            self.lrs.append(lr)
            self.f = f_new
        else:
            lr = self.lr
        x_new = self.x + lr * (x_new - self.x)

        s = x_new - self.x
        grad_new = self.loss.gradient(x_new)
        y = grad_new - self.grad
        self.grad = grad_new
        Bs = self.B @ s
        sBs = s @ Bs
        Binv_y = self.B_inv @ y
        y_Binv_y = y @ Binv_y
        self.B += np.outer(y, y)/(y@s) - np.outer(Bs, Bs)/sBs
        self.B_inv += (s@y + y_Binv_y) * np.outer(s, s) / (s@y)**2
        self.B_inv -= (np.outer(Binv_y, s) + np.outer(s, Binv_y)) / (s@y)
        self.x = x_new

    def init_run(self, *args, **kwargs):
        super(Bfgs, self).init_run(*args, **kwargs)
        if self.B is None:
            self.B = self.L * np.eye(self.loss.dim)
            self.B_inv = 1 / self.L * np.eye(self.loss.dim)
        else:
            self.B_inv = np.linalg.pinv(self.B)
        self.grad = self.loss.gradient(self.x)
        if self.line_search:
            self.f = self.loss.value(self.x)
            self.lrs = []


#%%
import random
import numpy as np
from numpy.random import randn
num_data  = 200
e_z = randn(num_data)
e_y = randn(num_data)

Z = e_z
Y = 2*Z + e_y
# %%
np.corrcoef(Z, Y)

# %%
import scipy.stats
import matplotlib.pyplot as plt
%matplotlib inline
Z_std = scipy.stats.zscore(Z)
Y_std = scipy.stats.zscore(Y)

plt.scatter(Z_std, Y_std)
# %%
e_z = randn(num_data)
e_y = randn(num_data)

Y = e_y
Z = 2*Y + e_z
np.corrcoef(Z, Y)

# %%
Z_std = scipy.stats.zscore(Z)
Y_std = scipy.stats.zscore(Y)

plt.scatter(Z_std, Y_std)
# %%

e_x = randn(num_data)
e_y = randn(num_data)
e_z = randn(num_data)

Z = 3.3*e_x + e_z
Y = 3.3*e_x + e_y

np.corrcoef(Z, Y)
# %%
Z_std = scipy.stats.zscore(Z)
Y_std = scipy.stats.zscore(Y)

plt.scatter(Z_std, Y_std)
# %%
num_data = 600
e_x = randn(num_data)
e_y = randn(num_data)

x = e_x
y = e_y

plt.scatter(x, y)
# %%
np.corrcoef(x, y)
# %%
z = x + y

x_new = np.array([])
y_new = np.array([])
# %%

for i in range(num_data):
    if z[i] > 0.0:
        x_new = np.append(x_new, x[i])
        y_new = np.append(y_new, y[i])

plt.scatter(x_new, y_new)
# %%
np.corrcoef(x_new, y_new)
# %%

num_data = 200
x_1 = np.random.randint(15, 76, num_data)

x_2 = np.random.randint(0, 2, num_data)
# %%
from scipy.special import expit # 1.
e_x = randn(num_data)

z_base = x_1 + (1 - x_2)*10 - 40 + 5*e_z

z_prob = expit(0.1 * z_base)
# %%
Z = np.array([])
for i in range(num_data):
    Z_i = np.random.choice(2, size=1, p=[1-z_prob[i], z_prob[i]])[0]
    Z = np.append(Z, Z_i)
# %%
e_y = randn(num_data)
Y = -x_1 + 30*x_2 + 10*Z + 80 + 10*e_y

# %%
import pandas as pd
df = pd.DataFrame({'age':x_1,
                   'Sex':x_2,
                   'WatchedCM':Z,
                   'PurchaseAmount':Y,
                   })
df.head()

# %%
print(df[df["WatchedCM"] == 1.0].mean())
print("-----------")
print(df[df["WatchedCM"] == 0.0].mean())
# %%
from sklearn.linear_model import LinearRegression
X = df[["age","Sex","WatchedCM"]]
y = df["PurchaseAmount"]

reg = LinearRegression().fit(X, y)
print("Coef:", reg.coef_)
# %%
from sklearn.linear_model import LogisticRegression
X = df[["age", "Sex"]]
Z = df["WatchedCM"]

reg = LogisticRegression().fit(X, Z)
print("Coef_beta:", reg.coef_)
print("Coef_alpha:", reg.intercept_)
# %%

Z_pre = reg.predict_proba(X)
print(Z_pre[0:5])
print("-----")
print(Z[0:5])
# %%

ATE_i = Y/Z_pre[:, 1]*Z - Y/Z_pre[:, 0]*(1-Z)
ATE = 1/len(Y)*ATE_i.sum()
print("predicted_ATE", ATE)
# %%
X = df[["age","Sex","WatchedCM"]]
y = df["PurchaseAmount"]

reg2 = LinearRegression().fit(X, y)
X_0 = X.copy()
X_0["WatchedCM"] = 0
Y_0 = reg2.predict(X_0)

X_1 = X.copy()
X_1["WatchedCM"] = 1
Y_1 = reg2.predict(X_1)

X = df[["age", "Sex"]]
Z = df["WatchedCM"]

reg = LogisticRegression().fit(X, Z)
Z_pre = reg.predict_proba(X)
print(Z_pre[0:5])
# %%
ATE_1_i = Y/Z_pre[:, 1]*Z + (1-Z/Z_pre[:, 1])*Y_1
ATE_0_i = Y/Z_pre[:, 0]*(1-Z) + (1-(1-Z)/Z_pre[:, 0])*Y_0
ATE = 1/len(Y)*(ATE_1_i-ATE_0_i).sum()
print("Estimated_ATE",ATE)
# %%

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split

X = df[["age", "Sex"]]
Z = df["WatchedCM"]

X_train, X_val, Z_train, Z_val = train_test_split(
    X, Z, train_size = 0.6, random_state = 0)

clf = DecisionTreeClassifier(max_depth=1, random_state=0)
clf.fit(X_train, Z_train)
print("Performance_of_Depth1:",clf.score(X_val, Z_val))
# %%

clf = DecisionTreeClassifier(max_depth=2, random_state=0)
clf.fit(X_train, Z_train)
print("Performance_of_Depth2:",clf.score(X_val, Z_val))

clf = DecisionTreeClassifier(max_depth=3, random_state=0)
clf.fit(X_train, Z_train)
print("Performance_of_Depth3:",clf.score(X_val, Z_val))
# %%

from sklearn.tree import DecisionTreeRegressor
X = df[["age", "Sex"]]
Y = df["PurchaseAmount"]

X_train, X_val, Y_train, Y_val = train_test_split(
    X, Y, train_size = 0.6, random_state = 0)

reg = DecisionTreeRegressor(max_depth=2, random_state=0)
reg.fit(X_train, Y_train)
print("Performance_of_Depth1:",reg.score(X_val, Y_val))

reg = DecisionTreeRegressor(max_depth=3, random_state=0)
reg.fit(X_train, Y_train)
print("Performance_of_Depth2:",reg.score(X_val, Y_val))

reg = DecisionTreeRegressor(max_depth=4, random_state=0)
reg.fit(X_train, Y_train)
print("Performance_of_Depth3:",reg.score(X_val, Y_val))
# %%
from sklearn.ensemble import RandomForestClassifier

X = df[["age", "Sex"]]
Z = df["WatchedCM"]

X_train, X_val, Z_train, Z_val = train_test_split(
    X, Z, train_size = 0.6, random_state = 0)

clf = RandomForestClassifier(max_depth=1, random_state=0)
clf.fit(X_train, Z_train)
print("Performance_of_Depth1:",clf.score(X_val, Z_val))

clf = RandomForestClassifier(max_depth=2, random_state=0)
clf.fit(X_train, Z_train)
print("Performance_of_Depth2:",clf.score(X_val, Z_val))

clf = RandomForestClassifier(max_depth=3, random_state=0)
clf.fit(X_train, Z_train)
print("Performance_of_Depth3:",clf.score(X_val, Z_val))

import numpy,from numpy,import scipy,from scipy


import numpy as np
import matplotlib.pyplot as plt

entrada = np.array([[-0.4712, 1.7698], [0.1103, 3.1334], [2.0263,3.2474],
                   [1.5697, 0.7579], [1.7254, 4.0834], [2.2676, 0.4092],
                   [-0.4753, 1.1308], [3.2018, 3.1839], [2.0614,  1.6423],
                   [2.4969, 1.6099], [7.1547, 5.4719], [5.8240, 6.5220],
                   [7.0105, 8.9157], [6.3086, 6.0023], [6.1122, 6.2530],
                   [4.1822, 5.1714], [7.5074, 7.1391], [8.5628, 7.4580],
                   [6.9596, 5.4075], [6.7379, 10.1990], [2.1959, 7.1072],
                   [4.9906, 7.8603], [4.0592, 6.7196], [-0.3881, 6.8434],
                   [3.1318, 6.1018], [3.2421, 8.2583], [1.2560, 5.9102],
                   [2.8671, 5.8639], [1.8885, 5.8148], [1.0263, 7.9487],
                   [4.9782, 0.8005], [6.5436, 2.1400], [6.4685, 2.3265],
                   [7.8461, 1.3620], [6.6673, 2.8004], [6.8124, 2.7228],
                   [5.8382, 1.9450], [7.1404, 3.3512], [7.1251, 4.9571],
                   [4.7644, 2.3254],[7.5, 10.4], [-2.23, -1.522], [1.9, -7.2], [13.455, -5.0],[-3, -4],
                    [3.388, 5.239],[0.23, 0.1], [-1, 2.34]])

def plot(idx):
    idx = np.array(idx)
    plt.scatter(entrada[:, 0], entrada[:, 1], c = idx, s=100)
    plt.scatter(Centroide[:, 0], Centroide[:, 1], s=1000, c=np.array([i for i in range(len(Centroide))]), marker='*')
    plt.title('Centroides')
    plt.xlabel('Entrada X0')
    plt.ylabel('Entrada X1')
    plt.axis('equal')
    plt.pause(0.75)

def initList(size):
    mylist = list()
    for i in range(size):
        mylist.append( list() ) #different object reference each time
    return mylist

def init(NCentroides, NEntradas):
     idx = np.random.permutation(entrada.shape[0])[0:NCentroides]
     return entrada[idx, :]

def EuclideanDistance(Centroide, Entrada):
    distance = np.zeros((Entrada.shape[0], Centroide.shape[0]))
    for k in range(Centroide.shape[0]):
        for i in range(Entrada.shape[0]):
            for j in range(Entrada.shape[1]):
                distance[i, k] += (Entrada[i, j] - Centroide[k, j])**2
            distance[i, k] = np.sqrt(distance[i, k])
    return distance

def KMeans(Entrada, Centroide):

    oldC = np.zeros((Centroide.shape))
    count = 0
    while True:
        count += 1
        pointCentroides = initList(Centroide.shape[0])
        Distance = EuclideanDistance(Centroide, Entrada)
        Distance = list(Distance)
        idx = []
        for i in range(len(Distance)):
            Distance[i]= list(Distance[i])
        for i in range(Entrada.shape[0]):
            shortest = min(Distance[i])
            index = Distance[i].index(shortest)
            idx.append(index)
            pointCentroides[index].append(Entrada[i, :].tolist())
        nppc = [0]*len(pointCentroides)
        for x in range(len(pointCentroides)):
            nppc[x] = len(pointCentroides[x])
            pointCentroides[x] = np.array(pointCentroides[x])
            pointCentroides[x] = sum(pointCentroides[x])/len(pointCentroides[x])
            Centroide[x] = pointCentroides[x]
        if (Centroide == oldC).all():
            plot(idx)
            break
        else:
            plot(idx)
            plt.gcf().clear()
        oldC = np.copy(Centroide)
        print('Centroides finais: ', Centroide, '\nCount', count)
    plt.show()
    return Centroide, nppc

Centroide = init(6, entrada.shape[1])
KMeans(entrada, Centroide)

# nc = 15
# nmppc = int(0.1*entrada.shape[0])
# for i in range(nc, 0, -1):
#     Centroide = init(i, entrada.shape[1])
#     _, xxx = KMeans(entrada, Centroide)
#     if sum(list(map(lambda x: x >= nmppc, xxx))) == i:
#         print(i)
#         break


import os
import numpy as np
import random
from constraint import *

def create_graph_pair(n,k):
	"""
		Starts with a disjoint set of n vertices (zero edges). Iteratively
		adds edges selected uniformly at random while the resulting graph
		admits a k-coloring. The penultimate and last of such graphs, which
		differ only by a single edge, are respectively k-colorable and not
		k-colorable.
	"""
	k_colorable = True
	M1 = np.zeros((n,n),dtype=int)
	M2 = np.zeros((n,n),dtype=int)
	while k_colorable:

		# Choose (and add) an edge uniformly at random
		a,b = random.choice([ (i,j) for i in range(n) for j in range(n) if i != j and M1[i,j]==0])
		M2[a,b] = 1

		# Create a CSP problem with n integer variables each of which can assume k different values ("colors")
		problem = Problem()
		problem.addVariables(range(n), range(k))
		for i in range(n):
			for j in range(n):
				if M2[i,j] == 1:
					# Add one constraint for each edge
					problem.addConstraint(lambda x,y: x != y, (i,j))
				#end
			#end
		#end

		# Check if k-colorable
		k_colorable = problem.getSolution() is not None

		if k_colorable:
			M1[a,b] = 1
		#end
	#end

	return M1, M2
#end

def write_graph(M, k, k_colorable, path):
	with open(path,"w") as out:
		out.write("p {} {} {} {}\n".format(M.shape[0], len(np.nonzero(M)[0]), k, k_colorable ))

		for (i,j) in zip(list(np.nonzero(M)[0]), list(np.nonzero(M))[1]):
			out.write("{} {}\n".format(i,j))
		#end
	#end
#end

def read_graph(path):
	with open(path,"r") as f:
		n, m, k, k_colorable = [ int(x) for x in f.readline().split()[1:]]
		M = np.zeros((n,n),dtype=int)
		for edge in range(m):
			i,j = [ int(x) for x in f.readline().split() ]
			M[i,j] = 1
		#end
	#end
	return M,k,k_colorable
#end

def create_dataset(n, samples = 1000, path="instances"):

	if not os.path.exists(path):
		os.makedirs(path)
	#end if

	for i in range(samples//2):
		# Select a random k ~ Bernouilli(0.3) + Geo(0.4)
		k = 3 #random.choice(range(2,5+1))
		print("Creating instances pair with k={}".format(k))
		M1, M2 = create_graph_pair(n,k)
		write_graph(M1,k,0,"{}/{}.graph".format(path,2*i))
		write_graph(M2,k,1,"{}/{}.graph".format(path,2*i+1))
	#end for
#end

if __name__ == '__main__':
	create_dataset(20, samples = 32*128, path = "train")
	create_dataset(20, samples = 32*128, path = "test")
#end


import numpy as np

            # zip Function
softmax_outputs = np.array([[ 0.7 , 0.1 , 0.2 ],
                            [ 0.1 , 0.5 , 0.4 ],
                            [ 0.02 , 0.9 , 0.08 ]])
class_target = [0,1,1]

print("Length : ",len(softmax_outputs))
print("Shape : ",softmax_outputs.shape)

for indx, distribution in  zip(class_target, softmax_outputs):
    print(distribution[indx])

print(softmax_outputs[[0,1,2], class_target])   #0,1,2 define the row
b=softmax_outputs[range(len(softmax_outputs)), class_target]
print("here We are", b)  #size of array can also work
# print(softmax_outputs[range(0,3), class_target])

''' Now apply Cross entropy on this values'''
print("Final CE", -np.log(softmax_outputs[range(len(softmax_outputs)), class_target]))

cal = -np.log(softmax_outputs[range(len(softmax_outputs)), class_target])
average_loss = np.mean(cal)
print(average_loss)

''' What if class target have 3*3 dimension instead of 1'''
softmax_outputs = np.array([[ 0.7 , 0.1 , 0.2 ],
                            [ 0.1 , 0.5 , 0.4 ],
                            [ 0.02 , 0.9 , 0.08 ]])

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

output = np.sum(softmax_outputs*class_target, axis=1)
print('average_loss', np.mean(-np.log(output)))
# print(output)


import matplotlib.pyplot as plt
import numpy as np

""" a = np.float64(5)
i = np.float64(1)
while True:
   b = np.float64(a + 10**(-i))
   print("b:%.16f, a:%.16f, i:%.0f "%(b,a,i));
   if a == b:
      break
   i += 1 """

"""
funcion  X(t) = 1.7  y dejando el función de w
"""

###Funciones auxiliares

#funcion a resolver
g = 32.17
t = 1
def  func(x):
  value = (3.4/g)*x**2 + 0.5*(np.exp(x*t) - np.exp(-x*t)) - np.sin(x*t)
  return value

def sign(x):
  if x > 0:
    return 1
  elif x < 0:
    return -1
  else:
    return 0

###Metodo

#longitud intervalo
ai = -1.0
bi = 1.5

#Tolerancia
Tol = 1.0e-5

#Error inicial
error  = 1.0

#Nmax de interaciones
Nmax = 1000
iteracion = 0

#Verificacion del valor medio

if (sign(func(ai))* sign(func(bi))<0):
    while(error > Tol):
        pi = 0.5*(ai+bi)
        pi_previo = pi

        #redefinimos los limites del intervalo
        #if(abs(func(pi)) < Tol):
          # print("La raiz del polinomio es %.5f"%(pi))
        #else:
        if(sign(func(pi)) == sign(func(ai))):
            ai = pi
            bi = bi
        elif(sign(func(pi)) == sign(func(bi))):
            ai = ai
            bi = pi

        pi = 0.5*(ai+bi)
        error = abs(pi - pi_previo)
        iteracion = iteracion+1

        print("pi=%f\t ai=%f\t f(pi)=% f\t error=%f"%(pi,ai,func(pi),error))

        if(iteracion > Nmax):
            print("Numero de iteraciones excedido")
            break
else:
    print("Intervalo inadecuado")

print("Cero de F(x)  = %f , F(pi)= %.5f"%(pi, func(pi)))

"""
x1 = np.linspace(-1.5,1.5)
y1  = []

for i in range(0,len(x1)):
  y1.append(func(x1[i]))

fig = plt.figure()
ax = plt.axes()
ax.plot(x1, y1, label='Datos Discretos')
#ax.plot(x_interpol, y_interpol,'.', label='Puntos interpolados')
#ax.plot(x_interpol, np.sin(x_interpol), label='sin(x)')
ax.legend()
plt.show()
"""


from pyccel.decorators import types

#==============================================================================
@types('double[:]','int','double')
def find_span( knots, degree, x ):
    """
    Determine the knot span index at location x, given the
    B-Splines' knot sequence and polynomial degree. See
    Algorithm A2.1 in [1].

    For a degree p, the knot span index i identifies the
    indices [i-p:i] of all p+1 non-zero basis functions at a
    given location x.

    Parameters
    ----------
    knots : array_like
        Knots sequence.

    degree : int
        Polynomial degree of B-splines.

    x : float
        Location of interest.

    Returns
    -------
    span : int
        Knot span index.

    """
    # Knot index at left/right boundary
    low  = degree
    high = 0
    high = len(knots)-1-degree

    # Check if point is exactly on left/right boundary, or outside domain
    if x <= knots[low ]: returnVal = low
    elif x >= knots[high]: returnVal = high-1
    else:
        # Perform binary search
        span = (low+high)//2
        while x < knots[span] or x >= knots[span+1]:
            if x < knots[span]:
               high = span
            else:
               low  = span
            span = (low+high)//2
        returnVal = span

    return returnVal

#==============================================================================
@types('double[:]','int','double','int','double[:]')
def basis_funs( knots, degree, x, span, values ):
    """
    Compute the non-vanishing B-splines at location x,
    given the knot sequence, polynomial degree and knot
    span. See Algorithm A2.2 in [1].

    Parameters
    ----------
    knots : array_like
        Knots sequence.

    degree : int
        Polynomial degree of B-splines.

    x : float
        Evaluation point.

    span : int
        Knot span index.

    Results
    -------
    values : numpy.ndarray
        Values of p+1 non-vanishing B-Splines at location x.

    Notes
    -----
    The original Algorithm A2.2 in The NURBS Book [1] is here
    slightly improved by using 'left' and 'right' temporary
    arrays that are one element shorter.

    """
    from numpy      import empty
    left   = empty( degree  , dtype=float )
    right  = empty( degree  , dtype=float )

    values[0] = 1.0
    for j in range(0,degree):
        left [j] = x - knots[span-j]
        right[j] = knots[span+1+j] - x
        saved    = 0.0
        for r in range(0,j+1):
            temp      = values[r] / (right[r] + left[j-r])
            values[r] = saved + right[r] * temp
            saved     = left[j-r] * temp
        values[j+1] = saved


#Nessas linhas de codigo o objetivo é calcular a taxa media de retorno anual para um portfolio

import numpy as np
import pandas as pd
from pandas_datareader import data as wb
import matplotlib.pyplot as plt

tickers = ['AAPL', 'MSFT', 'PG', 'GE']

new_data = pd.DataFrame()

for t in tickers:
    new_data[t] = wb.DataReader(t, data_source='yahoo', start='1995-1-1')['Adj Close']

#Vamos criar um grafico de linhas para entender como essas açoes se comportaram em todo o periodo analisado.
#Para normalizar os dados na base 100 podemos fazer P1/P0 * 100
#O indexador .iloc[0] ira extrair os dados da primeira coluna da tabela

(new_data / new_data.iloc[0] * 100).plot(figsize=(15, 6))
#Fazendo isso, esses calculos vao normalizar o grafico com 100 como parametro, todas iniciando no mesmo ponto vertical 100

#O comando .loc{rotulo} o rotulo é para indicar a primeira linha, as datas sao rotulos
#Para usar o .iloc[numero da linha], usa-se o numero da linha que se deseja
#Pode-se usar os dois, depende da praticidade que o programador achar
plt.show()

#Tem como objetivo analisar o historico das acoes e tentar prever o futuro, uma negociacao lucrativa

#Iremos calcular o retorno simples dessas açoes e criar uma nova tabela com eles
#Usa-se mais retornos simples para negociaçoes num mesmo periodo de tempo
#Utiliza-se a funcao numpy
returns = (new_data / new_data.shift(1)) - 1
returns.head()

weights = np.array([0.25, 0.25, 0.25, 0.25])
#Estamos atribuindo que os pesos das açoes sao iguais, e sempre os pesos devem somar 1
#Utilizando o metodo np.dot, podemos calcular o produto vetorial ou de matrizes de forma rapida
#Em python a matriz unidimensional ou multidimensional que obtivemos é referida como o produto dot entre as variaveis
#Fazendo isso iremos multiplicar o peso de cada açao com o seu respectivo retorno
#Fazendo isso obtem-se o retorno diario da carteira, e não é isso que desejamos no momento
#Podemos calcular o anual como
annual_returns = returns.mean() * 250

np.dot(annual_returns, weights)

pfolio1 = str(round(np.dot(annual_returns, weights), 5) * 100) + '%'
print(pfolio1)

weights2 = np.array([0.4, 0.4, 0.15, 0.05])

pfolio2 = str(round(np.dot(annual_returns, weights2), 5) * 100) + '%'

print(pfolio2)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
GeeksforGeeks-numpy_in_python-set_1-introduction-2_array_creation.py
￣
GeeksforGeeks
https://www.geeksforgeeks.org/

NumPy in Python | Set 1 (Introduction)
(Contributed by Nikhil Kumar.)
https://www.geeksforgeeks.org/numpy-in-python-set-1-introduction/

To read more about the related topics,
  NumPy Reference
  https://docs.scipy.org/doc/numpy-1.10.1/reference/index.html

￣
2019-07-04 (Thu)
"""
# Numpy in Python > Introduction > 2.Array Creation

# This example covers:
#   1. Arrays in Numpy
#     creation (from a list)
#     type
#     ndim
#     shape
#     size
#     dtype
#
#   2. Array creation
#     from a list
#     from a tuple
#     zeros
#     *ones
#     full
#     *empty  No example presented by the tutorial. So I added examples by myself
#     random
#     arange
#     linspace
#     reshape
#     flatten
#
#   3. Array Indexing
#     Slicing
#     Integer array indexing
#     Boolean array indexing
#
#   4. basic operations
#     Operations on single array
#     Unary operators
#     Universal functions (ufunc)
#
#   5. Sorting array
#     np.sort( arr ), sort the array (row-wise)
#     axis=1, row-wise sorting
#     axis=0, column-wise sorting
#     kind='mergesort', selecting the sorting method with
#     axis=None, flatten and sort the all elements
#     sort a structured array
#     order='name' defined by dtypes
#     order=['grad_year','cgpa'] defined by dtypes
# Read more about:
#   numpy.empty
#   https://docs.scipy.org/doc/numpy/reference/generated/numpy.empty.html
#
#    Recommended Posts:
#    Python | Numpy numpy.ndarray.__ne__()
#    Python | Numpy numpy.ndarray.__and__()
#    Python | Numpy numpy.ndarray.__neg__()
#    Python | Numpy numpy.ndarray.__isub__()
#    Python | Numpy numpy.ndarray.__pos__()
#    Python | Numpy numpy.ndarray.__iadd__()
#    Python | Numpy numpy.ndarray.__xor__()
#    Python | Numpy numpy.ndarray.__eq__()
#    Python | Numpy numpy.ndarray.__ge__()
#    Python | Numpy numpy.ndarray.__imul__()
#    Python | Numpy numpy.ndarray.__lshift__()
#    Python | Numpy numpy.ndarray.__rshift__()
#    Python | Numpy numpy.ndarray.__pow__()
#    Python | Numpy numpy.ndarray.__divmod__()
#    Python | Numpy numpy.ndarray.__invert__()

import numpy as np

line="-" * 30

#====================================================================
print("1. Arrays in Numpy")
print( line )

arr = np.array( [[1,2,3],[4,2,5]] )
print("type=", type(arr))
#type= <class 'numpy.ndarray'>
print("number of dimensions=", arr.ndim)
#number of dimensions= 2
print("Shape=", arr.shape)
#Shape= (2, 3)
print("Size=", arr.size)
#Size= 12
print("Data type=", arr.dtype)
#Data type= int64

#====================================================================
print("2. Array creation")
print( line )

a = np.array( [[1,2,4],[5,8,7]], dtype='float' )
print("Array created from list with type float\n",a)
# [[1. 2. 4.]
# [5. 8. 7.]]

b = np.array( (1,3,2) )
print("Array created from tuple\n",b)
# [1 3 2]

c = np.zeros( (3,4) )
print("3x4 array initialized with all zeros\n", c)
# [[0. 0. 0. 0.]
# [0. 0. 0. 0.]
# [0. 0. 0. 0.]]

d = np.full( (3,3),6,dtype='complex')
print("3x3 array initialized with all 6s\n", d)
# [[6.+0.j 6.+0.j 6.+0.j]
# [6.+0.j 6.+0.j 6.+0.j]
# [6.+0.j 6.+0.j 6.+0.j]]

# These empty examples are not in the tutorial.
# So I added them by myself.
# https://docs.scipy.org/doc/numpy/reference/generated/numpy.empty.html
d_empty = np.empty( (2,2) )
print("2x2 array initialized with empty\n", d_empty)
# [[1.9044942e-316 0.0000000e+000]
# [0.0000000e+000 0.0000000e+000]]

# [] works, too
d_empty_square = np.empty( [2,2] )
print("2x2 array initialized with empty\n", d_empty_square)
# [[1.9044942e-316 0.0000000e+000]
# [0.0000000e+000 0.0000000e+000]]

d_empty_int = np.empty( (2,2), dtype='int')
print("2x2 array initialized with empty\n", d_empty_int)
# [[38547392        0]
# [       0        0]]

d_empty_complex = np.empty( (2,2), dtype='complex')
print("2x2 array initialized with empty\n", d_empty_complex)
# [[0.0e+000+1.06718180e-321j 0.0e+000+2.03676547e-316j]
# [1.4e-322+6.91236450e-310j 4.9e-324+0.00000000e+000j]]

e = np.random.random( (2,2) )
print("2x2 array initialized with random numbers\n", e)
# [[0.33910781 0.9765249 ]
# [0.4583446  0.91109638]]

f = np.arange(0,30,5)
print("A sequential array: 0 to 30 with steps of 5\n", f)
# [ 0  5 10 15 20 25]
# Note 30 is missing.

g = np.linspace(0,5,10)
print("A sequential array: 0 to 5 with 10 values in-between\n", g)
#[0.         0.55555556 1.11111111 1.66666667 2.22222222 2.77777778
# 3.33333333 3.88888889 4.44444444 5.        ]

arr = np.array( [[1,2,3,4],[5,2,4,2],[1,2,0,1]] )
print("Original array: 3x4 array has 12 elements in total\n", arr)
# [[1 2 3 4]
# [5 2 4 2]
# [1 2 0 1]]

newarr = arr.reshape(2,2,3)
print("Reshaped array: 2x2x3 array has 12 elements, too\n", newarr)
# [[[1 2 3]
#  [4 5 2]]
#
# [[4 2 1]
#  [2 0 1]]]

arr = np.array( [[1,2,3],[4,5,6]] )
flarr = arr.flatten()
print("Original array\n",arr)
# [[1 2 3]
# [4 5 6]]
print("Flattened array\n",flarr)
# [1 2 3 4 5 6]

#====================================================================
print("3. Array Indexing")
print( line )

arr = np.array( [[-1,2,0,4],[4,-0.5,6,0],[2.6,0,7,8],[3,-7,4,2.0]] )
print(arr)
#[[-1.   2.   0.   4. ]
# [ 4.  -0.5  6.   0. ]
# [ 2.6  0.   7.   8. ]
# [ 3.  -7.   4.   2. ]]

# Slicing array
temp = arr[:2, ::2]
print("first two rows & alternate columns (0,2)\n",temp)
#[[-1.  0.]
# [ 4.  6.]]

# Integer array indexing
temp = arr[[0,1,2,3],[3,2,1,0]]
print("arr[0,3],arr[1,2], arr[2,1], arr[3,0]")
print( temp )
#[4. 6. 0. 3.]

# Boolean array indexing
idx = arr > 0  # Indices for the element bigger than 0
print( idx )
#[[False  True False  True]
# [ True False  True False]
# [ True False  True  True]
# [ True False  True  True]]

# temp is a sequence selected from arr.
temp = arr[idx]
print( temp )
# [2.  4.  4.  6.  2.6 7.  8.  3.  4.  2. ]

#====================================================================
print("4. Basic Operations")
print( line )
# Plethora of built-in arithmetic functions are provided in Numpy.

print("Operations on single array")
a = np.array( [1,2,5,3] )

# The arithmetic operation is added to every element.
print( a+1 )  # 1 is added to every element.
#[2 3 6 4]
print( a-3 )  # 3 is subtracted to every element.
#[-2 -1  2  0]
print( a*10 )
#[10 20 50 30]

# Power of a
print( a**2 )
#[ 1  4 25  9]

# Modify the existing array
a *=2
# Each element is doubled.
print( a )
#[ 2  4 10  6]

# Transpose of the array a
print( a.T )
#[ 2  4 10  6]
# Output is the same because of the rank is 1.(?)
# Let's check with rank=2 case.

b = np.array( [[1,2,3], [3,4,5], [9,6,0]] )
print(b)
#[[1 2 3]
# [3 4 5]
# [9 6 0]]

print(b.T)
#[[1 3 9]
# [2 4 6]
# [3 5 0]]

print("Unary operators")
# Many unary operations are provided as a method of ndarray class.
# This includes sum, min, max, etc.
# These functions can also be applied row-wise or column-wise
#   by setting an axis parameter.

arr = np.array( [[1,5,6], [4,7,2], [3,1,9]] )
print( arr )
#[[1 5 6]
# [4 7 2]
# [3 1 9]]

# Max for the matrix
print( arr.max() )
# 9

# Row-wise Max            # GREP
print( arr.max(axis=1) )  # GREP: This is not intuitive to me.
# [6 7 9]                 # GREP

# Column-wise Max         # GREP
print( arr.max(axis=0) )  # GREP: This is not intuitive to me.
# [4 7 9]                 # GREP

print( arr.sum() )
# 38

# Column-wise sum
print( arr.sum(axis=0) )
#[ 8 13 17]

# Row-wise sum
print( arr.sum(axis=1) )
# [12 13 13]

# For each row, cumulative sum
print( arr.cumsum( axis=1) )
#[[ 1  6 12]
# [ 4 11 13]
# [ 3  4 13]]

print("Binary operators")
# These operations are applied elementwise.

a = np.array( [[1,2], [3,4]] )
print(a)
#[[1 2]
# [3 4]]

b = np.array( [[4,3], [2,1]] )
print(b)
#[[4 3]
# [2 1]]

# Elementwise sum
print(a+b)
#[[5 5]
# [5 5]]

# Elementwise multiplication
print( a*b )
#[[4 6]
# [6 4]]

# Matrix multiplication
print( a.dot(b) )
#[[ 8  5]
# [20 13]]

print("Universal functions (ufunc)")
# Mathematical functions such as sin, cos, & exp operate elementwise on an array.

a = np.array( [0,np.pi/2, np.pi] )
print( a )
# [0.         1.57079633 3.14159265]

print( np.sin(a) )
#[0.0000000e+00 1.0000000e+00 1.2246468e-16]

# I don't like this about Numpy.
# sin(pi) must be 0, not a very small number like this.
print( np.sin( np.pi ) )
# 1.2246467991473532e-16

# cos(np.pi/2) must be 0, not a very small number like this.
# What's the difference between cos( np.pi/2 - epsilon ) & cos( np.pi/2 )?
print( np.cos( np.pi/2 ) )
#6.123233995736766e-17

print( np.cos(a) )
#[ 1.000000e+00  6.123234e-17 -1.000000e+00]

print( np.exp(a) )
#[ 1.          4.81047738 23.14069263]

print( np.sqrt(a) )
#[0.         1.25331414 1.77245385]

print("4. Sorting array")
# np.sort method makes the sorting task easy for us.

a = np.array( [[1,4,2], [3,4,6], [0,-1,5]] )
print(a)
#[[ 1  4  2]
# [ 3  4  6]
# [ 0 -1  5]]

print( np.sort(a) )
#[[ 1  2  4]
# [ 3  4  6]
# [-1  0  5]]
# This is a row-wise sorting, right?

# Row-wise sorting.
# axis=1 is not necessary as a matter of fact.
# I used this option just to classify.
print( np.sort(a,axis=1) )
#[[ 1  2  4]
# [ 3  4  6]
# [-1  0  5]]

# Column-wise sorting
print( np.sort(a,axis=0) )
#[[ 0 -1  2]
# [ 1  4  5]
# [ 3  4  6]]

# Column-wise sorting AND mergesort is chosen!
print( np.sort(a,axis=0, kind='mergesort') )
#[[ 0 -1  2]
# [ 1  4  5]
# [ 3  4  6]]
# Of course, the sorted result is identical.

print( np.sort(a,axis=None) )
#[-1  0  1  2  3  4  4  5  6]
# The 2d array is flattened and then sorted!

# Structured array
dtypes = [('name','S10'),('grad_year',int),('cgpa',float)]

# Values to be put into an array
values = [('Hrithik',2009,8.5),('Ajay',2008,8.7),('Pankaj',2008,7.9),('Aakash',2009,9.0)]

# Create an array that takes in values and dtypes
arr = np.array(values, dtype=dtypes)
print(arr)
#[(b'Hrithik', 2009, 8.5) (b'Ajay', 2008, 8.7) (b'Pankaj', 2008, 7.9)
# (b'Aakash', 2009, 9. )]
# Q: What does b mean?

print( np.sort( arr,order='name') )
#[(b'Aakash', 2009, 9. ) (b'Ajay', 2008, 8.7) (b'Hrithik', 2009, 8.5)
# (b'Pankaj', 2008, 7.9)]

print( np.sort(arr, order=['grad_year','cgpa']))
#[(b'Pankaj', 2008, 7.9) (b'Ajay', 2008, 8.7) (b'Hrithik', 2009, 8.5)
# (b'Aakash', 2009, 9. )]


"""
    Simple Implementation of K-nearest neighbor algorithm.
"""

import numpy as np
import matplotlib.pyplot as plt

def edist(x, y):
    """ Compute the Euclidean distance between two samples x, y \in R^d."""
    try:
        dist = np.sqrt(np.sum((x-y)**2))
    except ValueError:
        print 'Dimensionality of samples must match!'
    else:
        return dist

def manhattan_dist(x, y):
    """ Compute the Manhattan distance between two samples x, y \in R^d."""
    try:
        dist = np.sum(np.abs(x-y))
    except ValueError:
        print 'Dimensionality of samples must match!'
    else:
        return dist

def knn(query, data, k=5, metric=edist):
    """
        Find [k] nearest neighbors of [query] from data.
        Data [data] is given as an np.array of size n x d,
        where d is the dimensionality of sample, n is the number of samples.
        [metric]: distance function. Default to Euclidean distance.
    """
    n, d = data.shape
    if k > n: k = n

    # compute distances from query to all data samples.
    dist_array = np.asarray([edist(query, x) for x in data])

    # return indices of k nearest neighbors of query.
    return np.argsort(dist_array)[:k]

def knn_classifier(query, data, labels, k=5, metric=edist):
    """
        KNN-based classifier.
        [labels]: array of sample labels.
        Return sample labels and k-neighbors indices.
    """
    k_indices = knn(query, data, k, metric)
    counts = np.bincount(labels[k_indices])

    return np.argmax(counts), k_indices

def test_knn():
    # Generate 2d uniform data samples
    data = np.random.rand(200, 2)

    # Query sample
    query = np.random.rand(1, 2)[0]

    k_indices = knn(query, data, metric=manhattan_dist)

    # Plotting the data samples and query.
    plt.plot(data[:,0], data[:,1], 'ob', query[0],query[1], 'or')

    # Show k neighbors
    plt.plot(data[k_indices,0], data[k_indices,1], 'o',
            markerfacecolor='None', markersize=15, markeredgewidth=1)

    plt.show()

def test_classifier():
    # Generate 2d uniform data samples
    data = np.random.rand(200, 2)
    labels = np.array(np.random.rand(200) > 0.5, dtype=int)

    # Query
    query = np.random.rand(1, 2)[0]

    # Classifying...
    qlabel, k_indices = knn_classifier(query, data, labels)
    print 'Classified label of query: %d' % (qlabel)

    # Visualization. Note that: label = 1(0) -> c = red(blue)
    plt.scatter(data[:,0], data[:,1], c=labels, alpha=0.8)
    plt.scatter(query[0], query[1], c='g', s=40)
    plt.plot(data[k_indices,0], data[k_indices,1], 'o', markerfacecolor='None', markersize=15, markeredgewidth=1)
    plt.show()

if __name__ == '__main__':
    #test_knn()
    test_classifier()


'''
Miscellaneous math functions.
'''

from __future__ import absolute_import, division, print_function, unicode_literals

import numpy as np

def matrix_sqrt(X=None, symmetric=False, inverse=False, eigs=None):
    '''Returns the matrix square root of X.

    Arguments:

        `X` (square class::`numpy.ndarrray`)

        `symmetric` (bool, default False):

            If True, `X` is assumed to be symmetric, which speeds up
            calculation of the square root.

        `inverse` (bool, default False):

            If True, computes the matrix square root of inv(X).

        `eigs` (2-tuple):

            `eigs` must be a 2-tuple whose first element is an array of
            eigenvalues and whose second element is an ndarray of eigenvectors
            (individual eigenvectors are in columns). If this argument is
            provided, computation of the matrix square root is much faster. If
            this argument is provided, the `X` argument is ignored (in this
            case, it can be set to None).

    Returns a class::`numpy.ndarray` `S`, such that S.dot(S) = X
    '''
    if eigs is not None:
        (vals, V) = eigs
    else:
        (vals, V) = np.linalg.eig(X)
    k = len(vals)
    if inverse is False:
        SRV = np.diag(np.sqrt(vals))
    else:
        SRV = np.diag(1. / np.sqrt(vals))
    if symmetric:
        return V.dot(SRV).dot(V.T)
    else:
        return V.dot(SRV).dot(np.linalg.inv(V))

def get_histogram_cdf_points(data, cdf_vals, ignore=None, mask=None):
    '''Returns input values corresponding to the data's CDF values.

    Arguments:

        `data` (ndarray):

            The data for which to determine the CDF values

        `cdf_vals` (sequence of floats):

            A sequence defining the CDF values for which the values of `data`
            should be returned. Each value should be in the range [0, 1]. For
            example, to get the values of `data` corresponding to the 1% lower
            tail and 5% upper tail, this argument would be (0.01, 0.95).

        `ignore` (numeric, default `None`):

            A scalar value that should be ignored when computing histogram
            points (e.g., a value that indicates bad data). If this valus is
            not specified, all data are used.

    Return value:

        A list specifying the values in `data` that correspond to the
        associated CDF values in `cdf_vals`.
    '''
    data = data.ravel()
    if mask is not None:
        data = data[mask.ravel() != 0]
        if len(data) == 0:
            raise Exception('All pixels are masked.')
    if ignore is not None and ignore in data:
        data = data[np.where(data != ignore)]
        if len(data) == 0:
            raise Exception('No data to display after masking and ignoring.')
    isort = np.argsort(data)
    N = len(data)
    return [data[isort[int(x * (N - 1))]] for x in cdf_vals]


import sympy as sp

def christoffel(ds, g_mn, abc = [], ABC = []):

    # ds contiene el orden de las variables en el intervalo
    # g_mn es la métrica, en forma de 2D tupla

    # calcula \Gamma_{ab}^c.

    # ABC contiene múltiples tuplas abc. Se usa para calcular varios símbolos
    # en una sola llamada.

    #Constantes que podrían aparecer en la métrica
    G, M, R, C1, C2, C3 = sp.symbols('G M R C1 C2 C3')

    orden = [] #el orden en el que aparecen las variables de la meteica

    for i, e in enumerate(ds):
        #Las variables de la métrica
        if e != '':
            exec("var"+str(i)+"=sp.symbols('"+e+"')")
            exec("orden.append(var"+str(i)+")")

    ordenSt = [str(k) for k in orden]
    d = len(ordenSt)

    #la métrica con los íncices a b abajo
    gabD = sp.zeros(d, d)
    for i, row in enumerate(g_mn):
        for j, elem in enumerate(row):
            if i >= d or j >= d: continue
            if elem != '': gabD[i,j] = elem
            else: gabD[i,j] = 0

    #y con los índices arriba,
    gabU = gabD.inv()

    gabD = gabD.tolist()
    gabU = gabU.tolist()

    if ABC == [] and abc != []:
        #Vamos a calcular solo el símbolo \Gamma_{ab}^c
        a = abc[0]
        b = abc[1]
        c = abc[2]

        ai = ordenSt.index(a)
        bi = ordenSt.index(b)
        ci = ordenSt.index(c)

        chrst = 0

        for di in range(len(gabD)):
            chrst += 1./2*gabU[ci][di]*(sp.diff(gabD[bi][di], ordenSt[ai]) + sp.diff(gabD[di][ai], ordenSt[bi]) - sp.diff(gabD[ai][bi], ordenSt[di]))

        return(chrst)

    elif ABC != [] and abc == []:
        #vamos a calcular varios símbolos de una sola vez
        CHRIST = []

        for elem in ABC:
            a = elem[0]
            b = elem[1]
            c = elem[2]

            ai = ordenSt.index(a)
            bi = ordenSt.index(b)
            ci = ordenSt.index(c)
            chrst = 0
            for di in range(len(gabD)):
                chrst += 1./2*gabU[ci][di]*(sp.diff(gabD[bi][di], ordenSt[ai]) + sp.diff(gabD[di][ai], ordenSt[bi]) - sp.diff(gabD[ai][bi], ordenSt[di]))
            CHRIST.append(chrst)

        return CHRIST
    else: print("wrong call! either abc or ABC must be empty")

'''
abc = ["r", "t", "t"]
ds = ['t', 'r', 'th', 'fi']
g_mn = [['-(1-2*G*M/r)', '', '', ''], ['', '1/(1-2*G*M/r)', '', ''], ['', '', 'r**2', ''], ['', '', '', 'r**2*sin(th)**2']]
print(christoffel(ds, g_mn, abc))
'''


import math
import numpy as np
import matplotlib.pylab as plt

def func(x):
    """
    Исследуемая функция.
    :param x:
    :return:
    """
    y = math.asin((x - 1) ** 2)
    return y

def show_func():
    """
    Построение графика функции.
    :return:
    """
    x = np.linspace(0, 2, 4001)
    y = np.zeros(len(x))
    for i in range(len(x)):
        y[i] = func(x[i])
    plt.plot(x, y)
    plt.grid()
    plt.show()

def dif1(x):
    """
    Первая производная (разностная).
    :param x:
    :return:
    """
    h = 1e-7
    y = (func(x + h) - func(x - h)) / (2 * h)
    return y

def dif2(x):
    """
    Вторая производная (разностная).
    :param x:
    :return:
    """
    h = 1e-7
    y = (func(x + h) - 2 * func(x) + func(x - h)) / (h ** 2)
    return y

def Newton(x):
    """
    Метод Ньютона (с разностными производными).
    :param x:
    :return:
    """
    eps = 1e-14
    x_error = []
    x2 = x
    for i in range(100):
        x1 = x2
        x2 = x1 - (dif1(x1) / dif2(x1))
        x_error.append([x2, x1, abs(x2 - x1)])
        if abs(x2 - x1) < eps:
            break
    if dif2(x2) > 0:
        print('Точка минимума: x = ', end='')
    elif dif2(x2) < 0:
        print('Точка максимума: x = ', end='')
    print(x2)
    R_theor = x_error[-2][2]
    print('Теоретическая ошибка: R_theor =', R_theor)
    return x2, x_error

def find_min():
    """
    Поиск точки минимума.
    :return:
    """
    x, x_error = Newton(0.5)
    x_0 = 1
    R_real = abs(x_0 - x)
    print('Реальная ошибка: R_real =', R_real)
    print('\nСписок ошибок:')
    for i in x_error:
        print(f'|{i[0]} - {i[1]}| = {i[2]}')

def dif1_a(x):
    """
    Первая производная (аналитическая).
    :param x:
    :return:
    """
    y = (2 * x - 2) / math.sqrt(1 - (x - 1) ** 4)
    return y

def dif2_a(x):
    """
    Вторая производная (аналитическая).
    :param x:
    :return:
    """
    y = (2 * (1 + (2 * (x - 1) ** 4) / (1 - (x - 1) ** 4))) / math.sqrt(1 - (x - 1) * 4)
    return y

def Newton_a(x):
    """
    Метод Ньютона (с аналитическими производными).
    :param x:
    :return:
    """
    eps = 1e-14
    x_error = []
    x2 = x
    for i in range(100):
        x1 = x2
        x2 = x1 - (dif1_a(x1) / dif2_a(x1))
        x_error.append([x2, x1, abs(x2 - x1)])
        if abs(x2 - x1) < eps:
            break
    if dif2_a(x2) > 0:
        print('Точка минимума: x = ', end='')
    elif dif2_a(x2) < 0:
        print('Точка максимума: x = ', end='')
    print(x2)
    R_theor = x_error[-2][2]
    print('Теоретическая ошибка: R_theor =', R_theor)
    return x2, x_error

def find_min_a():
    """
    Поиск точки минимума.
    :return:
    """
    x, x_error = Newton(0.5)
    x_0 = 1
    R_real = abs(x_0 - x)
    print('Реальная ошибка: R_real =', R_real)

    print('\nСписок ошибок:')
    for i in x_error: print(f'|{i[0]} - {i[1]}| = {i[2]}')

if __name__ == '__main__':
    find_min_a()


import numpy as np
import pandas as pd
from pandas_datareader import DataReader
from pandas_datareader._utils import RemoteDataError
import scipy.stats as st

def ewma_vol(returns, lamb=0.94):

    returns = np.array(returns)

    size = np.array(range(len(returns)))[::-1]
    mean = np.mean(returns)

    vol = np.sqrt(np.sum((returns-mean) ** 2 * (1-lamb) * (lamb ** size)))
    return vol

def ewma_corr(a, b, lamb=0.94):
    a = np.array(a)
    b = np.array(b)

    size = np.array(range(len(a)))[::-1]
    corr = np.sum((1-lamb) * (lamb ** size) * (a - np.mean(a)) * (b - np.mean(b)))

    vol1 = ewma_vol(a, lamb)
    vol2 = ewma_vol(b, lamb)

    corr = corr / (vol1 * vol2)

    return corr

def Value_at_risk(tickers, date, weights=None, EWMA_model=True, confidence=0.99, samples=252, lamb=0.94):

    """
    Calculates the daily Value at Risk of a
    given stock or portfolio (list of stocks)

    The model assumes a parametric T-distribution for the returns.

    The returns are modeled as logarithm.

    -------------------------------------------------------
    tickers:
        List of stock names, ex: [GOOG, AAPL] or [GOOG] for just one stock
        Important: You must pass the exact name used in https://finance.yahoo.com/
    date:
        The date of the VaR.
        Note: The VaR always refers to the maximum loss of the next day of the date.
    weights:
        The weight of each stock in the portfolio composition.
        If None, assumes a equally weighed portfolio.
    EWMA_model:
        To calculate the VaR using the EWMA model of volatility and correlation
        EWMA means Exponentially Weighted Moving Average
    confidence:
        The level of confidence of the VaR.
    samples:
        How many past return days to use to calculate the VaR
    lamb:
        It's the lambda parameter for EWMA model.
        More on: https://www.investopedia.com/articles/07/ewma.asp
    """

    # Deals with possible errors

    if not isinstance(tickers, list):
        raise Exception("You must pass the argument tickers as a list.")

    tickers = [t.upper() for t in tickers]

    if weights is None:
        q = len(tickers)
        weights = np.array([1/q for _ in range(q)]) # Equal weights
    else:
        if len(weights) != len(tickers):
            raise Exception('weights and tickers must have the same size')
        weights = np.array(weights)

    # Start processing

    volatility = np.array([])

    start = pd.to_datetime(date, dayfirst=True)
    adjust_date = ((30 + samples)/252) * 365 # Some extra days to compensate holidays
    start = start - pd.to_timedelta(adjust_date, unit='d')
    date = pd.to_datetime(date, dayfirst=True)

    all_data = pd.DataFrame()

    for pos, ticker in enumerate(tickers):

        try:
            data = DataReader(ticker, 'yahoo', start, date)
        except Exception as e:
            print(f"Couldn't find {ticker} in Yahoo Finance. Error code: {e}")

        size = data.shape[0]
        data = data.iloc[size-(samples+1):]

        data[f'Log Returns {ticker}'] = np.log(data['Adj Close'] / data['Adj Close'].shift(1))
        data = data[f'Log Returns {ticker}'].to_frame()
        data.dropna(inplace=True)

        if EWMA_model:
            vol = ewma_vol(data[f'Log Returns {ticker}'], lamb=lamb)
        else:
            vol = data[f'Log Returns {ticker}'].std(ddof=1)

        volatility = np.append(volatility, vol)

        if pos == 0:
            all_data = all_data.append(data)
        else:
            all_data = pd.merge(all_data, data, left_index=True, right_index=True)

    if EWMA_model:
        corr = all_data.corr(ewma_corr)
    else:
        corr = all_data.corr()

    factor = st.t.ppf(q=confidence, df=samples)
    weights_vol = weights * volatility

    var = np.sqrt(np.dot(np.dot(weights_vol.T, corr), weights_vol)) * factor

    return var

# Ticker name must be exactly the same in https://finance.yahoo.com/
var = Value_at_risk(['GOOG', 'PETR4.SA', 'ITUB4.SA', 'VALE3.SA'], '12/02/2021', weights=[0.3, 0.1, 0.4, 0.2],
                    EWMA_model=True, confidence=0.99, samples=252, lamb=0.94)

print(f'Value at risk = {round(var*100,3)}%')


import numpy as np
import matplotlib.pyplot as plt

def pi():
    x = np.random.rand(1)
    y = np.random.rand(1)

    hyp = x**2 + y**2

    return(hyp)

k = 0
n = 1000

for i in range(n):
    x = np.random.rand(1)
    y = np.random.rand(1)
    hyp = x**2 + y**2

    if hyp < 1:
        k+=1
        plt.figure(1)
        plt.scatter(x,y,color='r')
    else:
        plt.figure(1)
        plt.scatter(x,y,color='b')

plt.show()

approx = k/n
print(approx)


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

import RNG
import math
import numpy as np
from scipy.stats import norm
from scipy import stats

ZRNG = RNG.InitializeRNSeed()
n = 10000
T = 1.0
m = 32
vol = 0.3
r = 0.05
X0 = 50.0
K = 55.0
Interval = T/m
alpha = 0.05

T2 = (m+1)*Interval/2.0
Sigma2 = (2*m+1)*vol*vol/(3.0*m)
delta = (vol*vol - Sigma2)/2.0
d = (math.log(X0/K)+(r-delta+Sigma2/2)*T2)/(math.sqrt(Sigma2*T2))
muvc = math.exp(-delta*T2)*X0*norm.cdf(d) - math.exp(-r*T2)*K*norm.cdf(d-math.sqrt(Sigma2*T2))

vList = [] # List to keep the option values
vcList = [] # List to keep vc values

for i in range(n):
    Sum = 0.0
    Product = 1.0
    X = X0
    for j in range(m):
        Z = RNG.Normal(0,1,1)
        X = X * math.exp((r - vol**2/2) * Interval + vol * math.sqrt(Interval) * Z)
        Sum = Sum + X
        Product = Product * X
    v = math.exp(-r * T) * max(Sum/m - K, 0)
    vc = math.exp(-r * T) * max(Product**(1.0/m) - K, 0)
    vList.append(v)
    vcList.append(vc)

vList = np.array(vList)
vcList = np.array(vcList)
vbar = vList.mean()
vcbar = vcList.mean()

print "v Mean", vList.mean()
print "v Std", vList.std()
print "vc Mean", vcList.mean()
print "vc Std", vcList.std()

beta1 =  sum(np.multiply(vList-vbar,vcList-vcbar))/sum((vcList-vcbar)**2)
beta0 = vbar - beta1*(vcbar-muvc)
part1 = sum((vList - beta0 - beta1*(vcList-muvc))**2)/(n-2.0)
part2 = 1.0/n + (vcbar-muvc)**2/sum((vcList-vcbar)**2)
SIGMA = part1 * part2

error = stats.t.ppf(1-alpha/2,n-2) * math.sqrt(SIGMA)
CI = "(" + str(beta0 - error) + ", " + str(beta0 + error) + ")"
print "m =", m, ", CI:", CI


import numpy as np

a = np.array([3,1,9,1,5,3,7,8,9,5])     # One Dimentional array
b = np.array([[1,7,3,4],[9,3,6,1],[9,2,8,1]])   # Two Dimentional array
print("a :" ,a)
print("b :", b)

print("\nAccessing a certain item.")
print("1D : ")
print(a[2])     # Starts with 0
print(a[-1])    # Prints last element
print("2D : ")
print(b[1][2])

print("\nFinding the dimension :")
print(a.ndim,"Dimensional array")
print(b.ndim,"Dimensional array")

print("\nShape (Rows, Column)")
print(b.shape)

print("\nSize(Number of elements)")
print(b.size)

print("\nDatatype :")
print(a.dtype)

print("\nUpdating an array :")
print("1D : ")
print(a)
a[1] = 6
print(a)
print("2D :")
print(b)
b[1][2] = 8
print(b)

print("\nPrinting only fixed values(Read comments) : ")
print("1D : ")
print("a :" ,a)
print(a[:3])
print(a[3:])
print(a[3:8])
print(a[::2])   # Skips a value (prints all the second terms)
print(a[::3])   # Prints only the third value
print(a[2::3])  # Starts from the second step and prints only the third term from then
print(a[8::-2]) # Prints from the reverse direction

print("2D : ")
print("b :\n", b)
print(b[:2,:1])
print(b[:2,:2])
print(b[0,:])   # Prints only the first row
print(b[:,0])   # Prints only the first column

print("\nData Conversions : ")
c = np.array([[1,7,6,4],[2,8.4,7,11],[2,6,4.3,12]],dtype = int)
print("Int : \n",c)
c = np.array([[1,7,6,4],[2,8.4,7,11],[2,6,4.3,12]],dtype = float)
print("Float : \n",c)

print("\nConverting a 1D array into a 2D array : ")
c = np.arange(1,10).reshape(3,3)    # 3 rows and 3 columns
print(c)

print("\nConcatenating Arrays : ")
a = np.arange(0,10,2)
b = np.arange(0,10,3)
c = np.concatenate([a,b])
print(c)
c = c.reshape(3,3)
print("After converting to a 2d array : \n",c)

print("\nComparing elements of two arrays : ")
a = np.array([6,7,3,9])
b = np.array([5,7,9,9])
print(a==b)
print(a>b)

print("\nComparing complete arrays : ")
a = np.array([5,6,7,8])
b = np.array([1,2,3,4])
c = np.array([1,2,3,4])
print(np.array_equal(a,b))
print(np.array_equal(b,c))

print("\nTo add elements at the end of the array : ")
print("a :", a)
print(np.append(a,[100,200,300]))

print("\nGengerating random numbers : ")
big_data = np.random.random_integers(1,100,size=1000)   # Generating 1000 random numbers from 1-100
print(big_data)

input("Press Enter key to exit ")


"""
This modules shows the numerically solution of a differential equation with
Scipy. The problem framed is the Newton's law of cooling:

    dT/dt = -k*T

where k is a positive constant that determines the rate of cooling. The
solution has the general form:

    T(t) = T0 * exp(-k*t)
"""
import numpy as np
import matplotlib.pyplot as plt

from scipy import integrate

# True solution
def true_solution(t):
    return 50*np.exp(-0.2*t)

# Define the general form of the differential equation (y -> T)
def f(t, y):
    return -0.2*y

# Time range
t_range = (0, 10)

# Initial temperature
T0 = np.array([50])

scipy_sol = integrate.solve_ivp(f, t_range, T0, max_step=0.1)

t_vals = scipy_sol.t
T_vals = scipy_sol.y[0, :]

fig, (ax1, ax2) = plt.subplots(1, 2, tight_layout=True)

ax1.plot(t_vals, T_vals)
ax1.set_xlabel("$t$", usetex=True)
ax1.set_ylabel("$T$", usetex=True)
ax1.set_title("Solution of the cooling equation")

err = np.abs(T_vals - true_solution(t_vals))
ax2.semilogy(t_vals, err)
ax2.set_xlabel("$t$", usetex=True)
ax2.set_ylabel("Error", usetex=True)
ax2.set_title("Error in approximation (RK4)")

plt.show()


import numpy as np

def __fact(window):
    """Computes the amplitude conpensation factor to apply to a FFT for the given window.
    Just equivalent to 1/RMS(window).

    Args:
       window ( iterable object):  The windows to analyse.

    Returns:
        float: The compensation factor.
    """
    return 1./np.sqrt(np.mean(np.square(window)))

def fft(waveform, sampling_frequency=1., window=None, remove_mean=True):
    """Compute the FFT of the given signal wf and return result in a fashion way.

    Args:
        wf ( iterable object):  The time domain signal on which you want to compute FFT.
        fs (Optional[float]): Sampling frequency of wf, used for frequency vector normalization.
        window ( Optional[iterable object]):  The window to apply.
        removeMean (Optional[bool]):  Set to True if you want to remove mean on signal befor
            computing FFT.

    Returns:
        dict: The FFT result simplified and stored in a dict. The FFT result is trucated from F=0 to
            F=Fs/2 and amplitude is normalized to its real value and in case of windowing, the
            window correction factor is applied.
            keys ( strings ):
                f ( numpy array of float ): Frequency vector normalized to given "fs" frequency
                mod ( numpy array of float ): Amplitude vector divided by len(wf) and corrected if a
                    window is applied.
                phi ( numpy array of float ): Phase vector.
    """
    scale_factor = 1./len(waveform)
    if remove_mean:
        waveform = waveform - np.mean(waveform)
    if not window is None:
        waveform = waveform*window
        scale_factor = scale_factor *__fact(window)
    spectrum = np.fft.fft(waveform) *scale_factor
    frequency = np.fft.fftfreq(len(spectrum), 1/sampling_frequency)
    frequency[int(len(frequency)/2)] = abs(frequency[int(len(frequency)/2)])
    return {"f":frequency[0:int(len(frequency)/2)+1],
            "mod":abs(spectrum[0:int(len(spectrum)/2)+1]),
            "phi":np.angle(spectrum[0:int(len(spectrum)/2)+1], False)}


# -*- coding: utf-8 -*-
"""
Euler discovered the remarkable quadratic formula:

n^2 + n + 41

It turns out that the formula will produce 40 primes for the consecutive values n = 0 to 39. However, when n = 40, 402 + 40 + 41 = 40(40 + 1) + 41 is divisible by 41, and certainly when n = 41, 41^2 + 41 + 41 is clearly divisible by 41.

The incredible formula  n^2 − 79n + 1601 was discovered, which produces 80 primes for the consecutive values n = 0 to 79. The product of the coefficients, −79 and 1601, is −126479.

Considering quadratics of the form:

n^2 + an + b, where |a| < 1000 and |b| < 1000

where |n| is the modulus/absolute value of n
e.g. |11| = 11 and |−4| = 4
Find the product of the coefficients, a and b, for the quadratic expression that produces the maximum number of primes for consecutive values of n, starting with n = 0.
"""
import numpy as np
from itertools import count
def primes_up_to(n):
    if n < 2:
        return np.zeros(n+1, dtype=bool)

    A = np.ones(n+1, dtype=bool)
    A[0] = A[1] = False
    for i in xrange(2, int(np.sqrt(n))+1):
        if A[i]:
            for j in xrange(i**2, n+1, i):
                A[j] = False
    return np.where(A)[0]

def isprime(n):
    """Returns True if n is prime."""
    if n < 2:
        return False
    if n == 2 or n == 3:
        return True
    if n % 2 == 0 or n % 3 == 0:
        return False
    i = 5
    w = 2
    while i * i <= n:
        if n % i == 0:
            return False
        i += w
        w = 6 - w
    return True

def prime_length(a, b):
    f = lambda n: n*n + a*n + b
    nprimes = 0
    for n in count():
        if isprime(f(n)):
            nprimes += 1
        else:
            break
    return nprimes

p = primes_up_to(1000)
prime_set = set(p)

best_a, best_b, best_length = 0, 0, 0
for b in p:
    a_set = p - b - 1
    for a in a_set:
        nprimes = prime_length(a, b)
        if nprimes > best_length:
            best_a, best_b, best_length = a, b, nprimes
print best_a, best_b, best_length
print best_a * best_b


import numpy as np

# Idea:
# 1) Draw a horizontal line to the right of each point and extend it to infinity

# 2) Count the number of times the line intersects with polygon edges.

# 3) A point is inside the polygon if either count of intersections is odd or
#    point lies on an edge of polygon.  If none of the conditions is true, then
#    point lies outside.

# Given three colinear points p, q, r, the function checks if
# point q lies on line segment 'pr'
def onSegment(p, q, r):
    if (q[0] <= max(p[0], r[0]) and q[0] >= min(p[0], r[0]) and q[1] <= max(p[1], r[1]) and q[1] >= min(p[1], r[1])):
        return True
    return False

# To find orientation of ordered triplet (p, q, r).
# The function returns following values
# 0 --> p, q and r are colinear
# 1 --> Clockwise
# 2 --> Counterclockwise
def orientation(p, q, r):
    val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1])

  	# colinear
    if (val == 0):
    	return 0

   	# clock or counterclock wise
    if (val > 0):
    	return 1
    else:
    	return 2

def is_intersect(p1, q1, p2, q2):
	# Find the four orientations needed for general and special cases
    o1 = orientation(p1, q1, p2)
    o2 = orientation(p1, q1, q2)
    o3 = orientation(p2, q2, p1)
    o4 = orientation(p2, q2, q1)

    # General case
    if (o1 != o2 and o3 != o4):
        return True

    # Special Cases
    # p1, q1 and p2 are colinear and p2 lies on segment p1q1
    if (o1 == 0 and onSegment(p1, p2, q1)):
    	return True

    # p1, q1 and p2 are colinear and q2 lies on segment p1q1
    if (o2 == 0 and onSegment(p1, q2, q1)):
    	return True

    # p2, q2 and p1 are colinear and p1 lies on segment p2q2
    if (o3 == 0 and onSegment(p2, p1, q2)):
    	return True

    # p2, q2 and q1 are colinear and q1 lies on segment p2q2
    if (o4 == 0 and onSegment(p2, q1, q2)):
    	return True

    return False # Doesn't fall in any of the above cases

def is_point_in_polygon(polygon, point):
	# Create a point for line segment from p to infinite
	extreme = [point[0], 1e9]

	# Count intersections of the above line with sides of polygon
	count = 0
	i = 0

	while True:
		j = (i+1) % len(polygon)

		# Check if the line segment from 'p' to 'extreme' intersects
        # with the line segment from 'polygon[i]' to 'polygon[j]'
		if is_intersect(polygon[i], polygon[j], point, extreme):
			# If the point 'p' is colinear with line segment 'i-j',
			# then check if it lies on segment. If it lies, return true,
			# otherwise false
			if orientation(polygon[i], point, polygon[j])==0:
				return onSegment(polygon[i], point, polygon[j])
			count = count + 1

		i = j
		if i==0:
			break

	return count % 2 == 1

# use this function to check if a bounding box is inside the polygon
def is_bounding_box_intersect(bounding_box, polygon):
	for i in range(len(bounding_box)):
		if is_point_in_polygon(polygon, bounding_box[i]):
			return True
	return False

def check_bbox_intersect_polygon(polygon, bbox):
	"""

	Args:
	polygon: List of points (x,y)
	bbox: A tuple (xmin, ymin, xmax, ymax)

	Returns:
	True if the bbox intersect the polygon
	"""
	x1, y1, x2, y2 = bbox
	bb = [(x1, y1), (x2, y1), (x2, y2), (x1, y2)]
	return is_bounding_box_intersect(bb, polygon)

def cosin_similarity(a2d, b2d, debug=False):
	a = np.array((a2d[1][0] - a2d[0][0], a2d[1][1] - a2d[0][1])).astype(float)
	b = np.array((b2d[1][0] - b2d[0][0], b2d[1][1] - b2d[0][1])).astype(float)
	tmp1 = np.dot(a, b)
	tmp2 = (np.linalg.norm(a)*np.linalg.norm(b*1.0))
	if debug:
		print(a, b, tmp1, tmp2)
	return tmp1/tmp2


# -*- coding: utf-8 -*-
"""
partial influence demonstrates the partial impact of base and exponents

Copyright (c) 2016 - RocketRedNeck.com RocketRedNeck.net

RocketRedNeck and MIT Licenses

RocketRedNeck hereby grants license for others to copy and modify this source code for
whatever purpose other's deem worthy as long as RocketRedNeck is given credit where
where credit is due and you leave RocketRedNeck out of it for all other nefarious purposes.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

import matplotlib.pyplot as plot
import numpy as np

def dfdb(B, E):
    """
    B is the base
    E is the exponent
    f = B^E
    partial df/dB = E * B**(E-1)
    """
    out = E * (B**(E-1))
    return out

def dfde(B, E):
    """
    B is the base
    E is the exponent
    f = B^E
    partial df/dE = B**(E) * ln(B)
    """
    out = (B**E) * np.log(B)
    return out

plot.figure(1)
plot.cla()
plot.grid()

x = 5
Bs = np.arange(-x,+x,0.5)     # Start, Stop, Step
Es = np.arange(-x,+x,0.5)

# For each E held constant
for E in Es:
    plot.plot(Bs,dfdb(Bs,E))

plot.figure(2)
plot.cla()
plot.grid()

# For each B help constant
for B in Bs:
    plot.plot(Es,dfde(B,Es))

plot.show()


from __future__ import division
from scipy.stats import triang
from scipy.stats import norm
from scipy.stats import uniform
from sklearn import preprocessing

from cea.utilities import latin_hypercube
import pandas as pd
import numpy as np
import numpy.ma as ma

__author__ = "Jimeno A. Fonseca"
__copyright__ = "Copyright 2017, Architecture and Building Systems - ETH Zurich"
__credits__ = ["Jimeno A. Fonseca"]
__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "Daren Thomas"
__email__ = "cea@arch.ethz.ch"
__status__ = "Production"

def latin_sampler(locator, num_samples, variables, region):
    """
    This script creates a matrix of m x n samples using the latin hypercube sampler.
    for this, it uses the database of probability distribtutions stored in locator.get_uncertainty_db()
    it returns clean and normalized samples.

    :param locator: pointer to locator of files of CEA
    :param num_samples: number of samples to do
    :param variables: list of variables to sample
    :return:
        1. design: a matrix m x n with the samples where each feature is normalized from [0,1]
        2. design_norm: a matrix m x n with the samples where each feature is normalized from [0,1]
        3. pdf_list: a dataframe with properties of the probability density functions used in the exercise.

    """

    # get probability density function PDF of variables of interest
    variable_groups = ('ENVELOPE', 'INDOOR_COMFORT', 'INTERNAL_LOADS','SYSTEMS')
    database = pd.concat([pd.read_excel(locator.get_uncertainty_db(region), group, axis=1)
                          for group in variable_groups])
    pdf_list = database[database['name'].isin(variables)].set_index('name')

    # get number of variables
    num_vars = pdf_list.shape[0]  # alternatively use len(variables)

    # get design of experiments
    samples = latin_hypercube.lhs(num_vars, samples=num_samples, criterion='maximin')
    for i, variable in enumerate(variables):

        distribution = pdf_list.loc[variable, 'distribution']
        #sampling into lhs
        min = pdf_list.loc[variable, 'min']
        max = pdf_list.loc[variable, 'max']
        mu = pdf_list.loc[variable, 'mu']
        stdv = pdf_list.loc[variable, 'stdv']
        if distribution == 'triangular':
            loc = min
            scale = max - min
            c = (mu - min) / (max - min)
            samples[:, i] = triang(loc=loc, c=c, scale=scale).ppf(samples[:, i])
        elif distribution == 'normal':
            samples[:, i] = norm(loc=mu, scale=stdv).ppf(samples[:, i])
        elif distribution == 'boolean': # converts a uniform (0-1) into True/False
            samples[:, i] = ma.make_mask(np.rint(uniform(loc=min, scale=max).ppf(samples[:, i])))
        else:  # assume it is uniform
            samples[:, i] = uniform(loc=min, scale=max).ppf(samples[:, i])

    min_max_scaler = preprocessing.MinMaxScaler(copy=True, feature_range=(0, 1))
    samples_norm = min_max_scaler.fit_transform(samples)

    return samples, samples_norm, pdf_list


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

def rbf_kernel_pca(X, gamma, n_components):
    """
    RBF kernel PCA implementation.

    Parameters
    ------------
    X: {NumPy ndarray}, shape = [n_samples, n_features]

    gamma: float
      Tuning parameter of the RBF kernel

    n_components: int
      Number of principal components to return

    Returns
    ------------
     X_pc: {NumPy ndarray}, shape = [n_samples, k_features]
       Projected dataset

    """
    # Calculate pairwise squared Euclidean distances
    # in the MxN dimensional dataset.
    sq_dists = pdist(X, 'sqeuclidean')

    # Convert pairwise distances into a square matrix.
    mat_sq_dists = squareform(sq_dists)

    # Compute the symmetric kernel matrix.
    K = exp(-gamma * mat_sq_dists)

    # Center the kernel matrix.
    N = K.shape[0]
    one_n = np.ones((N, N)) / N
    K = K - one_n.dot(K) - K.dot(one_n) + one_n.dot(K).dot(one_n)

    # Obtaining eigenpairs from the centered kernel matrix
    # numpy.eigh returns them in sorted order
    eigvals, eigvecs = eigh(K)
    print(np.sqrt(eigvals[-1]))
    print(np.sqrt(eigvals[-2]))

    # Collect the top k eigenvectors (projected samples)
    #X_pc = np.column_stack((eigvecs[:, -i]
    #                        for i in range(1, n_components + 1)))

    # scikit-learnの結果と比べてみても, たぶんこれが正しい気がする
    # ただ結局各成分にスケール因子が入るだけなので、
    # 学習という意味ではどちらでも良いのかもしれない
    X_pc = np.column_stack((np.sqrt(eigvals[-i]) * eigvecs[:, -i]
                            for i in range(1, n_components + 1)))

    # PCA固有ベクトルvをデータサンプルに直すには X v とする必要がある
    # ここで正規化された特異ベクトルの間の関係を使う。
    #   X v_i = sigma_i a_i      (sigma_i = sqrt(lambda_i))
    # よって sqrt(lambda_i) a_i で主成分方向に基底変換したデータサンプルになる。

    return X_pc

##
# 本文の後で出てくるバージョン
# 計算は一緒で返すものが違うだけ
# 固有値と固有ベクトルを返す
#
def rbf_kernel_pca2(X, gamma, n_components):
    """
    RBF kernel PCA implementation.

    Parameters
    ------------
    X: {NumPy ndarray}, shape = [n_samples, n_features]

    gamma: float
      Tuning parameter of the RBF kernel

    n_components: int
      Number of principal components to return

    Returns
    ------------
     X_pc: {NumPy ndarray}, shape = [n_samples, k_features]
       Projected dataset

     lambdas: list
       Eigenvalues

    """
    # Calculate pairwise squared Euclidean distances
    # in the MxN dimensional dataset.
    sq_dists = pdist(X, 'sqeuclidean')

    # Convert pairwise distances into a square matrix.
    mat_sq_dists = squareform(sq_dists)

    # Compute the symmetric kernel matrix.
    K = exp(-gamma * mat_sq_dists)

    # Center the kernel matrix.
    N = K.shape[0]
    one_n = np.ones((N, N)) / N
    K = K - one_n.dot(K) - K.dot(one_n) + one_n.dot(K).dot(one_n)

    # Obtaining eigenpairs from the centered kernel matrix
    # numpy.eigh returns them in sorted order
    eigvals, eigvecs = eigh(K)

    # Collect the top k eigenvectors (projected samples)
    alphas = np.column_stack((eigvecs[:, -i]
                              for i in range(1, n_components + 1)))

    # Collect the corresponding eigenvalues
    lambdas = [eigvals[-i] for i in range(1, n_components + 1)]

    return alphas, lambdas

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

##
# カーネルを線形にしてみた
# test_kpca.py で使う
#
def linear_kernel_pca(X, n_components):
    """
    RBF kernel PCA implementation.

    Parameters
    ------------
    X: {NumPy ndarray}, shape = [n_samples, n_features]

    gamma: float
      Tuning parameter of the RBF kernel

    n_components: int
      Number of principal components to return

    Returns
    ------------
     X_pc: {NumPy ndarray}, shape = [n_samples, k_features]
       Projected dataset

    """
    # 線形カーネル関数は内積(x_i, x_j)とする
    N = X.shape[0]
    K = np.ones((N, N))
    for i in range(N):
        for j in range(N):
            K[i, j] = np.dot(X[i, :], X[j, :])
    print(K.shape)

    # Center the kernel matrix.
    N = K.shape[0]
    one_n = np.ones((N, N)) / N
    K = K - one_n.dot(K) - K.dot(one_n) + one_n.dot(K).dot(one_n)

    # Obtaining eigenpairs from the centered kernel matrix
    # numpy.eigh returns them in sorted order
    eigvals, eigvecs = eigh(K)
    print(np.sqrt(eigvals[-1]))
    print(np.sqrt(eigvals[-2]))

    # Collect the top k eigenvectors (projected samples)
    #X_pc = np.column_stack((eigvecs[:, -i]
    #                        for i in range(1, n_components + 1)))

    # scikit-learnの結果と比べてみても, たぶんこれが正しい気がする
    # ただ結局各成分にスケール因子が入るだけなので、
    # 学習という意味ではどちらでも良いのかもしれない
    X_pc = np.column_stack((np.sqrt(eigvals[-i]) * eigvecs[:, -i]
                            for i in range(1, n_components + 1)))

    # PCA固有ベクトルvをデータサンプルに直すには X v とする必要がある
    # ここで正規化された特異ベクトルの間の関係を使う。
    #   X v_i = sigma_i a_i      (sigma_i = sqrt(lambda_i))
    # よって sqrt(lambda_i) a_i で主成分方向に基底変換したデータサンプルになる。

    return X_pc


'''
Dada a função f(x)=A.sen(x)/x

onde A = 10. Calcule \int_0^\pi f(x) dx

    1. Use o método de tentativa e erro
    2. Use o método de amostragem média
'''
import numpy as np
import matplotlib.pyplot as plt
import random as rand

def montecarlotnterr(fx, sup, inf, esq, dir, n):
    xs = list(rand.uniform(esq, dir) for i in range(n))
    ys = list(rand.uniform(inf, sup) for i in range(n))
    ni = 0
    for x, y in zip(xs, ys):
        if y <= fx(x):
            ni += 1
    return (ni/n)*((dir-esq)*(sup-inf))

def montecarlomed(fx, esq, dir, n):
    xs = np.array(list(rand.uniform(esq, dir) for i in range(n)))
    ym = sum(fx(xs))/n
    return (dir - esq) * ym

a = 10
n = 1000
fx = lambda x: a * np.sin(x)/x

# Atividade
print('Integração por Monte Carlo')
print(f'N = {n}')
print(f'Tentativa e Erro = {montecarlotnterr(fx, 10, 0, 0, np.pi, n)}')
print(f'Amostragem Média = {montecarlomed(fx, 0, np.pi, n)}')

ns = np.arange(1, n)
itent = []
imed = []
for i in ns:
    itent.append(montecarlotnterr(fx, 10, 0, 0, np.pi, i))
    imed.append(montecarlomed(fx, 0, np.pi, i))

plt.plot(ns, itent, label='Tentativa e Erro')
plt.plot(ns, imed, label='Amostragem Média')
plt.xlabel('N')
plt.ylabel('Integral')
plt.legend()
plt.grid()
plt.savefig("funcaomontecarlo.png")