import numpy as np
from scipy.special.basic import factorial

class ZernikeGenerator(object):

    def __init__(self, nPixelOnDiameter):
        self._nPixel = nPixelOnDiameter
        self._rhoMap, self._thetaMap = self._polar_array(self._nPixel)
        self._dx = None
        self._dy = None
        self._dictCache = {}
        self._dictDxCache = {}
        self._dictDyCache = {}

    def getRadius(self):
        return self._nPixel / 2.

    def _derivativeCoeffX(self, index):
        if (self._dx is None) or (self._dx.shape[0] < index):
            self._dx = self._computeDerivativeCoeffX(index)
        return self._dx[0:index, 0:index]

    def _derivativeCoeffY(self, index):
        if (self._dy is None) or (self._dy.shape[0] < index):
            self._dy = self._computeDerivativeCoeffY(index)
        return self._dy[0:index, 0:index]

    @staticmethod
    def degree(index):
        n = int(0.5 * (np.sqrt(8 * index - 7) - 3)) + 1
        cn = n * (n + 1) / 2 + 1
        if n % 2 == 0:
            m = int(index - cn + 1) // 2 * 2
        else:
            m = int(index - cn) // 2 * 2 + 1
        radialDegree = n
        azimuthalFrequency = m
        return radialDegree, azimuthalFrequency

    def _rnm(self, radialDegree, azimuthalFrequency, rhoArray):
        n = radialDegree
        m = azimuthalFrequency
        rho = rhoArray
        if (n - m) % 2 != 0:
            raise Exception("n-m must be even. Got %d-%d" % (n, m))
        if abs(m) > n:
            raise Exception("The following must be true |m|<=n. Got %d, %d" %
                            (n, m))
        mask = np.where(rho <= 1, False, True)

        if(n == 0 and m == 0):
            return np.ma.masked_array(data=np.ones(rho.shape), mask=mask)
        rho = np.where(rho < 0, 0, rho)
        Rnm = np.zeros(rho.shape)
        S = (n - abs(m)) // 2
        for s in range(0, S + 1):
            CR = pow(-1, s) * factorial(n - s) / \
                (factorial(s) * factorial(-s + (n + abs(m)) / 2) *
                 factorial(-s + (n - abs(m)) / 2))
            p = CR * pow(rho, n - 2 * s)
            Rnm = Rnm + p
        return np.ma.masked_array(data=Rnm, mask=mask)

    def _polar(self, index, rhoArray, thetaArray):
        n, m = ZernikeGenerator.degree(index)
        rho = rhoArray
        theta = thetaArray

        Rnm = self._rnm(n, m, rho)
        NC = np.sqrt(2 * (n + 1))
        if m == 0:
            return np.sqrt(0.5) * NC * Rnm
        if index % 2 == 0:
            return NC * Rnm * np.cos(m * theta)
        else:
            return NC * Rnm * np.sin(m * theta)

    def _polar_array(self, nPixel):
        X, Y = np.mgrid[-1 + 1. / nPixel: 1 - 1. / nPixel: nPixel * 1j,
                        -1 + 1. / nPixel: 1 - 1. / nPixel: nPixel * 1j]
        r = np.sqrt(X ** 2 + Y ** 2)
        th = np.arccos(np.transpose(X * 1. / r))
        th = np.where(th < 2. * np.pi, th, 0)
        th = np.where(X < 0, 2. * np.pi - th, th)
        return r, th

    def getZernikeDict(self, indexVector):
        ret = {}
        for index in indexVector:
            ret[index] = self.getZernike(index)
        return ret

    def getZernike(self, index):
        if index not in list(self._dictCache.keys()):
            self._dictCache[index] = self._polar(index, self._rhoMap,
                                                 self._thetaMap)
        return self._dictCache[index]

    def __getitem__(self, index):
        return self.getZernike(index)

    def _computeDerivativeCoeffX(self, index):
        jmax = index
        G_mat = np.zeros((jmax, jmax))
        for i in range(1, jmax + 1):
            for j in range(1, jmax + 1):
                ni, mi = ZernikeGenerator.degree(i)
                nj, mj = ZernikeGenerator.degree(j)
                if (
                    (
                        (
                            (
                                mi != 0 and mj != 0
                            ) and (
                                (
                                    _isEven(i) and _isEven(j)
                                ) or (
                                    _isOdd(i) and _isOdd(j)
                                )
                            )
                        ) or (
                            (
                                (mi == 0) and _isEven(j)
                            ) or (
                                (mj == 0) and _isEven(i)
                            )
                        )
                    ) and (
                        (mj == mi + 1) or (mj == mi - 1)
                    ) and (
                        j < i
                    )
                ):
                    G_mat[i - 1, j - 1] = np.sqrt((ni + 1) * (nj + 1))
                    if ((mi == 0) or (mj == 0)):
                        G_mat[i - 1, j - 1] *= np.sqrt(2)
        return G_mat

    def _computeDerivativeCoeffY(self, index):
        jmax = index
        G_mat = np.zeros((jmax, jmax))
        for i in range(1, jmax + 1):
            for j in range(1, jmax + 1):
                ni, mi = ZernikeGenerator.degree(i)
                nj, mj = ZernikeGenerator.degree(j)
                if (
                    (
                        (
                            (
                                mi != 0 and mj != 0
                            ) and (
                                (
                                    _isOdd(i) and _isEven(j)
                                ) or (
                                    _isEven(i) and _isOdd(j)
                                )
                            )
                        ) or (
                            (
                                (mi == 0) and _isOdd(j)
                            ) or (
                                (mj == 0) and _isOdd(i)
                            )
                        )
                    ) and (
                        (mj == mi + 1) or (mj == mi - 1)
                    ) and (
                        j < i
                    )
                ):
                    G_mat[i - 1, j - 1] = np.sqrt((ni + 1) * (nj + 1))
                    if ((mi == 0) or (mj == 0)):
                        G_mat[i - 1, j - 1] *= np.sqrt(2)
                    if (
                        (
                            (
                                (mj == mi + 1) and _isOdd(i)
                            ) or (
                                (mj == mi - 1) and _isEven(i)
                            )
                        ) and (
                            mi != 0
                        )
                    ):
                        G_mat[i - 1, j - 1] *= -1

        return G_mat

    def getDerivativeXDict(self, indexVector):
        ret = {}
        for index in indexVector:
            ret[index] = self.getDerivativeX(index)
        return ret

    def getDerivativeYDict(self, indexVector):
        ret = {}
        for index in indexVector:
            ret[index] = self.getDerivativeY(index)
        return ret

    def getDerivativeX(self, index):
        if index not in self._dictDxCache:
            self._dictDxCache[index] = self._computeDerivativeX(index)
        return self._dictDxCache[index]

    def _computeDerivativeX(self, index):
        coeffX = self._derivativeCoeffX(index)
        dx = self.getZernike(1) * 0.
        for i in range(1, index):
            dx += coeffX[index - 1, i - 1] * self.getZernike(i)
        return dx

    def getDerivativeY(self, index):
        if index not in self._dictDyCache:
            self._dictDyCache[index] = self._computeDerivativeY(index)
        return self._dictDyCache[index]

    def _computeDerivativeY(self, index):
        coeffY = self._derivativeCoeffY(index)
        dy = self.getZernike(1) * 0.
        for i in range(1, index):
            dy += coeffY[index - 1, i - 1] * self.getZernike(i)
        return dy

    @staticmethod
    def radialOrder(j):
        return np.ceil(0.5 * (np.sqrt(8 * j + 1) - 3))

def _isOdd(num):
    return num % 2 != 0

def _isEven(num):
    return num % 2 == 0


import numpy as np

def garch_filter(beta, gamma, v_r, mu, sigma2_inf, sigma2_0):
    '''
    input:
    beta, gamma: garch(1,1) beta & gamma
    v_r: historical return
    mu: drift
    sigma2_inf: sigma_inf squared squared
    sigma2_0: the initial sigma squared

    output: dictionary of
    eps: vector of residuals
    sigma2: vector of sigma squared
    sigma2_next: next sigma squared
    '''

    alpha = sigma2_inf * (1 - beta - gamma)
    v_eps = np.ones_like(v_r)
    v_sigma2 = np.ones_like(v_r)

    sigma2_nxt = sigma2_0

    for n in range(len(v_r)):
        v_sigma2[n] = sigma2_nxt
        v_eps[n] = (v_r[n] - mu)/np.sqrt(sigma2_nxt)
        sigma2_nxt = alpha + beta * v_sigma2[n] + gamma * v_sigma2[n] * (v_eps[n]**2)

    return {'eps':v_eps, 'sigma2':v_sigma2, 'sigma2_next':sigma2_nxt}

def garch_return_simulation(beta, gamma, mu, sigma2_inf, sigma2_0, v_eps):

    v_r = np.zeros_like(v_eps)
    v_sigma2 = np.zeros_like(v_eps)

    sigma2_t = sigma2_0

    a = sigma2_inf * (1.0 - beta - gamma)
    for t in range(v_eps.size):
        eps = v_eps[t]
        v_r[t] = mu + np.sqrt(sigma2_t) * eps
        v_sigma2[t] = sigma2_t
        sigma2_t = a + beta * sigma2_t + gamma * sigma2_t * (eps**2)
    return {'r':v_r, 'sigma2': v_sigma2 }

def garch_mle_obj(v_r, mu, v_sigma2):
    return - np.sum(np.log(v_sigma2) + (v_r-mu)**2/v_sigma2)

def garch_exp_variance(sigma2_1, sigma2_inf, beta, gamma, v_t):
    return sigma2_inf + (1.0 - (beta+gamma)**v_t)/(1-(beta+gamma)) * (sigma2_1 - sigma2_inf)/v_t


#dualMat(mts)           :   Takes list of matrices, computes their dual.

import numpy as np

__all__ = ['dualMat']

def dualMat(mts, lid = False):
    r"""Takes as input a list of matrices, an optional argument stating if
        the matrices are linearly independent and returns a list of matrices
        dual (under Frobenius Norm) to the input list of matrices

    Parameters
    ----------
    mts : list of numpy.ndarrays
          A list of matrices

    lid : bool
          Optional, False by default. If True assumes matrices are
          linearly independent

    Returns
    ----------
    mts : list of numpy.ndarrays
          The dual matrices(under Frobenius Norm) to the set of input matrices.
          If matrices are linearly independent, it uses regular inverse
          otherwise uses(less numerically accurate) pseudo-inverse.
    """
    vc = []
    #Each matrix is a ket, place it as a bra making a row of vecRows matrix
    for mt in mts:
        (d,d) = mt.shape
        vcR = np.ndarray.flatten(mt).conj()
        vc += [np.array([vcR])]
    vecRows =  np.vstack(vc)
    #Construct matrix with dual vectors as its columns
    if lid:
        try:
            dualVecCols = np.linalg.inv(vecRows)
        except:
            raise Exception('Cannot find dual matrices')
    else:
        try:
            dualVecCols = np.linalg.pinv(vecRows)
        except:
            raise Exception('Cannot find dual matrices')

    (row, col) = dualVecCols.shape
    mts = []
    #Reshape the columns as matrices of same size as input
    for i in xrange(col):
        mt = dualVecCols[:,i].reshape(d,d)
        mts += [zerOut(mt, tol = 1e-15)]
    return mts


import matplotlib.pyplot as plt
import numpy as np
from Exercise1.newton_raphson import newton_raphson
from Exercise1.bisection import bisection
from Exercise1.secant import secant
from Exercise1.mult_newton_raphson import mult_newton_raphson
from Exercise1.iterations_comparison import bisection_iterations, newton_iterations, secant_iterations

def g(x):
    return np.e ** ((np.sin(x)) ** 3) + x ** 6 - 2 * (x ** 4) - x ** 3 - 1

def gprime(x):
    return 3 * (np.e ** ((np.sin(x)) ** 3)) * ((np.sin(x)) ** 2) * np.cos(x) + 6 * (x ** 5) - 8 * (x ** 3) - 3 * (
           x ** 2)

def g_second_der(x):
    # return 3 * np.cos(x) * (216 * np.cos(x) ** 2 - 432 * np.cos(x)) * np.sin(x) ** 2 + np.sin(x) * (
    #        576 * np.cos(x) ** 3 * np.sin(x) + 564 * np.cos(x) * np.sin(x)
    #        - 354 * np.sin(x)) + np.sin(x) ** 3 * (432 * np.sin(x) - 432 * np.cos(x) * np.sin(x)) \
    #       + np.cos(x) * (-144 * np.cos(x) ** 4 - 282 * np.cos(x) ** 2 + 354 * np.cos(x) + 24)
    h = 0.001
    return (gprime(x + h) - gprime(x)) / h

def main():
    # sub question a
    print("Bisection")

    root, iterations = bisection(g, -1.5, -1.0)
    print("root = "+str(root))
    print("iterations ="+str(iterations))

    root, iterations = bisection(g, 1.25, 1.75)
    print("root = "+str(root))
    print("iterations ="+str(iterations))

    root, iterations = bisection(g, -0.05, 0.05)
    print("root = "+str(root))
    print("iterations ="+str(iterations))

    root, iterations = bisection(g, -0.5, 0.5)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    root, iterations = bisection(g, 0, 1)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    root, iterations = bisection(g, -1.5, 1.5)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    print()
    print("Newton-Raphson")

    root, iterations = newton_raphson(g, gprime, -1.4)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    root, iterations = newton_raphson(g, gprime, 1.7)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    root, iterations = newton_raphson(g, gprime, 0.25)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    root, iterations = newton_raphson(g, gprime, 0.5)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    root, iterations = newton_raphson(g, gprime, -0.25)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    root, iterations = newton_raphson(g, gprime, -0.5)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    root, iterations = newton_raphson(g, gprime, 0)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    print()
    print("Secant")

    root, iterations = secant(g, -1.5, -1.0)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    root, iterations = secant(g, 1.3, 1.9)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    root, iterations = secant(g, -0.25, 0.25)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    root, iterations = secant(g, -0.5, 0.5)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

    root, iterations = secant(g, 0, 1.5)
    print("root = " + str(root))
    print("iterations =" + str(iterations))

main()


"""CPIE helper functions
"""

import numpy as np

def mean_and_covariance(solutions):
    """Calculate mean vector and covariance matrix of the solutions
    Arguments:
        solutions {list of Solution} -- target
    Returns:
        (numpy array, numpy matrix) -- Mean vector and covariance matrix
    """
    sol_size = len(solutions)
    dimension = solutions[0].x.size
    # calc mean
    mu = sum(s.x for s in solutions) / len(solutions)
    #calc variance
    variance = np.zeros((dimension, dimension))
    for s in solutions:
        diff = s.x - mu
        variance += np.outer(diff, diff)
    variance /= sol_size
    return mu, variance

# ToDo Speed up with numpy
def k_means_mahalanobis(solutions, k=2, max_iter=100):
    """k-means clustering with mahalanobis distance.
    Arguments:
        solutions {list of Solution} -- Clustering target
    Keyword Arguments:
        k {int} -- Number of division (default: {2})
        max_iter {int} -- Max inner iteration (default: {100})
    Returns:
        list of (list of Solution) -- k clustered solutions
    """
    assert k <= len(solutions), "k should be less than or equarl to len(solutions)"
    seed_bases = np.random.choice(solutions, size=k, replace=False)
    seeds = [s.x.copy() for s in seed_bases]
    dimension = seeds[0].size
    BInvs = [np.eye(dimension) for i in range(k)]
    class_indices = [0] * len(solutions)
    for t in range(max_iter):
        is_changed = False
        classes = [[] for i in range(k)]
        # classify solutions
        for i, s in enumerate(solutions):
            distances = [np.linalg.norm(np.dot(BInv, s.x - seed))
                         for seed, BInv in zip(seeds, BInvs)]
            class_index = np.argmin(distances)
            if class_index != class_indices[i]:
                is_changed = True
            class_indices[i] = class_index
            classes[class_index].append(s)
        if not is_changed or t == max_iter - 1:
            break
        # update
        for i, c in enumerate(classes):
            if len(c) == 0:
                seeds[i] = np.zeros(dimension)
                BInvs[i] = np.eye(dimension)
            elif len(c) <= dimension:
                seeds[i] = sum(s.x for s in c) / len(c)
                BInvs[i] = np.eye(dimension)
            else:
                seeds[i], covariance = mean_and_covariance(c)
                BInvs[i] = np.linalg.inv(np.linalg.cholesky(covariance))
    return classes


import numpy as np
from scripts.helpers import sigmoid

def compute_mse(y, tx, w):
    """Function to compute mean square error (MSE).
    Args:
        y  (numpy array): Matrix output of size N x 1.
        tx (numpy array): Matrix input of size N x D.
        w  (numpy array): Matrix weight (parameters of the model) of size D x 1.
    Returns:
        mse (float, scalar) : The mean square error (MSE) for given model w.
    """

    value_error = y - tx.dot(w)
    mse         = np.inner(value_error, value_error)/(2 * y.shape[0])
    return mse

def compute_rmse(y, tx, w):
    """Function to compute root mean square error (RMSE).
    Args:
        y  (numpy array): Matrix output of size N x 1.
        tx (numpy array): Matrix input of size N x D.
        w  (numpy array): Matrix weight (parameters of the model) of size D x 1.
    Returns:
        rmse (float, scalar) : The root mean square error (RMSE) for given model w.
    """

    rmse = np.sqrt(2*compute_mse(y, tx, w))
    return rmse

def compute_loss_logistic(y, tx, w):
    """Function to compute cost of logistic regression by negative log likelihood.
    Args:
        y  (numpy array): Matrix output of size N x 1.
        tx (numpy array): Matrix input of size N x D.
        w  (numpy array): Matrix weight (parameters of the model) of size D x 1.
    Returns:
        loss (float, scalar) : The loss/cost value of logistic regression for given model w.
    """

    y_hat = sigmoid(tx.dot(w))
    loss  = (np.transpose(y)).dot(np.log(y_hat + 1e-5)) + (np.transpose(1 - y)).dot(np.log(1 - (y_hat - 1e-5)))
    loss  = np.squeeze(- loss)
    return loss

def compute_loss_logistic_regularized(y, tx, w, lambda_):
    """Function to compute cost of regularized logistic regression by negative log likelihood.
    Args:
        y       (numpy array): Matrix output of size N x 1.
        tx      (numpy array): Matrix input of size N x D.
        w       (numpy array): Matrix weight (parameters of the model) of size D x 1.
        lambda_ (float)      : Penalty constant.
    Returns:
        loss (float, scalar) : The loss/cost value of regularized logistic regression for given model w.
    """

    y_hat            = sigmoid(tx.dot(w))
    loss             = (np.transpose(y)).dot(np.log(y_hat + 1e-5)) + (np.transpose(1 - y)).dot(np.log(1 - (y_hat - 1e-5)))
    regularized_loss = loss - (lambda_ * np.inner(w, w))
    final_loss       = np.squeeze(- regularized_loss)
    return final_loss


import math

import numpy as np

def bisezione(f, a, b, tol):
    """
    Algoritmo di Bisezione per il calcolo dello zero di una funzione.

    :param f: la funzione di cui calcolare lo zero
    :param a: il valore minimo dell'intervallo
    :param b: il valore massimo dell'intervallo
    :param tol: la tollerenza
    :return: (zero della funzione, numero di iterazioni, iterazioni)
    """

    def sign(value):
        return math.copysign(1, value)

    fa, fb, x = f(a), f(b), None

    if sign(fa) == sign(fb):
        print("sign(fa) == sign(fb) => Non applicabile")
        return None, 0, []

    max_iterazioni = int(math.ceil(math.log2((b - a) / tol)))
    it, xk = 0, []
    while it < max_iterazioni and abs(b - a) >= tol + np.spacing(1) * max(abs(a), abs(b)):
        x = a + (b - a) / 2  # Calcolo il punto medio
        xk.append(x)
        fx = f(x)
        if sign(fx) == sign(fa):
            a, fa = x, fx
        else:
            b, fb = x, fx
        it += 1
    return x, it, xk


import numpy as np
from math import sqrt, floor
from scipy.special import eval_genlaguerre

def gaussian_laguerre(p, l, mode_field_diameter=1, grid=None):
	r'''Creates a Gaussian-Hermite mode.

	This function evaluates a (p,l) order Gaussian-Laguerre mode on a grid.
	The definition of the modes are the following,

	.. math::
		\exp{\left(-\frac{r^2}{w_0^2}\right)} L_p^{|l|}\left(\frac{2r^2}{w_0^2} \right) \left(\sqrt{2}\frac{r}{w_0}\right)

	Here :math:`w_0` is the mode_field_radius, which is :math:`\mathrm{MFD}/2`.
	And :math:`L_p^{|l|}` are the generalized Laguerre Polynomials.
	All modes are numerical normalized to have a total power of 1.

	More details on generalized Laguerre Polynomials can be found on:
	http://mathworld.wolfram.com/AssociatedLaguerrePolynomial.html

	Parameters
	----------
	p : int
		The radial order.
	l : int
		The azimuthal order.
	mode_field_diameter : scalar
		The mode field diameter of the mode.
	grid : Grid
		The grid on which to evaluate the mode.

	Returns
	-------
	Field
		The evaluated mode.
	'''
	from ..field import Field

	if grid.is_separated and grid.is_('polar'):
		R, Theta = grid.separated_coords
	else:
		R, Theta = grid.as_('polar').coords

	# Easy access
	r = 2*R/mode_field_diameter
	r2 = r**2
	# The mode
	lg = (r*sqrt(2))**(abs(l)) * np.exp(-r2) * np.exp(-1j*l*Theta) * eval_genlaguerre(p, abs(l), 2*r2)
	# Numerically normalize the modes
	lg /= np.sum(np.abs(lg)**2 * grid.weights)

	return Field(lg, grid)

# High level functions
def make_gaussian_laguerre_basis(grid, pmax, lmax, mode_field_diameter, pmin=0):
	'''Creates a Gaussian-Laguerre mode basis.

	This function evaluates Gaussian-Laguerre modes. For each radial order
	within [pmin, pmax] it will calculate the azimuthal order [-lmax, lmax] inclusive.
	This function returns a ModeBasis made out of these Gaussian-Laguerre modes.

	Parameters
	----------
	grid : Grid
		The grid on which to evaluate the Gaussian-Laguerre mode.
	pmax : int
		The maximum radial order of the modes.
	lmax : int
		The maximum azimuthal order.
	mode_field_diameter : scalar
		The mode field diameter of the Gaussian-Laguerre mode.
	pmin : int
		The minimal radial order.

	Returns
	-------
	ModeBasis
		The Gaussian-Laguerre modes.
	'''
	from .mode_basis import ModeBasis

	modes = [gaussian_laguerre(pi, li, mode_field_diameter, grid) for li in range(-lmax, lmax + 1) for pi in range(pmin, pmax)]
	return ModeBasis(modes)


from mpl_toolkits.mplot3d import Axes3D  # noqa: F401 unused import
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
from single_var_gradient_decent import LinearRegressionUsingGD

def plot_result(x, y, y_predicted):
    plt.subplots(1, 1)

    # Actual data points
    plt.scatter(x, y, s=10)
    plt.xlabel('\u03B80')
    plt.ylabel('\u03B81')

    # Predicted data points
    plt.plot(x, y_predicted, color='r')
    plt.show()

def plot_cost_function_2d(theta_1, theta_2, cost):
    fig, ax = plt.subplots(1, 1)
    ax.contourf(theta_1,
                theta_2,
                cost,
                levels=[0, 1, 2, 4, 6, 8, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
                cmap=cm.coolwarm,
                antialiased=True)

    plt.xlabel('\u03B81')
    plt.ylabel('\u03B82')
    plt.show()

def plot_cost_function_3d(theta_1, theta_2, cost):
    fig = plt.figure()
    ax = fig.gca(projection='3d')
    ax.plot_surface(theta_1,
                    theta_2,
                    cost,
                    cmap=cm.coolwarm,
                    linewidth=0, antialiased=True, )

    plt.xlabel('\u03B80')
    plt.ylabel('\u03B81')
    ax.set_zlabel('J(\u03B80, \u03B81)')
    ax.set_zlim(0, 25)
    plt.show()

def get_cost_function(theta_1, theta_2, x, y, points_n):
    m = theta_1.shape[0]
    cost = np.zeros([theta_1.shape[0], theta_1.shape[1]])
    for i in range(points_n):
        residuals = ((theta_1 * x[i] + theta_2) - y[i]) ** 2
        cost += residuals
    cost = cost / (2 * m)
    return cost

def create_mesh_grid():
    theta_1 = np.arange(-10, 14, 0.05)
    theta_2 = np.arange(-100, 100, 0.05)
    theta_1, theta_2 = np.meshgrid(theta_1, theta_2)
    return theta_1, theta_2

def plot_cost_function(x, y, points_n):
    theta_1, theta_2, = create_mesh_grid()
    cost = get_cost_function(theta_1, theta_2, x, y, points_n)
    plot_cost_function_3d(theta_1, theta_2, cost)
    plot_cost_function_2d(theta_1, theta_2, cost)

def plot_raw_data(x, y):
    plt.scatter(x, y, s=10)
    plt.xlabel('\u03B80')
    plt.ylabel('\u03B81')
    plt.show()

def create_data(points_n):
    x = np.random.rand(points_n, 1) * 20
    y = (2 * (x + (2 * np.random.rand(points_n, 1)))) + 1
    return x, y

def main():
    points_n = 50
    x, y = create_data(points_n)

    plot_raw_data(x, y)
    plot_cost_function(x, y, points_n)

    # Model initialization
    # Sci-kit learn implementation:
    # regression_model = LinearRegression()
    regression_model = LinearRegressionUsingGD()

    # Fit the data(train the model)
    regression_model.fit(x, y)

    # Predict
    y_predicted = regression_model.predict(x)

    # model evaluation
    rmse = mean_squared_error(y, y_predicted)
    r2 = r2_score(y, y_predicted)

    # For sci-kit learn implementation:
    # print('Slope:', regression_model.coef_)
    # print('Intercept:', regression_model.intercept_)
    print('Slope:', regression_model.w)
    print('Intercept:', regression_model.b)
    print('Root mean squared error: ', rmse)
    print('R2 score: ', r2)

    # plot
    plot_result(x, y, y_predicted)

if __name__ == '__main__':
    main()


'''
Defines function `calc_periodic_kernel`

Examples
--------

'''

import numpy as np

def calc_periodic_kernel(x_QF, x_train_NF=None, length_scale=1.0, period=1.0):
    ''' Evaluate periodic kernel to produce matrix between two datasets.

    Will compute the kernel function for all possible pairs of feature vectors,
    one from the query dataset, one from the reference training dataset.

    Args
    ----
    x_QF : 2D numpy array, shape (Q, F) = (n_query_examples, n_features)
        Feature array for *query* dataset
        Each row corresponds to the feature vector on example

    x_train_NF : 2D numpy array, shape (N, F) = (n_train_examples, n_features)
        Feature array for reference *training* dataset
        Each row corresponds to the feature vector on example

    Returns
    -------
    k_QN : 2D numpy array, shape (Q, N)
        Entry at index (q,n) corresponds to the kernel function evaluated
        at the feature vectors x_QF[q] and x_train_NF[n]
    '''
    assert x_QF.ndim == 2
    assert x_train_NF.ndim == 2

    Q, F = x_QF.shape
    N, F2 = x_train_NF.shape
    assert F == F2

    k_QN = np.zeros((Q, N))
    # TODO compute kernel between rows of x_QF and rows of x_train_NF
    for i in range(Q):
        for  j in range(N):
            k_QN[i][j] = np.exp(-0.5 *(np.square(np.sin((np.pi / period) * (x_train_NF[j] - x_QF[i]))) / np.square(length_scale)))
    # Ensure the kernel matrix positive definite
    # By adding a small positive to the diagonal
    M = np.minimum(Q, N)
    k_QN[:M, :M] += 1e-08 * np.eye(M)
    return k_QN

#
# np.set_printoptions(precision=3, suppress=1)
#
# # Part 1: Simple kernel evaluations with F=1 features
# x_zero_11 = np.asarray([[0.0]])
# x_one_11 = np.asarray([[1.0]])
#
# # Kernel of x=0.0 with itself should be 1.0
# k_11 = calc_periodic_kernel(x_zero_11, x_zero_11, length_scale=2.0, period=0.3)
# print(k_11.ndim)
# # 2
# print(k_11)
# # array([[1.]])
#
# # Kernel of x=1.0 with itself should be 1.0
# print(calc_periodic_kernel(x_one_11, x_one_11, length_scale=2.0, period=0.3))
# # array([[1.]])
#
# # Kernel of x and z=x+period should be 1.0
# p = 0.3
# print(calc_periodic_kernel(x_one_11, x_one_11 + p, length_scale=2.0, period=p))
# # array([[1.]])
# print(calc_periodic_kernel(x_one_11, x_one_11 + 3 * p, length_scale=2.0, period=p))
# # array([[1.]])
#
# # A few other tests
# print(calc_periodic_kernel(x_one_11, x_zero_11, length_scale=0.5, period=0.3))
# # array([[0.223]])
# print(calc_periodic_kernel(x_one_11, x_zero_11, length_scale=2.0, period=0.95))
# # array([[0.997]])
#
# # Part 2: Kernel evaluations with several examples at once (still F=1)
# x_train_31 = np.asarray([[0.0], [1.0], [2.0]])
# print(calc_periodic_kernel(x_train_31, x_train_31, length_scale=2.0, period=0.95))
# # array([[1.   , 0.997, 0.987],
# #        [0.997, 1.   , 0.997],
# #        [0.987, 0.997, 1.   ]])
# x_test_21 = np.asarray([[-0.5], [0.5]])
# print(calc_periodic_kernel(x_test_21, x_train_31, length_scale=2.0, period=0.95))
# # array([[0.883, 0.889, 0.9  ],
# #        [0.883, 0.883, 0.889]])


# --------------
import pandas as pd
import numpy as np
import math

#Code starts here
class complex_numbers(object):
    def __init__(self, real=0.00, imag=0.00):
        self.real = real
        self.imag = imag

    def __repr__(self):

        if self.real == 0.0 and self.imag == 0.0:
            return "0.00"
        if self.real == 0:
            return "%.2fi" % self.imag
        if self.imag == 0:
            return "%.2f" % self.real
        return "%.2f %s %.2fi" % (self.real, "+" if self.imag >= 0 else "-", abs(self.imag))

    def __add__(self, other):
        real = self.real + other.real
        imag = self.imag + other.imag
        return complex_numbers(real,imag)

    def __sub__(self, other):
        real = self.real - other.real
        imag = self.imag - other.imag
        return complex_numbers(real,imag)

    def __mul__(self, other):
        real = self.real * other.real - self.imag * other.imag
        imag = self.real * other.imag + self.imag * other.real
        return complex_numbers(real,imag)

    def __truediv__(self, other):
        sr, si, o_r, oi = self.real, self.imag,other.real, other.imag # short forms
        r = float(o_r**2 + oi**2)
        return complex_numbers((sr*o_r+si*oi)/r, (si*o_r-sr*oi)/r)

    def absolute(self):
        return math.sqrt(self.real**2 + self.imag**2)

    def conjugate(self):
        real = self.real
        imag = -self.imag
        return complex_numbers(real,imag)

    def argument(self):
        return math.degrees((math.atan(self.imag/self.real)))

comp_1 = complex_numbers(3,5)
print('Complex Number 1: ',comp_1)

comp_2 = complex_numbers(4,4)
print('Complex Number 2: ',comp_2)

comp_sum= (comp_1+comp_2)
print('Sum of Complex Number 1 & 2: ', comp_sum)

comp_diff= (comp_1-comp_2)
print('Difference of Complex Number 1 & 2: ',comp_diff)

comp_prod= (comp_1*comp_2)
print('Product of Complex Number 1 & 2: ',comp_prod)

comp_quot= (comp_1/comp_2)
print('Quotient of Complex Number 1 & 2: ',comp_quot)

comp_abs=comp_1.absolute()
print('Absolute value of Complex Number 1: ',comp_abs)

comp_conj= comp_1.conjugate()
print('Conjugate value of Complex Number 1: ',comp_conj)

comp_arg=comp_1.argument()
print('Argument value of Complex Number 1: ',comp_arg)


# -*- coding: utf-8 -*-
"""
Created on Wed Mar  6 10:51:55 2019

Metric and affine rectification of images using parallel lines (in 2D)

@author: Gopiraj
"""

#loading the necessary libraries
import numpy as np
import cv2

#Reading the image
img = cv2.imread('floor.png')

#making the first line
p1 = [171, 244, 1]
p2 = [422, 123, 1]

l1 = np.cross(p1, p2)
l1 = l1/l1[-1]

#making the second line
p3 = [143, 117, 1]
p4 = [338, 247, 1]

l2 = np.cross(p3, p4)
l2 = l2/l2[-1]

#line parallel to l1
p5 = [108, 191, 1]
p6 = [356, 88, 1]

l3 = np.cross(p5, p6)
l3 = l3/l3[-1]

#line parallel to l2
p7 = [226, 87, 1]
p8 = [424, 200, 1]

l4 = np.cross(p7, p8)
l4 = l4/l4[-1]

#calculating the vanishing points
x1 = np.cross(l1, l3)
x1 = x1/x1[-1]

x2 = np.cross(l2, l4)
x2 = x2/x2[-1]

#calculating the vanishing line
vLine = np.cross(x1, x2)
vLine = vLine/vLine[-1]

#Transformation to make vanishing line to infinity
H = np.eye(3)
H[2, 0] = vLine[0]
H[2, 1] = vLine[1]

#removing the projective distortion
res = cv2.warpPerspective(img, H, (img.shape[1], img.shape[0]))

cv2.imwrite('floor_affineRect.png', res)

#detecting pairs of lines in the affine rectified image
p1 = [107, 151, 1]
p2 = [330, 98, 1]

l1_m = np.cross(p1, p2)
l1_m = l1_m/l1_m[-1]

p3 = [113, 91, 1]
p4 = [212, 156, 1]

l2_m = np.cross(p3, p4)
l2_m = l2_m/l2_m[-1]

p5 = [73, 129, 1]
p6 = [295, 75, 1]

l3_m = np.cross(p5, p6)
l3_m = l3_m/l3_m[-1]

p7 = [185, 71, 1]
p8 = [289, 136, 1]

l4_m = np.cross(p7, p8)
l4_m = l4_m/l4_m[-1]

#2 pairs of parallel lines in affine rectified image
lines = [[], []]
lines[0].append(l1_m)
lines[0].append(l3_m)
lines[1].append(l2_m)
lines[1].append(l4_m)

#transforming the parallel lines
nlines = 2
RHS = np.zeros((nlines,1))
A = np.zeros((nlines, 2))
for k in range(0,nlines):
    RHS[k] = -lines[0][k][1]*lines[1][k][1]
for k in range(0,nlines):
    A[k,0] = lines[0][k][0]*lines[1][k][0]
    A[k,1] = lines[0][k][0]*lines[1][k][1] + lines[0][k][1]*lines[1][k][0]
s = np.linalg.lstsq(A,RHS)[0]
S = np.array([[s[0][0], s[1][0]],[s[1][0],1]])

#lines transform as l' = H^-T * l
u,s,vh = np.linalg.svd(S,full_matrices=1,compute_uv=1)

A = np.linalg.cholesky(S)

H1 = np.zeros((3,3))
H1[0:2,0:2] = A
H1[2,2] = 1

res = cv2.warpPerspective(res, np.linalg.inv(H1).T, (img.shape[1], img.shape[0]))

cv2.imwrite('floor_metricRect.png', res)

#combined transformation
Hc = np.linalg.inv(H1).T #affine rectification
Hc[2, :2] = vLine[:2] #projective rectification

#performing rectification on the original image
res = cv2.warpPerspective(img, Hc, (img.shape[1], img.shape[0]))

cv2.imwrite('combined_rect.png', res)

#cv2.namedWindow("res", cv2.WINDOW_FREERATIO)
cv2.imshow("res", res)
cv2.imshow("orig", img)
cv2.waitKey(0)
cv2.destroyAllWindows()


import numpy as np
import matplotlib.pyplot as plt
import time
#import seaborn as sns

#biblioteca para obter a distribuicao normal acumulada
from scipy.stats import norm

def calcula_u(N, M, L, sigma, K, T, vetoriza = True):
    delta_x     = 2*L/N
    delta_tal   = T/M

    u = np.zeros((N+1, M+1))

    if vetoriza:
        #Calculando a base

        for i in range(N+1):
            x_i = i*delta_x-L

            u[i][0] = K*max(np.e**x_i - 1, 0)

        for j in range(M+1):
            tal_j = j * delta_tal

            u[N][j] = K * np.e**(L+sigma**2*tal_j/2)
            u[0][j] = 0

        # Calculando as demais posicoes
        for j in range(M):
            tal_j = j * delta_tal

            u_i_menos_um    = u[0:-2, j]
            u_i             = u[1:-1, j]
            u_i_mais_um     = u[2:  , j]

            u[1:-1, j+1]    = u_i + (delta_tal/delta_x**2)*(sigma**2/2)*(u_i_menos_um-2*u_i+u_i_mais_um)

    else:
        for j in range(M+1):
            tal_j = j * delta_tal
            for i in range(N+1):
                x_i = i*delta_x-L

                if i == 0:
                    u[i][j] = 0

                elif i == N:
                    u[i][j] = K * np.e**(L+sigma**2*tal_j/2)

                elif j==0:
                    u[i][j] = K*max(np.e**x_i - 1, 0)

                else:
                    u[i][j] = u[i][j-1] + (delta_tal/delta_x**2)*(sigma**2/2)*(u[i-1][j-1]-2*u[i][j-1]+u[i+1][j-1])

    return u

def calcula_V(u, N, M, r, T):
    delta_tal   = T/M
    V = np.zeros((N+1, M+1))
    for j in range(M+1):
        tal_j = j * delta_tal
        V[:, j] = u[:, j] * np.e**(-r*tal_j)

    return V

def calcula_S(N, M, L, sigma, K, T, r):
    delta_x     = 2*L/N
    delta_tal   = T/M

    S1 = np.zeros((N+1, M+1)) # e^x_i
    S2 = np.zeros((N+1, M+1)) # e^((r-sigma^2/2)*tal_j)
    S  = np.zeros((N+1, M+1)) # K * (S1/S2)

    for j in range(M+1):
        tal_j = j * delta_tal
        S2[:, j] =  np.e**((r-sigma**2/2)*tal_j)

    for i in range(N+1):
        x_i = i*delta_x-L
        S1[i, :] = np.e**(x_i)

    S = K * (S1/S2)
    return S

def calcula_u_analitico(N, M, L, sigma, K, T):
    delta_x     = 2*L/N
    delta_tal   = T/M

    u = np.zeros((N+1, M+1))
    for j in range(M+1):
        tal_j = j * delta_tal
        for i in range(N+1):
            x_i = i*delta_x-L
            if j==0:
                u[i][j] = K*max(np.e**x_i-1, 0)
            else:
                d1 = (x_i + sigma**2*tal_j)/(sigma*np.sqrt(tal_j))
                d2 = x_i/(sigma*np.sqrt(tal_j))
                N1 = norm.cdf(d1)
                N2 = norm.cdf(d2)

                u[i][j] = K*np.e**(x_i + sigma**2*tal_j/2)*N1-K*N2
    return u

def calcula_aproximacao_V(V, S, t, N, M, L, sigma, K, T, r, interpola = True):
    delta_x     = 2*L/N
    delta_tal   = T/M

    tal = T-t
    x = np.log(S/K) + (r-sigma**2/2)*tal

    i_p = int((x+L)/delta_x)
    j_p = round(tal/delta_tal)

    if interpola:
        x_i         = i_p*delta_x-L
        x_i_mais_um = (i_p+1)*delta_x-L
        opcao =  ((x_i_mais_um-x)*V[i_p][j_p]-(x_i-x)*V[i_p+1][j_p])/(x_i_mais_um-x_i)
        return opcao
    else:
        return V[i_p][j_p]

def cenario_1(show_graph=True):
    arquivo = open("report_cenario_1.txt", "w")
    #============
    #=== Ex 1 ===
    #============
    N       = 1000
    L       = 10
    M       = 100
    K       = 1
    sigma   = 0.01
    T       = 1
    r       = 0.01
    u = calcula_u(N, M, L, sigma, K, T)
    V = calcula_V(u, N, M, r, T)

    S = 1
    t = 0

    preco_opcao_agora = calcula_aproximacao_V(V, S, t, N, M, L, sigma, K, T, r)
    imprime_report(arquivo, N, L, M, K, sigma, T, r, S, t, preco_opcao_agora)

    opcao_compra_1000 = preco_opcao_agora*1000

    print("Precificação da opção de compra de R$1000.00 do ativo para o tempo presente, considerando que o ativo tem preço de R$1.00 hoje: R${:.2f}".format(opcao_compra_1000))

    #============
    #=== Ex 2 ===
    #============

    gera_cenarios_lucro(V, 0.5, N, M, L, sigma, K, T, r, 1000, opcao_compra_1000, show_graph, "Cenários de lucro e prejuízo para diversos preços do ativo em t=0.5", "grafico_1_cenario_1.png")

    # Valor da opcao em funcao do preco do ativo em t=0
    gera_cenarios_preco_do_ativo(V, 0., N, M, L, sigma, K, T, r,show_graph, "Valor da opção para diversos preços do ativo em t=0", "grafico_2_cenario_1.png")

    # Valor da opcao em funcao do preco do ativo em t=0.5
    gera_cenarios_preco_do_ativo(V, 0.5, N, M, L, sigma, K, T, r,show_graph, "Valor da opção para diversos preços do ativo em t=0.5", "grafico_3_cenario_1.png")

    # Valor da opcao em funcao do preco do ativo em t=1.0
    gera_cenarios_preco_do_ativo(V, 1., N, M, L, sigma, K, T, r,show_graph, "Valor da opção para diversos preços do ativo em t=1.0", "grafico_4_cenario_1.png")

    #============
    #=== Ex 3 ===
    #============

    sigma = 0.02
    u = calcula_u(N, M, L, sigma, K, T)
    V = calcula_V(u, N, M, r, T)

    preco_opcao_agora = calcula_aproximacao_V(V, S, t, N, M, L, sigma, K, T, r)
    imprime_report(arquivo, N, L, M, K, sigma, T, r, S, t, preco_opcao_agora)

    opcao_compra_1000 = preco_opcao_agora*1000

    print("Precificação da opção de compra de R$1000.00 do ativo mudando apenas a volatilidade para 0.02: R${:.2f}".format(opcao_compra_1000))

    gera_cenarios_lucro(V, 0.5, N, M, L, sigma, K, T, r, 1000, opcao_compra_1000, show_graph, "Cenários de lucro e prejuízo para diversos preços do ativo em t=0.5 com sigma = 0.02", "grafico_5_cenario_1.png")
    # Valor da opcao em funcao do preco do ativo em t=0
    gera_cenarios_preco_do_ativo(V, 0., N, M, L, sigma, K, T, r,show_graph, "Valor da opção para diversos preços do ativo em t=0 com sigma = 0.02", "grafico_6_cenario_1.png")

    # Valor da opcao em funcao do preco do ativo em t=0.5
    gera_cenarios_preco_do_ativo(V, 0.5, N, M, L, sigma, K, T, r,show_graph, "Valor da opção para diversos preços do ativo em t=0.5 com sigma = 0.02", "grafico_7_cenario_1.png")

    # Valor da opcao em funcao do preco do ativo em t=1.0
    gera_cenarios_preco_do_ativo(V, 1., N, M, L, sigma, K, T, r,show_graph, "Valor da opção para diversos preços do ativo em t=1.0 com sigma = 0.02", "grafico_8_cenario_1.png")

    #============
    #=== Ex 4 ===
    #============

    r = 0.1
    sigma = 0.1
    u = calcula_u(N, M, L, sigma, K, T)
    V = calcula_V(u, N, M, r, T)

    preco_opcao_agora = calcula_aproximacao_V(V, S, t, N, M, L, sigma, K, T, r)
    imprime_report(arquivo, N, L, M, K, sigma, T, r, S, t, preco_opcao_agora)

    opcao_compra_1000 = preco_opcao_agora*1000

    print("Precificação da opção de compra de R$1000.00 do ativo com r = 0.1 e sigma = 0.1: R${:.2f}".format(opcao_compra_1000))

    gera_cenarios_lucro(V, 0.5, N, M, L, sigma, K, T, r, 1000, opcao_compra_1000, show_graph, "Cenários de lucro e prejuízo para diversos preços do ativo em t=0.5 com sigma = 0.1 e r = 0.1", "grafico_9_cenario_1.png")
    # Valor da opcao em funcao do preco do ativo em t=0
    #gera_cenarios_preco_do_ativo(V, 0., N, M, L, sigma, K, T, r,show_graph, "Valor da opção para diversos preços do ativo em t=0 com sigma = 0.1 e r = 0.1", "grafico_10_cenario_1.png")

    # Valor da opcao em funcao do preco do ativo em t=0.5
    #gera_cenarios_preco_do_ativo(V, 0.5, N, M, L, sigma, K, T, r,show_graph, "Valor da opção para diversos preços do ativo em t=0.5 com sigma = 0.1 e r = 0.1", "grafico_11_cenario_1.png")

    # Valor da opcao em funcao do preco do ativo em t=1.0
    #gera_cenarios_preco_do_ativo(V, 1., N, M, L, sigma, K, T, r,show_graph, "Valor da opção para diversos preços do ativo em t=1.0 com sigma = 0.1 e r = 0.1", "grafico_12_cenario_1.png")

    arquivo.close()
    return

def cenario_2(show_graph=True):
    arquivo = open("report_cenario_2.txt", "w")
    N       = 1000
    L       = 10
    M       = 1000
    K       = 5.7
    sigma   = 0.1692
    T       = 3/12
    r       = 0.1075
    u = calcula_u(N, M, L, sigma, K, T)
    V = calcula_V(u, N, M, r, T)

    S = 5.6376
    t = 0

    preco_opcao_dezembro = calcula_aproximacao_V(V, S, t, N, M, L, sigma, K, T, r)
    imprime_report(arquivo, N, L, M, K, sigma, T, r, S, t, preco_opcao_dezembro)
    opcao_compra_100_mil = preco_opcao_dezembro*100000
    print("Premio da opção de compra de US$100000.00 para o tempo presente: R${:.2f}".format(opcao_compra_100_mil))

    # Sabendo o valor do dolar em 1 de janeiro de 2022
    S = 5.5780503347
    t = 1/12
    preco_opcao_janeiro = calcula_aproximacao_V(V, S, t, N, M, L, sigma, K, T, r)
    imprime_report(arquivo, N, L, M, K, sigma, T, r, S, t, preco_opcao_janeiro)
    saldo = (preco_opcao_janeiro-preco_opcao_dezembro)*100000
    print("Prejuízo da compra de US$100000.00 em janeiro de 2022: R${:.2f}".format(saldo))

    # Sem saber o valor do dolar em 1 de janeiro de 2022
    gera_cenarios_lucro(V, 1/12, N, M, L, sigma, K, T, r, 100000, opcao_compra_100_mil, show_graph, "Cenários de lucro e prejuízo para diversos preços do dólar em t=1/12", "grafico_1_cenario_2.png")

    arquivo.close()
    return

def imprime_report(arquivo, N, L, M, K, sigma, T, r, S, t, V):
    arquivo.write("Parametros:\n")
    arquivo.write("N        = {}\n".format(N))
    arquivo.write("L        = {}\n".format(L))
    arquivo.write("M        = {}\n".format(M))
    arquivo.write("K        = {:.2f}\n".format(K))
    arquivo.write("sigma    = {:.2f}\n".format(sigma))
    arquivo.write("T        = {:.2f}\n".format(T))
    arquivo.write("r        = {:.2f}\n".format(r))
    arquivo.write("S0       = {:.2f}\n".format(S))
    arquivo.write("t        = {:.2f}\n".format(t))
    arquivo.write("Precificacao opcao:\n")
    arquivo.write("V        = {:.2f}\n".format(V))
    arquivo.write("\n\n")
    return

def gera_cenarios_lucro(V, t, N, M, L, sigma, K, T, r, valor_comprado, gasto_inicial, show_graph, titulo = "", nome_imagem = ""):
    k       = 100
    S_min   = K/2
    S_max   = 3*K/2
    delta_S = (S_max-S_min)/k
    k_i     = np.arange(k)
    S_list  = k_i*delta_S+S_min
    cenarios = []
    for S_i in S_list:
        resultado_i = calcula_aproximacao_V(V, S_i, t, N, M, L, sigma, K, T, r)*valor_comprado-gasto_inicial
        cenarios.append(resultado_i)

    if show_graph:
        fig, ax = plt.subplots(figsize = (11, 6))
        ax.plot(S_list, cenarios)
        ax.grid(visible = True, axis = "y", linestyle = "--")
        ax.set_title(titulo)
        ax.set_xlabel("Preço do ativo")
        ax.set_ylabel("Saldo final")
        plt.savefig(nome_imagem)
        plt.show()
    return cenarios

def gera_cenarios_preco_do_ativo(V, t, N, M, L, sigma, K, T, r, show_graph, titulo = "", nome_imagem = ""):
    k       = 10000
    S_min   = 2*K/3
    S_max   = 4*K/3
    delta_S = (S_max-S_min)/k
    k_i     = np.arange(k)
    S_list  = k_i*delta_S+S_min
    cenarios = []
    for S_i in S_list:
        resultado_i = calcula_aproximacao_V(V, S_i, t, N, M, L, sigma, K, T, r)
        cenarios.append(resultado_i)

    if show_graph:
        fig, ax = plt.subplots(figsize = (11, 6))
        ax.plot(S_list, cenarios)
        ax.grid(visible = True, axis = "y", linestyle = "--")
        ax.set_title(titulo)
        ax.set_xlabel("Preço do ativo")
        ax.set_ylabel("Valor da opção")
        plt.savefig(nome_imagem)
        plt.show()
    return cenarios

def compara_tempo_execucao():
    tic = time.process_time()
    u   = calcula_u(1000,500, 10, 0.2, 1, 1, vetoriza=False)
    toc = time.process_time()
    no_vectorization = (toc-tic)*1000
    tic = time.process_time()
    u   = calcula_u(1000,500, 10, 0.2, 1, 1)
    toc = time.process_time()
    vectorization = (toc-tic)*1000
    print("Tempo de execução do método sem vetorização {:.2f} ms".format(no_vectorization))
    print("Tempo de execução do método com vetorização {:.2f} ms".format(vectorization))
    return

def interface():
    print("===========================================")
    print("============ Escolha uma opcao ============")
    print("===========================================")
    print("c1 - Rodar o cenário 1")
    print("c2 - Rodar o cenário 2")
    print("c3 - Rodar o cenário 3")
    print("ti - Comparar o tempo de execução do método vetorizado com o sem")
    #print("an - Comparar o resultado obtido pelo método numérico com o analítico")
    print("ex - Finalizar o programa")
    res = input("Operação escolhida: ")
    if res == "c1":
        cenario_1()
        print()
        interface()

    elif res == "c2":
        cenario_2()
        print()
        interface()

    elif res == "c3":
        print("não implementado ainda =(")
        print()
        interface()

    elif res == "ti":
        compara_tempo_execucao()
        print()
        interface()

    elif res == "ex":
        print("ex")
        print()

    else:
        print("operacao invalida, selecione outra")
        print()
        interface()

        return

interface()


#We import our libs:
import numpy as np
import matplotlib.pyplot as plt
from numba import jit

@jit
def solver(N):
    # Make the initial guess for solution matrix
    V = np.zeros((N,N))

    # Solver:
    iterations = 0
    eps = 1e-10 # Convergence threshold
    error = 1e4 # Large dummy error
    while iterations < 1e4 and error > eps:
        V_temp = np.copy(V)
        error = 0
        # we make this accumulate in the loop
        for j in range(1,N-1):
            for i in range(1,N-1):
                V[i,j] = 0.25*(V[i+1,j] + V[i-1,j] + V[i,j-1] + V[i,j+1] + rho[i,j]*ds**2)
                error += abs(V[i,j]-V_temp[i,j])
            iterations += 1
    print("iterations =", iterations)
    return V

# Set dimensions of the problem:
L = 1.0
N = 21
ds = L/N

# Define arrays used for plotting:
x = np.linspace(0,L,N)
y = np.copy(x)
X, Y = np.meshgrid(x,y)

# Make the charge density matrix:
rho0 = 1.0
rho = np.zeros((N,N))
rho[int(round(N/2.0)),int(round(N/2.0))] = rho0
# for j in range(round(N/2.0)-int(N/20.0),round(N/2.0)+int(N/20.0)):
#     rho[round(N/2.0)-int(N/30.0),j] = rho0
#     rho[round(N/2.0)+int(N/30.0),j] = -rho0

# Solver:
V = solver(N)

# Plotting:
eps = 3
zoomX = X[round(N/2.0)-eps:round(N/2.0)+eps]
zoomY = Y[round(N/2.0)-eps:round(N/2.0)+eps]
zoomV = V[round(N/2.0)-eps:round(N/2.0)+eps]
plt.figure(figsize=(5,3))
CS = plt.contour(zoomX, zoomY, zoomV, 30) # Make a contour plot
plt.clabel(CS, inline=1, fontsize=10)
plt.title("PDE solution of a point charge")
CB = plt.colorbar(CS, extend="both")
plt.show()

# Print matrix:
print(zoomV)


import numpy as np
import matplotlib.pyplot as plt
from colorsys import hls_to_rgb

def colorize(z):
    zy=np.flipud(z)
    r = np.abs(zy)
    arg = np.angle(zy)

    h = (arg + np.pi)  / (2 * np.pi) + 0.5
    l = 1.0 - 1.0/(1.0 + r**.75)
    s = .8

    c = np.vectorize(hls_to_rgb) (h,l,s) # --> tuple
    c = np.array(c)  # -->  array of (3,n,m) shape, but need (n,m,3)
    c = c.swapaxes(0,2)
    c = c.swapaxes(0,1)
    return c

def plot_complex(f, xbounds, ybounds, res):
    x = np.linspace(xbounds[0], xbounds[1], res)
    y = np.linspace(ybounds[0], ybounds[1], res)
    X,Y = np.meshgrid(x,y)
    Z=f(X+Y*1j)
    plt.pcolormesh(X, Y, np.angle(Z), cmap='hsv', vmin=-np.pi, vmax=np.pi)
    plt.show()

def plot_complex2(f, xbounds, ybounds, res):
    x = np.linspace(xbounds[0],xbounds[1], res)
    y = np.linspace(ybounds[0],ybounds[1], res)
    X,Y = np.meshgrid(x,y)
    Z=f(X+Y*1j)
    Zc = colorize(Z)
    plt.imshow(Zc, extent=(xbounds[0], xbounds[1], ybounds[0], ybounds[1]))
    plt.show()

################################################
################################################
# PLOTS

def check_plot():
    f = lambda x:np.sqrt(x**2+1)
    x = np.linspace(-3, 3, 401)
    y = np.linspace(-3, 3, 401)
    X,Y = np.meshgrid(x,y)
    Z=f(X+Y*1j)
    plt.pcolormesh(X, Y, np.angle(Z), cmap='hsv', vmin=-np.pi, vmax=np.pi)
    plt.gca().set_aspect('equal', adjustable='box')
    plt.savefig('check_plot.png', bbox_inches='tight', pad_inches=0)
    plt.close()

def plot_id():
    f = lambda x:x
    x = np.linspace(-1, 1, 401)
    y = np.linspace(-1, 1, 401)
    X,Y = np.meshgrid(x,y)
    Z=f(X+Y*1j)
    plt.pcolormesh(X, Y, np.angle(Z), cmap='hsv', vmin=-np.pi, vmax=np.pi)
    plt.gca().set_aspect('equal', adjustable='box')
    plt.savefig('Identity.png', bbox_inches='tight', pad_inches=0)
    plt.close()

def zeros():
    f = lambda x:x**3-1j*x**4-3*x**6
    x = np.linspace(-1, 1, 401)
    y = np.linspace(-1, 1, 401)
    X,Y = np.meshgrid(x,y)
    Z=f(X+Y*1j)
    plt.pcolormesh(X, Y, np.angle(Z), cmap='hsv', vmin=-np.pi, vmax=np.pi)
    plt.gca().set_aspect('equal', adjustable='box')
    plt.savefig('zeros.png', bbox_inches='tight', pad_inches=0)
    plt.close()

def essential_pole():
    f = lambda x : np.exp(1/x)
    x = np.linspace(-1, 1, 803)
    y = np.linspace(-1, 1, 803)
    X,Y = np.meshgrid(x,y)
    Z=f(X+Y*1j)
    plt.pcolormesh(X, Y, np.angle(Z), cmap='hsv', vmin=-np.pi, vmax=np.pi)
    plt.gca().set_aspect('equal', adjustable='box')
    plt.savefig('essential_pole.png', bbox_inches='tight', pad_inches=0)
    plt.close()

if __name__=='__main__':
	check_plot()
	plot_id()
	zeros()
	essential_pole()


import numpy as np
import xlsxwriter as xl
import time

# Função utilizada: f(x) = 3 * cos(x) - (e^x)/3 // Intervalo: [-5; 2]// h: 0.75 // Precisão: 10^-5

# Utilizando o método da Secante para o intervalo [-5; -4.25]:

tempo_inicial = time.time()

def test(x):
    x_barra_aplicado = 3 * np.cos(x) - (np.exp(x)/3)
    return x_barra_aplicado

"""# Achando os dois valores de f(x) com os valores iniciais escolhidos:
x_barra_0 = test(-5)  # 0.8487405740566503
x_barra_1 = test(-4.25)    # -1.3430172143777117 """

def secante():
    c = 2
    x_barra = [-5, -4.25]  # Os dois vlores iniciais são os dois extremos de I
    x_barra_aplicado = [0.8487405740566503, -1.3430172143777117]
    def funcao_iteracao():
        resultado = x_barra[-1] - (x_barra_aplicado[-1] * (x_barra[-1] - x_barra[-2])) / (x_barra_aplicado[-1] - x_barra_aplicado[-2])
        return resultado
    while True:
        x_barra_atual = funcao_iteracao()
        x_barra.append(x_barra_atual)
        x_barra_aplicado_atual = test(x_barra_atual)
        x_barra_aplicado.append(x_barra_aplicado_atual)
        if x_barra_aplicado_atual < 0:
            modulo_x_aplicado_atual = x_barra_aplicado_atual * (-1)
        else:
            modulo_x_aplicado_atual = x_barra_aplicado_atual
        if modulo_x_aplicado_atual < 10 ** -5:
            break
        else:
            c+= 1
    return x_barra[-1], x_barra, x_barra_aplicado, c

raiz_aproximada = secante()[0]
lista_x_barra = secante()[1]
lista_x_aplicado = secante()[2]
iteracoes = secante()[3]

print('Questao teste, intervalo [-5; -4.25]:')
print(f'A raiz aproximada é: {raiz_aproximada}')
print(f'Para encontrar essa raiz, foram necessárias {iteracoes} iterações.')
print(lista_x_barra)
print(lista_x_aplicado)

"""# Criando a tabela com os valores obtidos
# Criando o arquivo
outWorkbook = xl.Workbook("Questao_03_1o_intervalo_secante.xlsx")
outSheet = outWorkbook.add_worksheet()

# Declarando os títulos

# Escrevendo os dados no arquivo
outSheet.write("A1", "x_barra")
outSheet.write("B1", "f(x_barra)")

for number, item in enumerate(lista_x_barra):
    outSheet.write(number + 1, 0, item)
for number, item in enumerate(lista_x_aplicado):
    outSheet.write(number + 1, 1, item)
outWorkbook.close()"""

tempo_final = time.time()
tempo_gasto = tempo_final - tempo_inicial
print(f'Foram gastos {tempo_gasto}s.')


import csv
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
def plot(data, cluster_value, k):
    x_val = data[:,0]
    y_val = data[:,1]
    colors = cm.rainbow(np.linspace(0,1,k))
    for i in range(k):
        x = x_val[cluster_value[:] == i]
        y = y_val[cluster_value[:] == i]
        color = colors[i,:]
        plt.scatter(x,y, c=color)
    plt.show()

def read_in(filename):
    data = np.genfromtxt(filename, delimiter=None)
    return data
def kmeans(data, k):
    cluster_value = np.random.randint(0,k, data.shape[0])
    cluster_mean = np.zeros((k,2))
    repeat = True
    previous_loss = 2e10
    while (repeat == True):
        for i in range(10):
            for n in range(k):
                cluster_mean[n,:] = np.mean(data[cluster_value[:] == n], axis=0)
            data_distance = np.zeros((data.shape[0], k))
            loss = 0
            for i in range(data.shape[0]):
                for j in range(k):
                    data_distance[i,j] = np.linalg.norm(data[i] - cluster_mean[j])
            for i in range(data.shape[0]):
                loss += data_distance[i,cluster_value[i]]
            if (previous_loss - loss < 1): #algorithm has converged
                repeat = False
            previous_loss = loss
            for i in range(data.shape[0]):
                cluster_value[i] = np.argmin(data_distance[i,:])
    return cluster_value, previous_loss
def cmeans(data, c, m): #fuzzy c-means
    one = np.ones(c)
    cluster = np.zeros(data.shape[0])
    cluster_value = np.zeros((data.shape[0], c))
    previous_loss = 2e10
    for i in range(data.shape[0]):
        cluster_value[i,:] = np.random.dirichlet(one)
    repeat = True
    while(repeat == True): #repeat until convergence is met
        centroid = np.zeros((c,2))
        for i in range(c):
            for j in range(data.shape[0]):
                centroid[i,:] += np.multiply(np.power(cluster_value[j,i], m), data[j,:])
            sum = 0
            for j in range(data.shape[0]):
                sum += np.power(cluster_value[j,i], m)
            centroid[i,:] = np.divide(centroid[i,:], sum)
        for i in range(data.shape[0]):
            for j in range(c):
                sum = 0
                temp = np.abs(np.linalg.norm(data[i,:] - centroid[j,:]))
                for k in range(c):
                    temp2 = np.abs(np.linalg.norm(data[i,:] - centroid[k,:]))
                    val = temp / temp2
                    val = np.power(val, (2/(m-1)))
                    sum += val
                cluster_value[i,j] = 1 / sum
        for i in range(data.shape[0]):
            cluster[i] = np.argmax(cluster_value[i,:])
        loss = 0
        for i in range(data.shape[0]):
            loss += np.linalg.norm(data[i,:] - centroid[int(cluster[i])]) #calculate loss
        if (previous_loss - loss < 1):
            repeat = False
        previous_loss = loss
    return cluster, loss
def main():
    data = read_in('data/cluster_dataset.txt')
    k = 3
    loss = np.NaN
    cluster_value = None
    for i in range(10):
        new_cluster_value, new_loss = cmeans(data, k, 3)
        if (np.isnan(loss)):
            loss = new_loss
            cluster_value = new_cluster_value
        if (new_loss < loss):
            loss = new_loss
            cluster_value = new_cluster_value
    print("c-means loss: ")
    print(loss)
    plot(data, cluster_value, k)
    loss = np.NaN
    for i in range(10):
        new_cluster_value, new_loss = kmeans(data, k)
        if (np.isnan(loss)):
            loss = new_loss
            cluster_value = new_cluster_value
        if (new_loss < loss):
            loss = new_loss
            cluster_value = new_cluster_value
    print("k-means loss: ")
    print(loss)
    plot(data, cluster_value, k)

if __name__ == '__main__':
    main()


import numpy as np
import matplotlib.pyplot as plt

G_z = 0.08 #T/m
gamma = 2*np.pi*42.58e6 #rad/(sT)
z_0 = 0.001 #m
tau_m = 0.005 #s
omega_0 = gamma*G_z*z_0

t_min = 0
t_max = tau_m
N = 1000
t = np.linspace(t_min, t_max, N) #s
#y = np.sin(omega_0*(t))/(np.pi*gamma*(t)) #center
#y = np.sin(omega_0*(t-tau_m/2))/(np.pi*gamma*(t-tau_m/2)) #case1
#y = np.sin(omega_0/2*(t-tau_m/2))/(np.pi*gamma*(t-tau_m/2)) #case2
#y = 2*np.sin(omega_0/2*(t-tau_m/2))/(np.pi*gamma*(t-tau_m/2))*np.cos(3*omega_0/2*(t-tau_m/2)) #case3
#y = -2*np.sin(omega_0/2*(t-tau_m/2))/(np.pi*gamma*(t-tau_m/2))*np.sin(3*omega_0/2*(t-tau_m/2)) #case4

"""
#signal of rf pulse

plt.plot(t, y, label="$H(t)$", color="blue", linewidth=2)

plt.xlabel("t/s")
plt.ylabel("H(t)/T")

plt.title("rf pulse")

plt.xlim(t_min, t_max)
#plt.ylim(-0.0001, 0.0001)

plt.legend()

plt.show()
"""

#ifft of rf pulse

tt = np.linspace(-tau_m/2, tau_m/2, N) #s
#yy = np.fft.fft(np.sin(omega_0*(tt))/(np.pi*gamma*(tt))) #case1
yy = np.fft.fft(np.sin(omega_0/2*(tt))/(np.pi*gamma*(tt))) #case2, and xx should plus 0.0015
#yy = np.fft.fft(2*np.sin(omega_0/2*(tt))/(np.pi*gamma*(tt))*np.cos(3*omega_0/2*(tt))) #case3

yyf = abs(yy) #case1,2,3

"""
#case4
yy = np.fft.fft(-2*np.sin(omega_0/2*(tt))/(np.pi*gamma*(tt))*np.sin(3*omega_0/2*(tt))) # case4
c = 1
yyf = []
for yyy in yy:
    yyyf = abs(yyy)
    yyyphase = np.arctan(np.imag(yyy)/np.real(yyy))
    if yyyphase>0:
        c = -1
        yyyf = c*yyyf
    yyf.append(yyyf)
"""

xx = np.fft.fftfreq(N,tau_m/N)/gamma/G_z*2*np.pi #z-axis
#print(yyf)

plt.plot(np.fft.fftshift(xx),np.fft.fftshift(yyf), label="$iFFT$", color="blue", linewidth=2)
plt.title("iFFT of rf pulse")
plt.xlim(-0.003, 0.003)
plt.xlabel("z_0/m")
plt.ylabel("Relative Intensity")
plt.show()


import numpy as np
import math

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

def base_sigmoid(x):
    return 1 / (1 + math.exp(-x))

print(base_sigmoid(3))

# 0 - 1之间的函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

print(sigmoid(a))

def sigmoid_derivative(x):
    s = 1 / (1 + np.exp(-x))
    ds = s * (1 - s)
    return ds

print("sigmoid_derivative(x) = " + str(sigmoid_derivative(a)))

def image2vector(x):
    return x.reshape(x.shape[0] * x.shape[1] * x.shape[2], 1)

image = np.array([[[0.67826139, 0.29380381],
                   [0.90714982, 0.52835647],
                   [0.4215251, 0.45017551]],

                  [[0.92814219, 0.96677647],
                   [0.85304703, 0.52351845],
                   [0.19981397, 0.27417313]],

                  [[0.60659855, 0.00533165],
                   [0.10820313, 0.49978937],
                   [0.34144279, 0.94630077]]])

print(image2vector(image))

def normalizeRows(x):
    norm = np.linalg.norm(x, axis=1, keepdims=True)
    x = x / norm
    return x

b = np.array([
    [0, 3, 4],
    [1, 6, 4],
])
print(normalizeRows(b))

def L1(y_hat, y):
    loss = np.sum(np.abs(np.subtract(y, y_hat)))
    return loss

def L2(y_hat, y):
    loss = np.sum(np.square(np.subtract(y, y_hat)))
    return loss


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

Copyright (c) 2022 Jongrae.K

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.
"""

from sympy import symbols, Matrix, simplify, expand

def quat_x_quat(qp, q):
    qp_v = Matrix(qp[0:3])
    qp4 = qp[-1]
    q_v = Matrix(q[0:3])
    q4 = q[-1]

    qxq_v = qp4*q_v  + qp_v*q4 - qp_v.cross(q_v)
    qxq_4 = qp4*q4 - qp_v.dot(q_v)

    qxq = Matrix([qxq_v, qxq_4])
    return qxq

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

q1, q2, q3, q4 = symbols('q1 q2 q3 q4')
w1, w2, w3 = symbols('w1 w2 w3')

q = Matrix([[q1],[q2],[q3],[q4]])
qinv = Matrix([[-q1],[-q2],[-q3],[q4]])

w = Matrix([[w1],[w2],[w3]])
wx = Matrix([[0, -w3, w2],[w3, 0, -w1],[-w2, w1, 0]])

Omega = Matrix([[-wx, w],[-w1,-w2,-w3,0]])

dqdt = (1/2)*Omega@q

# obtain dqinv/dt: Equation (4) in the solution
qinv_dot = -1*simplify(expand(quat_x_quat(qinv,quat_x_quat(dqdt, qinv))))

p1, p2, p3, p4 = symbols('p1,p2,p3,p4')
p = Matrix([[p1],[p2],[p3],[p4]])

# prove dqdt (x) p = (1/2) Omega (q (x) p): Equation (6) in the solution
out1 = simplify(expand(quat_x_quat(dqdt,p)-(1/2)*Omega*quat_x_quat(q,p)))
print('out1 must be equal to zero: ', out1)

r1, r2, r3, r4 = symbols('r1,r2,r3,r4')
r = Matrix([[r1],[r2],[r3],[r4]])

# prove p (x) (q (x) r) = (p (x) q) (x) r: Equation (7) in the solution
out2 = simplify(expand(quat_x_quat(p,quat_x_quat(q,r)) - quat_x_quat(quat_x_quat(p,q),r)))
print('out2 must be equal to zero: ', out2)


import matplotlib.pylab as pl
import random
import math
import numpy as np

"""
NumRep Checkpoint 1: MonteCarlo simulations of Muon decay
Simon McLaren
"""

# Returns a value for the muon lifetime probability density at a specified time
def evaluateMuonDistribution(time, tau):
    return float((1/tau)*math.exp(-(time/tau)))

muonLifetime = 2.2 # in microseconds
numberofsimulateddecays = 1000
numberofsimulatedlifetimes = 500
totalMuonLifetimes = []
# Parameters for sampling a random number from the distribution
fmax = evaluateMuonDistribution(0, muonLifetime) # Max value of e^-x function is at 0 for the range 0 to inf
mint = 0.
maxt = 22.

# Simulate 500 muon lifetimes
for j in range(numberofsimulatedlifetimes):
    listOfDecayTimes = []
    # Simulate 1000 muon decay times
    for i in range(numberofsimulateddecays):
        # Draw a random time from the distribution using the box method
        y2 = 10.
        y1 = 1.
        while y2 > y1:
            randomt = mint + (maxt - mint) * random.random()
            y1 = evaluateMuonDistribution(randomt, muonLifetime)
            y2 = fmax * random.random()
        listOfDecayTimes.append(randomt)

    estimatedMuonLifetime = (sum(listOfDecayTimes)/len(listOfDecayTimes))
    totalMuonLifetimes.append(estimatedMuonLifetime)

# Plot histogram
pl.hist(totalMuonLifetimes[:], bins = 100, range = [1,3])
pl.xlabel("Estimated Muon Lifetime (microseconds)")
pl.title("Hisogram of Muon Lifetimes")
pl.savefig("muonlifetimehistogram.png")

totalMuonLifetimes = np.array(totalMuonLifetimes)

# Print results
simulationMuonLifetime = np.mean(totalMuonLifetimes) # Estimated muon lifetime from the simulation
standardDeviationMuonLifetime = np.std(totalMuonLifetimes) # Standard deviation of the data
print "The estimated muon lifetime is %f microseconds." %(simulationMuonLifetime)
print "The standard deviation of the 500 muon lifetimes is %f." %(standardDeviationMuonLifetime)
print "The standard error of the mean is %f." %(standardDeviationMuonLifetime/math.sqrt(numberofsimulatedlifetimes))


import numpy as np
from numpy import floor
import matplotlib.pyplot as plt
class CubicHermite():
    def __init__(self,xi,yi):
        '''
        inited by control points
        :param xi:
        :param yi:
        '''
        self.xi=xi
        self.yi=yi
        assert len(xi)==len(yi)
        self.num = len(xi)

    def _get_arr(self,idx):
        if idx<0:
            return self.yi[0]
        elif idx>=len(self.yi):
            return self.yi[-1]
        else:
            return self.yi[idx]
    def _CubicHermite(self,A,B,C,D,t):
        '''

        '''
        a = -0.5*A  + 1.5* B - 1.5 * C +0.5* D
        b = A -2.5*B + 2*C - 0.5*D
        c = -0.5*A  + 0.5*C
        d = B
        return a * t * t * t + b * t * t + c * t + d

    def _fit(self,x,i):

        idx=0
        if x<=self.xi[0]:
            idx=0
        elif x>=self.xi[-1]:
            idx=len(self.xi)-1
        else:
            while idx< len(self.yi)-1:
                if x>=self.xi[idx] and x<self.xi[idx+1]:
                    break
                idx+=1

        x = i*self.step
        t = x - floor(x)
        A = self._get_arr(idx - 1)
        B = self._get_arr(idx + 0)
        C = self._get_arr(idx + 1)
        D = self._get_arr(idx + 2)
        y = self._CubicHermite(A, B, C, D, t)
        return y

    def __call__(self, xs):
        ys = []
        i=0
        self.num_samples = len(xs)
        self.step = (self.num-1)/(self.num_samples-1)
        for x in xs:
            ys.append(self._fit(x,i))
            i+=1

        return np.array(ys)

if __name__ == '__main__':
    xi = np.array([0, 50, 100, 150, 200])
    yi = np.array([0, -100, 0, -50, 0])
    interp_hermite = CubicHermite(xi,yi)

    x=np.linspace(0,200,29)
    #print(x)
    y = interp_hermite(x)
    print(y)

    plt.plot(x,y,'b-*')
    plt.plot(xi,yi,'ro')

    plt.show()


from sympy import Symbol, Derivative
import numpy as np

#
#
#  Trabalho2:Parte 3 -Encontra uma raiz aproximada para os sistemas de equações abaixo,usando o metodo de Newton para sistemas não lineares.
#
#  F(x1,x2) = 6x1^3 + x1*x2 - 3x2^3 - 4 = 0
#  F(x1,x2) = x2^2 - 18x1*x2^2 + 16x2^3 + 1 = 0
#
#
#
#
#
#
#  Autor       : Marlon Brendo Ramos
#  Instituição : Universidade Federal de Uberlândia
#  Curso       : Sistemas de Informação
#  Disciplina  : Métodos Numéricos
#  Tecnologias : Python3.7
#
#  --------------------------------------------------------------------------------------------------------------------------
#  Esse programa permite a resolução do sistema de equações não lineares abaixo,usando o método de Newton
#
#  F(x1,x2) = 6x1^3 + x1*x2 - 3x2^3 - 4 = 0
#  F(x1,x2) = x2^2 - 18x1*x2^2 + 16x2^3 + 1 = 0
#
#  O programa imprime todas as iterações na saída padrão e seus respectivos valores de k , x^k+1 e || x^k+1 - x^k || ,
#  considerando a precisão de e=10^-3 ou 0.001.
#
#
#
#  Exemplo de saída:
#
#--------Iteracao k ------------- 0
#
#   Xk =  [2, 2]
#   X^k+1 =  [1.36864407 1.33474576]
#   || x^k+1 - x^k || =  0.6652542372881356
#
#----------------------------------
#...
#
#

#Calcula  a matriz jacobiana, utilizando
#derivadas parciais em relaçao a x e y e monta
# uma matriz com as derivadas
def calculaMatrizjacobiana():

    f1 = '6*x**3 + x*y - 3*y**3 -4'
    f2 = 'x**2 - 18*x*y**2 + 16*y**3 +1'
    x1= Symbol('x')
    x2= Symbol('y')

    matrizjacobiana = np.zeros((2,2))
    matrizjacobiana=[

                      [ str( Derivative.doit(Derivative(f1, x1))),   str( Derivative.doit(Derivative(f1, x2)) ) ],
                      [ str( Derivative.doit(Derivative(f2, x1)) ) , str( Derivative.doit(Derivative(f2, x2)) ) ]

    ]

    return matrizjacobiana

#Define J(x^k) iniciada por valores de  xk
#tal que x0[2,2]
def defineJxk(xk,matrizjacobiana):

    x=xk[0]
    y=xk[1]
    Fxk=[["",""],["",""]]
    for i in range(2):
        for j in range(2):
                Fxk[i][j]=eval(matrizjacobiana[i][j])

    return Fxk

#Define -F(x^k).Calcula-se o valor  das funções no xk
def defineFxk(xk):
    return [
            ( 6*xk[0]**3 + xk[0]*xk[1] - 3*xk[1]**3 -4)      * -1,
            (xk[0]**2 - 18*xk[0]*xk[1]**2 + 16*xk[1]**3 +1 ) * -1
    ]

if "__main__" == __name__:

    norma=1
    k=0
    xk=[2,2] #inicia os vetores x0 como [2,2]

    matrizjacobiana=calculaMatrizjacobiana()

    while norma > 0.001:

        Jxk=defineJxk(xk,matrizjacobiana)
        Fxk=defineFxk(xk)

        #Buscando a inversa das matrizes para achar as soluções
        inv=np.linalg.inv(Jxk) #Aplica a inversa da matriz jacobiana
        sk=np.dot(inv,Fxk) #Encontra as soluções x1,x2 para o sistema
        xkprox=xk + sk #Soma os vetores de X^k + S^k
        norma=max(abs(xkprox-xk)) #Encontra a norma fazendo || x^k+1 - x^k ||

        print("--------Iteracao k = {:d}-------------".format(k))
        print("\nXk = ",xk)
        print("X^k+1 = ",xkprox)
        print("|| x^k+1 - x^k || = ",norma)
        print("\n")
        xk=xkprox #atribui o vetor anterior como sendo o próximo
        k+=1


"""
This module implements various modules of the network.
You should fill in code into indicated sections.
"""
import numpy as np

class LinearModule(object):
    """
    Linear module. Applies a linear transformation to the input data.
    """

    def __init__(self, in_features, out_features):
        """
        Initializes the parameters of the module.

        Args:
          in_features: size of each input sample
          out_features: size of each output sample

        TODO:
        Initialize weights self.params['weight'] using normal distribution with mean = 0 and
        std = 0.0001. Initialize biases self.params['bias'] with 0.

        Also, initialize gradients with zeros.
        """

        ########################
        # PUT YOUR CODE HERE  #
        #######################
        self.params = {}

        self.params['weight'] = np.random.normal(0, 0.0001, (out_features, in_features))

        self.params['bias'] = np.zeros((1, out_features))

        self.grads = {}
        self.grads['weight'] = np.zeros((out_features, in_features))
        self.grads['bias'] = np.zeros((1, out_features))

        self.intermediate = {}
        self.intermediate["x"] = np.zeros((in_features, 1))

        # raise NotImplementedError

        ########################
        # END OF YOUR CODE    #
        #######################

    def forward(self, x):
        """
        Forward pass.

        Args:
          x: input to the module
        Returns:
          out: output of the module

        TODO:
        Implement forward pass of the module.

        Hint: You can store intermediate variables inside the object. They can be used in backward pass computation.
        """

        ########################
        # PUT YOUR CODE HERE  #
        #######################
        batch_size = x.shape[0]

        # store intermediate result
        self.intermediate["x"] = x.copy()

        output_size = self.params["weight"].shape[0]

        out = x @ self.params["weight"].T + np.broadcast_to(self.params["bias"], (batch_size,output_size))

        ########################
        # END OF YOUR CODE    #
        #######################

        return out

    def backward(self, dout):
        """
        Backward pass.

        Args:
          dout: gradients of the previous module
        Returns:
          dx: gradients with respect to the input of the module

        TODO:
        Implement backward pass of the module. Store gradient of the loss with respect to
        layer parameters in self.grads['weight'] and self.grads['bias'].
        """

        ########################
        # PUT YOUR CODE HERE  #
        #######################
        batch_size, n_neurons = dout.shape
        # compute gradient with respect to input of module

        dx = dout @ self.params["weight"]

        # store gradient updates
        self.grads["weight"] = dout.T @ self.intermediate["x"]
        # self.grads['bias'] = np.sum(dout, axis=0)[:, None].T
        self.grads['bias'] = np.ones(batch_size) @ dout

        ########################
        # END OF YOUR CODE    #
        #######################
        return dx

class SoftMaxModule(object):
    """
    Softmax activation module.
    """

    def __init__(self):
      self.intermediate = np.zeros(1)

    def forward(self, x):
        """
        Forward pass.
        Args:
          x: input to the module
        Returns:
          out: output of the module

        TODO:
        Implement forward pass of the module.
        To stabilize computation you should use the so-called Max Trick - https://timvieira.github.io/blog/post/2014/02/11/exp-normalize-trick/

        Hint: You can store intermediate variables inside the object. They can be used in backward pass computation.
        """

        ########################
        # PUT YOUR CODE HERE  #
        #######################
        # vectorize max_trick

        b = np.max(x, axis=1, keepdims=True)
        x_shift = np.exp(x-b)
        out = x_shift / np.sum(x_shift, axis=1, keepdims=True)

        # b = np.amax(x, 1)
        # temp_x = x - b[:, None]
        # temp_x = np.exp(temp_x)
        # temp_x = np.sum(temp_x, axis=1)
        # temp_x = np.log(temp_x)
        # denominator = b + temp_x
        # out = np.exp(x - denominator[:, None])

        self.intermediate = out.copy()

        ########################
        # END OF YOUR CODE    #
        #######################

        return out

    def backward(self, dout):
        """
        Backward pass.
        Args:
          dout: gradients of the previous modul
        Returns:
          dx: gradients with respect to the input of the module

        TODO:
        Implement backward pass of the module.
        """

        ########################
        # PUT YOUR CODE HERE  #
        #######################

        inter_step = np.multiply(dout, self.intermediate)
        temp_x = np.einsum("in, in, ij->ij", dout, self.intermediate, self.intermediate)

        dx = inter_step - temp_x

        ########################
        # END OF YOUR CODE    #
        #######################

        return dx

class CrossEntropyModule(object):
    """
    Cross entropy loss module.
    """

    def forward(self, x, y):
        """
        Forward pass.
        Args:
          x: input to the module
          y: labels of the input
        Returns:
          out: cross entropy loss

        TODO:
        Implement forward pass of the module.
        """

        ########################
        # PUT YOUR CODE HERE  #
        #######################

        batch_size = x.shape[0]
        log_x = np.log(x)
        samples_loss = -np.sum(np.multiply(y, log_x), axis=1) / batch_size
        out = np.sum(samples_loss)

        ########################
        # END OF YOUR CODE    #
        #######################

        return out

    def backward(self, x, y):
        """
        Backward pass.
        Args:
          x: input to the module
          y: labels of the input
        Returns:
          dx: gradient of the loss with the respect to the input x.

        TODO:
        Implement backward pass of the module.
        """

        ########################
        # PUT YOUR CODE HERE  #
        #######################

        batch_size = x.shape[0]
        dx = - (np.divide(y, x)) / batch_size

        ########################
        # END OF YOUR CODE    #
        #######################

        return dx

class ELUModule(object):
    """
    ELU activation module.
    """
    def __init__(self):
      self.intermediate = np.zeros(1)

    def forward(self, x):
        """
        Forward pass.

        Args:
          x: input to the module
        Returns:
          out: output of the module

        TODO:
        Implement forward pass of the module.

        Hint: You can store intermediate variables inside the object. They can be used in backward pass computation.
        """
        ########################
        # PUT YOUR CODE HERE  #
        #######################
        out = np.where(x >= 0, x, np.exp(x) - 1)

        self.intermediate = x.copy()

        ########################
        # END OF YOUR CODE    #
        #######################

        return out

    def backward(self, dout):
        """
        Backward pass.
        Args:
          dout: gradients of the previous module
        Returns:
          dx: gradients with respect to the input of the module

        TODO:
        Implement backward pass of the module.
        """

        ########################
        # PUT YOUR CODE HERE  #
        #######################
        elu_derivative = np.where(self.intermediate >= 0, 1, np.exp(self.intermediate))
        dx = np.multiply(dout, elu_derivative)

        ########################
        # END OF YOUR CODE    #
        #######################
        return dx


import numpy as np
import copy

class LeastSquareEstimator:
    '''
    A class that performs least square estimation recursively.
    see https://ocw.mit.edu/courses/mechanical-engineering/2-160-identification-estimation-and-learning-spring-2006/lecture-notes/lecture_2.pdf
    '''
    def __init__(self, initial_value, initial_covar, forgetting_factor=1.0):
        '''
        Ctor.
        :param state_size number of state variables to estimate.
        :param forgetting_factor a number within (0.0, 1.0] that discounts old samples.
        '''
        if ((forgetting_factor > 1.0) or \
            (forgetting_factor <= 0.0)):
            raise ValueError('Invalid forgetting factor.')

        self._theta = initial_value
        self._P = initial_covar
        self._alpha = forgetting_factor

    def update(self, phi, y):
        '''
        Update the estimate with new sample (phi, y).
        The model is theta.T * phi == y
        '''
        denom = self._alpha + np.dot(phi, np.dot(self._P, phi))

        self._theta += np.dot(self._P, phi) / denom * (y - np.dot(phi, self._theta))
        self._P = 1.0 / self._alpha * (self._P - np.dot(self._P, np.dot(np.outer(phi, phi), self._P)) / denom)

    def get_estimate_mean(self):
        return copy.deepcopy(self._theta)

    def get_estimate_covar(self):
        return copy.deepcopy(self._P)

if (__name__ == '__main__'):
    pass


import pymc3 as pm
import numpy as np
from statsmodels.stats.moment_helpers import corr2cov
from theano import tensor as tt

def linear():
    np.random.seed(0)
    size = 200
    true_intercept = 1
    true_slope = 2

    x = np.linspace(0, 1, size)
    # y = a + b*x
    true_regression_line = true_intercept + true_slope * x
    # add noise
    y = true_regression_line + np.random.normal(scale=.1, size=size)

    data = dict(x=x, y=y)

    with pm.Model() as model:  # model specifications in PyMC3 are wrapped in a with-statement
        pm.glm.GLM.from_formula('y ~ x', data)
    return model, {'Intercept': (true_intercept, 0.1), 'x': (true_slope, 0.1)}

def read_test_data():
    """
    :return: Z vector array, S covariance matrix array
    """
    mu = np.arange(3)
    corr_coeffs = np.array([-0.3, 0.1, 0.7])
    ndim = int(np.sqrt(1 + (4 * len(corr_coeffs) * 2)) + 1) // 2
    corr = np.zeros((ndim, ndim))
    corr[np.triu_indices(ndim, k=1)] = corr_coeffs
    corr[np.diag_indices(ndim)] = 1
    corr = corr + corr.T - np.diag(corr.diagonal())

    std = np.array([1, 2, 0.1])
    cov = np.dot(corr, np.dot(np.diag(std), corr))
    Z = np.random.multivariate_normal(mu, cov, 7000)
    S = np.tile(np.eye(3), (7000, 1, 1)) * 0.01
    return Z, S, (mu, corr_coeffs, corr, cov, std)

def correlation():
    np.random.seed(0)
    values, S, (true_mu, true_corr_coeffs, true_corr, true_cov, true_std) = read_test_data()
    nmeas, ndim = values.shape
    with pm.Model() as model:
        packed_L = pm.LKJCholeskyCov('packed_L', n=ndim, eta=1, sd_dist=pm.HalfCauchy.dist(2.5))
        L = pm.expand_packed_triangular(ndim, packed_L)
        cov = pm.Deterministic('cov', L.dot(L.T))

        std = pm.Deterministic('std', tt.sqrt(tt.diag(cov)))
        diag = tt.diag(std)
        diaginv = tt.nlinalg.matrix_inverse(diag)
        corr = tt.dot(diaginv, tt.dot(cov, diaginv))

        indices = np.triu_indices(ndim, k=1)
        pm.Deterministic('corr_coeffs', corr[indices])

        mu = pm.Normal('mu', mu=values.mean(axis=0), sd=values.std(axis=0), shape=ndim)  # centre of gaussian
        pm.MvNormal('like', mu=mu, chol=L, observed=values, shape=ndim)
    return model, {'mu': (true_mu, 0.1), 'cov': (true_cov, 0.1)}

import numpy,from theano,from statsmodels,import pymc3


from numpy import minimum

INF = 999999

def coins_changing(v,coin_list):
    """
    int v: given value to exchange with coins
    list coin_list: a sequence of coin values, like 1p,2p,5p...

    return the number of coins
    """
    k = len(coin_list)     # number of denominations of the coin
    C = [INF] * (v + 1)    # minimum number of coins needed to make the change
    P = [INF] * (v + 1)    # extra array P to store the "coin used to get the best answer"

    C[0] = 0
    C[1] = 1

    for i in range(2,v+1):
        for j in range(1,k):
            if (i >= coin_list[j] and C[i] > 1 + C[i-coin_list[j]]):
                C[i] = 1 + C[i-coin_list[j]]
                P[i] = j

    while v > 0:
        j = P[v]
        v = v - coin_list[j]

    return C[v]

def coins_changing1(d, n, k):
    M = [0]*(n+1)
    S = [0]*(n+1)

    for j in range(1, n+1):
        minimum = INF
        coin = 0

        for i in range(1, k+1):
            if(j >= d[i]):
                minimum = min(minimum, 1+M[j-d[i]])
                coin = i
        M[j] = minimum
        S[j] = coin

    l = n
    while(l>0):
        print(d[S[l]])
        l = l-d[S[l]]
    return M[n]

if __name__ == '__main__':
    Coins = [0, 1, 5, 10]
    print(coins_changing1(Coins,12,3))


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

# each point is length, width, type(0, 1)

data = [[3,   1.5, 1],
        [2,   1,   0],
        [4,   1.5, 1],
        [3,   1,   0],
        [3.5, .5,  1],
        [2,   .5,  0],
        [5.5, 1,   1],
        [1,   1,   0]]

mystery_flower = [4.5, 1]

# network

#    o
#   / \
#  o   o

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

def sigmoid_p(x):
    return sigmoid(x) * (1-sigmoid(x))

T = np.linspace(-5, 5, 100)
Y = sigmoid(T)

# scatter data
plt.axis([0, 6, 0, 6])
plt.grid()
for i in range(len(data)):
    point = data[i]
    color = "r"
    if point[2] == 0:
        color = "b"
    plt.scatter(point[0], point[1], c=color)

# Training loop

learning_rate = 0.2
costs = []

w1 = np.random.randn()
w2 = np.random.randn()
b = np.random.randn()

for i in range(50000):
    ri = np.random.randint(len(data))
    point = data[ri]

    z = point[0] * w1 + point[1] * w2 + b
    pred = sigmoid(z)

    target = point[2]
    cost = np.square(pred - target)

    dcost_pred = 2 * (pred - target)
    dpred_dz = sigmoid_p(z)

    dz_dw1 = point[0]
    dz_dw2 = point[1]
    dz_db = 1

    dcost_dz = dcost_pred * dpred_dz

    dcost_dw1 = dcost_dz * dz_dw1
    dcost_dw2 = dcost_dz * dz_dw2
    dcost_db = dcost_dz * dz_db

    w1 = w1 - learning_rate * dcost_dw1
    w2 = w2 - learning_rate * dcost_dw2
    b = b - learning_rate * dcost_db

    if i % 100 == 0:
        cost_sum = 0
        for j in range(len(data)):
            point = data[ri]

            z = point[0] * w1 + point[1] * w2 + b
            pred = sigmoid(z)

            target = point[2]
            cost_sum += np.square(pred - target)
        costs.append(cost_sum / len(data))

plt.plot(costs)

# seeing model predictions

for i in range(len(data)):
    point = data[i]
    print(point)
    z = point[0] * w1 + point[1] * w2 + b
    pred = sigmoid(z)
    print("Pred: {}".format(pred))


from lib.operators.Operator import Operator
import numpy as np

class Tanh(Operator):
    def __init__(self):
        super().__init__()

    @staticmethod
    def function(x):
        return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))

    @staticmethod
    def derivative(x):
        return 1 - np.power(Tanh.function(x), 2)


from math import exp, log, pow

import matplotlib.pyplot as plt
import networkx          as nx

class GraphProp:
    def __init__(self, graph):
        self.graph = graph

        self.m = None
        self.c = None

    def avg_path_length(self):
        if nx.number_connected_components(self.graph) == 1:
            return nx.average_shortest_path_length(self.graph)
        else:
            print('[Error] graph is not connected')

    def degree_distribution(self):
        deg = [self.graph.degree(node) for node in self.graph.nodes()]
        x = sorted(list(set(deg)))
        y = [deg.count(i) for i in x]
        return x, y

    def max_node_degree(self):
        return max(self.graph.degree(n) for n in self.graph.nodes())

    def plot_degree_distribution(self, line=False, axis=None, dot_size=7):
        if line and not (self.m and self.c):
            self.power_law_coefficients()
        x, y = self.degree_distribution()
        # plt.title('Node degree distribution')
        plt.xlabel('Node degree')
        plt.ylabel('Count')
        plt.plot(x, y, 'co', markersize=dot_size)

        if axis:
            plt.axis(axis)
        else:
            plt.axis([0, max(x)*1.2, 0, max(y)*1.2])

        if line:
            yy = [self.c * pow(x[i], self.m) for i in range(len(x))]
            plt.plot(x, yy)

        plt.show()

    def plot_degree_distribution_loglog(self, line=False):
        if line and not (self.m and self.c):
            self.power_law_coefficients()
        x, y = self.degree_distribution()
        plt.title('Node degree distribution logarithmic scale')
        plt.xlabel('Node degree')
        plt.ylabel('Count')
        plt.loglog(x, y, 'co')
        if line:
            yy = [self.c * pow(x[i], self.m) for i in range(len(x))]
            plt.loglog(x, yy)
        plt.show()

    def power_law_coefficients(self):
        x, y = self.degree_distribution()

        n = len(x)
        log_x = [log(i) for i in x]
        log_y = [log(i) for i in y]

        x_avg = sum(log_x) / float(n)
        y_avg = sum(log_y) / float(n)

        m = sum((log_x[i] * log_y[i] for i in range(n))) - n * x_avg * y_avg
        m /= sum(n * n for n in log_x) - n * x_avg * x_avg

        log_c = y_avg * sum(log_x[i] * log_x[i] for i in range(n)) - x_avg * sum(log_x[i] * log_y[i] for i in range(n))
        log_c /= sum(n * n for n in log_x) - n * x_avg * x_avg
        # log_c = y_avg - m * x_avg
        c = exp(log_c)

        self.m, self.c = m, c
        return m, c


import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm

M = 40 # GRID POINTS on space interval
N = 70 # GRID POINTS on time interval

x0 = 0
xL = 1

# ----- Spatial discretization step -----
dx = (xL - x0)/(M - 1)

t0 = 0
tF = 10

# ----- Time step -----
dt = (tF - t0)/(N - 1)

r = 0.4

# ----- Creates grids -----
xspan = np.linspace(x0, xL, M)
tspan = np.linspace(t0, tF, N)

# ----- Initializes matrix solution U -----
U = np.zeros((M, N))

# ----- Initial condition -----
U[:,0] = np.sin((np.pi*xspan))

# ----- Dirichlet Boundary Conditions -----
U[0,:] = 0.0
U[-1,:] = 0.0

# ----- Equation (15.8) in Lecture 15 -----
for k in range(0, N-1):
    for i in range(1, M-1):
        U[i, k+1] = r*U[i-1, k] + (1-2*r)*U[i,k] + r*U[i+1,k]

X, T = np.meshgrid(tspan, xspan)

fig = plt.figure()
ax = fig.gca(projection='3d')

surf = ax.plot_surface(X, T, U, cmap=cm.coolwarm,
                       linewidth=0, antialiased=False)

ax.set_xlabel('Time')
ax.set_ylabel('Space')
ax.set_zlabel('U')
plt.tight_layout()
plt.show()


import math
import numpy as np
from fractions import Fraction

def solution(m):
    # Your code here
    if len(m) == 1:
        return [1, 1]

    # find A - probability matrix, TR - terminal states vector, ABS - absorbing states vector
    A = np.array(m).astype(float)
    TR = []
    ABS = []
    for state in range(len(A)):
        sumState = float(sum(A[state]))
        if sumState:
            A[state] = A[state] / sumState
            TR.append(state)
        else:
            ABS.append(state)

    shapeA = len(A)  # must be a square matrix

    # find fundamental matrix P
    #            TR  ABS
    #       TR  | Q | R |
    # P  =  ABS | O | I |
    qShape = len(TR)
    Q = np.zeros((qShape, qShape))
    rShape = len(ABS)
    R = np.zeros((qShape, rShape))

    for row in range(shapeA):
        if row in TR:
            qRow = []
            rRow = []
            for col in range(shapeA):
                if col in TR:
                    qRow.append(A[row][col])
                else:
                    rRow.append(A[row][col])
            Q[row] = qRow
            R[row] = rRow

    # find N = (I - Q)^-1
    IQ = np.identity(qShape) - Q
    N = np.linalg.inv(IQ)

    # find B = NR
    B = np.matmul(N, R)

    # since S0 is the only initial state, we should only parse B[0]
    nominators = []
    denominators = []
    for val in B[0]:
        nominators.append(Fraction(val).limit_denominator().numerator)
        denominators.append(Fraction(val).limit_denominator().denominator)
    # find the least common denominator
    lcd = 1
    for d in denominators:
        lcd = abs(lcd * d) // math.gcd(lcd, d)

    # rearrange nominators, add lcd and return
    for idx in range(len(nominators)):
        nominators[idx] = nominators[idx] * int(lcd/denominators[idx])
    nominators.append(lcd)

    return nominators

print(solution([
    [0, 1, 0, 0, 0, 1],
    [4, 0, 0, 3, 2, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0]
]))

print(solution([
    [0, 2, 1, 0, 0],
    [0, 0, 0, 3, 4],
    [0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0]
]))


import numpy as np
from sigmoid import *

def cost_function_reg(theta, X, y, lmd):
    m = y.size

    # You need to return the following values correctly
    cost = 0
    grad = np.zeros(theta.shape)

    # ===================== Your Code Here =====================
    # Instructions : Compute the cost of a particular choice of theta
    #                You should set cost and grad correctly.
    #
    hypothesis = sigmoid(np.dot(X, theta))

    reg_theta = theta[1:]

    cost = np.sum(-y * np.log(hypothesis) - (1 - y) * np.log(1 - hypothesis)) / m \
           + (lmd / (2 * m)) * np.sum(reg_theta * reg_theta)

    normal_grad = (np.dot(X.T, hypothesis - y) / m).flatten()

    grad[0] = normal_grad[0]
    grad[1:] = normal_grad[1:] + reg_theta * (lmd / m)

    # ===========================================================

    return cost, grad


import numpy as np

def linear_kernel(x1, x2):
    return np.inner(x1, x2) + 1

def rbf_kernel(x1, x2, gamma = 2):
    k = np.exp(-gamma*(np.linalg.norm(x1 - x2)**2))
    return k


import numpy as np

def QR(matrix):
    H, W = matrix.shape

    np_dtype = np.float64

    rest = np.zeros((H, 1), dtype=np_dtype)
    Q = np.zeros_like(matrix, dtype=np_dtype)
    R = np.zeros_like(matrix, dtype=np_dtype)

    Q[:, 0] = matrix[:, 0] / np.sqrt(np.sum(np.square(matrix[:, 0])))
    R[0, 0] = np.matmul( matrix[:, 0].T, Q[:, 0] )

    for i in range(1, W):
        rest = np.zeros(H, dtype=np_dtype)
        for j in range(0, i):
            R[j, i] = np.matmul( matrix[:, i].T, Q[:, j] )
            rest += R[j, i] * Q[:, j]

        Q[:, i] = matrix[:, i] - rest
        Q[:, i] = Q[:, i] / np.sqrt(np.sum(np.square(Q[:, i])))
        R[i, i] = np.matmul( matrix[:, i].T, Q[:, i] )

    return Q, R

if __name__ == "__main__":
    A = np.array(
        [[ 1, 1, 0],
         [1, 0, 1],
         [0, 1, 1]])
    q, r = QR(A)
    q_np, r_np = np.linalg.qr(A)
    print('-----result-------')
    print('Q:\n', q)
    print('R:\n', r)
    print('QxR:\n', np.matmul(q, r))
    print('-------end--------')

    print('-----numpy-------')
    print('Q:\n', q_np)
    print('R:\n', r_np)
    print('QxR:\n', np.matmul(q_np, r_np))
    print('-------end--------')