import numpy as np
from scipy.linalg import inv, det

def multivariate_kl(m1, s1, m2, s2):
    """
    Multivariate KL-divergence measure for high-dimensional gaussians. For
    use with the parameters, rather than evaluating the empirical distributions.
    See derivation:
    https://stats.stackexchange.com/questions/234757/how-to-use-kullback-leibler-divergence-if-mean-and-standard-deviation-of-of-two

    For the sake of notation: N(m1, s1) ~ p, and N(m2, s2) ~ q

    Parameters
    ----------
    m1, m2 : array, shape (d,)
        Means of the two distributions.
    s1, s2 : array, shape (d, d)
        Covariance matrices of the two distributions.

    Returns
    -------
    kl : float
        KL-divergence.
    """
    s2inv = inv(s2)
    deltamu = m2 - m1
    a = np.log(det(s2) / det(s1))
    b = np.trace(s2inv @ s1)
    c = deltamu.dot(s2inv).dot(deltamu)
    d = - m1.shape[0]
    return 0.5 * (a + b + c + d)

def multivariate_js(m1, s1, m2, s2):
    """
    Jensen-Shannon divergence measure for high-dimensional gaussians. For
    use with analytic parameters, rather than evaluating empirical distributions.
    See formulation: https://en.wikipedia.org/wiki/Jensen%E2%80%93Shannon_divergence

    For the sake of notation: N(m1, s1) ~ p, and N(m2, s2) ~ q

    Parameters
    ----------
    m1, m2 : array, shape (d,)
        Means of the two distributions.
    s1, s2 : array, shape (d, d)
        Covariance matrices of the two distributions.

    Returns
    -------
    js : float
        JS-divergence.
    """
    pq = multivariate_kl(m1, s1, m2, s2)
    qp = multivariate_kl(m2, s2, m1, s1)
    return 0.5 * (pq + qp)

def multivariate_hellinger(u1, cov1, u2, cov2, gamma=0.00125):
    """
    Hellinger distance measure for high-dimensional gaussians. For
    use with analytic parameters, rather than evaluating empirical distributions.

    For the sake of notation: N(m1, s1) ~ p, and N(m2, s2) ~ q

    Parameters
    ----------
    u1, u2 : array, shape (d,)
        Means of the two distributions.
    cov1, cov2 : array, shape (d, d)
        Covariance matrices of the two distributions.
    gamma: float
        Probability measure

    Returns
    -------
    hellinger : float
            Hellinger distance.
    """

    mcov = 0.5 * cov1 + 0.5 * cov2
    dets = np.sqrt(np.sqrt(np.linalg.det(cov1)) * np.sqrt(
        np.linalg.det(cov2)) / np.linalg.det(mcov))
    mahala = (u1 - u2).dot(np.linalg.pinv(mcov)).dot(u1 - u2)
    h = np.exp(-gamma * mahala) * dets
    return 1 - np.sqrt(1 - h)


#!/usr/bin/env python3

from __future__ import print_function
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets, linear_model

# heigh(cm), input data, each row is a data point
X = np.array([[147, 150, 153, 158, 163, 165, 168, 170, 173, 175, 178, 180, 183]]).T

# weight(kg)
y = np.array([49, 50, 51, 54, 58, 59, 60, 62, 63, 64, 66, 67, 68])

# Building Xbar
one = np.ones((X.shape[0], 1))
Xbar = np.concatenate((one, X), axis=1) # each point is one row

# Calculating weights of the fitting line
A = np.dot(Xbar.T, Xbar)
b = np.dot(Xbar.T, y)
w = np.dot(np.linalg.pinv(A), b)

# weights
w_0, w_1 = w[0], w[1]

# y1 = w_1 * 155 + w_0
# y2 = w_1 * 160 + w_0
#
# print('Input 155cm, true output 52kg, predicted output %.2fkg' %(y1))
# print('Input 160cm, true output 56kg, predicted output %.2fkg' %(y2))

# fit the model by Linear Regression
regr = linear_model.LinearRegression()
regr.fit(X, y)

# Compare two results
print('scikit-learn solution : w_1 = ', regr.coef_[0], 'w_0 = ', regr.intercept_)
print('our solution          : w_1 = ', w[1], 'w_0 = ', w[0])


"""
===============================
Minima and roots of a function
===============================

Demos finding minima and roots of a function.
"""

############################################################
# Define the function
############################################################

import numpy as np

x = np.arange(-10, 10, 0.1)
def f(x):
    return x**2 + 10*np.sin(x)

############################################################
# Find minima
############################################################

from scipy import optimize

# Global optimization
grid = (-10, 10, 0.1)
xmin_global = optimize.brute(f, (grid, ))
print("Global minima found %s" % xmin_global)

# Constrain optimization
xmin_local = optimize.fminbound(f, 0, 10)
print("Local minimum found %s" % xmin_local)

############################################################
# Root finding
############################################################

root = optimize.root(f, 1)  # our initial guess is 1
print("First root found %s" % root.x)
root2 = optimize.root(f, -2.5)
print("Second root found %s" % root2.x)

############################################################
# Plot function, minima, and roots
############################################################

import matplotlib.pyplot as plt
fig = plt.figure(figsize=(6, 4))
ax = fig.add_subplot(111)

# Plot the function
ax.plot(x, f(x), 'b-', label="f(x)")

# Plot the minima
xmins = np.array([xmin_global[0], xmin_local])
ax.plot(xmins, f(xmins), 'go', label="Minima")

# Plot the roots
roots = np.array([root.x, root2.x])
ax.plot(roots, f(roots), 'kv', label="Roots")

# Decorate the figure
ax.legend(loc='best')
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
ax.axhline(0, color='gray')
plt.show()


"""Numpy version of euclidean distance, etc.
Notice the input/output shape of methods, so that you can better understand
the meaning of these methods."""
import numpy as np

def normalize(nparray, order=2, axis=0):
  """Normalize a N-D numpy array along the specified axis."""
  norm = np.linalg.norm(nparray, ord=order, axis=axis, keepdims=True)
  return nparray / (norm + np.finfo(np.float32).eps)

def compute_dist(array1, array2, type='euclidean'):
  """Compute the euclidean or cosine distance of all pairs.
  Args:
    array1: numpy array with shape [m1, n]
    array2: numpy array with shape [m2, n]
    type: one of ['cosine', 'euclidean']
  Returns:
    numpy array with shape [m1, m2]
  """
  assert type in ['cosine', 'euclidean']
  if type == 'cosine':
    array1 = normalize(array1, axis=1)
    array2 = normalize(array2, axis=1)
    dist = np.matmul(array1, array2.T)
    return dist
  else:
    # shape [m1, 1]
    square1 = np.sum(np.square(array1), axis=1)[..., np.newaxis]
    # shape [1, m2]
    square2 = np.sum(np.square(array2), axis=1)[np.newaxis, ...]
    squared_dist = - 2 * np.matmul(array1, array2.T) + square1 + square2
    squared_dist[squared_dist < 0] = 0
    dist = np.sqrt(squared_dist)
    return dist


__all__ = ['sigmoid', 'minimum_jerk']

import numpy as np

def sigmoid(x, A=0, K=1, C=1, Q=1, B=1, v=1, x_offset=0):
    """
    Returns f(x) = A + (K - A) / ((C + Q * np.exp(-B*(x - x_offset)))**(1/v))
    This is a generalized logistic function.
    The default arguments reduce this to a simple sigmoid:
        f(x) = 1 / (1 + np.exp(-x))
    Args:
        x (np.ndarray):
        A (float):
        K (float):
        C (float):
        Q (float):
        B (float):
        v (float):
        x_offset:

    Returns:
        np.ndarray: A + (K - A) / ((C + Q * np.exp(-B*(x - x_offset)))**(1/v))
    """
    y = A + (K - A) / ((C + Q * np.exp(-B*(x - x_offset)))**(1/v))
    return y

def minimum_jerk(x: np.ndarray, a0=0, af=1, degree=1, duration=None) -> np.ndarray:
    r"""
    A 1-D trajectory that minimizes jerk (3rd time-derivative of position).
    A minimum jerk trajectory is considered "smooth" and to be a feature of natural limb movements.
    https://storage.googleapis.com/wzukusers/user-31382847/documents/5a7253343814f4Iv6Hnt/minimumjerk.pdf

    A minimum-jerk trajectory is defined by:
    ```math
    trajectory = a0 + (af - a0) * (10(dx^3) - 15(dx^4) + 6(dx^5))
    ```
    where a0 is the resting position, and af is the finishing position.

    duration is assumed to be the extent of x but it may be overidden.
    Args:
        x:
        a0:
        af:
        degree:
        duration (float): Total duration of x in seconds. If None (default), calculated duration from x.

    Returns:
        a0 + (af - a0) * (10*(dx.^3) - 15*(dx.^4) + 6*(dx.^5))
    """
    x = np.array(x)[:, None]
    assert(x.size == x.shape[0]), f"x must be 1D trajectory, found {x.shape}"

    a0 = np.atleast_2d(a0)
    af = np.atleast_2d(af)

    if duration is None:

        sorted_x = np.sort(x, axis=0)
        dx = np.diff(x, axis=0)
        duration = sorted_x[-1] - sorted_x[0] + np.min(dx)

    dx = x / duration

    if degree not in [1, 2]:
        # Default - no derivative
        k0 = a0
        x1 = 10 * dx**3
        x2 = -15 * dx**4
        x3 = 6 * dx**5
    elif degree == 1:
        # Velocity
        k0 = np.zeros_like(a0)
        x1 = 30 * dx**2
        x2 = -60 * dx**3
        x3 = 30 * dx**4
    elif degree == 2:
        # Acceleration
        k0 = np.zeros_like(a0)
        x1 = 60 * dx
        x2 = -180 * dx**2
        x3 = 120 * dx**3

    return k0 + (af - a0) * (x1 + x2 + x3)


import numpy as np

class Quaternion:

    """
    returns Q matrix of a quaternion. An anti-symmetric orthogonal
    matrix that helps with quaternion multiplication.
    See http://www.diva-portal.org/smash/get/diva2:1010947/FULLTEXT01.pdf
    """
    @staticmethod
    def Q_Matrix(q):
        q0 = q[0]
        q1 = q[1]
        q2 = q[2]
        q3 = q[3]
        return np.array([  [q0, -q1, -q2, -q3],
                           [q1, q0, -q3, q2],
                           [q2, q3, q0, -q1],
                           [q3, -q2, q1, q0]])
    """
    Returns Quaternion : the conjugate of the quaternion in question
    """
    @staticmethod
    def conjugate(q):
        q0 = q[0]
        q1 = q[1]
        q2 = q[2]
        q3 = q[3]
        return np.array([q0,-q1,-q2,-q3])

    """
    Returns rotation matrix of quaternion.
    """
    @staticmethod
    def rotationMatrix(q):
        q0 = q[0]
        q1 = q[1]
        q2 = q[2]
        q3 = q[3]
        R = np.zeros([3,3])

        R[0,0] = q0**2 + q1**2 - q2**2 - q3**2
        R[1,0] = 2*(q1*q2 + q0*q3)
        R[2,0] = 2*(q1*q3 - q0*q2)

        R[0,1] = 2*(q1*q2 - q0*q3)
        R[1,1] = q0**2 - q1**2 + q2**2 - q3**2
        R[2,1] = 2*(q2*q3 + q0*q1)

        R[0,2] = 2*(q1*q3 + q0*q2)
        R[1,2] = 2*(q2*q3 - q0*q1)
        R[2,2] = q0**2 - q1**2 - q2**2 + q3**2
        return R
    """
    q : List_like object that contains 4 elements e.g. ndarray, list, or tupple
    """
    def __init__(self, q):
        if len(q) != 4:
            raise Exception("Quaternion must have 4 real elements")
        self.q = np.array([q[0],q[1],q[2],q[3]])
        self.C = Quaternion.conjugate(self.q)
        self.Q = Quaternion.Q_Matrix(self.q)
        self.R = Quaternion.rotationMatrix(self.q)

    """
    Returns Length of the quaternion. Must always be 4.
    """
    def __len__(self):
        return len(self.q)
    def __str__(self) -> str:
        return "Quaternion(["+str(self[0])+","+str(self[1])+","+str(self[2]) +","+ str(self[3])+"])"
    def __repr__(self):
        return "Quaternion(["+str(self[0])+","+str(self[1])+","+str(self[2]) +","+ str(self[3])+"])"
    def __getitem__(self,key):
        return self.q[key]

    def __mul__(self,other):
        if not isinstance(other, (float, int)):
            raise TypeError("Right operand should be a numerical scalar value. It can't be " + str(type(other)))
        return Quaternion(other * self.q)
    def __rmul__(self,other):
        if not isinstance(other, (float, int)):
            raise TypeError("Left operand should be a numerical scalar value. It can't be " + str(type(other)))
        return Quaternion(other * self.q)

    """
    Quaternion multiplication. Plain and simple.
    """
    def __matmul__(self,other):
        if len(other) != 4:
            raise Exception("Right operand quaternion must have 4 elements")
        result = np.dot(self.Q, other.q)
        return Quaternion(result)
    """
    Returns the norm of the quaternion.
    """
    def norm(self):
        return np.linalg.norm(self.q)

    """
    Returns unit quaternion of the current quaternion.
    """
    def normalize(self):
        return Quaternion(self.q/self.norm())

    """
    Returns the inverse of the quaternion. q*q_inv = [1,0,0,0] (unit quaternion)
    """
    def inv(self):
        return Quaternion(self.C / (self.norm() ** 2))

    """
    Rotates vector, or any point in affine space, and expressing its image in a fixed reference frame

    Input v: an array-like containing 3 elements representing the vector expressed in a fixed frame.
    Returns: rotation of v in the fixed frame by the used quaternion.
    """
    def rotate(self,v):
        if len(v) != 3:
            raise ValueError("Vector v must have (3) elements. But it in reality, it had : ("+ str(len(v))+  ") elements")

        return self.R @ v
    """
    Transforms vector v to another reference frame, represented by quaternion q.
    """
    def transform(self,v):
        if len(v) != 3:
            raise ValueError("Vector v must have (3) elements. But it in reality, it had : ("+ str(len(v))+  ") elements")

        return self.R.T @ v


'''
Created on 2020-03-30 11:12:12
Last modified on 2020-11-03 15:03:06

@author: L. F. Pereira (lfpereira@fe.up.pt)

Main goal
---------
Define matrix-related functions.

Notes
-----
-Care must be taken with imports to make sure this module can be used inside
Abaqus.
-scipy is not used because it does not exit in Abaqus.
'''

# imports

# third-party
import numpy as np

# TODO: test using abaqus python

# function definition

def symmetricize_vector(vec):
    '''
    Create a symmetric matrix given a vector.

    Parameters
    ----------
    vec : array-like
        Elements ordered by its position in the upper triangular matrix.
    '''

    # compute dimension
    n = int(1. / 2. * (-1. + np.sqrt(1. + 8. * len(vec))))

    # assign variables to the right positions
    matrix = np.empty((n, n))
    k = 0
    for i in range(n):
        for j in range(i, n):
            matrix[i, j] = vec[k]
            if i != j:
                matrix[j, i] = matrix[i, j]
            k += 1

    return np.array(matrix)

def sqrtm(matrix):
    '''
    Square root of a square symmetric matrix.

    Parameters
    ----------
    matrix : array-like. shape: [n, n]
        Symmetric matrix
    '''

    # get eigenvalues and vectors
    w, v = np.linalg.eig(matrix)

    # define spectral decomposition
    spec_decomp = np.zeros(np.shape(matrix))
    for i in range(np.size(w)):
        spec_decomp[i, i] = w[i]
    spec_decomp_sqrt = np.sqrt(spec_decomp)

    # square root of the original matrix
    matrix_sqrt = np.dot(v, np.dot(spec_decomp_sqrt, v.transpose()))

    return matrix_sqrt


import dezero as dz
from dezero.functions import Square, Exp
import numpy as np

def numerical_diff(f, x, eps=1e-4):
    """p.58에 나오는 수치 미분 함수. 중앙 차분으로 구현

    컴퓨터는 극한을 취급할 수 없어서 극한과 비슷한, 아주 작은 값으로 극한값을 대체하여 미분 연산에 대신 사용.

    수치 미분의 결과에는 자릿수 누락 때문에 오차가 포함되기 쉽다는 문제가 있으며,
    더 큰 문제로는 개산량이 매우 많다는 점이 있음.

    :param eps: epsilon의 약어. 아주 작은 양의 부동소수점값을 담는 변수.
    """
    x0 = dz.Variable(x.data - eps)
    x1 = dz.Variable(x.data + eps)
    y0 = f(x0)
    y1 = f(x1)
    return (y1.data - y0.data) / (2 * eps)

f = Square()
x1 = dz.Variable(np.array(2.0))
dy = numerical_diff(f, x1)
print(dy)

# 예상과 달리 eps가 더 작아지니 오차가 더 커짐

dy_1e6 = numerical_diff(f, x1, eps=1e-6)
print(dy_1e6)

dy_1e9 = numerical_diff(f, x1, eps=1e-9)
print(dy_1e9)

print("--------------------")

def f(x):
    """p.59에 나오는 임의의 연산 함수 """
    A = Square()
    B = Exp()
    C = Square()
    return C(B(A(x)))

x2 = dz.Variable(np.array(0.5))
dy2 = numerical_diff(f, x2)
print(dy2)


import numpy as np
import matplotlib.pyplot as plt

def prior(H):
    """
    Densidad de probabilidad de H
    (H es la probabilidad de sacar cara).
    """
    p = np.ones(len(H))
    return p

def like(secuencia, H):
    """
    Likelihod de sacar una secuencia de caras y sellos, dado H.
    H es la probabilidad de sacar una cara.
    """
    L = np.ones(len(H))
    n_caras = secuencia.count('c')
    n_sello = secuencia.count('s')
    L *= H**n_caras
    L *= (1-H)**n_sello
    return L

def posterior(H, secuencia):
    """
    Posterior calculado con la normalizacion adecuada
    """
    post =  like(secuencia, H) * prior(H)
    evidencia = np.trapz(post, H)
    return  post/evidencia

def maximo_sigma(x, y):
    deltax = x[1] - x[0]

    # maximo de y
    ii = np.argmax(y)

    # segunda derivada
    d = (y[ii+1] - 2*y[ii] + y[ii-1]) / (deltax**2)

    return x[ii], 1.0/np.sqrt(-d)

secuencia = 'scccc'
H = np.linspace(1E-4, 1.0-1.0E-4, 100)
post = posterior(H, secuencia)

max, sigma = maximo_sigma(H, np.log(post))

gauss = (1.0/np.sqrt(2.0*np.pi*sigma**2))*np.exp(-0.5*(H-max)**2/(sigma**2))

plt.figure()
plt.plot(H, post, label='datos={}'.format(secuencia))
plt.plot(H, gauss, ':', label='Aproximacion Gaussiana')
plt.title('H= {:.2f} $\pm$ {:.2f}'.format(max, sigma))
plt.xlabel('H')
plt.ylabel('prob(H|datos)')
plt.legend()
plt.savefig('coins')


from skrf.mathFunctions import LOG_OF_NEG
import skrf as rf
import unittest
import numpy as np
from numpy import e, log, pi, isnan, inf
from numpy.testing import assert_equal, run_module_suite, assert_almost_equal

class TestUnitConversions(unittest.TestCase):
    """
    Test unit-conversion functions
    """

    def setUp(self):
        pass

    def test_complex_2_magnitude(self):
        """
        Test complex to magnitude conversion with:
            5 = 3 + 4j
        """
        assert_almost_equal(rf.complex_2_magnitude(3+4j), 5.0)

    def test_complex_2_db10(self):
        """
        Test complex to db10 conversion with:
            10 [dB] = 10 * log10(6+8j)
        """
        assert_almost_equal(rf.complex_2_db10(6+8j), 10.0)

    def test_complex_2_degree(self):
        """
        Test complex to degree conversion with:
            90 = angle(0 + 1j)
        """
        assert_almost_equal(rf.complex_2_degree(0+1j), 90.0)

    def test_complex_2_quadrature(self):
        """
        Test complex to quadrature conversion with:
            2, pi  = abs(2j), angle(2j) * abs(2j)
        """
        assert_almost_equal(rf.complex_2_quadrature(0+2j), (2, pi))

    def test_complex_components(self):
        """
        Test complex components:
        """
        assert_almost_equal(rf.complex_components(0+2j), (0, 2, 90, 2, pi))

    def test_complex_2_reim(self):
        """
        Test complex to (real, imag) conversion:
        """
        assert_almost_equal(rf.complex_2_reim(1+2j), (1,2))

    def test_magnitude_2_db(self):
        """
        Test magnitude to db conversion
        """
        assert_almost_equal(rf.magnitude_2_db(10, True), 20)
        assert_almost_equal(rf.magnitude_2_db(10, False), 20)

        assert_almost_equal(rf.magnitude_2_db(0), -inf)
        assert_almost_equal(rf.magnitude_2_db(-1, True), LOG_OF_NEG)
        assert_almost_equal(rf.magnitude_2_db([10, -1], True), [20, LOG_OF_NEG])
        self.assertTrue(isnan(rf.magnitude_2_db(-1, False)))

        assert_equal(rf.mag_2_db, rf.magnitude_2_db) # Just an alias

    def test_mag_2_db10(self):
        """
        Test magnitude to db10 conversion
        """
        assert_almost_equal(rf.mag_2_db10(10, True), 10)
        assert_almost_equal(rf.mag_2_db10(10, False), 10)

        assert_almost_equal(rf.magnitude_2_db(0), -inf)
        assert_almost_equal(rf.mag_2_db10(-1, True), LOG_OF_NEG)
        assert_almost_equal(rf.mag_2_db10([10, -1], True), [10, LOG_OF_NEG])
        self.assertTrue(isnan(rf.mag_2_db10(-1, False)))

    def test_db10_2_mag(self):
        """
        Test db10 to mag conversion
        """
        assert_almost_equal(rf.db10_2_mag(3+4j), 10**((3+4j)/10))

    def test_magdeg_2_reim(self):
        """
        Test (mag,deg) to (re+j*im)
        """
        assert_almost_equal(rf.magdeg_2_reim(1, 90), (0+1j))

    def test_dbdeg_2_reim(self):
        """
        Test (db, deg) to (re+j*im)
        """
        assert_almost_equal(rf.dbdeg_2_reim(20,90), (0+10j))

    def test_np_2_db(self):
        """
        Test Np to dB conversion with:
            1 [Np] = 20/ln(10) [dB]
        """
        assert_almost_equal(rf.np_2_db(1), 20/log(10))

    def test_db_2_np(self):
        """
        Test dB to Np conversion with:
            1 [dB] = ln(10)/20 [Np]
        """
        assert_almost_equal(rf.db_2_np(1), log(10)/20)

    def test_radian_2_degree(self):
        assert_almost_equal(rf.radian_2_degree(pi), 180)

    def test_feet_2_meter(self):
        """
        Test feet to meter length conversion
        """
        assert_almost_equal(rf.feet_2_meter(0.01), 0.003048)
        assert_almost_equal(rf.feet_2_meter(1), 0.3048)

    def test_meter_2_feet(self):
        """
        Test meter to feet length conversion
        """
        assert_almost_equal(rf.meter_2_feet(0.01), 0.0328084)
        assert_almost_equal(rf.meter_2_feet(1), 3.28084)

    def test_db_per_100feet_2_db_per_100meter(self):
        """
        Test attenuation unit conversion dB/100feet to dB/100m
        """
        assert_almost_equal(rf.db_per_100feet_2_db_per_100meter(), rf.meter_2_feet(), decimal=2)
        assert_almost_equal(rf.db_per_100feet_2_db_per_100meter(2.5), 8.2, decimal=2)
        assert_almost_equal(rf.db_per_100feet_2_db_per_100meter(0.28), 0.92, decimal=2)

    def test_inf_to_num(self):
        """
        Test inf_to_num function
        """
        # scalar
        assert_equal(rf.inf_to_num(np.inf), rf.INF)
        assert_equal(rf.inf_to_num(-np.inf), -rf.INF)

        # array
        x = np.array([0, np.inf, 0, -np.inf])
        y = np.array([0, rf.INF, 0, -rf.INF])
        assert_equal(rf.inf_to_num(x), y)

if __name__ == "__main__":
    # Launch all tests
    run_module_suite()


# Cosine annealing learning rate schedule
# https://machinelearningmastery.com/snapshot-ensemble-deep-learning-neural-network/

#from matplotlib import pyplot
from math import pi
from math import cos
from math import floor

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

figdir = "../figures"
def save_fig(fname):
    if figdir: plt.savefig(os.path.join(figdir, fname))

# cosine annealing learning rate schedule
def cosine_annealing(epoch, n_epochs, n_cycles, lrate_max):
	epochs_per_cycle = floor(n_epochs/n_cycles)
	cos_inner = (pi * (epoch % epochs_per_cycle)) / (epochs_per_cycle)
	return lrate_max/2 * (cos(cos_inner) + 1)

# create learning rate series
n_epochs = 100
n_cycles = 5
lrate_max = 0.01
series = [cosine_annealing(i, n_epochs, n_cycles, lrate_max) for i in range(n_epochs)]
# plot series
plt.figure()
plt.plot(series)
fname = 'lrschedule_cosine_annealing.pdf'
save_fig(fname)
plt.show()


#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Wed Jul 26 19:29:06 2017

@author: luke

Levi-Civita in python:
https://stackoverflow.com/questions/20908754/how-to-speed-up-a-vector-cross-product-calculation

getitem with multiple arguments:
    https://stackoverflow.com/questions/1685389/possible-to-use-more-than-one-argument-on-getitem
"""
import numpy as np

def make_Levi_Civita():
    eijk = np.zeros((3, 3, 3))
    eijk[0, 1, 2] = eijk[1, 2, 0] = eijk[2, 0, 1] = 1
    eijk[0, 2, 1] = eijk[2, 1, 0] = eijk[1, 0, 2] = -1
    return eijk

eijk = make_Levi_Civita()

class LeviCivita(object):
    def __init__(self):
        self.lc = eijk
    def __call__(self,i,j,k):
        return self.lc[i,j,k]

    def __getitem__(self, pos):
        i,j,k = pos
        return self.lc[i,j,k]

    def __repr__(self):
        return 'LeviCivita({})'.format(self.lc)

    def __str__(self):
        return 'LeviCivita({})'.format(self.lc)

if __name__ == '__main__':
    self = LeviCivita()


# Exercise 7.29
# Author: Noah Waterfield Price

from Polynomial import Polynomial
from numpy import exp
import sys

def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n - 1)

x = float(sys.argv[1])
Nlist = sys.argv[2:]
plist = []
for N in Nlist:
    coeffs = [1. / factorial(k) for k in xrange(int(N) + 1)]
    plist.append(Polynomial(coeffs))

print '=' * 35
print '%-5s %-16s %-16s' % ('N', 'Taylor approx.', 'Exact')
print '-' * 35
for N, p in zip(Nlist, plist):
    print '%-5s %-16.12s %-16.12s' % (N, p(x), exp(x))
print '-' * 35

"""
Sample run:
python Polynomial_exp.py 0.5 2 5 10 15 25
===================================
N     Taylor approx.   Exact
-----------------------------------
2     1.625            1.6487212707
5     1.6486979166    1.6487212707
10    1.6487212706     1.6487212707
15    1.6487212707     1.6487212707
25    1.6487212707     1.6487212707
-----------------------------------
python Polynomial_exp.py 3 2 5 10 15 25
===================================
N     Taylor approx.   Exact
-----------------------------------
2     8.5              20.085536923
5     18.4             20.085536923
10    20.079665178     20.085536923
15    20.085534431     20.085536923
25    20.085536923     20.085536923
-----------------------------------
python Polynomial_exp.py 10 2 5 10 15 25
===================================
N     Taylor approx.   Exact
-----------------------------------
2     61.0             22026.465794
5     1477.6666666     22026.465794
10    12842.305114     22026.465794
15    20952.886968     22026.465794
25    22026.076360     22026.465794
-----------------------------------
"""


import sys
import numpy as np
from numpy import pi
from numpy import newaxis
rg = np.random.default_rng(1)  # create instance of default random number generator

########################################################################################################################
# Changing the shape of an array
print("\nChanging the shape\n")

"An array has a shape given by the number of elements along each axis:"

a = np.floor(10 * rg.random((3, 4)))  # Create array xx4 of random floats
print(a)
"""array([[3., 7., 3., 4.],
       [1., 4., 2., 2.],
       [7., 2., 4., 9.]])"""
print(a.shape)  # (3, 4)

"""The shape of an array can be changed with various commands.
Note that the following three commands all return a modified array, but do not change the original array:"""

print(a.ravel())  # returns the array, flattened
# array([3., 7., 3., 4., 1., 4., 2., 2., 7., 2., 4., 9.])
print(a.reshape(6, 2))  # returns the array with a modified shape
"""array([[3., 7.],
       [3., 4.],
       [1., 4.],
       [2., 2.],
       [7., 2.],
       [4., 9.]])"""
print(a.T)  # returns the array, transposed
"""array([[3., 1., 7.],
       [7., 4., 2.],
       [3., 2., 4.],
       [4., 2., 9.]])"""
print(a.T.shape)  # (4, 3)
print(a.shape)  # (3, 4)

"""The reshape function returns its argument with a modified shape,
whereas the ndarray.resize method modifies the array itself:"""

print(a)  # original array
"""array([[3., 7., 3., 4.],
       [1., 4., 2., 2.],
       [7., 2., 4., 9.]])"""
a.resize((2, 6))  # change the array itself
print(a)
"""array([[3., 7., 3., 4., 1., 4.],
       [2., 2., 7., 2., 4., 9.]])"""

"""If a dimension is given as -1 in a reshaping operation, the other dimensions are automatically calculated:"""

a.reshape(3, -1)  # reshape with unknown last parameter -> auto calculate
"""array([[3., 7., 3., 4.],
       [1., 4., 2., 2.],
       [7., 2., 4., 9.]])"""

########################################################################################################################
print("\nStacking together different arrays\n")

"""Several arrays can be stacked together along different axes:"""

a = np.floor(10 * rg.random((2, 2)))  # new array 2x2
print(a)
"""array([[9., 7.],
       [5., 2.]])"""
b = np.floor(10 * rg.random((2, 2)))  # new array 2x2
print(b)
"""array([[1., 9.],
       [5., 1.]])"""
print(np.vstack((a, b)))  # stack vertically
"""array([[9., 7.],
       [5., 2.],
       [1., 9.],
       [5., 1.]])"""
print(np.hstack((a, b)))  # Stack horizontally
"""array([[9., 7., 1., 9.],
       [5., 2., 5., 1.]])"""

"""The function column_stack stacks 1D arrays as columns into a 2D array.
It is equivalent to hstack only for 2D arrays:"""

print(np.column_stack((a, b)))  # with 2D arrays
"""array([[9., 7., 1., 9.],
       [5., 2., 5., 1.]])"""
a = np.array([4., 2.])
b = np.array([3., 8.])
print(np.column_stack((a, b)))  # returns a 2D array
"""array([[4., 3.],
       [2., 8.]])"""
print(np.hstack((a, b)))        # the result is different
"""array([4., 2., 3., 8.])"""
print(a[:, newaxis])  # view `a` as a 2D column vector
"""array([[4.],
       [2.]])"""
print(np.column_stack((a[:, newaxis], b[:, newaxis])))  # stacks columns
"""array([[4., 3.],
       [2., 8.]])"""
print(np.hstack((a[:, newaxis], b[:, newaxis])))  # the result is the same
"""array([[4., 3.],
       [2., 8.]])"""

"""On the other hand, the function row_stack is equivalent to vstack for any input arrays.
In fact, row_stack is an alias for vstack:

In general, for arrays with more than two dimensions,
    hstack stacks along their second axes,
    vstack stacks along their first axes,
    and concatenate allows for an optional arguments giving the number of the axis along which the concatenation
    should happen."""

print(np.column_stack is np.hstack)  # False
print(np.row_stack is np.vstack)  # True

"""In complex cases, r_ and c_ are useful for creating arrays by stacking numbers along one axis.
They allow the use of range literals :."""

print(np.r_[1:4, 0, 4])  # create complex array
"""array([1, 2, 3, 0, 4])"""

########################################################################################################################
print("\nSplitting one array into several smaller ones\n")

"""Using hsplit, you can split an array along its horizontal axis,
either by specifying the number of equally shaped arrays to return,
or by specifying the columns after which the division should occur:

vsplit splits along the vertical axis, and array_split allows one to specify along which axis to split.
"""

a = np.floor(10 * rg.random((2, 12)))
print(a)
"""array([[6., 7., 6., 9., 0., 5., 4., 0., 6., 8., 5., 2.],
       [8., 5., 5., 7., 1., 8., 6., 7., 1., 8., 1., 0.]])"""
# Split `a` into 3
print(np.hsplit(a, 3))
"""[array([[6., 7., 6., 9.],
       [8., 5., 5., 7.]]),
 array([[0., 5., 4., 0.],
       [1., 8., 6., 7.]]),
 array([[6., 8., 5., 2.],
       [1., 8., 1., 0.]])]"""
# Split `a` after the third and the fourth column
print(np.hsplit(a, (3, 4)))
"""[array([[6., 7., 6.],
       [8., 5., 5.]]),
 array([[9.],
       [7.]]),
 array([[0., 5., 4., 0., 6., 8., 5., 2.],
       [1., 8., 6., 7., 1., 8., 1., 0.]])]"""


#!/usr/bin/python
"""
author  : Bhekimpilo Ndhlela
author  : 18998712
module  : Applied Mathematics(Numerical Methods) TW324
task    : computer assignment 05 question 6
since   : Friday-27-04-2018
"""

def question_a(f, n, w0, I, G=9.81, C2=1.0/1000.0):
    h = 10.0/float(n) # step size
    w = zeros(n+1, dtype=float)
    w[0] = w0
    for i in xrange(1, n+1):
        w[i] = w[i-1] + h * f(w[i-1])
    return abs_error(w[-1], I)

def explicit_trapezium(f, n, w0, I, G=9.81, C2=1.0/1000.0):
    h = 10.0/float(n) # step size
    w, wt = zeros(n+1, dtype=float), zeros(n+1, dtype=float)
    w[0] = w0
    for i in xrange(1, n+1):
        wt[i] = w[i-1] + h * f(w[i-1])
        w[i]  = w[i-1] + h * f(wt[i-1] + h/2.0 * f(wt[i]))
    return abs_error(w[-1], I)

def explicit_midpoint(f, n, w0, I, G=9.81, C2=1.0/1000.0):
    h = 10.0/float(n) # step size
    w, wt = zeros(n+1, dtype=float), zeros(n+1, dtype=float)
    w[0] = w0
    for i in xrange(1, n+1):
        wt[i] = w[i-1] + 0.5 * h * f(w[i-1])
        w[i]  = w[i-1] + h * f(wt[i])
    return abs_error(w[-1], I)

def debug_on(N, err_eulr,err_mdp, err_trap, debug=False):
    if debug == True:
        print "*" * 125
        print "The Exact Value I = {:.20f}".format(float(I))
        print "*" * 125
        print "N ", "\t\t\t\t","Euler's Method", "\t\t\t\t\t\t" , "Explicit Midpoint", "\t\t\t\t\t","Explicit Trapezium"
        print "*" * 125
        for n, em, emm, etm in zip(N, err_eulr, err_mdp, err_trap):
            temp = ""
            if n == 10:
                temp = "  "
            elif n == 100:
                temp = " "
            print n,"\t\t\t",temp,"{:.20f}".format(em), "\t\t", temp,"{:.20f}".format(emm), "\t\t",temp,"{:.20f}".format(etm)

def abs_error(xc, x):
    return abs(float(xc) - float(x))

def plot_computed_error(N, abs_err_0, abs_err_1=None, abs_err_2=None):
    plt.ylabel("n = number of points")
    plt.xlabel("h = step size)")
    plt.xscale('log'); plt.yscale('log')
    if abs_err_1 == None and abs_err_2 == None:
        plt.title("6(b.) Absolute Error of Euler's method with n = 10, 100 1000")
        plt.plot(N, abs_err_0, 'k-')
        plt.show()
    else:
        plt.title("(6a.) Absolute Error of Euler's, Explicit Midpoint"\
                   "and Explicit Trapezium methods with n = 10, 100 1000")
        plt.plot(N, abs_err_0, 'k-', label="Error Euler's Method")
        plt.plot(N, abs_err_1, 'b-', label="Error Explicit Midpoint Method")
        plt.plot(N, abs_err_2, 'r-', label="Error Explicit Trapezium Method")
        plt.legend(bbox_to_anchor=(1.0, 1.0))
        plt.show()

if __name__ == "__main__":
    from numpy import (linspace, array, zeros)
    from scipy import (integrate, special)
    import matplotlib.pyplot as plt
    from math import (sqrt, tanh)

    f = lambda t : 9.81 - (1.0/1000.0) * (t**2)
    I = sqrt(9.81/(1.0/1000.0)) * tanh(10. * sqrt(9.81*(1.0/1000.0)))
    N = [10, 100, 1000]

    # get absolute error using Euler's meth6od
    abs_err_eulr = [question_a(f, n, 0.0, I) for n in N]
    abs_err_trap = [explicit_trapezium(f, n, 0.0, I) for n in N]
    abs_err_mdp = [explicit_midpoint(f, n, 0.0, I) for n in N]

    # debug or print the acquired values
    debug_on(N, abs_err_eulr, abs_err_mdp, abs_err_trap, debug=True)

    # plot the error for question 6(a.)
    plot_computed_error(N, abs_err_eulr)
    #plot the error for question 6(a.) and 6(b.) on the same cartesion plane
    plot_computed_error(N, abs_err_eulr, abs_err_mdp, abs_err_trap)
else:
    from sys import exit
    exit("USAGE: python question6.py")


"""
Provides utilities specific to the Browian Paths example
"""

from typing import Optional

import numpy as np

def simulate_wiener_process(time_steps: np.ndarray, n_paths: int) -> np.ndarray:
    """
    Simulate `n_paths` paths of the Wiener process at time
    steps as provided in the `time_steps` array

    Returns:
    A np.ndarray of shape (n, len(time_steps)) with each row
    representing a realisation of the path
    """

    time_differences = np.ediff1d(time_steps)
    normal_noise = np.random.normal(size=(n_paths, len(time_differences))) * time_differences
    wiener_paths = np.insert(np.cumsum(normal_noise, axis=1), 0, 0, axis=1)

    return wiener_paths

def simulate_gbm_process(
    time_steps: np.ndarray,
    n_paths: int,
    mu: float,
    sigma: float,
    initial_value: Optional[float] = 1,
) -> np.ndarray:
    """
    Simulate `n_paths` of a Stochastic process driven by the
    Geometric Brownian Motion dynamics with return `mu` and
    volatility `sigma`, at the time steps as provided in the
    `time_steps` array. Optionally specify a starting value
    which is taken to be one by default.

    Returns:
    An np.ndarray of shape (n, len(time_steps)) with each row
    representing a relisation of the process's path at the
    specified nodes
    """

    drift_component = (mu - 0.5*sigma*sigma) * np.tile(time_steps, reps=(n_paths, 1))
    wiener_paths = simulate_wiener_process(time_steps, n_paths)
    diffusion_component = sigma * wiener_paths
    gbm_paths = initial_value * np.exp(drift_component + diffusion_component)

    return gbm_paths


#!/usr/bin/env python

"""

an example of solving Poisson's equation via smoothing only.  Here, we
solve

u_xx = sin(x)
u = 0 on the boundary [0,1]

The analytic solution is u(x) = -sin(x) + x sin(1)

M. Zingale (2013-03-31)

"""
#from io import *
import numpy
import pylab
import sys

# the analytic solution
def true(x):
    return -numpy.sin(x) + x*numpy.sin(1.0)

# the L2 error norm
def error(ilo, ihi, dx, r):

    # L2 norm of elements in r, multiplied by dx to
    # normalize
    return numpy.sqrt(dx*numpy.sum((r[ilo:ihi+1]**2)))

# the righthand side
def f(x):
    return numpy.sin(x)

def computeResidual(ilo, ihi, dx, phi, frhs):

    r = numpy.zeros(len(phi))

    r[ilo:ihi+1] = frhs[ilo:ihi+1] - \
        (phi[ilo+1:ihi+2] - 2.0*phi[ilo:ihi+1] + phi[ilo-1:ihi])/dx**2

    return r

def smoothRun(nx):

    xmin = 0.0
    xmax = 1.0

    ng = 1

    print nx

    # initialize the solution to zero.  Put one ghost cell on either end
    phi = numpy.zeros(nx + 2*ng, dtype=numpy.float64)

    phinew = numpy.zeros(nx + 2*ng, dtype=numpy.float64)

    ilo = ng
    ihi = ng + nx - 1

    # coordinates of centers
    dx = (xmax - xmin)/nx
    x = (numpy.arange(nx+2*ng) - ng + 0.5)*dx + xmin

    # initialize the RHS using the function f
    frhs = numpy.zeros(nx + 2*ng, dtype=numpy.float64)
    frhs[ilo:ihi+1] = f(x[ilo:ihi+1])

    # smooth
    n = numpy.arange(20000) + 1
    e = []
    r = []

    # fill the ghost cells
    phi[ilo-1] = -phi[ilo]
    phi[ihi+1] = -phi[ihi]

    print "source norm: ", error(ilo, ihi, dx, frhs)
    print numpy.sum(frhs[ilo:ihi+1])

    for i in n:

        # do Jacobi
        #phinew[ilo:ihi+1] = \
        #    (-dx*dx*frhs[ilo:ihi+1] + phi[ilo+1:ihi+2] + phi[ilo-1:ihi])/2.0
        # phi[:] = phinew[:]

        # this also does Jacobi, since phi on the RHS is evaluated before
        # the LHS is updated
        #phi[ilo:ihi+1] = \
        #    0.5*(-dx*dx*frhs[ilo:ihi+1] + phi[ilo+1:ihi+2] + phi[ilo-1:ihi])

        # red-black Gauss-Seidel -- first do the odd, then even points
        print phi[ilo:ihi+1:2]
        print phi[ilo:ihi+1]
        phi[ilo:ihi+1:2] = \
            0.5*(-dx*dx*frhs[ilo:ihi+1:2] + \
                      phi[ilo+1:ihi+2:2] + phi[ilo-1:ihi:2])

        # fill the ghost cells
        phi[ilo-1] = -phi[ilo]
        phi[ihi+1] = -phi[ihi]

        phi[ilo+1:ihi+1:2] = \
            0.5*(-dx*dx*frhs[ilo+1:ihi+1:2] + \
                      phi[ilo+2:ihi+2:2] + phi[ilo:ihi:2])

        # fill the ghost cells
        phi[ilo-1] = -phi[ilo]
        phi[ihi+1] = -phi[ihi]

        # compute the true error (wrt the analytic solution)
        e.append(error(ilo, ihi, dx, phi - true(x)))

        # compute the residual
        resid = computeResidual(ilo, ihi, dx, phi, frhs)

        r.append(error(ilo, ihi, dx, resid))

    r = numpy.array(r)
    e = numpy.array(e)

    return n, r, e

# test the multigrid solver
N = [16, 32, 64]

c = ["r", "g", "b"]

for nx in N:

    n, r, e = smoothRun(nx)
    color = c.pop()
    pylab.plot(n, e, color=color, label = `nx`)
    pylab.plot(n, r, color=color, ls=":")

ax = pylab.gca()
ax.set_xscale('log')
ax.set_yscale('log')

pylab.xlabel("# of iterations")
pylab.ylabel("L2 norm of true error (solid) and residual (dotted)")
#pylab.legend(frameon=False, fontsize="small")

pylab.savefig("smooth-error.png")


x = 1
print x + x + 1
from sympy import Symbol
x = Symbol('x')
print x + x + 1
a = Symbol('x')
print a + a + 1
x = Symbol('x')
y = Symbol('y')
z = Symbol('z')
s = x*y + x*y
print s
p = x*(x + x)
print p
from sympy import factor, expand
expr = x**2 - y**2
print factor(expr)
factors = factor(expr)
print expand(factors)
expr = x**3 + 3*x**2*y + 3*x*y**2 + y**2
factors = factor(expr)
print factors
print expand(factors)
expr = x*y + x + y
print factor(expr)
expr = x*x + 2*x*y + y*y
print expr
from sympy import pprint
pprint(expr)
expr = 1 + 2*x + 2*x**2
pprint(expr)
from sympy import init_printing
init_printing(order='rev-lex')
pprint(expr)

def printseries(n):
    init_printing(order='rev-lex')
    x = Symbol('x')
    series = x
    for i in range(2, n+1):
        series = series + (x**i)/i
    pprint(series)
if __name__ == '__main__':
    n = input('Enter the number of terms you want in the series: ')
    printseries(int(n))

print x*x + y*y + x*y + y*y
expr = x*x + y*y + x*y + y*y
res = expr.subs({x:1, y:2})
print res

print expr.subs({x:1-y})

expr_subs = expr.subs({x:1-y})
from sympy import simplify
print simplify(expr_subs)

def print_series(n, x_val):
    init_printing(order='rev-lex')
    x = Symbol('x')
    series = x
    for i in range(2, n+1):
        series = series + (x**i)/i
    pprint(series)
    series_value = series.subs({x:x_val})
    print 'Value of the series at {0}: {1}'.format(x_val, series_value)

if __name__ == '__main__':
    n = input('Enter the number of terms you want in the series: ')
    x_value = input('Enter the value of x at which you want to evaluate the series: ')
    print_series(int(n), float(x_value))

from sympy import sympify
expr = input('Enter a mathematical expression: ')
expr = sympify(expr)
print 2 * expr

from sympy.core.sympify import SympifyError
expr = input('Enter a mathematical expression: ')
try:
    expr = sympify(expr)
except SympifyError:
    print 'Invalid Input'

from sympy import expand

def product(expr1, expr2):
    prod = expand(expr1 * expr2)
    print prod

if __name__ == '__main__':
    expr1 = input('Enter the first expression: ')
    expr2 = input('Enter the second expression: ')

    try:
        expr1 = sympify(expr1)
        expr2 = sympify(expr2)
    except SympifyError:
        print 'Invalid Input'
    else:
        product(expr1, expr2)

from sympy import solve
x = Symbol('x')
expr = x - 5 - 7
print solve(expr)

expr = x**2 + 5*x + 4
print solve(expr, dict=True)

expr = x**2 + x + 1
print solve(expr, dict=True)

x = Symbol('x')
a = Symbol('a')
b = Symbol('b')
c = Symbol('c')

expr = a*x*x + b*x + c
print solve(expr, x, dict=True)

s = Symbol('s')
u = Symbol('u')
t = Symbol('t')
a = Symbol('a')
expr = u*t + (1/2)*a*t*t - s
t_expr = solve(expr,t, dict=True)
pprint(t_expr)

y = Symbol('y')
expr1 = 2*x + 3*y - 6
expr2 = 3*x + 2*y - 12
print solve((expr1, expr2), dict=True)

soln = solve((expr1, expr2), dict=True)
soln = soln[0]
print expr1.subs({x:soln[x], y:soln[y]})
print expr2.subs({x:soln[x], y:soln[y]})

from sympy.plotting import plot
plot(2*x + 3)
plot((2*x + 3), (x, -5, 5))
plot(2*x + 3, (x, -5, 5), title='A Line', xlabel='x', ylabel='2x+3')
p = plot(2*x + 3, (x, -5, 5), title='A Line', xlabel='x', ylabel='2x+3', show=False)
p.save(line.png)

expr = input("Enter an expression with an 'x' and a 'y': ")
expr = sympify(expr)
y = Symbol('y')
print solve(expr, y)

solutions = solve(expr, 'y')
expr_y = solutions[0]
print expr_y

def plot_expression(expr):

    y = Symbol('y')
    solutions = solve(expr, y)
    expr_y = solutions[0]
    plot(expr_y)

if __name__ == '__main__':
    expr = input('Enter your expression in terms of x and y: ')
    try:
        expr = sympify(expr)
    except SympifyError:
        print 'Invalid Input'
    else:
        plot_expression(expr)

plot(2*x+3, 3*x+1)

p = plot(2*x+3, 3*x+1, legend=True, show=False)
p[0].line_color = 'b'
p[1].line_color = 'r'
p.show()


"""Vectorized anomaly conversion scripts"""

import numpy as np

def true_to_ecc(theta,e):
    """Converts true anomaly to eccentric anomaly.

       Args:
           theta(numpy array): array of true anomalies (in radians)
           e(float): eccentricity

       Returns:
           numpy array: array of eccentric anomalies (in radians)
    """

    pi2=2*np.pi
    raw = np.arctan2((1-e**2)*np.sin(theta), e+np.cos(theta))
    raw = raw%pi2

    # revolution correction code
    correct = (theta//pi2)*pi2
    raw = raw+correct
    correct = np.clip((raw-theta)//pi2,0,None)*pi2

    return raw-correct

def ecc_to_mean(E,e):
    """Converts eccentric anomaly to mean anomaly.

       Args:
           E(numpy array): array of eccentric anomalies (in radians)
           e(float): eccentricity

       Returns:
           numpy array: array of mean anomalies (in radians)
    """

    return E - e*np.sin(E)

def mean_to_t(M,a):
    """Converts mean anomaly to time elapsed.

       Args:
           M(numpy array): array of mean anomalies (in radians)
           a(float): semi-major axis

       Returns:
           numpy array: numpy array of time elapsed
    """

    n = (a**3/398600.4405)**0.5
    return n*(M-M[0])

if __name__ == "__main__":
    thetas = np.linspace(0,4*np.pi,21)
    e = 0.7151443
    print(thetas)
    ecc = true_to_ecc(thetas,e)
    print(ecc)
    mean = ecc_to_mean(ecc,e)
    print(mean)
    t = mean_to_t(mean,26505.1836)
    print(t)


# -*- coding: utf-8 -*-
"""
Created on Sun Oct 30 17:04:38 2016

@author: Owner
"""

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

# ===============  Gauss Elimination =============== #

def Gaussian_elimination(n, A, b):
    x = np.zeros(n)

    # Forward elimination
    for k in range(1, n):  # e.g. for column 1
        for i in range(k + 1, n + 1):  # from line 2 to n
            w = A[i-1, k-1]/A[k-1, k-1]

            for j in range(k, n + 1):  # from line 1 to n in column
                A[i-1, j-1] = A[i-1, j-1] - w*A[k-1, j-1]

            b[i-1] = b[i-1] - w*b[k-1]

    x[n-1] = b[n-1]/A[n-1, n-1]
    # print np.rint(A)#でAを整数(四捨六入で５は偶数になるほうに丸める)に変換して表示（上三角)

    # Back substitution
    for i in range(n - 1, 0, -1):
        for j in range(i + 1, n + 1):
            b[i-1] = b[i-1] - A[i-1, j-1]*x[j-1]

        x[i-1] = b[i-1]/A[i-1, i-1]

    return x
    print(x)
# ==================================================== #

# ============== Gauss Elimination w/ Partial Pivoting ============= #

def Gaussian_elimination_pivot(n, A, b):
    x = np.zeros(n)

    piv = np.zeros(n).astype(int)  # numpyオブジェクト.astype(型)でまとめて型変換
    for i in range(0, n):
        piv[i] = i  # piv = [0,1,2,...,n-1]

    for k in range(0, n):
        amax = A[piv[k], k]  # k列の(k,k)以下の行の要素のなかで最大値を探す
        imax = k
        for i in range(k+1, n):
            if amax < abs(A[piv[i], k]):
                amax = abs(A[piv[i], k])
                imax = i
            else:
                pass
            if imax != k:  # Aの行を直接は入れ替えず、pivで入れ替えを記憶
                a = piv[k]
                piv[k] = piv[imax]
                piv[imax] = a
            else:
                pass
        for i in range(k+1, n):
            w = A[piv[i], k]/A[piv[k], k]
            for j in range(k+1, n):
                A[piv[i], j] = A[piv[i], j] - w*A[piv[k], j]

            b[piv[i]] = b[piv[i]] - w*b[piv[k]]

    x[n-1] = b[piv[n-1]]/A[piv[n-1], n-1]

    for i in range(n-2, -1, -1):
        for j in range(i+1, n):
            b[piv[i]] = b[piv[i]] - A[piv[i], j]*x[j]
        x[i] = b[piv[i]]/A[piv[i], i]

    return x
    print(x)
# ===================================================== #

# ================== Jacobi method ====================== #

def Jacobi_method(n, A, b, eps):
    # A = L + D + Uと分解し、Dx = (-L-U)x + bを収束させる。
    e = 1.0  # 誤差ベクトル（epsより大きければなんでもいい）
    list_e = []

    x = np.zeros(n)
    for i in range(0, n):
        x[i] = b[i]/A[i, i]
        # Aの対角成分が支配的となることがおおいので、解の初期値は何の情報もない場合はこうしておく。
    D = np.diagflat(np.diag(A))
    T = -(A - D)

    while e > eps:
        list_e.append(e)
        x_old = x
        x = np.dot(np.diagflat(1/np.diag(A)), np.dot(T, x_old) + b)
        e = np.linalg.norm(x - x_old)

    return x
    print(x)
    print("Jacobi法ーー誤差:{0}".format(e))

    plt.plot(list_e)
    plt.show()

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

# ============================= Gauss-Seidel method ======================= #

def Gauss_Seidel(n, A, b, eps):
    # A = L + D + Uと分解し、(D+L)x = -Ux + bを収束させる。
    e = 1.0  # 誤差ベクトル（epsより大きければなんでもいい）
    list_e = []

    x = np.zeros(n)
    for i in range(0, n):
        x[i] = b[i]/A[i, i]
        # Aの対角成分が支配的となることがおおいので、解の初期値は何の情報もない場合はこうしておく。

    S = np.tril(A)  # S = L + D
    T = -(A - S)
    S_inv = np.linalg.inv(S)

    while e > eps:
        list_e.append(e)
        x_old = x
        x = np.dot(S_inv, np.dot(T, x_old) + b)
        e = np.linalg.norm(x-x_old)

    return x
    print(x)
    print("Gauss-Seidel法ーー誤差:{0}".format(e))

    plt.plot(list_e)
    plt.show()

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

# ====================== SOR method ==================== #

def SOR(n, A, b, eps, omega):
    # A = L + D + Uと分解し、(D + omega*L)x = ((1-omega)D - U)x + omega*bを収束させる。
    e = 1.0  # 誤差ベクトル（epsより大きければなんでもいい）
    list_e = []

    x = np.zeros(n)
    for i in range(0, n):
        x[i] = b[i]/A[i, i]
        # Aの対角成分が支配的となることがおおいので、解の初期値は何の情報もない場合はこうしておく。

    L = np.tril(A, -1)  # 下三角行列を返す関数。parameter<0で対角成分含まず下のみ抽出。
    U = np.triu(A, 1)  # 上三角行列を返す関数。parameter>0で対角成分含まず上のみ抽出。
    D = np.diagflat(np.diag(A))

    S = D + omega*L
    T = (1-omega)*D - omega*U
    S_inv = np.linalg.inv(S)

    while e > eps:
        list_e.append(e)
        x_old = x
        x = np.dot(S_inv, np.dot(T, x_old) + omega*b)
        e = np.linalg.norm(x-x_old)

    return x
    print(x)
    print("SOR法ーー誤差:{0}".format(e))

    plt.plot(list_e)
    plt.show

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

if __name__ == '__main__':

    # 1 Benchmark solution by numpy.linalg.solve()
    start = time.time()

# initialization
    A = np.array([[5., -3., -1., 0., 2., 1.],
                  [0., -5., 4., 1., 0., 2.],
                  [-1., 3., -5., -2., 3., 3.],
                  [-1., 0., 3., 4., -2., -1.],
                  [0., 3., 3., -1., 3., -4.],
                  [2., 3., 2., 3., 2., -5.]])

    b = np.array([12., 6., 3., 9., 12., 21.])

# ----------------------main routine----------------------- #
    x = np.linalg.solve(A, b)
    print(x)

    elapsed_time = time.time() - start
    print("numpy.linalg.solve()")
    print("  Execution time: {0}".format(elapsed_time))
# --------------------------------------------------------- #

# 2 Gauss Elimination (normal)
    start = time.time()

# initialization
    n = 6

    A = np.array([[5., -3., -1., 0., 2., 1.],
                  [0., -5., 4., 1., 0., 2.],
                  [-1., 3., -5., -2., 3., 3.],
                  [-1., 0., 3., 4., -2., -1.],
                  [0., 3., 3., -1., 3., -4.],
                  [2., 3., 2., 3., 2., -5.]])

    b = np.array([12., 6., 3., 9., 12., 21.])

# -------------------------main routine------------------ #
    Gaussian_elimination(n, A, b)

    elapsed_time = time.time() - start
    print("Gauss Elimination（normal):")
    print("  Execution time: {0}".format(elapsed_time))
# ------------------------------------------------------------- #

# 3 Gauss Elimination（w/ partial pivot)
    start = time.time()

# initialization
    n = 6

    A = np.array([[5., -3., -1., 0., 2., 1.],
                  [0., -5., 4., 1., 0., 2.],
                  [-1., 3., -5., -2., 3., 3.],
                  [-1., 0., 3., 4., -2., -1.],
                  [0., 3., 3., -1., 3., -4.],
                  [2., 3., 2., 3., 2., -5.]])

    b = np.array([12., 6., 3., 9., 12., 21.])

# ------------------main routine----------------------- #
    Gaussian_elimination_pivot(n, A, b)

    elapsed_time = time.time() - start
    print("Gauss Elimination（w/ partial pivot):")
    print("  Execution time: {0}".format(elapsed_time))
# -------------------------------------------------------- #

# 4 Jacobi
    start = time.time()

# initialization
    n = 6

    A = np.array([[5., -3., -1., 0., 2., 1.],
                  [0., -5., 4., 1., 0., 2.],
                  [-1., 3., -5., -2., 3., 3.],
                  [-1., 0., 3., 4., -2., -1.],
                  [0., 3., 3., -1., 3., -4.],
                  [2., 3., 2., 3., 2., -5.]])

    b = np.array([12., 6., 3., 9., 12., 21.])

# ----------------------main routine-------------------------- #
    Jacobi_method(n, A, b, 1e-10)

    elapsed_time = time.time() - start
    print("Jacobi method:")
    print("  Execution time: {0}".format(elapsed_time))

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

# 5 Gauss-Seidel
    start = time.time()

# initialization
    n = 6

    A = np.array([[5., -3., -1., 0., 2., 1.],
                  [0., -5., 4., 1., 0., 2.],
                  [-1., 3., -5., -2., 3., 3.],
                  [-1., 0., 3., 4., -2., -1.],
                  [0., 3., 3., -1., 3., -4.],
                  [2., 3., 2., 3., 2., -5.]])

    b = np.array([12., 6., 3., 9., 12., 21.])

# ---------------- main routine ----------------- #
    Gauss_Seidel(n, A, b, 1e-10)

    elapsed_time = time.time() - start
    print("Gauss-Seidel")
    print("  Execution time: {0}".format(elapsed_time))

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

# 6 SOR
    start = time.time()

# initialization
    n = 6

    A = np.array([[5., -3., -1., 0., 2., 1.],
                  [0., -5., 4., 1., 0., 2.],
                  [-1., 3., -5., -2., 3., 3.],
                  [-1., 0., 3., 4., -2., -1.],
                  [0., 3., 3., -1., 3., -4.],
                  [2., 3., 2., 3., 2., -5.]])

    b = np.array([12., 6., 3., 9., 12., 21.])

# ---------------------- main routine --------------------- #
    SOR(n, A, b, 1e-10, 0.8)

    elapsed_time = time.time() - start
    print("SOR method")
    print("  Execution time: {0}".format(elapsed_time))

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


import numpy as np
import math
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier as baseline

def euclidean_distance(x, y, numpy=True):
	"""
	x: numpy array of first coordinate
	y: numpy array of second coordinate
	"""

	if numpy:
		# alternatively
		# np.sqrt(np.sum(x - y) ** 2)
		return np.linalg.norm(x - y)
	else:
		return sum(((a - b) ** 2 for a, b in zip(x, y)))

def majority(top_k_labels):
	assert isinstance(top_k_labels, list), "Need to pass a list"
	return max(set(top_k_labels), key=top_k_labels.count)

def knn_v01(xs, ys, query, k):
	distances = [(euclidean_distance(x, y), y) for x, y in zip(xs, ys)]
	distances_sorted = sorted(distances, key=lambda x: x[0])
	top_k_labels = [d[1] for d in distances[:k]]

	return majority(top_k_labels)

def baseline_prediction(x, y, query, baseline, k=1, algorithm='brute'):
	baseline_model = baseline(k, algorithm=algorithm)
	baseline_model.fit(x, y)
	return baseline_model.predict([query])

def test_helpers():
	"tests helper functions"

	assert majority([1,1,1]) == 1
	assert majority([1,1,1,2]) == 1
	assert majority([1,1,1,1,1,0]) == 1
	assert majority([1,0,0,0,0]) == 0
	assert majority([1]) == 1
	assert majority([1,1,2,2]) == 1  # ???
	assert majority([10,12]) == 10

	assert euclidean_distance(np.array([1,1]), np.array([1,1])) == 0
	assert euclidean_distance(np.array([1,1]), np.array([0,0])) == math.sqrt(2)
	assert euclidean_distance(np.array([3,5]), np.array([4,4])) == math.sqrt(2)
	assert euclidean_distance(np.array([10,100]), np.array([50,-50])) == math.sqrt(40 ** 2 + 150 ** 2)
	assert euclidean_distance(np.array([0,0]), np.array([-1,1])) == math.sqrt(2)

	print "All unit tests passed"

def test():
	"tests the main algorithm"

	# version to test
	implementations = [knn_v01]
	knn = implementations[-1]

	# dataset
	iris = datasets.load_iris()
	x = iris.data[:, :2]  # for simplicity and viz
	y = iris.target

	# test for correctness
	query = np.array([0, 0])
	print knn(x, y, query, 1), baseline_prediction(x, y, query, baseline, 1)
	assert knn(x, y, query, 1) == baseline_prediction(x, y, query, baseline, 1)
	assert knn(x, y, query, 2) == baseline_prediction(x, y, query, baseline, 2)
	assert knn(x, y, query, 5) == baseline_prediction(x, y, query, baseline, 5)

	query = np.array([10, 10])
	print baseline_prediction(x, y, query, baseline, 1), knn(x, y, query, 1)
	assert knn(x, y, query, 1) == baseline_prediction(x, y, query, baseline, 1)
	assert knn(x, y, query, 2) == baseline_prediction(x, y, query, baseline, 2)
	assert knn(x, y, query, 5) == baseline_prediction(x, y, query, baseline, 5)

	# performance test

	print "All integration tests passed"

if __name__ == '__main__':
	test_helpers()
	test()


import numpy as np
from fft import dft,inv_dft,inv_fft,fft

def multiply(A, B):
    m=len(A)
    n=len(B)
    prod = [0] * (m + n - 1);
    for i in range(m):
        for j in range(n):
            prod[i + j] += A[i] * B[j];
    return prod;

#driver code
#Randomly generating the two coefficient arrays with size 4
param1 = list(np.random.randint(low = 0, high = 1000, size = 4))
param2 = list(np.random.randint(low = 0, high = 1000, size = 4))
#The result generated by "convolution for loop" method
print("The answer obtained by brute force multiplication: \n", multiply(param1,param2),"\n")

#degree bound extension
l = [0 for i in range(0,4)]
param1.extend(l)
param2.extend(l)

PA = fft(param1)
PB = fft(param2)

#pointwise multiply
C = []
for i in range(PA.shape[0]):
    C.append(PA[i]*PB[i])

#print the answer obtained by inverse fft
print("The answer obtained by calling inverse fft function \n",inv_fft(C),"\n")


'''
Use o método RK45 com passo variável para resolver o problema:

dx/dt = 1 + x^2 ;  x(0)=0

Use uma tolerância de 10^{-5} para o controle do erro.

Coloque em uma tabela os resultados para o tempo, o valor resultante com a integração RK45, a solução exata e o erro
com relação a solução exata.

Note que a solução diverge em \pi/2, portanto use um tempo final menor do que este valor.

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

def passovarRK5(x0, tf, dt, tol):
    df = lambda x: 1 + x**2
    xs = [x0]
    ts = [0]
    for t in np.arange(dt, tf+dt, dt):
        ts.append(t)
        k1 = dt * df(x0)
        k2 = dt * df(x0 + ((k1 * dt)/4))
        k3 = dt * df(x0 + ((3 * dt * k1)/32) + ((9 * dt * k2)/32))
        k4 = dt * df(x0 + ((1932 * dt * k1)/2197) - ((7200 * dt * k2)/2197) + ((7296 * dt * k3)/2197))
        k5 = dt * df(x0 + ((439 * dt * k1)/216) - (8 * dt * k2) + ((3680 * dt * k3)/513) - ((845 * dt * k4)/4104))
        k6 = dt * df(x0 - ((8 * dt * k1)/27) + (2 * dt * k2) - ((3544 * dt * k3)/2565) + ((1859 * dt * k4)/4104) - ((11 * dt * k5)/40))

        x5, x6 = x0, x0

        x5 = x5 + ((25 * k1)/216) + ((1408 * k3)/2565) + ((2197 * k4)/4101) - (k5/5)
        x6 = x6 + ((16 * k1)/135) + ((6656 * k3)/12825) + ((28561 * k4)/56430) - ((9 * k5)/50) + ((2 * k6)/55)

        dtnovo = dt*(tol/(abs(x5 - x6)))**(1/6)
        if dtnovo > 2 * dt:
            dt = 2 * dt
        if dtnovo < dt / 2:
            dt = dt / 2
        x0 = x5
        xs.append(x0)
    return ts, xs

x0 = 0
tf = 1.51
tol = 1e-5
dt = 0.01

t = np.linspace(0, tf, 100)
fx = np.tan(t)

plt.plot(passovarRK5(x0, tf, dt, tol)[0], passovarRK5(x0, tf, dt, tol)[1], label='RK45')
plt.plot(t, fx, label='Analítica')
plt.grid()
plt.legend()
plt.xlabel('t')
plt.ylabel('f(t)')
plt.savefig('passovarRK5.png', dpi=300)

tt = np.array(passovarRK5(x0, tf, dt, tol)[0])
ft = np.array(passovarRK5(x0, tf, dt, tol)[1])
fan = np.tan(tt)
err = abs(ft - fan)

print(f'|t   |RK45   |Exata  |Erro')
for tmp, rk, an, er in zip(tt, ft, fan, err):
    print(f'|{tmp:.2f}|{rk:<7.3f}|{an:<7.3f}|{er:.3f}')


"""
Here, the definition of activation functions

Functions must be used with numpy arrays!
"""
from __future__ import annotations

from enum import Enum
from typing import Callable
from typing import Optional

import numpy as np

def _relu_function(x):
    return np.maximum(x, 0)

def _relu_derivative(x):
    x[x <= 0] = 0
    x[x > 0] = 1
    return x

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

def _sigmoid_derivative(x):
    f = _sigmoid_function
    return f(x) * (1 - f(x))

def _softplus_function(x):
    return np.log(1 + np.power(np.e, x))

_softplus_derivative = _sigmoid_function

class ActivationFunction(Enum):
    """
    A enumeration of activation functions. Each element contains the function and the derivative of the function
    """
    ReLu = ("Rectified linear unit", _relu_function, _relu_derivative)
    Sigmoid = ("Soft step", _sigmoid_function, _sigmoid_derivative)
    SoftPlus = ("Softplus", _softplus_function, _softplus_derivative)

    def __init__(self, nickname: str, f: Callable, df: Callable):
        self.nickname = nickname
        self.f = f
        self.df = df

    @classmethod
    def get_by_name(cls, name: str) -> Optional[ActivationFunction]:
        """
        Get ActivationFunction object by name or None, if there is no function with this name
        """
        activation_function = next((f for f in cls if f.name.lower() == name.lower()), None)
        if not activation_function:
            raise ValueError(f"Non-existing function name: {name}")
        return activation_function


#
# @lc app=leetcode id=935 lang=python3
#
# [935] Knight Dialer
#

# @lc code=start
import numpy as np

class Solution:
    def knightDialer(self, n: int) -> int:
        """
        A is adjency matrix, number of n-length paths for i -> j equals to (i, j) in A^n
        """

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

        counter, N, mod = np.identity(10, int), n - 1, 10 ** 9 + 7
        while N:
            if N % 2:
                counter = counter @ adj % mod
            adj = adj @ adj % mod
            N //= 2

        return 10 if n == 1 else np.sum(counter) % mod

# @lc code=end


from __future__ import division
import math

import numpy as np
from numpy import pi

import numdifftools.fornberg as ndf

@np.vectorize
def CxDerivative(f, z0, n=1, contour=None, absIntegrationTol=1e-10, verbose=False):
    r"""
    Compute the derivaive of an analytic function using Cauchy's
    Integral Formula for Derivatives.

    .. math::

        f^{(n)}(z_0) = \frac{n!}{2\pi i} \oint_C \frac{f(z)}{(z-z_0)^{n+1}} dz

    Parameters
    ----------
    f : function
        Function of a single variable f(x).
    z0 : complex
        Point to evaluate the derivative at.
    n : int
        The order of the derivative to evaluate.
    contour : :class:`Contour <cxroots.Contour.Contour>`, optional
        The contour, C, in the complex plane which encloses the point z0.
        By default the contour is the circle |z-z_0|=1e-3.
    absIntegrationTol : float, optional
        The absolute tolerance required of the integration routine.
    verbose : bool, optional
        If True runtime information will be printed.  False be default.

    Returns
    -------
    f^{(n)}(z0) : complex
        The nth derivative of f evaluated at z0
    """
    if contour is None:
        from .contours.Circle import Circle
        C = lambda z0: Circle(z0, 1e-3)
    else:
        C = lambda z0: contour

    integrand = lambda z: f(z)/(z-z0)**(n+1)
    integral = C(z0).integrate(integrand, absTol=absIntegrationTol, verbose=verbose)
    return integral * math.factorial(n)/(2j*pi)

def find_multiplicity(root, f, df=None, rootErrTol=1e-10, verbose=False):
    """
    Find the multiplicity of a given root of f by computing the
    derivatives of f, f^{(1)}, f^{(2)}, ... until
    |f^{(n)}(root)|>rootErrTol.  The multiplicity of the root is then
    equal to n.  The derivative is calculated with `numdifftools <http://numdifftools.readthedocs.io/en/latest/api/numdifftools.html#numdifftools.fornberg.derivative>`_
    which employs a method due to Fornberg.

    Parameters
    ----------
    root : complex
        A root of f, f(root)=0.
    f : function
        An analytic function of a single complex variable such that
        f(root)=0.
    df : function, optional
        The first derivative of f.  If not known then df=None.
    contour : Contour, optional
        The integration contour used to evaluate the derivatives.
    rootErrTol : float, optional
        It will be assumed that f(z)=0 if numerically |f(z)|<rootErrTol.
    verbose : bool, optional
        If True runtime information will be printed.  False be default.

    Returns
    -------
    multiplicity : int
        The multiplicity of the given root.
    """
    if abs(f(root)) > rootErrTol:
        raise ValueError("""
            The provided 'root' is not a root of the given function f.
            Specifically, %f = abs(f(root)) > rootErrTol = %f
            """%(abs(f(root)), rootErrTol))

    n = 1
    while True:
        if df is not None:
            if n==1:
                err = abs(df(root))
            else:
                # ndf.derivative returns an array [f, f', f'', ...]
                err = abs(ndf.derivative(df, root, n-1)[n-1])
        else:
            err = abs(ndf.derivative(f, root, n)[n])

        if verbose:
            print('n', n, '|df^(n)|', err)

        if err > rootErrTol:
            break

        n += 1

    return n


import numpy as np
import pandas as pd

def median(df, values_col, weights_col, dropna = True):
    _df = df[[values_col, weights_col]]
    _df.dropna(subset=[values_col], inplace = dropna)
    _df = _df.sort_values(values_col).reset_index()
    _df['cumsum'] = _df[weights_col].cumsum()
    median_cumsum = _df[weights_col].sum() / 2
    median_iloc = np.searchsorted(_df['cumsum'], median_cumsum)
    return _df[values_col].iloc[median_iloc]

# def median2(df, values_col, weights_col, dropna = True):
#     _df = df[[values_col, weights_col]]
#     _df.dropna(subset=[values_col], inplace = dropna)
#     values = _df[values_col].to_numpy()
#     weights = _df[weights_col].to_numpy()
#     sort_index = values.argsort()
#     cumsum_arr = np.cumsum([weights[i] for i in sort_index])
#     median_iloc = np.searchsorted(cumsum_arr, cumsum_arr[-1]/2)
#     return np.array([values[i] for i in sort_index])[median_iloc]

def quantile(df, values_col, weights_col, q, dropna = True):
    _df = df[[values_col, weights_col]]
    _df.dropna(subset=[values_col], inplace = dropna)
    _df = _df.sort_values(values_col).reset_index()
    # _df['cumsum'] = _df[weights_col].cumsum()
    # quantile_cumsum = np.quantile(_df['cumsum'], q)
    cumsum = _df[weights_col].cumsum().to_numpy()
    quantile_iloc = np.searchsorted(cumsum, np.quantile(cumsum, q))
    return _df[values_col].iloc[quantile_iloc]


import numpy as np

def euclideanDistance(src, targ):
    '''
        Calculates euclidean distance between two arrays
    '''
    try:
        return np.linalg.norm(a-b)

    except:
        return "Error while calculating the euclidean distances for the above data types"

def isStringPalindrome(data):
    '''
        Checks if input string or corresponding string from input is a palindrome
    '''

    try:
        # Convert input type to string
        data = str(data)
        return True if data==data[::-1] else False

    except:
        print("Error while processing, please check the input is correct")

def isPrime(n):
    '''
        Checks if a given number is prime or not

        Source: GeeksforGeeks
    '''
    try:
        n = int(n)
        return all([(n % j) for j in range(2, int(n**0.5)+1)]) and n>1
    except:
        print("Error Occured While Checking for prime, please check the input is correct")
        return False


import numpy as np
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score

def softmax(x):
    """
    Compute softmax values for each sets of scores in x.

    Parameters:
        x (numpy.ndarray): array containing m samples with n-dimensions (m,n)
    Returns:
        x_softmax (numpy.ndarray) softmaxed values for initial (m,n) array
    """
    e_x = np.exp(x - np.max(x))
    return e_x / e_x.sum(axis=1, keepdims=1)

def compute_acc_bin(conf_thresh_lower, conf_thresh_upper, conf, pred, true):
    """
    # Computes accuracy and average confidence for bin

    Args:
        conf_thresh_lower (float): Lower Threshold of confidence interval
        conf_thresh_upper (float): Upper Threshold of confidence interval
        conf (numpy.ndarray): list of confidences
        pred (numpy.ndarray): list of predictions
        true (numpy.ndarray): list of true labels

    Returns:
        (accuracy, avg_conf, len_bin): accuracy of bin, confidence of bin and number of elements in bin.
    """
    filtered_tuples = [x for x in zip(pred, true, conf) if x[2] > conf_thresh_lower and x[2] <= conf_thresh_upper]
    if len(filtered_tuples) < 1:
        return 0,0,0
    else:
        correct = len([x for x in filtered_tuples if x[0] == x[1]])  # How many correct labels
        len_bin = len(filtered_tuples)  # How many elements falls into given bin
        avg_conf = sum([x[2] for x in filtered_tuples]) / len_bin  # Avg confidence of BIN
        accuracy = float(correct)/len_bin  # accuracy of BIN
        return accuracy, avg_conf, len_bin

def ECE(conf, pred, true, bin_size = 0.1):

    """
    Expected Calibration Error

    Args:
        conf (numpy.ndarray): list of confidences
        pred (numpy.ndarray): list of predictions
        true (numpy.ndarray): list of true labels
        bin_size: (float): size of one bin (0,1)  # TODO should convert to number of bins?

    Returns:
        ece: expected calibration error
    """

    upper_bounds = np.arange(bin_size, 1+bin_size, bin_size)  # Get bounds of bins

    n = len(conf)
    ece = 0  # Starting error

    for conf_thresh in upper_bounds:  # Go through bounds and find accuracies and confidences
        acc, avg_conf, len_bin = compute_acc_bin(conf_thresh-bin_size, conf_thresh, conf, pred, true)
        ece += np.abs(acc-avg_conf)*len_bin/n  # Add weigthed difference to ECE

    return ece

def test_classification_net_logits2(logits, labels):
    '''
    This function reports classification accuracy and confusion matrix given logits and labels
    from a model.
    '''
    labels_list = []
    predictions_list = []
    confidence_vals_list = []

    softmaxs = softmax(logits)
    confidence_vals = np.max(softmaxs, axis=1)
    predictions = np.argmax(softmaxs, axis=1)
    labels_list.extend(labels.tolist())
    predictions_list.extend(predictions.tolist())
    confidence_vals_list.extend(confidence_vals.tolist())
    accuracy = accuracy_score(labels_list, predictions_list)
    return confusion_matrix(labels_list, predictions_list), accuracy, labels_list,\
        predictions_list, confidence_vals_list


#!/usr/bin/env python

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import sys
import argparse

class Parabola() :
    def __init__(self,npts,size):
        mpl.rcParams['toolbar'] = 'None'
        self.size = size
        self.npts = npts
        self.fig = plt.figure(figsize=(8,8))
        self.ax = self.fig.add_subplot()
        self.ax.set_xlim(-size,size)
        self.ax.set_ylim(-size,size)

    def drawVertical(self,invert,color) :
        self.t = np.linspace(-self.size,self.size,self.npts)
        self.x = self.t
        if not invert :
            self.y = self.size*self.x**2
        else :
            self.y = -self.size*self.x**2
        self.ax.plot(self.x,self.y,color)

    def drawHorizontalRight(self,invert,color) :
        if not invert :
            self.t = np.linspace(0,self.size,self.npts)
            self.y = self.t
            self.x = self.size*self.t**2
        else :
            self.t = np.linspace(0,self.size,self.npts)
            self.y = -self.t
            self.x = self.size*self.t**2
        self.ax.plot(self.x,self.y,color)

    def drawHorizontalLeft(self,invert,color) :
        if not invert :
            self.t = np.linspace(-self.size,0,self.npts)
            self.y = self.t
            self.x = -self.size*self.t**2
        else :
            self.t = np.linspace(-self.size,0,self.npts)
            self.y = -self.t
            self.x = -self.size*self.t**2
        self.ax.plot(self.x,self.y,color)

    def drawAxis(self) :
        points = (-self.size,self.size)
        zeros = (0,0)
        self.ax.plot(points,zeros,'black',linestyle = 'dotted')
        self.ax.plot(zeros,points,'black',linestyle = 'dotted')

    def display(self) :
        plt.show()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='-vb -vt -hr -hl : default all')
    parser.add_argument('-vb', action="store_true")
    parser.add_argument('-vt', action="store_true")
    parser.add_argument('-hr', action="store_true")
    parser.add_argument('-hl', action="store_true")
    args = parser.parse_args()
    if not(args.vb) and not(args.vt) and not(args.hr) and not(args.hr) :
        args.vb = True; args.vt = True; args.hr = True; args.hl = True;
    parabola = Parabola(1000,1.01)
    if args.vb :
        parabola.drawVertical(True,'darkblue')
    if args.vt :
        parabola.drawVertical(False,'blue')
    if args.hr :
        parabola.drawHorizontalRight(True,'darkred')
        parabola.drawHorizontalRight(False,'red')
    if args.hl :
        parabola.drawHorizontalLeft(True,'limegreen')
        parabola.drawHorizontalLeft(False,'green')
    parabola.drawAxis()
    parabola.display()


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

import matplotlib.pyplot as plt
import numpy as np
from numpy import linalg as la
from scipy import optimize

## Metoda Gradient

## Date: Q, q
## f(x) = 1/2 x^TQx + q^Tx
Q = np.array([[1.52,1.5],[1.5,1.5]])
q = np.array([2,2])
f = lambda x: 0.5*x.T@Q@x + q.T@x

V = la.eigvals(Q)

print("")
print("")
print("#######################")
print("f (x) = 0.5*x^T Q x + q.T x")
print("Valori proprii Q:",V[0],V[1] )
print("Numar conditionare L/sigma: ", V[0]/V[1])
print("#######################")
print("")
print("Metoda Gradient cu pas constant alpha = 1/Lips")
print("")
print("#######################")

k1 = 0
eps = 10e-7
x0 = np.array([-9,9])
grad = Q@x0+q
grad0 = grad

### Constanta Lipschitz a gradientului
Lips = np.max(la.eigvals(Q))
mu = np.min(la.eigvals(Q))
nr_cond = Lips/mu

alpha = 1/Lips

all_x_i = [x0[0]]
all_y_i = [x0[1]]
all_f_i = [f(x0)]
criteriu_stop = la.norm(grad)
x = x0

while (criteriu_stop > eps):

    x = x - alpha*grad
    grad = Q@x+q

    criteriu_stop = la.norm(grad)
    k1 = k1+1

    all_x_i.append(x[0])
    all_y_i.append(x[1])
    all_f_i.append(f(x))

solMG = x

id_all_x_i = [x0[0]]
id_all_y_i = [x0[1]]
id_all_f_i = [f(x0)]
criteriu_stop = la.norm(grad0)
x = x0
k2 = 0

while (criteriu_stop > eps):

    grad = Q@x+q
    alpha = (la.norm(grad)**2)/(grad.T@Q@grad)
    x = x - alpha*grad

    criteriu_stop = la.norm(grad)
    k2 = k2+1

    id_all_x_i.append(x[0])
    id_all_y_i.append(x[1])
    id_all_f_i.append(f(x))

solMG_id = x
sol = -la.inv(Q)@q

#### Plot ####

x, y = np.mgrid[-10:10:0.1, -10:10:0.1]
x = x.T
y = y.T

fig = plt.figure(1, figsize=(4, 4))
plt.clf()
plt.axes([0, 0, 1, 1])

fcont = 0.5*Q[0,0]*(x**2) + 0.5*Q[1,1]*(y**2) + Q[1,0]*x*y + q[0]*x+ q[1]*y
contours = plt.contour(fcont, extent=[-10, 10, -10, 10],
                    cmap=plt.cm.gnuplot)

#Etichete pentru multimile izonivel
plt.clabel(contours, inline=1,
                fmt='%1.1f', fontsize=10)

plt.plot(id_all_x_i, id_all_y_i, 'm-', linewidth=2)
plt.plot(id_all_x_i, id_all_y_i, 'g+')
plt.plot(all_x_i, all_y_i, 'b-', linewidth=2)
plt.plot(all_x_i, all_y_i, 'k+')
plt.plot(sol[0], sol[1], 'rx', markersize = 14)

fig.savefig('MG_quad_cs.pdf')

print("#######################")
print("")
print("Numar conditionare problema: ",nr_cond)
print("")
print("Numar de iteratii pas constant: ",k1)
print("Numar de iteratii pas ideal: ",k2)
print("")
print("Solutie gasita de MG: ",'(',solMG[0],solMG[1],')')
print("Solutie optima: ",'(',sol[0],sol[1],')')
print("Valoare optima: ",f(sol))
print(0.5*(Q[0,0]*(sol[0]**2) + Q[1,1]*(sol[1]**2)) + Q[1,0]*sol[0]*sol[1] + q[0]*sol[0]+ q[1]*sol[1])
#print("Solutie gasita de MG: ",'(',solMG[0],solMG[1],')')
print("")
print("#######################")

Tehnici de Optimizare (TO)/Seminar/2/metoda_gradient.py


import numpy as np

def softmax(L):
    expL = np.exp(L)
    sumExpL = sum(expL)
    result = []
    for i in expL:
        result.append(i*1.0/sumExpL)
    return result

    # Note: The function np.divide can also be used here, as follows:
    # def softmax(L):
    #     expL(np.exp(L))
    #     return np.divide (expL, expL.sum())


import numpy as np

def ackley(coordinate: np.ndarray) -> float:
    """
    n-dimensional Ackley function. Bounded by -30 <= coordinate[i] <= 30
    :param coordinate: n-dimensional numpy array with dtype float
    :return: function value at the given coordinate
    """
    assert np.all((-30 <= coordinate) & (coordinate <= 30)), 'Coordinates have to be in [-30, 30]'
    first_sum = 0.0
    second_sum = 0.0
    for c in coordinate:
        first_sum += c ** 2.0
        second_sum += np.cos(2.0 * np.pi * c)
    n = float(len(coordinate))
    return -20.0 * np.exp(-0.2 * np.sqrt(first_sum / n)) - np.exp(second_sum / n) + 20 + np.e

def main():
    import numpy as np
    from matplotlib import pyplot
    from mpl_toolkits.mplot3d import Axes3D
    # define range for input
    r_min, r_max = -5.0, 5.0
    # sample input range uniformly at 0.1 increments
    xaxis = np.arange(r_min, r_max, 0.1)
    yaxis = np.arange(r_min, r_max, 0.1)
    # create a mesh from the axis
    x, y = np.meshgrid(xaxis, yaxis)
    # compute targets
    results = ackley(np.array([x, y]))
    # create a surface plot with the jet color scheme
    figure = pyplot.figure()
    axis = figure.gca(projection='3d')
    axis.plot_surface(x, y, results, cmap='jet')
    # show the plot
    pyplot.show()

if __name__ == '__main__':
    main()


import numpy as np
#------------------------------------------------------------------------------------------------
def convolucion(A,B):
    filas = len(A) - len(B) + 1
    columnas = len(A[0]) - len(B[0]) + 1
    C = np.zeros((filas,columnas))
    for i in range(len(C)):
        for j in range(len(C[0])):
            suma = 0
            for k in range(len(B)):
                for l in range(len(B[0])):
                    suma += A[k + i][l + j]*B[k][l]
            C[i][j] = suma
    return C
#------------------------------------------------------------------------------------------------
matriz1 = np.array([[6,9,0,3],[8,4,9,1],[4,1,3,12],[3,2,1,100]])
kernell1 = np.array([[1,0,2],[5,0,9],[6,2,1]])
matriz2 = np.array([[1,2,3,4,5,6],[7,8,9,10,11,12],[0,0,1,16,17,18],[0,1,0,7,23,24],[1,7,6,5,4,3]])
kernell2 = np.array([[1,1,1],[0,0,0],[2,10,3]])
#------------------------------------------------------------------------------------------------
print("Primer ejemplo: ","\n",convolucion(matriz1,kernell1))
print("Segundo ejemplo: ","\n",convolucion(matriz2,kernell2))


#!/usr/bin/env python
# coding: utf-8

# In[3]:

import pandas as pd
import numpy as np

from scipy import stats

def black_76(days_to_expiry, futures_price, strike_price, implied_volatility,
             interest_rate, option_type="call"):

    if option_type not in ["call", "put"]:
        raise ValueError("Must provide 'call' for European call or 'put' for European put option.")

    F = futures_price
    K = strike_price
    sigma = implied_volatility
    r = interest_rate

    time_to_expiry = (days_to_expiry) / 365

    d_1 = (np.log(F / K) + 0.5 * (time_to_expiry) * sigma ** 2) / (sigma * np.sqrt(time_to_expiry))
    d_2 = d_1 - sigma * np.sqrt(time_to_expiry)

    if option_type == "call":
        C = np.exp(-r * (time_to_expiry)) * (F * stats.norm.cdf(d_1) - K * stats.norm.cdf(d_2))

        return C
    else:
        P = np.exp(-r * (time_to_expiry)) * (K * stats.norm.cdf(-d_2) - F * stats.norm.cdf(-d_1))

        return P

def tune(F_vect, delta=1/12):

    if type(F_vect) != np.ndarray:
        raise TypeError("Must provide numpy array.")

    n = len(F_vect) - 1

    x, y = F_vect[0:-1], F_vect[1:]

    s_x, s_y = np.sum(x), np.sum(y)

    s_xx = np.sum(x ** 2)
    s_xy = np.sum(x * y)
    s_yy = np.sum(y ** 2)

    a = (n * s_xy - s_x * s_y) / (n * s_xx - s_x **2)
    b = (s_y - a * s_x) / n
    sd = np.sqrt((n * s_yy - s_y ** 2 - a * (n * s_xy - s_x * s_y)) / (n * (n-2)))

    lambda_par = - np.log(a) / delta
    mu = b / (1 - a)

    return mu, lambda_par

def gbm_path_gen(t, T, F_init, sigma, n=12):

    path = np.zeros(n)
    ttm = T - t
    dt = (ttm.days / (n * 365))

    path[0] = F_init

    for i in range(n - 1):
        path[i+1] = path[i] + path[i] * sigma * np.sqrt(dt) * np.random.randn()

    return path

def vasicek_path_gen(t, T, F_init, lambda_par, mu, sigma, n=12):

    path = np.zeros(n)
    ttm = T - t
    dt = (ttm.days / (n * 365))

    path[0] = F_init

    for i in range(n - 1):
        path[i+1] = path[i] + lambda_par * (mu - path[i]) * dt + sigma * np.sqrt(dt) * np.random.randn()

    return path

def garch_path_gen(t, T, F_init, lambda_par, mu, sigma, n=12):

    path = np.zeros(n)
    ttm = T - t
    dt = (ttm.days / (n * 365))

    path[0] = F_init

    for i in range(n - 1):
        path[i+1] = path[i] + lambda_par * (mu - path[i]) * dt + sigma * np.sqrt(dt) * path[i] * np.random.randn()

    return path

def monte_vasicek(t, T, F, K, sigma, r, lambda_par, mu, m=1e5, n=12):

    sim_start_date, sim_final_date = pd.to_datetime(t), pd.to_datetime(T)
    monte_mat = np.zeros((m, n))
    a_val = 0

    for j in range(m):
        vasicek_mat[j, :] = vasicek_path_gen(pd.to_datetime(sim_start_date), pd.to_datetime(sim_final_date), F,
                                             lambda_par, mu, sigma, n=n)
        a_val += max((vasicek_mat[j, -1] - K), 0)

    price = (a_value / m) * (np.exp(-r * (10/365)))

    return price

def monte_garch(t, T, T_e, F, K, sigma, r, lambda_par, mu, m=1000, n=12):

    sim_start_date, sim_final_date = pd.to_datetime(t), pd.to_datetime(T)
    monte_mat = np.zeros((m, n))
    a_val = 0

    for j in range(m):
        monte_mat[j, :] = garch_path_gen(sim_start_date, sim_final_date, F, lambda_par, mu, sigma, n=n)

        a_val += max((monte_mat[j, -1] * (np.exp(-r * (10 / 365))) - K, 0))

    price = (a_val / m) * (np.exp(-r * (T_e / 365)))

    return price


import numpy as np
from math import log

def ld_stat(l, n_sources, n_snapshots):
    """Computes the sufficient statistic for source number detection in MDL/AIC.

    Args:
        l (~numpy.ndarray): A 1D vector of the eigenvalues of the covariance
            matrix in ascending order.
        n_sources (int): Number of sources.
        n_snapshots (int): Number of snapshots.

    References:
        [1] H. L. Van Trees, Optimum array processing. New York: Wiley, 2002.
    """
    if l.ndim != 1:
        raise ValueError('A 1D numpy vector expected.')
    n_sensors = l.size
    diff = n_sensors - n_sources
    l = l[:diff]
    return n_snapshots * diff * log(np.sum(l) / diff / (np.prod(l)**(1./diff)))

def aic(x, n_snapshots):
    """Detects source numbers using AIC.

    Args:
        x (~numpy.ndarray): A 1D vector of the eigenvalues of the covariance
            matrix in ascending order, or the covariance matrix itself.
        n_snapshots (int): Number of snapshots.

    Notes:
        AIC is inconsistent, and tends to asymptotically overestimate the
        number of sources. However, it tends to give a higher probability of a
        correct decision.

    References:
        [1] H. L. Van Trees, Optimum array processing. New York: Wiley, 2002.
    """
    if x.ndim > 1:
        x = np.linalg.eigvalsh(x)
    n_sensors = x.size
    ld = np.zeros((n_sensors, 1))
    for i in range(n_sensors):
        ld[i] = ld_stat(x, i, n_snapshots) + i * (2 * n_sensors - i)
    return np.argmin(ld)

def mdl(x, n_snapshots):
    """Detects source number using MDL.

    Args:
        x (~numpy.ndarray): A 1D vector of the eigenvalues of the covariance
            matrix in ascending order, or the covariance matrix itself.
        n_snapshots (int): Number of snapshots.

    Notes:
        MDL is consistent.

    References:
        [1] H. L. Van Trees, Optimum array processing. New York: Wiley, 2002.
    """
    if x.ndim > 1:
        x = np.linalg.eigvalsh(x)
    n_sensors = x.size
    ld = np.zeros((n_sensors, 1))
    for i in range(n_sensors):
        ld[i] = ld_stat(x, i, n_snapshots) + 0.5 * (i * (2 * n_sensors - i) + 1) * log(n_snapshots)
    return np.argmin(ld)

def sorte(x):
    r"""Detects source number using SORTE.

    Arg:
        x: (~numpy.ndarray): A 1D vector of the eigenvalues of the covariance
            matrix in ascending order, or the covariance matrix itself.

    Refereces:
        [1] Z. He, A. Cichocke, S. Xie, and K. Choi, "Detecting the number of
        clusters in n-way probabilistic clustering," IEEE Trans. Pattern
        Anal. Mach. Intell., vol. 32, pp. 2006-2021, Nov. 2010.
    """
    if x.ndim > 1:
        x = np.linalg.eigvalsh(x)
    # SORTE requires descending order.
    x = x[::-1]
    n = x.size
    if n < 4:
        raise ValueError('At least four eigenvalues required.')
    diffs = x[:-1] - x[1:]
    sigmas = [np.var(diffs[k:]) for k in range(n - 1)]
    s = np.zeros((n - 2,))
    for k in range(n - 2):
        if np.abs(sigmas[k]) < np.finfo(np.float_).eps:
            s[k] = np.inf
        else:
            s[k] = sigmas[k + 1] / sigmas[k]
    return np.argmin(s[:-1]) + 1


"""Statistical tests to estimate population proportions using statsmodels

These functions are created from using basic python libraries

The module contains useful functions for evaluating AB tests
1. one_prop_conf_interval
2. one_prop_hypothesis
3. two_props_diff_conf_interval
4. two_props_hypothesis

"""

import numpy as np
import statsmodels.stats.proportion as prop_stats

def one_prop_conf_interval(values: np.ndarray,
                           conf_level: float = 0.95) -> tuple:
    """calculates confidence interval for a proportion

    Args:
        values (np.array): sample values (values are of values 0 and 1)
        conf_level (float): confidence level

    Returns:
        tuple: lower and upper bounds of confidence interval
    """
    ci = prop_stats.proportion_confint(values.sum(), len(values),
                                       alpha=1-conf_level)
    return ci

def one_prop_hypothesis(values: np.ndarray,
                        null_val: float = 0,
                        alternative: str = "two-sided") -> tuple:
    """[z test for comparing the proportion of 1 population with null value

    Args:
        values (np.ndarray): sample values
        null_val (float, optional): null value. Defaults to 0.
        alternative (str, optional): two-sided/larger/smaller.
                                     Defaults to "two-sided".

    Returns:
        tuple: z statistic, p value
    """
    count = np.sum(values)
    nob = len(values)
    return prop_stats.proportions_ztest(count, nob, alternative=alternative)

def two_props_diff_conf_interval(values1: np.ndarray, values2: np.ndarray,
                                 conf_level: float) -> tuple:
    """Calculates the confidence interval for the diff between two proportions

    Args:
        values1 (np.array): sample 1 binary(0/1) values
        values2 (np.array): sample 2 binary(0/1) values
        conf_level (float): confidence level

    Returns:
        tuple: lower and upper values of confidence interval
    """
    count1, count2 = values1.sum(), values2.sum()
    nobs1, nobs2 = len(values1), len(values2)
    ci = prop_stats.confint_proportions_2indep(count1, nobs1, count2, nobs2,
                                               alpha=1-conf_level,
                                               method="wald")
    return ci

def two_props_hypothesis(values1: np.ndarray,
                         values2: np.ndarray,
                         alternative: str = "two-sided") -> tuple:
    """z test for comparing two proportions

    Args:
        values1 (np.array): sample 1 binary(0/1) values
        values2 (np.array): sample 2 binaray(0/1) values
        alternative (str, optional): two-sided/larger/smaller.
                                     Defaults to "two-sided".

    Returns:
        tuple: z_statistic and p value of the test
    """
    samples = np.vstack((values1, values2))
    counts = samples.sum(axis=1)
    nobs = [np.size(samples, 1)]*2
    return prop_stats.proportions_ztest(counts, nobs, alternative=alternative)


# -*- coding: utf-8 -*-
from numpy import array
from numpy import eye,dot,zeros,sort
from scipy.linalg import svd,inv,eig
if __name__=='__main__':
    m=array([[1,0,0,0,2],
             [0,0,3,0,0],
             [0,0,0,0,0],
             [0,4,0,0,0]])
    #py的svd得出的d是一个数组
    u,d,vt=svd(m)
    print '---test svd---'
    print 'u',u
    print 'd',d
    print 'vt',vt
    #为了验证,构造dz矩阵,其为m*n的(4*5)
    #这里注意dz的构造方式
    dz=zeros(vt.shape[0])
    #print 'vt.shape[0]', vt.shape[0], vt.shape[1]
    dz[:len(d)]+=d
    print 'dz', dz
    #ndarray的*和matrix*是不同的,matrix的*对应dot
    print eye(len(d),vt.shape[0])*dz
    t=dot(u,eye(len(d),vt.shape[0])*dz)
    print dot(t,vt) #should be equal to m
    print '---test inv---'
    print inv(u)
    print inv(vt)
    print '---test mt*m---'
    ms=dot(m.T,m)
    print ms
    #eig可以求方阵的特征值与特征向量
    evals, evecs = eig(ms)
    #
    sevals=sort(evals)[::-1]
    v=vt.T
    print sevals
    print dz**2
    print '---test at*t=lamb_i*vi---'
    for i in range(len(sevals)):
        print dot(ms,vt[i])
        print sevals[i]*vt[i]
        print ''


"""
This is the Python HW 5
for PSTAT 160B
Prof Ichiba
TA: Mousavi
Section: W 1:00 - 1:50pm
"""

# Import libraries
from __future__ import division
import random
import math
import matplotlib.pyplot as plt
import numpy as np

# In the class we see the simple symmetric random walk approximates the standard Brownian motion

def Part_A():
	# Simulate a Brownian motion-like sample path
	# Graphing (ti, U(ti)) from i = 0, 1, ... N where 2 ^ N
	# Where ti := i / N
	# And U(ti) = sum of iid normal random variables with mean 0 and variance 1 / N
	# Define constants
	N = (2 ** 10)
	mean = 0
	var = (1 / N)
	sd = math.sqrt(var)
	Ti = [0] # Initialize first time as zero
	values = [0] # Initialize the first point as zero

	# Loop through 0 to N
	# Get time values and generate iid normal random variables
	for i in range(1, N):
		Ti.append(i / N)
		cospi = np.random.normal(mean, sd)
		values.append(cospi)

	# Get the cumulative sum and save as a list
	# Thank you numpy
	# These U(ti) values represent B(ti) values
	UTi = np.cumsum(values)

	# Plot the sample path
	plt.plot(Ti, UTi)
	plt.show()

def Part_B():
	#  Repeat this simulation 10000 times to estimate the joint probability
	# P((max B(s) from (0 <= s <= 1) > b), B(1) < a) for b >= a, b >= 0
	# Can choose appropriate range of (b, a)
	# Here a = 0, b = 2
	a = 0
	b = 1
	count = 0

	num_sim = 10000
	current_sim = 0
	# Define constants (taken from part A)
	N = (2 ** 10)
	mean = 0
	var = (1 / N)
	sd = math.sqrt(var)

	# Run simulations
	while current_sim < num_sim:
		# Taken from part A
		Ti = [0] # Initialize first time as zero
		values = [0] # Initialize the first point as zero

		# Loop through 0 to N
		# Get time values and generate iid normal random variables
		for i in range(1, N):
			Ti.append(i / N)
			cospi = np.random.normal(mean, sd)
			values.append(cospi)

		# Get the cumulative sum and save as a list
		# Thank you numpy
		# These U(ti) values represent B(ti) values
		UTi = np.cumsum(values)

		# Check conditions: if max value is greater than b
		# And if the last value is less than a
		# If so increment the count
		maximum = max(UTi)
		last_point = UTi[-1]
		if maximum > b and last_point < a:
			count += 1

		# Increment count
		current_sim += 1

	# Print the probability
	prob = count / num_sim
	print("Part B:")
	print("The probability that P((max B(s) from (0 <= s <= 1) > b), B(1) < a) for b >= a, b >= 0 is %f" %prob)

def Part_C():
	# Let us denote T by the uniform random variable on the unit interval [0, 1]
	# independent of Brownian motion.
	# As in part b, estimate the tail probability P(|B(T)| >= x) ; x > 0

	# First we'll repeat Part A
	# Simulate a Brownian motion-like sample path
	# Graphing (ti, U(ti)) from i = 0, 1, ... N where 2 ^ N
	# Where ti := i / N
	# And U(ti) = sum of iid normal random variables with mean 0 and variance 1 / N
	# Define constants
	N = (2 ** 10)
	mean = 0
	var = (1 / N)
	sd = math.sqrt(var)
	Ti = [0] # Initialize first time as zero
	values = [0] # Initialize the first point as zero
	# Pick a value for x, x > 0
	x = 0.5

	num_sim = 1000
	current_sim = 0
	count = 0

	# Run simulations
	while current_sim < num_sim:
		# Taken from part A
		# Loop through 0 to N
		# Get time values and generate iid normal random variables
		for i in range(1, N):
			Ti.append(i / N)
			cospi = np.random.normal(mean, sd)
			values.append(cospi)

		# Get the cumulative sum and save as a list
		# Thank you numpy
		# These U(ti) values represent B(ti) values
		UTi = np.cumsum(values)

		# Generate uniform random variable
		T = np.random.uniform(0, 1)

		# Since time is linear and represents a proportion from 0 to 1
		# And t(0) corresponds to B(0), t(N) corresponds to B(N)
		# t(T) corresponds to B(T * N)
		TN = math.floor(T * N)

		# Now we index B(s) (or UTi) for the appropropriate value with T plugged in
		# We want the absolute value as well
		BT = abs(UTi[TN])

		# Check if the the absolute value is greater than x
		if BT > x:
			count += 1

		# Increment count
		current_sim += 1
		if current_sim % 100 == 0:
			print(current_sim)

	# Print results
	prob = count / num_sim
	print("Part C:")
	print("Our estimate of the tail probability P(|B(T)| >= x) ; x > 0 is %f" %prob)

Part_A()
Part_B()
Part_C()