import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from numpy.linalg import svd
from random import random

def get_sphere(n):
    s = [(2 * np.pi) * random() for i in range(n)]
    t = [np.pi * np.random.random() for i in range(n)]
    x = np.cos(s) * np.sin(t)
    y = np.sin(s) * np.sin(t)
    z = np.cos(t)
    return x, y, z

x, y, z = get_sphere(300)
S = np.row_stack([x, y, z])

A1 = np.random.rand(3, 3)
A2 = np.random.rand(3, 3)
A3 = np.random.rand(3, 3)

ellipsoid1 = A1 @ S
ellipsoid2 = A2 @ S
ellipsoid3 = A3 @ S

U1, sigma1, V1 = svd(A1)
U2, sigma2, V2 = svd(A2)
U3, sigma3, V3 = svd(A3)

x_start, y_start, z_start = [[0] * 3] * 3
x_end = [0] * 3
y_end = [0] * 3
z_end = [0] * 3

for i, s1 in enumerate(np.diag(sigma1)):
    a = np.dot(U1, s1)
    x_end[i] = a[0]
    y_end[i] = a[1]
    z_end[i] = a[2]
quiver1 = [x_start, y_start, z_start, x_end, y_end, z_end]

# plot 1

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect('equal')
ax.scatter(x, y, z)
ax.scatter(ellipsoid1[0], ellipsoid1[1], ellipsoid1[2], color='red')
ax.quiver(x_start, y_start, z_start, x_end, y_end, z_end, color='black')
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_zlim(-1.5, 1.5)
plt.show()

for i, s2 in enumerate(np.diag(sigma2)):
    a = np.dot(U2, s2)
    x_end[i] = a[0]
    y_end[i] = a[1]
    z_end[i] = a[2]
quiver2 = [x_start, y_start, z_start, x_end, y_end, z_end]

# plot 2

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect('equal')
ax.scatter(x, y, z)
ax.scatter(ellipsoid2[0], ellipsoid2[1], ellipsoid2[2], color='orange')
ax.quiver(x_start, y_start, z_start, x_end, y_end, z_end, color='black')
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_zlim(-1.5, 1.5)
plt.show()

# plot 3

for i, s3 in enumerate(np.diag(sigma3)):
    a = np.dot(U3, s3)
    x_end[i] = a[0]
    y_end[i] = a[1]
    z_end[i] = a[2]
quiver3 = [x_start, y_start, z_start, x_end, y_end, z_end]

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect('equal')
ax.scatter(x, y, z)
ax.scatter(ellipsoid3[0], ellipsoid3[1], ellipsoid3[2], color='yellow')
ax.quiver(x_start, y_start, z_start, x_end, y_end, z_end, color='black')
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_zlim(-1.5, 1.5)
plt.show()

# ellipsoid with max/min singular value > 100

A = np.random.rand(3, 3)
U, sigma, V = svd(A)

while sigma[0] / sigma[2] < 100:
    A = np.random.rand(3, 3)
    U, sigma, V = svd(A)

print(A)

ellipsoid = A @ S

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_title("Max/min singular value > 100")
ax.set_aspect('equal')
ax.scatter(x, y, z)
ax.scatter(ellipsoid[0], ellipsoid[1], ellipsoid[2], color='green')
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_zlim(-1.5, 1.5)
plt.show()

# plot S V^T, S sigma V^T, S U sigma V^T

U, sigma, V = svd(A1)
ellipsoid = S.transpose() @ V
ellipsoid = ellipsoid.transpose()

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_title("S * V^T")
ax.set_aspect('equal')
ax.scatter(x, y, z)
ax.scatter(ellipsoid[0], ellipsoid[1], ellipsoid[2], color='red')
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_zlim(-1.5, 1.5)
plt.show()

ellipsoid = S.transpose() * sigma @ V
ellipsoid = ellipsoid.transpose()

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_title("S * sigma * V^T")
ax.set_aspect('equal')
ax.scatter(x, y, z)
ax.scatter(ellipsoid[0], ellipsoid[1], ellipsoid[2], color='orange')
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_zlim(-1.5, 1.5)
plt.show()

ellipsoid = S.transpose() @ U * sigma @ V
ellipsoid = ellipsoid.transpose()

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_title("S * U * sigma * V^T")
ax.set_aspect('equal')
ax.scatter(x, y, z)
ax.scatter(ellipsoid[0], ellipsoid[1], ellipsoid[2], color='yellow')
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_zlim(-1.5, 1.5)
plt.show()


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

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

def relu(x):
    return max(0, x)

def gelu(x):
    return 0.5 * x * (1 + np.tanh(np.sqrt(2/np.pi)*(x + 0.044715*x**3)))

x_axis = np.arange(-3, 3, 0.1)
tan_h = [np.tanh(x) for x in x_axis]
sig = [sigmoid(x) for x in x_axis]
rel = [relu(x) for x in x_axis]
gel = [gelu(x) for x in x_axis]

names = ['tanh', 'Sigmoid', 'ReLU', 'GELU']

fig, ax = plt.subplots()
ax.plot(x_axis, tan_h, alpha=0.8)
ax.plot(x_axis, sig, alpha=0.8)
ax.plot(x_axis, rel, alpha=0.8)
ax.plot(x_axis, gel, alpha=0.8)

ax.set(title='Activation Functions')

plt.legend(names, loc='upper left', title='Activation Function')

fig.savefig("plots/activation_functions.png")
plt.show()


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

mpl.rcParams['axes.labelsize'] = 'x-large'
mpl.rcParams['legend.fontsize'] = 'x-large'
mpl.rcParams['xtick.labelsize'] = 'x-large'
mpl.rcParams['ytick.labelsize'] = 'x-large'
output_dir = './'

def T_k(k, x):
    return np.cos(k*np.arccos(x))

x = np.linspace(-1, 1, 100)

for k in range(6):
    plt.plot(x, T_k(k, x), label=f'T_{k}(x)', lw = 2.0)

plt.grid(True)
plt.xlabel('$x$')
plt.ylabel('$T_k(x)$')
plt.legend()
# plt.savefig('cheby.eps')

N = 20
k = np.arange(N+1)
xk = np.cos(k*np.pi/N)

plt.figure()
plt.plot(xk, np.zeros_like(xk), marker='x',lw=0.0)
plt.grid(True)
plt.xlabel('$x$')
plt.savefig('cgl_nodes.eps')
plt.show()


import numpy as np
from scipy.signal import convolve

def composite(y, dx=1, order=3):
    """
    Integrate y(x) for regularly spaced x.

    Parameters
    ----------
    y : array_like
        One-dimensional array to integrate.
    dx : float, optional
        Spacing between elements of `y`.
    order : int, optional
        Order of the interpolating polynomials. Default is 3, and other valid
        values are 1 (trapz), 2 (simps), 4, 5, 6 and 7.

    Returns
    -------
    composite : float
        Definite integral as approximated by the interpolating polynomials.

    See Also
    --------
    scipy.integrate.trapezoid, scipy.integrate.simpson
    gradiompy.integrate.cumulative_composite

	Note
	----
	The result is exact if `y` is sampled from a polynomial function of order
	`order` or less.

    Example
    -------
    >>> import numpy as np
    >>> from scipy import integrate as sp_integrate
    >>> from gradiompy import integrate as gp_integrate

    >>> x = np.linspace(-3,3,num=15)
    >>> dx = x[1]-x[0]
    >>> y = 8*x + 3*x**2 + x**3 - 2*x**5 + x**6 + 1/5*x**7
    >>> y_int = 4*x**2 + x**3 + 1/4*x**4 - 1/3*x**6 + 1/7*x**7 + 1/40*x**8
    >>> y_int = y_int[-1]-y_int[0]
    >>> y_int_trapz = sp_integrate.trapezoid(y,dx=dx)
    >>> y_int_simps = sp_integrate.simpson(y,dx=dx)
    >>> print('Integration error:')
    >>> print('  scipy.integrate')
    >>> print('    trapz    = %9.6f' % abs(y_int_trapz-y_int))
    >>> print('    simpson  = %9.6f' % abs(y_int_simps-y_int))
    >>> print('  gradiompy.integrate')
    >>> for order in range(1,8,2):
    >>>     y_int_composite = gp_integrate.composite(y,dx,order=order)
    >>>     print('    order %i  = %9.6f' % (order,abs(y_int_composite-y_int)))

    """
    # format inputs
    y = np.asarray(y)
    order = max(1,min(7,order))

    # integration coefficients
    coef_dic = {
        1: np.array([-1])/2.,
        2: np.array([-15,4,-1])/24.,
        3: np.array([-16,7,-4,1])/24.,
        4: np.array([-965,462,-336,146,-27])/1440.,
        5: np.array([-981,542,-496,306,-107,16])/1440.,
        6: np.array([-84161,55688,-66109,57024,-31523,9976,-1375])/120960.,
        7: np.array([-85376,64193,-91624,99549,-74048,35491,-9880,1215])/120960.}
    c_boundary = coef_dic[order] * dx

    # cumpute the integral
    m = len(c_boundary)
    z = np.sum(y) * dx
    dz_ini = c_boundary.dot(y[:+m])
    dz_end = c_boundary.dot(np.flip(y[-m:]))
    return z + dz_ini + dz_end

def cumulative_composite(y, dx=1, initial=[], order=3):
    """
    Cumulatively integrate y(x) for regularly spaced x.

    Parameters
    ----------
    y : array_like
        One-dimensional array to integrate.
    dx : float, optional
        Spacing between elements of `y`.
    initial : scalar, optional
        If given, insert this value at the beginning of the returned result.
        Typically this value should be 0. Default is [], which means no
        value at ``x[0]`` is returned and `res` has one element less than `y`
        along the axis of integration.
    order : int, optional
        Order of the interpolating polynomials. Default is 3, and other valid
        values are 1 (cumtrapz), 2 (cumsimps), 4, 5, 6 and 7. Odd values
        should be preferred over even ones.

    Returns
    -------
    cumulative_composite : ndarray
        The result of cumulative integration of `y`. If `initial` is empty or
        zero, the last element of this list is equal to the definite integral
        of y(x).

    See Also
    --------
    numpy.cumsum, numpy.convolve
    scipy.integrate.cumulative_trapezoid
    gradiompy.integrate.composite

    Note
	----
	The result is exact if `y` is sampled from a polynomial function of order
	`order` or less.

    Example
    -------
    >>> import numpy as np
    >>> from scipy import integrate as sp_integrate
    >>> from gradiompy import integrate as gp_integrate

    >>> x = np.linspace(-3,3,num=15)
    >>> dx = x[1]-x[0]
    >>> y = 8*x + 3*x**2 + x**3 - 2*x**5 + x**6 + 1/5*x**7
    >>> y_int = 4*x**2 + x**3 + 1/4*x**4 - 1/3*x**6 + 1/7*x**7 + 1/40*x**8
    >>> y_int_trapz = y_int [0] + sp_integrate.cumulative_trapezoid(y,dx=dx,initial=0)
    >>> print('Integration error:')
    >>> print('  scipy.integrate')
    >>> print('    cumtrapz = %9.6f' % np.linalg.norm(y_int_trapz-y_int))
    >>> print('  gradiompy.integrate')
    >>> for order in range(1,8,2):
    >>>     y_int_composite = gp_integrate.cumulative_composite(y,dx,order=order,initial=y_int[0])
    >>>     print('    order %i  = %9.6f' % (order,np.linalg.norm(y_int_composite-y_int)))

    """
    # format inputs
    y = np.asarray(y)
    if np.isscalar(initial): initial = [initial]
    order = max(1,min(7,order))

    # integration coefficients
    coef_dic = {
        1: (np.array([[]]),
            np.array([1,1])/2.),
        2: (np.array([[5,8,-1]])/12.,
            np.array([-1,13,13,-1])/24.),
        3: (np.array([[9,19,-5,1]])/24.,
            np.array([-1,13,13,-1])/24.),
        4: (np.array([[251,646,-264,106,-19],
                      [-19,346,456,-74,11]])/720.,
            np.array([11,-93,802,802,-93,11])/1440.),
        5: (np.array([[475,1427,-798,482,-173,27],
                      [-27,637,1022,-258,77,-11]])/1440.,
            np.array([11,-93,802,802,-93,11])/1440.),
        6: (np.array([[19087,65112,-46461,37504,-20211,6312,-863],
                      [-863,25128,46989,-16256,7299,-2088,271],
                      [271,-2760,30819,37504,-6771,1608,-191]])/60480.,
            np.array([-191,1879,-9531,68323,68323,-9531,1879,-191])/120960.),
        7: (np.array([[36799,139849,-121797,123133,-88547,41499,-11351,1375],
                      [-1375,47799,101349,-44797,26883,-11547,2999,-351],
                      [351,-4183,57627,81693,-20227,7227,-1719,191]])/120960.,
            np.array([-191,1879,-9531,68323,68323,-9531,1879,-191])/120960.)}
    coef = coef_dic[order]
    c_boundary = coef[0] * dx
    c_convolve = coef[1] * dx

    # compute the list to be accumulated
    m = c_boundary.shape[1]
    if m > 0:
        dy_ini = c_boundary.dot(y[:m])
        dy_end = np.flip(c_boundary.dot(np.flip(y[-m:])))
    else:
        dy_ini = []
        dy_end = []
    dy_mid = convolve(y,c_convolve,mode='valid',method='direct')
    dy = np.concatenate((initial,dy_ini,dy_mid,dy_end))

    # return the cumulative integral
    return np.cumsum(dy)

def trapezoid(y, dx=1):
    return composite(y, dx=dx, order=1)

def simpson(y, dx=1):
    return composite(y, dx=dx, order=3)

def cumulative_trapezoid(y, dx=1, initial=[]):
    return cumulative_composite(y, dx=dx, initial=initial, order=1)

def cumulative_simpson(y, dx=1, initial=[]):
    return cumulative_composite(y, dx=dx, initial=initial, order=3)


import numpy as np
import matplotlib.pyplot as plt
from math import sin, cos, exp, sqrt, log

# Graph parameters
plt.rcParams["xtick.labelsize"] = 14
plt.rcParams["ytick.labelsize"] = 14
plt.rcParams["axes.labelsize"] = 16

def main():

    # Constants
    a = 0.0  # Start the interval
    b = 10.0  # Finish the interval
    xa = 0.0  # Initial condition, x(a)
    exact_N = int(1e3)  # Number of points for the exact solution
    exact_h = (b - a) / exact_N

    c = 1.0  # Constant for the function

    # Exact solution
    exact_x = []
    time = np.arange(a, b, exact_h)
    for t in time:
        exact_x.append(exact_sol(t, a, xa, c))

    # Euler and Runge-kutta 2 solution
    N_list = []
    for i in range(3, 11):
        N_list.append(2**i)

    meanerror_rk2 = []
    meanerror_euler = []

    for N in N_list:  # Number of steps for rk2
        h = (b - a) / N  # Size of one step
        x = xa

        t_rk2 = np.arange(a, b, h)
        x_rk2 = []
        x_euler = []
        xe = x
        error_rk2 = 0.0
        error_euler = 0.0

        for t in t_rk2:

            error_rk2 += (x - exact_sol(t,a,xa,c)) ** 2  # Accumulating the error of Runge-Kutta 2
            error_euler += (xe - exact_sol(t,a,xa,c)) ** 2  # Accumulating the error of Euler

            x_rk2.append(x)
            k1 = h * f(x, t, c)
            k2 = h * f(x + 0.5 * k1, t + 0.5 * h, c)
            x += k2
            x_euler.append(xe)
            xe += k1

        if N == 128:
            plt.figure(figsize=(12,12))
            plt.plot(t_rk2, x_rk2, 'gs', label="Runge-Kutta2")
            plt.plot(t_rk2, x_euler, 'ro', label="Euler")
            plt.plot(time, exact_x, label="Exact solution")
            plt.xlabel("t")
            plt.ylabel("x(t)")
            plt.legend(loc='best', fontsize='xx-large')
            plt.show()

        error_rk2 /= len(t_rk2)
        error_euler /= len(t_rk2)
        meanerror_rk2.append(np.sqrt(error_rk2))
        meanerror_euler.append(np.sqrt(error_euler))

    # Graph
    plt.figure(figsize=(12,12))
    plt.loglog(N_list, meanerror_rk2, 'gs', label="Runge-Kutta2")
    plt.loglog(N_list, meanerror_euler, 'ro', label="Euler")
    plt.xlabel("N")
    plt.ylabel("Mean Error")
    plt.legend(loc='best', fontsize='x-large')
    plt.show()

    print((log(meanerror_euler[0])-log(meanerror_euler[len(N_list)-1]))/(log(1024.0)-log(8.0)))
    print((log(meanerror_rk2[0])-log(meanerror_rk2[len(N_list)-1]))/(log(1024.0)-log(8.0)))

def exact_sol(t, a, xa, c):
    b = xa - 2.0 * exp(-c*a) * cos(a)
    return 2.0 * exp(-c*t) * cos(t) + b

def f(x, t, c):
    return -2.0 * exp(-c*t) * (c * cos(t) + sin(t))

if __name__ == "__main__":
    main()


__all__ = ("rotate",)

from typing import Tuple, Union

import numpy as np

def rotate(
    pivot: np.ndarray,
    turning: np.ndarray,
    angle: Union[Tuple[float], Tuple[float, float, float]],
) -> np.ndarray:
    pivot = np.asarray(pivot)
    turning = np.asarray(turning)
    assert pivot.shape == turning.shape
    matrix = get_rotate_matrix(angle)
    return matrix @ (turning - pivot) + pivot

def get_rotate_matrix(
    angle: Union[Tuple[float], Tuple[float, float, float]]
) -> np.ndarray:
    if len(angle) == 1:
        return rotate_matrix_2d(angle[0])
    elif len(angle) == 3:
        return rotate_matrix_3d(angle)
    else:
        raise ValueError(f"ndim should be 2 or 3")

def rotate_matrix_2d(angle: float) -> np.ndarray:
    return np.array([[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]])

def rotate_matrix_3d(angle: Tuple[float, float, float]) -> np.ndarray:
    rotate_matrix_x = np.array(
        [
            [1, 0, 0],
            [0, np.cos(angle[0]), -np.sin(angle[0])],
            [0, np.sin(angle[0]), np.cos(angle[0])],
        ]
    )
    rotate_matrix_y = np.array(
        [
            [np.cos(angle[1]), 0, np.sin(angle[1])],
            [0, 1, 0],
            [-np.sin(angle[1]), 0, np.cos(angle[1])],
        ]
    )
    rotate_matrix_z = np.array(
        [
            [np.cos(angle[2]), -np.sin(angle[2]), 0],
            [np.sin(angle[2]), np.cos(angle[2]), 0],
            [0, 0, 1],
        ]
    )
    return rotate_matrix_x @ rotate_matrix_y @ rotate_matrix_z


import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import style

style.use('ggplot')

W=tf.Variable(np.random.randn(),)
b=tf.Variable(np.random.randn(),)
x=tf.placeholder(tf.float32)
linear_model=W*x+b

init=tf.global_variables_initializer()

sess=tf.Session()
sess.run(init)
#sess.run(linear_model,{x:[1,2,3,4]}))

y=tf.placeholder(tf.float32)
sq_deltas=tf.square(linear_model-y)
loss=tf.reduce_sum(sq_deltas)

optimizer=tf.train.GradientDescentOptimizer(0.01)
train=optimizer.minimize(loss)

x_train=np.asarray([3.3,4.4,5.5,6.71,6.93,4.168,9.779,6.182,7.59,2.167,
7.042,10.791,5.313,7.997,5.654,9.27,3.1])
y_train=np.asarray([1.7,2.76,2.09,3.19,1.694,1.573,3.366,2.596,2.53,1.221,
2.827,3.465,1.65,2.904,2.42,2.94,1.3])

sess.run(init)

for i in range(1000):
    for (X, Y) in zip(x_train, y_train):
        sess.run(train, feed_dict={x: X, y: Y})

print(sess.run([W, b, loss], {x:x_train,y:y_train}))

plt.plot(x_train,y_train,'ro',label='Original data')
plt.plot(x_train,sess.run(W) * x_train + sess.run(b),label='Fitted Line')
plt.legend()
plt.show()


# Plots various neural net activation functions.

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

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

def relu(z):
    return np.maximum(0, z)

def heaviside(z):
    return (z > 0)

def softplus(z):
    return np.log(1+np.exp(z))

def lrelu(z, lam=0.1):
    return np.maximum(lam*z, z)

def elu(z, alpha=1):
    return np.where(z < 0, alpha * (np.exp(z) - 1), z)

def elu2(z, lam=0.5):
    return np.maximum(0, z) + np.minimum(0, lam*(np.exp(z) - 1))

def swish(z):
    return z * sigmoid(z)

from scipy.special import erfc

# alpha and scale to self normalize with mean 0 and standard deviation 1
# (see equation 14 in the SELU paper):
alpha_0_1 = -np.sqrt(2 / np.pi) / (erfc(1/np.sqrt(2)) * np.exp(1/2) - 1)
scale_0_1 = (1 - erfc(1 / np.sqrt(2)) * np.sqrt(np.e)) * np.sqrt(2 * np.pi) * (2 * erfc(np.sqrt(2))*np.e**2 + np.pi*erfc(1/np.sqrt(2))**2*np.e - 2*(2+np.pi)*erfc(1/np.sqrt(2))*np.sqrt(np.e)+np.pi+2)**(-1/2)

def selu(z, scale=scale_0_1, alpha=alpha_0_1):
    return scale * elu(z, alpha)

z = np.linspace(-5, 5, 200)

#plt.figure(figsize=(11,4))
plt.figure()
plt.plot(z, sigmoid(z), "b-", linewidth=2, label="Sigmoid")
plt.plot(z, np.tanh(z), "g--", linewidth=2, label="Tanh")
plt.plot(z, relu(z), "m-.", linewidth=2, label="ReLU")
plt.grid(True)
plt.legend(loc="lower right", fontsize=14)
plt.title("Activation functions", fontsize=14)
plt.axis([-5, 5, -1.2, 1.2])
pml.savefig('activationFuns.pdf')
plt.show()

#plt.figure(figsize=(11,4))
plt.figure()
plt.plot(z, relu(z), "r-", linewidth=2, label="ReLU")
plt.plot(z, lrelu(z), "g--", linewidth=2, label="LReLU")
plt.plot(z, elu(z), "b-", linewidth=2, label="ELU")
plt.plot(z, selu(z), "k:", linewidth=2, label="SELU")
plt.plot(z, swish(z), "m-.", linewidth=2, label="swish")
plt.grid(True)
plt.legend(loc="upper left", fontsize=14)
plt.title("Activation functions", fontsize=14)
plt.axis([-2, 2, -1.2, 2])
pml.savefig('activationFuns2.pdf')
plt.show()

# From https://github.com/ageron/handson-ml2/blob/master/11_training_deep_neural_networks.ipynb
plt.figure()
z = np.linspace(-5, 5, 200)
plt.plot([-5, 5], [0, 0], 'k-')
plt.plot([-5, 5], [1, 1], 'k--')
plt.plot([0, 0], [-0.2, 1.2], 'k-')
plt.plot([-5, 5], [-3/4, 7/4], 'g--')
plt.plot(z, sigmoid(z), "b-", linewidth=2)
props = dict(facecolor='black', shrink=0.1)
plt.annotate('Saturating', xytext=(3.5, 0.7), xy=(5, 1), arrowprops=props, fontsize=14, ha="center")
plt.annotate('Saturating', xytext=(-3.5, 0.3), xy=(-5, 0), arrowprops=props, fontsize=14, ha="center")
plt.annotate('Linear', xytext=(2, 0.2), xy=(0, 0.5), arrowprops=props, fontsize=14, ha="center")
plt.grid(True)
plt.title("Sigmoid activation function", fontsize=14)
plt.axis([-5, 5, -0.2, 1.2])
pml.savefig("sigmoid_saturation_plot.pdf")
plt.show()


import numpy as np

def correlated_timeseries_example(N=10000, tau=5.0, seed=None):
    """Generate synthetic timeseries data with known correlation time.

    Parameters
    ----------
    N : int, optional
        length (in number of samples) of timeseries to generate
    tau : float, optional
        correlation time (in number of samples) for timeseries
    seed : int, optional
        If not None, specify the numpy random number seed.

    Returns
    -------
    dih : np.ndarray, shape=(num_dihedrals), dtype=float
        dih[i,j] gives the dihedral angle at traj[i] correponding to indices[j].

    Notes
    -----

    Synthetic timeseries generated using bivariate Gaussian process described
    by Janke (Eq. 41 of Ref. [1]).

    As noted in Eq. 45-46 of Ref. [1], the true integrated autocorrelation time will be given by
    tau_int = (1/2) coth(1 / 2 tau) = (1/2) (1+rho)/(1-rho)
    which, for tau >> 1, is approximated by
    tau_int = tau + 1/(12 tau) + O(1/tau^3)
    So for tau >> 1, tau_int is approximately the given exponential tau.

    References
    ----------
    .. [1] Janke W. Statistical analysis of simulations: Data correlations and error estimation.  In 'Quantum Simulations of Complex Many-Body Systems: From Theory to Algorithms'. NIC Series, VOl. 10, pages 423-445, 2002.

    Examples
    --------

    Generate a timeseries of length 10000 with correlation time of 10.

    >>> A_t = correlated_timeseries_example(N=10000, tau=10.0)

    Generate an uncorrelated timeseries of length 1000.

    >>> A_t = correlated_timeseries_example(N=1000, tau=1.0)

    Generate a correlated timeseries with correlation time longer than the length.

    >>> A_t = correlated_timeseries_example(N=1000, tau=2000.0)

    """

    # Set random number generator into a known state for reproducibility.
    random = np.random.RandomState(seed)

    # Compute correlation coefficient rho, 0 <= rho < 1.
    rho = np.exp(-1.0 / tau)
    sigma = np.sqrt(1.0 - rho * rho)

    # Generate uncorrelated Gaussian variates.
    e_n = random.randn(N)

    # Generate correlated signal from uncorrelated Gaussian variates using correlation coefficient.
    # NOTE: This will be slow.
    # TODO: Can we speed this up using vector operations?
    A_n = np.zeros([N], np.float32)
    A_n[0] = e_n[0]
    for n in range(1, N):
        A_n[n] = rho * A_n[n - 1] + sigma * e_n[n]

    return A_n


"""
Example to solve Kinematics of 2DoF Scara Arm.
"""
# Funções das Bibliotecas Utilizadas
from sympy import symbols, trigsimp, pprint
from sympy.physics.mechanics import dynamicsymbols
from sympy.physics.vector import ReferenceFrame, Vector
from sympy.physics.vector import time_derivative

# Variáveis Simbólicas
THETA_1, THETA_2 = dynamicsymbols('theta_1 theta_2')
L_1, L_2 = symbols('l_1 l_2', positive=True)

# Referenciais
# Referencial Parado
B0 = ReferenceFrame('B0')
B1 = ReferenceFrame('B1')
# Referencial móvel: theta_1 em relação a B0.z
B1.orient(B0, 'Axis', [THETA_1, B0.z])
B2 = ReferenceFrame('B2')
# Referencial móvel: theta_2 em relação a B1.z
B2.orient(B1, 'Axis', [THETA_2, B1.z])

# Vetores Posição entre os Pontos
# Vetor Nulo
B0_R_OA = Vector(0)
# Vetor que liga os pontos A e B expresso no referencial móvel B1
B1_R_AB = L_1 * B1.x
# Vetor que liga os pontos B e C expresso no referencial móvel B2
B2_R_BC = L_2 * B2.x

# Cinemática do ponto A em relação ao referencial B0
R_A = B0_R_OA
V_A = time_derivative(R_A, B0)
A_A = time_derivative(V_A, B0)

# Cinemática do ponto B em relação ao referencial B0
R_B = R_A + B1_R_AB.express(B0)
V_B = time_derivative(R_B, B0)
A_B = time_derivative(V_B, B0)

# Cinemática do ponto C em relação ao referencial B0
R_C = R_B.express(B0) + B2_R_BC.express(B0)
V_C = (time_derivative(R_C, B0))
A_C = (time_derivative(V_C, B0))

# Simplificação dos Resultados
R_A = (R_A.to_matrix(B0)).applyfunc(trigsimp)
V_A = (V_A.to_matrix(B0)).applyfunc(trigsimp)
A_A = (A_A.to_matrix(B0)).applyfunc(trigsimp)
R_B = (R_B.to_matrix(B0)).applyfunc(trigsimp)
V_B = (V_B.to_matrix(B0)).applyfunc(trigsimp)
A_B = (A_B.to_matrix(B0)).applyfunc(trigsimp)
R_C = (R_C.to_matrix(B0)).applyfunc(trigsimp)
V_C = (V_C.to_matrix(B0)).applyfunc(trigsimp)
A_C = (A_C.to_matrix(B0)).applyfunc(trigsimp)

# Resultados de C
pprint(R_C)
pprint(V_C)
pprint(A_C)


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

# Práctica 1, Ejercicio 1
# David Cabezas Berrido

import numpy as np
import sympy as sp
import matplotlib.pyplot as plt

#-------------------------------------------------------------------------------#
#------------- Ejercicio sobre la búsqueda iterativa de óptimos ---------------#
#-------------------------------------------------------------------------------#

#------------------------------Ejercicio 1 ------------------------------------#

u, v = sp.symbols('u v')

# Función a minimizar
E_sym=sp.Lambda((u,v), sp.simplify((u*sp.exp(v)-2*v*sp.exp(-u))**2))
def E(w):
    return sp.N(E_sym(w[0],w[1]))

# Derivada parcial de E respecto de u
Eu_sym=sp.Lambda((u,v), sp.simplify(sp.diff(E_sym(u,v),u)))
def Eu(w):
	return sp.N(Eu_sym(w[0],w[1]))

# Derivada parcial de E respecto de v
Ev_sym=sp.Lambda((u,v), sp.simplify(sp.diff(E_sym(u,v),v)))
def Ev(w):
	return sp.N(Ev_sym(w[0],w[1]))

# Gradiente de E
def gradE(w):
	return np.array((Eu(w), Ev(w)),np.float64)

# Algoritmo del gradiente descendente
def gd(w, lr, grad_fun, fun, epsilon, max_iters = 1000):

	it = 0

	while it < max_iters and fun(w)>epsilon:
		it+=1
		grad=grad_fun(w) # Calcula gradiente
		w=w-lr*grad      # Actualiza el punto
		# print(w, fun(w))

	return w, it

# Punto inicial
w=np.array([1,1],np.float64)
# Número máximo de iteraciones
max_iters=100
# Learning rate
lr=0.1
# Margen de error
epsilon=10**(-14)

w, num_ite = gd(w,lr,gradE,E,epsilon,max_iters)

print ('\nGRADIENTE DESCENDENTE')
print ('\nEjercicio 1\n')
print ('Numero de iteraciones: ', num_ite)
input("\n--- Pulsar Intro para continuar ---\n")
print ('Coordenadas obtenidas: (', w[0], ', ', w[1],')')

input("\n--- Pulsar Intro para continuar ---\n")

#----------------------------- Ejercicio 2 --------------------------------#

x, y = sp.symbols('x y')

# Función a minimizar
f_sym=sp.Lambda((x,y), sp.simplify((x-2)**2+2*(y+2)**2+2*sp.sin(2*sp.pi*x)*sp.sin(2*sp.pi*y)))
def f(w):
	return float(f_sym(w[0],w[1]))

# Derivada parcial de f respecto de x
fx_sym=sp.Lambda((x,y), sp.simplify(sp.diff(f_sym(x,y),x)))
def fx(w):
	return float(fx_sym(w[0],w[1]))

# Derivada parcial de f respecto de y
fy_sym=sp.Lambda((x,y), sp.simplify(sp.diff(f_sym(x,y),y)))
def fy(w):
	return float(fy_sym(w[0],w[1]))

# Gradiente de f
def gradf(w):
	return np.array((fx(w), fy(w)),np.float64)

# a) Usar gradiente descendente para minimizar la función f, con punto inicial (1,-1)
# tasa de aprendizaje 0.01 y max 50 iteraciones. Repetir con tasa de aprend. 0.1

def gd_grafica(w, lr, grad_fun, fun, max_iters = 1000):

	graf = []
	graf.append(fun(w))

	for _ in range(max_iters):
		grad=grad_fun(w)
		w=w-lr*grad
		graf.append(fun(w))
		#print(w, fun(w))

	graf = np.array(graf,np.float64)

	plt.plot(range(0,max_iters+1), graf, 'bo')
	plt.xlabel('Iteraciones')
	plt.ylabel('f(x,y)')
	plt.show()

# Punto inicial
w=np.array([1,-1],np.float64)
# Número máximo de iteraciones
max_iters=50

print ('Resultados ejercicio 2\n')
print ('\nGrafica con learning rate igual a 0.01')
lr=0.01 # Learning rate
gd_grafica(w,lr,gradf,f,max_iters)
print ('\nGrafica con learning rate igual a 0.1')
lr=0.1 # Learning rate
gd_grafica(w,lr,gradf,f,max_iters)
input("\n--- Pulsar tecla para continuar ---\n")

# b) Obtener el valor minimo y los valores de (x,y) con los
# puntos de inicio siguientes:

def gd(w, lr, grad_fun, fun, max_iters = 1000):

	for _ in range(max_iters):
		grad=grad_fun(w)
		w=w-lr*grad
		#print(w, fun(w))

	return w

lr=0.01 # Learning rate (no se especifica)
# Número máximo de iteraciones (tampoco se especifica)
max_iters=50

print ('Punto de inicio: (2.1, -2.1)\n')
w=gd(np.array((2.1,-2.1),np.float64),lr,gradf,f,max_iters)
print ('(x,y) = (', w[0], ', ', w[1],')\n')
print ('Valor minimo: ',f(w))

input("\n--- Pulsar tecla para continuar ---\n")

print ('Punto de inicio: (3.0, -3.0)\n')
w=gd(np.array((3.0,-3.0),np.float64),lr,gradf,f,max_iters)
print ('(x,y) = (', w[0], ', ', w[1],')\n')
print ('Valor minimo: ',f(w))

input("\n--- Pulsar tecla para continuar ---\n")

print ('Punto de inicio: (1.5, 1.5)\n')
w=gd(np.array((1.5,1.5),np.float64),lr,gradf,f,max_iters)
print ('(x,y) = (', w[0], ', ', w[1],')\n')
print ('Valor minimo: ',f(w))

input("\n--- Pulsar tecla para continuar ---\n")

print ('Punto de inicio: (1.0, -1.0)\n')
w=gd(np.array((1.0,-1.0),np.float64),lr,gradf,f,max_iters)
print ('(x,y) = (', w[0], ', ', w[1],')\n')
print ('Valor mínimo: ',f(w))

input("\n--- Pulsar tecla para salir ---\n")


# -*- coding: utf-8 -*-
"""
@author: Ozgur Kara
"""
import numpy as np

PI = np.pi

def sph2cart(az, el, r):
    """converting spherical coordinates to cartesian coordinates"""
    rsin_theta = r * np.sin(el)
    y = rsin_theta * np.sin(az)
    x = rsin_theta * np.cos(az)
    z = r * np.cos(el)
    return x, y, z

def between(value, a, b):
    """find and returns the substring which is between the characters of a and b"""
    pos_a = value.find(a)
    if pos_a == -1:
        return ""
    pos_b = value.rfind(b)
    if pos_b == -1:
        return ""
    adjusted_pos_a = pos_a + len(a)
    if adjusted_pos_a >= pos_b:
        return ""
    return value[adjusted_pos_a:pos_b]

def az_el_pair(az_num, el_num):
    azimuth = np.linspace(-PI, PI, az_num + 1)
    elevation = np.linspace(0,PI, el_num + 1)
    return azimuth, elevation


import numpy as np
import matplotlib.pyplot as plt

# Initializing important parametres
a = 0.5
b, r = 0.1, 0.1

f = lambda v: v*(a-v)*(v-1)
dvdt = lambda v, w, I: f(v)-w+I
dwdt = lambda v, w: b*v-r*w

def euler_integrate(v, w, dt, I, ttot):
	niter = int(ttot/dt)
	vhist = []
	whist = []
	for i in range(niter):
		v, w = (v + dvdt(v, w, I)*dt), (w + dwdt(v, w)*dt)
		vhist.append(v)
		whist.append(w)

	return vhist, whist

def nullclines(I, v):
	vnc = f(v) + I
	wnc = b*v/r
	return vnc, wnc

def plot_fig(y, title="", ylim=(), x=None, xlim=()):
	plt.figure()
	plt.title(title)
	color = ["b", "r"]
	if not x:
		for i in y:
			plt.plot(i)
	else:
		for i,j in enumerate(y):
			plt.plot(x, j, color=color[i])
	if ylim: plt.ylim(ylim)
	if xlim: plt.xlim(xlim)
	plt.xlabel("Time")
	plt.ylabel("Voltage")
	plt.legend(["V(t)", "W(t)"])
	plt.grid()
	plt.show()

def plot_nullclines(I, xlim, ylim, positions):
	color = ['palegreen', 'gold', 'tomato', 'deepskyblue', 'lightsteelblue']*3
	v = np.linspace(xlim[0], xlim[1], 100)
	w = np.linspace(xlim[0], xlim[1], 100)

	v_mesh, w_mesh = np.meshgrid(v, w)
	v_vel = dvdt(v_mesh, w_mesh, I)
	w_vel = dwdt(v_mesh, w_mesh)

	vnc, wnc = nullclines(I, v)

	plt.figure()
	plt.plot(v, vnc, 'b')
	plt.plot(v, wnc, 'r')
	plt.legend(['v nullcline', 'w nullcline'])
	plt.ylim(ylim[0], ylim[1])
	title = "Phase Plot for I=" + str(round(I, 2))
	plt.title(title)
	plt.xlabel('v-values')
	plt.ylabel('w-vaues')

	if positions:
		for i in range(len(positions)):
			plt.streamplot(v_mesh, w_mesh, v_vel, w_vel, density=2, start_points=[positions[i]], color=color[i], integration_direction="forward", arrowsize=2)
	else:
		plt.streamplot(v_mesh, w_mesh, v_vel, w_vel, color=color[0])
	plt.grid()
	plt.show()

#####################################################
# Case 1: I_ext = 0
dt = 0.1
ttot = 100
I = 0

# Nullclines
plot_nullclines(I, (-0.5,1.5), (-0.45,0.45), [])
plot_nullclines(I, (-0.5,1.5), (-0.45,0.45), [[0,0], [0.4,0], [0.6, 0], [1, 0]])

# Subcase 1: V(0) < a and W(0) = 0
x = list(np.linspace(0,100,1000))
vhist, whist = euler_integrate(0.4, 0, dt, I, ttot)
plot_fig([vhist, whist], "I=0, Subcase 1: V(0) < a and W(0) = 0", (-0.2,0.75), x)

# Subcase 2: V(0) > a and W(0) = 0
vhist, whist = euler_integrate(0.6, 0, 0.1, I, 100)
plot_fig([vhist, whist], "I=0, Subcase 2: V(0) > a and W(0) = 0", (-0.2,0.75), x)

#####################################################
# Case 2: I_ext = 0.6
dt = 0.1
ttot = 100
I = 0.6

# Nullclines
plot_nullclines(I, (-0.5,1.5), (0.15,0.95), [])
plot_nullclines(I, (-0.5,1.5), (0.15,0.95), [[0,0], [0.4,0], [0.6, 0], [1, 0]])

# Subcase 1: V(0) < a and W(0) = 0
x = list(np.linspace(0,100,1000))
vhist, whist = euler_integrate(0.4, 0, dt, I, ttot)
plot_fig([vhist, whist], "I=0.6, Subcase 1: V(0) < a and W(0) = 0", (-0.2,1.5), x)

# Subcase 2: V(0) > a and W(0) = 0
vhist, whist = euler_integrate(0.6, 0, 0.1, I, 100)
plot_fig([vhist, whist], "I=0.6, Subcase 2: V(0) > a and W(0) = 0", (-0.2,1.5), x)

#####################################################
# Case 3: I_ext = 1
dt = 0.1
ttot = 100
I = 1

# Nullclines
plot_nullclines(I, (-0.5,1.5), (0.55,1.45), [])
plot_nullclines(I, (-0.5,1.5), (0.55,1.45), [[0,0.6], [0.4,0.6], [0.6, 0.6], [1, 0.6], [0,1.4], [0.4,1.4], [0.6, 1.4], [1, 1.4]])

# Subcase 1: V(0) < a and W(0) = 0
x = list(np.linspace(0,100,1000))
vhist, whist = euler_integrate(0.4, 0, dt, I, ttot)
plot_fig([vhist, whist], "I=1, Subcase 1: V(0) < a and W(0) = 0", (-0.2,2), x)

# Subcase 2: V(0) > a and W(0) = 0
vhist, whist = euler_integrate(0.6, 0, 0.1, I, 100)
plot_fig([vhist, whist], "I=1, Subcase 2: V(0) > a and W(0) = 0", (-0.2,2), x)

#####################################################
# Case 4: I_ext = 0.02
dt = 0.1
ttot = 100
I = 0.02

# Choosing parameters
b, r = 0.01, 0.8

# Nullclines
plot_nullclines(I, (-0.5,1.5), (-0.45,0.45), [])
plot_nullclines(I, (-0.5,1.5), (-0.45,0.45), [[0,0.4], [0.1,0.4], [-0.1,0.4], [0,-0.4], [0.4,0.4], [0.6, 0.4], [1, 0.4], [0.1,-0.4], [-0.1,-0.4], [0.4,-0.4], [0.6, -0.4], [1, -0.4]])

# Subcase 1: V(0) < a and W(0) = 0
x = list(np.linspace(0,100,1000))
vhist, whist = euler_integrate(0.4, 0, dt, I, ttot)
plot_fig([vhist, whist], "I=0.02, Subcase 1: V(0) < a and W(0) = 0", (-0.2,2), x)

# Subcase 2: V(0) > a and W(0) = 0
vhist, whist = euler_integrate(0.6, 0, 0.1, I, 100)
plot_fig([vhist, whist], "I=0.02, Subcase 2: V(0) > a and W(0) = 0", (-0.2,2), x)


import numpy as np
from numpy import log, dot, e

class LogisticRegression:
    def __init__(self, lr=0.05, epochs=100, intercept=True):
        self.lr = lr
        self.epochs = epochs
        self.intercept = intercept
        self.bias = 0

    def addIntercept(self, X):
        intercept = np.ones((X.shape[0], 1))
        return np.concatenate((intercept, X), axis=1)

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

    def cost(self, h, y):
        return (-y * np.log(h) - (1 - y) * np.log(1 - h)).mean()

    def fit(self, X, y):
        if self.intercept:
            X = self.addIntercept(X)

        self.loss = []

        # weights initialization
        self.weight = np.zeros(X.shape[1])

        for i in range(self.epochs):
            z = np.dot(X, self.weight)
            h = self.sigmoid(z + self.bias)

            gradient = np.dot(X.T, (h - y)) / y.size
            bGradient = np.sum(h - y) / y.size

            self.weight -= self.lr * gradient
            self.bias -= self.lr * bGradient

            self.loss.append(self.cost(h, y))

    def predict_prob(self, X):
        if self.intercept:
            X = self.addIntercept(X)

        return self.sigmoid(np.dot(X, self.weight) + self.bias)

    def predict(self, X):
        return self.predict_prob(X) >= 0.5


from sympy.core.numbers import E
from sympy.core.symbol import symbols
from sympy.functions.elementary.exponential import log
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.geometry.curve import Curve
from sympy.integrals.integrals import line_integrate

s, t, x, y, z = symbols('s,t,x,y,z')

def test_lineintegral():
    c = Curve([E**t + 1, E**t - 1], (t, 0, log(2)))
    assert line_integrate(x + y, c, [x, y]) == 3*sqrt(2)


"""
  Name     : c10_03_exchange_futures.py
  Book     : Python for Finance (2nd ed.)
  Publisher: Packt Publishing Ltd.
  Author   : Yuxing Yan
  Date     : 6/6/2017
  email    : yany@canisius.edu
             paulyxy@hotmail.com
"""

import scipy as sp
def futuresExchangeRate(s0,rateDomestic,rateForeign,T):
    futureEx=s0*sp.exp((rateDomestic-rateForeign)*T)
    return futureEx

s0=1.25
rHome=0.01
rForeigh=0.02
T=3./12.
futures=futuresExchangeRate(s0,rHome,rForeigh,T)
print("futures=",futures)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Aug 23 20:14:35 2019

@author: amandaash
"""
import numpy as np
import matplotlib.pyplot as plt

x_val = np.arange(-10,10,0.1)

#x_val = [0.2]
summation = 0
relative_errors = []

approx_y = []
actual_y = []

for x in x_val:
    print('x = ',x)
    print("sin(x) = ", np.sin(x))
    actual_y.append(np.sin(x))
    initial_fact = 1.0
    N = 5
    #if x == 0.0:
        #continue

    summation = 0.0

    fact_array = np.arange(0,N+1,1)

    for n in fact_array:

        value = ((2*n) + 1)
        fact = (value)*initial_fact
        initial_fact = fact

        denomenator = fact

        iteration = (((-1)**(n))*((x)**(value)))/denomenator

        summation = summation + iteration

        if np.abs(iteration/summation) <= (1e-8):
            print("iteration/summation = ", np.abs(iteration/summation))
            print('sin(x) approximation complete ', n)
            break

    print('sin(x) approx ', summation)

    abs_err = np.sin(x) - summation
    rel_err = abs_err/x
    relative_errors.append(rel_err)
    approx_y.append(summation)

plt.plot(x_val, relative_errors,  '.', lw=1)
plt.xlabel('x')
plt.ylabel('relative error')
plt.show()

plt.plot(x_val, actual_y, '.', lw = 1, label = 'f(x) = sin(x)')
plt.plot(x_val, approx_y, '.', lw = 1, label = 'sin(x) approximation')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()

plt.plot(x_val, actual_y, '.', lw = 1, label = 'f(x) = sin(x)')
plt.plot(x_val, approx_y, '.', lw = 1, label = 'sin(x) approximation')
plt.xlabel('x')
plt.ylabel('y')
plt.xlim(-10,10)
plt.ylim(-3,3)
plt.legend()
plt.show()


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Python version: 3.6

import numpy as np
import math

def getSequence():
    inSequence = np.array([])
    inSeqString = input("\nPlease enter the array (elements separated by space): ")
    seqSplited = inSeqString.split()
    for i in range(len(seqSplited)):
        inSequence = np.append(inSequence, float(seqSplited[i]))
    return inSequence

def dft(seq):
    l = len(seq)
    out = np.zeros(l, dtype=complex)
    for i in range(l):
        for j in range(l):
            out[i] = out[i] + seq[j]*np.exp((-2j*math.pi*j*i)/l)
    return out

def ditfft(seq):
    l = len(seq)
    half_l = l // 2
    out = np.zeros(l, dtype=complex)

    if l == 1:
        out[0] = seq[0]
    else:
        seq_even = seq[0::2] #get all even indexed elements
        seq_odd = seq[1::2]  #get all odd indexed elements
        out_even = ditfft(seq_even)
        out_odd = ditfft(seq_odd)
        for m in range(l):
            out[m] = out_even[m % half_l] + out_odd[m % half_l] * np.exp(-1j*2*math.pi*m/l)
    return out

def diffft(seq):
    l = len(seq)
    half_l = l // 2
    out = np.zeros(l, dtype=complex)
    out1 = np.zeros(half_l, dtype=complex)
    out2 = np.zeros(half_l, dtype=complex)
    seq1 = np.zeros(half_l, dtype=complex)
    seq2 = np.zeros(half_l, dtype=complex)
    if l == 1:
        out[0] = seq[0]
    else:
        seq_hi = seq[0:half_l:1] #get 1st half of input array
        seq_lo = seq[half_l:l:1]  #get 2nd half of input array
        for m in range(half_l):
            seq1[m] = seq_hi[m] + seq_lo[m]
            seq2[m] = (seq_hi[m] - seq_lo[m]) * np.exp(-1j*2*math.pi*m/l)

        out1 = diffft(seq1)
        out2 = diffft(seq2)
        out = np.concatenate([out1,out2])
    return out

def reArrange(seq):
    l = len(seq)
    n = np.int(np.log2(l))
    out = np.zeros(l, dtype=complex)
    for i in range(l):
        bin_i = bin(i)
        b_i = str(bin_i)[2::]
        b = ''.join(['0'*(n-len(b_i)),b_i])
        k = 0
        for element in range(len(b)):
            if b[element] == '1':
                k = k + (2**element)
        out[k] = seq[i]
    return out

def viewable(seq):
    for i in range(len(seq)):
        if abs(seq[i].real) < 10**(-10):
            seq[i] = 0 + 1j*seq[i].imag
        if abs(seq[i].imag) < 10**(-10):
            seq[i] = seq[i].real
    return seq

def dct(seq):
    l = len(seq)
    out = np.zeros(l)
    for i in range(l):
        for j in range(l):
            out[i] = out[i] + 2*seq[j]*np.cos((math.pi*i*((2*j)+1))/(2*l))
    return out

def viewable_r(seq):
    for i in range(len(seq)):
        if abs(seq[i]) < 10**(-10):
            seq[i] = 0
    return seq

def dst(seq):
    l = len(seq)
    out = np.zeros(l)
    for i in range(l):
        for j in range(l):
            out[i] = out[i] + seq[j]*np.sin((math.pi*(i+1)*((2*j)+1))/(2*l))
    return out

def wht(seq):
    raise NotImplementedError()

def slant(seq):
    raise NotImplementedError()

def haar(seq):
    raise NotImplementedError()

def klt(seq):
    raise NotImplementedError()


from typing import Tuple, cast, Optional, List

import numpy as np

def z_normalization(data: np.ndarray) -> np.ndarray:
    std = data.std()
    if std == 0:
        return data

    result = data.copy()
    mean = result.mean()
    return (result - mean) / std

def calculate_mean(data: np.ndarray) -> float:
    return sum(data) / len(data)

def calculate_covariance_matrix(data: np.ndarray) -> Tuple[float, np.ndarray]:
    data_mean = data.mean()

    cov_matrix = 0.
    for vec in data:
        cov_matrix += np.dot((vec - data_mean).reshape(len(vec), 1), (vec - data_mean).reshape(1, len(vec)))
    cov_matrix /= len(data)

    return data_mean, cov_matrix

def mahalanobis_distance(x: np.ndarray, mean: float, cov_matrix: np.ndarray) -> float:
    distance = np.dot(x - mean, np.linalg.inv(cov_matrix))
    distance = np.dot(distance, (x - mean).T)
    return cast(float, distance)

def squared_error(predictions: np.ndarray, targets: np.ndarray) -> np.ndarray:
    return np.sqrt((predictions - targets) ** 2)

def ewma(data: np.ndarray, window: int, alpha: Optional[float] = None) -> np.ndarray:
    """Exponential weighted moving average"""
    alpha = alpha or (2. / (window + 1))
    t_ = window - 1
    ema = np.zeros_like(data, dtype=float)

    for i in range(len(data)):
        # Special Case
        if i > t_:
            ema[i] = (data[i] - ema[i - 1]) * alpha + ema[i - 1]
        else:
            ema[i] = np.mean(data[:i + 1])
    return ema

def find_anomaly_points(data: np.ndarray, offset: int = 500, threshold: float = None) -> List[int]:
    assert offset >= 1

    threshold = threshold or (data.mean() + data.std() * 3)
    anomaly_points = []

    i = 0
    while i <= len(data) - 1:
        if data[i] >= threshold:
            anomaly_points.append(i)
            i += offset
        else:
            i += 1

    return anomaly_points

def find_anomaly_points_by_median(data: np.array, offset: int = 500, threshold: int = 10) -> List[int]:
    """https://stackoverflow.com/a/45399188"""
    assert offset >= 1

    distances = np.abs(data - np.median(data))
    mdev = np.median(distances)

    anomaly_points = []

    i = 0
    while i <= len(data) - 1:
        if (distances[i] / (mdev or 1.)) >= threshold:
            anomaly_points.append(i)
            i += offset
        else:
            i += 1

    return anomaly_points


# -*- coding: utf-8 -*-
"""
Created on Tue Nov 24 09:38:13 2020

@author: RPP
"""

import numpy as np
import matplotlib.pyplot as plt

def gradientDescent(lr, maxEp):
    plt.close()
    plt.clf()
    minx = -5
    maxx = 5
    plotError(minx, maxx)

    #start GD in the min-max range
    nEp = 0
    x = np.random.rand() * (maxx-minx) + minx
    E = error(x)
    print("Erro 0: %f\t x0: %f" % (E, x))
    plt.plot(x, E, 'bo')
    plt.pause(1)

    #iterate GD
    while abs(E) > 10**(-5) and nEp < maxEp:
        xAnt = x
        Eant = E
        dx = -lr * dE_dx(x)
        x += dx
        E = error(x)
        nEp += 1
        print("nEp: %d - Erro: %f\t x: %f" % (nEp, E, x))

        plt.plot(xAnt, Eant, 'bo', x, E, 'ro')
        plt.plot([xAnt, x], [Eant, E], 'b')
        plt.draw()
        #wait = input("Press Enter to continue.")
        plt.pause(1)

def plotError(minx, maxx):
    step = 0.01
    x = np.arange(minx, maxx+step, step)
    E = error(x)
    plt.plot(x, E)

def error(x):
    return x ** 2

def dE_dx(x):
    return 2*x

if __name__ == "__main__":
    #gradientDescent(0.1, 20)
    #gradientDescent(1.5, 20)
    gradientDescent(0.3, 20)
    #gradientDescent(1, 20)
    #gradientDescent(0.5, 20)


'''
Nicholas Geneva
ngeneva@nd.edu
November 3, 2017
'''
import sys
import random
import numpy as np
import scipy as sc
import matplotlib as mlp
import matplotlib.pyplot as plt

from matplotlib import rc
from scipy import special
from scipy import stats

def markovChainWeight(x0, b0 = -1, b1 = 1, tk = 'uniform'):
    '''
    Completes a Markov chain for SIS MC integrals.
    See Ref: https://doi.org/10.1016/j.amc.2010.03.138
    Args:
        x0 (float) = point of interest
        b0 (float) = Lower bound of integral
        b1 (float) = Upper bound of integral
        tk (string) = Transition kernel type (uniform, guassian)
    Returns:
        w (float) = calculated weight
    '''
    k = 1
    #Construct markov chain
    if(tk == 'uniform'):
        while(True):
            #Transition kernal to next location
            x1 = np.random.uniform(b0-0.5,b1+0.5)
            pd = 1.0 - (b1-b0)/(b1-b0+1.0) #Probability of killing the chain
            p = 1.0/(b1-b0+1) #General probability

            if(x1 > b1 or x1 < b0): #Kill markov chain
                break
            k = k * 0.5*(x1 - x0)/p
            x0 = x1

    elif(tk == 'guassian'):
        mu = 0
        sigma = 0.75
        #Probability of killing the chain
        pd = 1.0 - (sc.stats.norm.cdf(b1, mu, sigma) - sc.stats.norm.cdf(b0, mu, sigma))
        while(True):
            #Transition to
            x1 = np.random.normal(mu,sigma)
            p =  sc.stats.norm.pdf(x1, mu, sigma)
            if(x1 > b1 or x1 < b0): #Kill markov chain
                break

            k = k * 0.5*(x1 - x0)/p
            x0 = x1
    else:
        print('Transition Kernel not supported')

    return k * x0/pd

if __name__ == '__main__':
    plt.close('all')
    mlp.rcParams['font.family'] = ['times new roman'] # default is sans-serif
    rc('text', usetex=True)

    N = 10000
    y = [0]
    for i in range(N):
        y.append(y[-1] + markovChainWeight(0,b0 = -1,b1 = 1,tk = 'guassian'))
    yNorm = [y0 / float(i+1) for i, y0 in enumerate(y)]

    print('Guassian Estimate: %0.5f' %(y[-1]/float(N)))

    y = [0]
    for i in range(N):
        y.append(y[-1] + markovChainWeight(0,b0 = -1,b1 = 1,tk = 'uniform'))
    yNorm = [y0 / float(i+1) for i, y0 in enumerate(y)]

    print('Uniform Estimate: %0.5f' % (y[-1]/float(N)))


"""
Objetivo: Resolver questão 2b do terceiro laboratorio.
    é exatamente o mesmo codigo da questão anterior porém mudando a função a ser passada e o palpite
"""
import matplotlib.pyplot as plt
import numpy as np
from Newton_Raphson import newton_raphson

y = lambda x: 2*x**3 - 7*x**2 + x  # f(x) = 2x^3 - 7x^2 + x
y_linha = lambda x: 6*x**2 - 14*x + 1  # f'(x) = 6x^2 - 14x + 1
ini = -1  # ponto inicial, escolhido arbitariamente
#Verificar o arquivo Nexton-Raphson.py para entender o funcionamento dessa função
resp = newton_raphson(ini, y, y_linha, 'q2')
print(f'Para essa X0 = {ini} levamos {resp["iterações"] - 1} iterações e temos como valor de f(x) = {resp["modulo"]}')
print('Abaixo seguem os graficos dos valores de f(x) e dos erros, respectivamente:')

# Grafico com os valores de f(x)
x_a = np.linspace(-1.2, 1.2, 30)  # valores escolhidos para melhor visualização do grafico
y_a = [y(i) for i in x_a]
plt.style.use('ggplot')
plt.figure(figsize=(7, 5))
plt.title(f'F(x) por X\ncom X0 = {ini}')
plt.xlabel('Valores de x')
plt.ylabel('Valores de f(x)')
# função com valores entre 0.4 e 0.8
plt.plot(x_a, y_a, label='Função exata')
# Nossa aproximação Newton-Raphson por iteração
plt.plot(resp['valores'], resp['valores_função'], label='Valores de Newton-Raphson por iteração')
plt.tight_layout()
plt.legend(loc='best')
plt.show()

# Grafico com os valores dos erros
plt.style.use('ggplot')
plt.figure(figsize=(7, 5))
plt.title('Erro por Iterações')
plt.xlabel('Numero de iterações')
plt.ylabel('Valores dos erros')
plt.plot([i for i in range(1, resp['iterações'])], resp['erros'])
plt.tight_layout()
plt.show()


"""ODE Integration Functions

This library contains a suite of functions to generate simulations of
stochastic and deterministic disease progressions with and without noise due to
model error.

"""

import numpy as np
import math

def SIRode(y0, time, beta, gamma):
    """Integrate SIR epidemic model

    Simulate a very basic deterministic SIR system.

    :param 2x1 numpy array y0: initial conditions
    :param Ntimestep length numpy array time: Vector of time points that \
    solution is returned at
    :param float beta: transmission rate
    :param float gamma: recovery rate

    :returns: (2)x(Ntimestep) numpy array Xsim: first row S(t), second row I(t)

    """

    Xsim = rk4(SIR_D, y0, time, args=(beta,gamma,))
    Xsim = Xsim.transpose()
    return Xsim

# Derivative for basic SIR system.
def SIR_D(y,t,beta,gamma):
    # y[0] = susceptible
    # y[1] = infected
    dy = np.zeros((2,1))

    dy[0] = -(beta)*y[0]*y[1]
    dy[1] = (beta)*y[0]*y[1] - gamma*y[1]
    return dy

###############################################################################
# Simulate a modified deterministic SIR system with parameters built to
# have a power-law scaling for the contact rate as in,
# "Semi-empirical power-law scaling of new infection rate to model
#  epidemic dynamics with inhomogeneous mixing."
#  Mathematical Biosciences 203 (2006) 301-318
# beta = transmission rate
# gamma = recovery rate
# nu = contact rate power-law
# Returns numpy array:
#    Xsim = (2)x(Ntimestep) first row S(t), second row I(t).
def SIRmod1ode(y0, time, beta, gamma, nu):
    # y0 = 2x1 numpy array of initial conditions.
    # time = Ntimestep length numpy array
    # beta = scalar
    # gamma = scalar
    # nu = scalar

    Xsim = rk4(SIRmod1_D, y0, time, args=(beta,gamma,nu,))
    Xsim = Xsim.transpose()
    return Xsim

# Derivative for SIR system.
def SIRmod1_D(y,t,beta,gamma,nu):
    # y[0] = susceptible
    # y[1] = infected
    dy = np.zeros((2,1))

    dy[0] = -(beta)*y[1]*math.pow(y[0],nu)
    dy[1] = (beta)*y[1]*math.pow(y[0],nu) - gamma*y[1]
    return dy

###############################################################################
# Simulate a modified deterministic SIR system with parameters built to
# have a power-law scaling for the contact rate as in,
# "Semi-empirical power-law scaling of new infection rate to model
#  epidemic dynamics with inhomogeneous mixing."
#  Mathematical Biosciences 203 (2006) 301-318
# With this instance we also introduce a time varying transmission rate
# similar to that used in, "Modeling the spread of influenza among cities"
# by James M. Hyman and Tara LaForce 2003.
# beta = transmission rate
# gamma = recovery rate
# nu = contact rate power-law
# alpha = amplitude of transmission rate variation
#         beta varies over [1-alpha,1+alpha]
# c = time of peak transmission rate
# w = width of ramp up and ramp down of transmission

# Returns numpy array:
#    Xsim = (2)x(Ntimestep) first row S(t), second row I(t).
def SIRmod2ode(y0, time, beta, gamma, nu, alpha, c, w):
    # y0 = 2x1 numpy array of initial conditions.
    # time = Ntimestep length numpy array
    # beta = scalar
    # mu = scalar
    # nu = scalar

    Xsim = rk4(SIRmod2_D, y0, time, args=(beta,gamma,nu,alpha,c,w,))
    Xsim = Xsim.transpose()
    return Xsim

# Derivative for SIR system.
def SIRmod2_D(y,t,beta,gamma,nu,alpha,c,w):
    # y[0] = susceptible
    # y[1] = infected
    # t = scalar time point
    dy = np.zeros((2,1))

    dy[0] = -(trans_rate(t,beta,alpha,c,w))*y[1]*math.pow(y[0],nu)
    dy[1] = (trans_rate(t,beta,alpha,c,w))*y[1]*math.pow(y[0],nu) - gamma*y[1]
    return dy

###############################################################################
# Simulate a basic deterministic SEIR system with parameters
# beta = transmission rate
# mu = incubation rate
# gamma = recovery rate
# Returns numpy array:
#    Xsim = (3)x(Ntimestep) first row S(t), second row I(t),
#           third row E(t).
def SEIRode(y0, time, beta, mu, gamma):
    # y0 = 3x1 numpy array of initial conditions.
    # time = Ntimestep length numpy array
    # beta = scalar
    # mu = scalar
    # gamma = scalar

    Xsim = rk4(SEIR_D, y0, time, args=(beta,mu,gamma,))
    Xsim = Xsim.transpose()
    return Xsim

# Derivative for basic SEIR system.
def SEIR_D(y,t,beta,mu,gamma):
    # y[0] = susceptible
    # y[1] = exposed
    # y[2] = infected/infectious
    dy = np.zeros((3,1))

    dy[0] = -(beta)*y[0]*y[2]
    dy[1] = (beta)*y[0]*y[2] - mu*y[1]
    dy[2] = mu*y[1] - gamma*y[2]
    return dy

###############################################################################
# Simulate a deterministic SEIR system with parameters built to
# have a power-law scaling for the contact rate as in,
# "Semi-empirical power-law scaling of new infection rate to model
#  epidemic dynamics with inhomogeneous mixing."
#  Mathematical Biosciences 203 (2006) 301-318
# With this instance we also introduce a time varying transmission rate
# similar to that used in, "Modeling the spread of influenza among cities"
# by James M. Hyman and Tara LaForce 2003.

# Returns numpy array:
#    Xsim = (3)x(Ntimestep) first row S(t), second row I(t),
#           third row E(t).
# Variables are (S0,E0,I0,beta,mu,gamma,nu,alpha,c,w)
# S0 = initial susceptible ratio
# E0 = initial exposed ratio
# I0 = initial infected ratio
# R0 = initial recovered ratio, S0+E0+I0+R0=1
# beta = base transmission rate (S0->E0)
# mu = incubation rate (E0->I0)
# gamma = recovery rate (I0->R0)
# nu = contact power-law scaling
# alpha = amplitude of transmission rate variation
#         beta varies over [1-alpha,1+alpha]
# c = time of peak transmission rate
# w = width of ramp up and ramp down of transmission
def SEIRplusode(y0, time, beta, mu, gamma, nu, alpha, c, w):
    # y0 = 3x1 numpy array of initial conditions.
    # time = Ntimestep length numpy array
    # beta = scalar
    # mu = scalar
    # gamma = scalar

    Xsim = rk4(SEIRplus_D, y0, time, args=(beta,mu,gamma,nu,alpha,c,w,))
    Xsim = Xsim.transpose()
    return Xsim

# Derivative for SEIR-plus system.
def SEIRplus_D(y,t,beta,mu,gamma,nu,alpha,c,w):
    # y[0] = susceptible
    # y[1] = exposed
    # y[2] = infected/infectious
    dy = np.zeros((3,1))

    dy[0] = -(trans_rate(t,beta,alpha,c,w))*y[2]*math.pow(y[0],nu)
    dy[1] = (trans_rate(t,beta,alpha,c,w))*y[2]*math.pow(y[0],nu) - mu*y[1]
    dy[2] = mu*y[1] - gamma*y[2]
    return dy

###############################################################################
# Time variable transmission function used in several of the above models.
# This varies over [beta*(1-alpha),beta*(1+alpha)]
def trans_rate(t,beta,alpha,c,w):
    k = 5.0 # parameter controlling transition length
    m = 4.0 # parameter controlling smoothness
    if (math.fabs(2.0*(t-c)/w) < 1):
        rate = (2*math.pow((1-math.pow(math.fabs(2.0*(t-c)/w),k)),m)) - 1.0
    else:
        rate = -1.0

    return (beta*(1 + alpha*rate))

###############################################################################
###############################################################################
# rk4-algorithm used in several of the above simulations.
#
# Integrate an ODE specified by
# y' = f(y,t,args), y(t0) = y0, t0 < t < T
# Using fourth order Runge-Kutta on a specified time grid.

# f() must return a numpy column array of outputs of the same
# dimension as that of y. It must take a numpy column array of
# variable values y, a single float time t, and any other arguments.

# The output is a numpy array of y values at the times in t of
# dimensions (len(t),len(y0)).
def rk4(func, y0, t, args=()):
    output = np.zeros((len(t),len(y0)))
    output[0,:] = y0[:,0].copy()
    yiter = y0.copy()

    for i in range(len(t)-1):
        h = t[i+1] - t[i]
        k1 = h*func(yiter, t[i], *args)
        k2 = h*func(yiter + .5*k1, t[i] + .5*h, *args)
        k3 = h*func(yiter + .5*k2, t[i] + .5*h, *args)
        k4 = h*func(yiter + k3, t[i] + h, *args)
        yiter = yiter + 0.16666666*(k1 + 2*k2 + 2*k3 + k4)
        output[i+1,:] = yiter[:,0].copy()

    return output


import numpy as np

#######################################

def init_matrix(size, init, std=None):

    input_size, output_size = size

    if init == 'zero':
        weights = np.zeros(shape=(input_size, output_size))

    elif init == 'sqrt_fan_in':
        sqrt_fan_in = np.sqrt(input_size)
        weights = np.random.uniform(low=-1.0/sqrt_fan_in, high=1.0/sqrt_fan_in, size=(input_size, output_size))

    elif init == 'glorot_uniform':
        limit = np.sqrt(6. / (input_size + output_size))
        weights = np.random.uniform(low=-limit, high=limit, size=(input_size, output_size))

    elif init == 'glorot_normal':
        scale = np.sqrt(2. / (input_size + output_size))
        weights = np.random.normal(loc=0.0, scale=scale, size=(input_size, output_size))

    elif init == 'alexnet':
        weights = np.random.normal(loc=0.0, scale=0.01, size=(input_size, output_size))

    elif init == 'normal':
        scale = std
        weights = np.random.normal(loc=0.0, scale=scale, size=(input_size, output_size))

    else:
        weights = np.random.normal(loc=0.0, scale=1.0, size=(input_size, output_size))

    return weights

#######################################

def init_filters(size, init, std=None):

    fh, fw, fin, fout = size

    if init == 'zero':
        weights = np.zeros(shape=(fh, fw, fin, fout))

    elif init == 'sqrt_fan_in':
        assert (False)

    elif init == 'glorot_uniform':
        limit = np.sqrt(6. / (fh*fw*fin + fh*fw*fout))
        weights = np.random.uniform(low=-limit, high=limit, size=(fh, fw, fin, fout))

    elif init == 'glorot_normal':
        scale = np.sqrt(2. / (fh*fw*fin + fh*fw*fout))
        weights = np.random.normal(loc=0.0, scale=scale, size=(fh, fw, fin, fout))

    elif init == 'alexnet':
        weights = np.random.normal(loc=0.0, scale=0.01, size=(fh, fw, fin, fout))

    elif init == 'normal':
        scale = std
        weights = np.random.normal(loc=0.0, scale=scale, size=(fh, fw, fin, fout))

    else:
        assert (False)

    return weights

#######################################

def init_local_filters(size, init, std=None):

    h, w, fh, fw, fin, fout = size

    if init == 'zero':
        weights = np.zeros(shape=(h, w, fh*fw*fin, fout))

    elif init == 'sqrt_fan_in':
        assert (False)

    elif init == 'glorot_uniform':
        limit = np.sqrt(6. / (fh*fw*fin + fh*fw*fout))
        weights = np.random.uniform(low=-limit, high=limit, size=(h, w, fh*fw*fin, fout))

    elif init == 'glorot_normal':
        scale = np.sqrt(2. / (fh*fw*fin + fh*fw*fout))
        weights = np.random.normal(loc=0.0, scale=scale, size=(h, w, fh*fw*fin, fout))

    elif init == 'alexnet':
        weights = np.random.normal(loc=0.0, scale=0.01, size=(h, w, fh*fw*fin, fout))

    elif init == 'normal':
        scale = std
        weights = np.random.normal(loc=0.0, scale=scale, size=(h, w, fh*fw*fin, fout))

    else:
        assert (False)

    return weights

#######################################


import numpy as np

def quantile_scaling(x, min_per=5, max_per=95):
    """
    Scale data using max and min quantiles
    """
    # see quantile_transform sklearn
    x_min = np.nanpercentile(x, min_per)
    x_max = np.nanpercentile(x, max_per)
    xrmp = (x - x_min) / (x_max - x_min)
    return xrmp, x_min, x_max


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

import time, datetime
import numpy as np
import pandas as pd
import scipy.stats as sp
import streamlit as st
import models.binomial as bn
import models.blackscholes as bs
import models.montecarlo as mc

class Option() :
    def __init__(self, ul_asset, type, strike, expiry, style="EU") :
        self.type = type
        self.ul_asset = ul_asset
        self.strike = strike
        self.expiry = expiry
        self.style = style

    def days_to_expiry(self) :
        today = datetime.datetime.now()
        expiry = datetime.datetime.strptime(self.expiry, "%Y-%m-%d")
        days_to_expiry = (expiry - today).days
        return days_to_expiry

    def get_payoff(self, spot) :
        if (self.type == "call") :
            payoff = np.maximum(0, spot - self.strike)
        elif (self.type == "put") :
            payoff = np.maximum(0, self.strike - spot)
        return payoff

    def get_price(self, model, **kwargs) :
        if (model == 1) :
            price = bn.price(self, spot=kwargs['spot'], riskfree=kwargs['riskfree'], dividend=kwargs['dividend'], volatility=kwargs['volatility'], steps=kwargs['steps'])
        elif (model == 2) :
            price = bs.price(self, spot=kwargs['spot'], riskfree=kwargs['riskfree'], dividend=kwargs['dividend'], volatility=kwargs['volatility'])
        elif (model == 3) :
            price = mc.price(self, spot=kwargs['spot'], riskfree=kwargs['riskfree'], dividend=kwargs['dividend'], volatility=kwargs['volatility'], steps=kwargs['steps'], simulations=kwargs['simulations'])
        return price

    def snpdf(self, spot, riskfree, dividend, volatility) :
        snpdf = (1 / (np.sqrt(2 * np.pi))) * (np.exp((-bs.d1(self, spot, riskfree, dividend, volatility) ** 2) / 2))
        return snpdf

    def get_delta(self, spot, riskfree, dividend, volatility) :
        cdf = sp.norm(0, 1).cdf
        t = self.days_to_expiry() / 365
        if (self.type == "call") :
            delta = np.exp(-dividend * t) * cdf(bs.d1(self, spot, riskfree, dividend, volatility))
        elif (self.type == "put") :
            delta = np.exp(-dividend * t) * (cdf(bs.d1(self, spot, riskfree, dividend, volatility)) - 1)
        return delta

    def get_gamma(self, spot, riskfree, dividend, volatility) :
        t = self.days_to_expiry() / 365
        gamma = (np.exp(-dividend * t) / (spot * volatility * np.sqrt(t))) * self.snpdf(spot, riskfree, dividend, volatility)
        return gamma

    def get_vega(self, spot, riskfree, dividend, volatility) :
        t = self.days_to_expiry() / 365
        vega = (0.01 * spot * np.exp(-dividend * t) * np.sqrt(t)) * self.snpdf(spot, riskfree, dividend, volatility)
        return vega

    def get_theta(self, spot, riskfree, dividend, volatility) :
        cdf = sp.norm(0, 1).cdf
        t = self.days_to_expiry() / 365
        if (self.type == "call") :
            theta = (-(((spot * volatility * np.exp(-dividend * t)) / (2 * np.sqrt(t))) * self.snpdf(spot, riskfree, dividend, volatility)) - (riskfree * self.strike * np.exp(-riskfree * t) * cdf(bs.d2(self, spot, riskfree, dividend, volatility))) + (dividend * spot * np.exp(-dividend * t) * cdf(bs.d1(self, spot, riskfree, dividend, volatility)))) / 365
        elif (self.type == "put") :
            theta = (-(((spot * volatility * np.exp(-dividend * t)) / (2 * np.sqrt(t))) * self.snpdf(spot, riskfree, dividend, volatility)) + (riskfree * self.strike * np.exp(-riskfree * t) * cdf(-bs.d2(self, spot, riskfree, dividend, volatility))) - (dividend * spot * np.exp(-dividend * t) * cdf(-bs.d1(self, spot, riskfree, dividend, volatility)))) / 365
        return theta

    def get_rho(self, spot, riskfree, dividend, volatility) :
        cdf = sp.norm(0, 1).cdf
        t = self.days_to_expiry() / 365
        if (self.type == "call") :
            rho = 0.01 * self.strike * t * np.exp(-riskfree * t) * cdf(bs.d2(self, spot, riskfree, dividend, volatility))
        elif (self.type == "put") :
            rho = -0.01 * self.strike * t * np.exp(-riskfree * t) * cdf(-bs.d2(self, spot, riskfree, dividend, volatility))
        return rho

    def get_greeks(self, spot, riskfree, dividend, volatility) :
        greeks = {
            "delta" : self.get_delta(spot, riskfree, dividend, volatility),
            "gamma" : self.get_gamma(spot, riskfree, dividend, volatility),
            "vega" : self.get_vega(spot, riskfree, dividend, volatility),
            "theta" : self.get_theta(spot, riskfree, dividend, volatility),
            "rho" : self.get_rho(spot, riskfree, dividend, volatility)
        }
        return greeks

class Call(Option) :
    def __init__(self, ul_asset, strike, expiry, style) :
        Option.__init__(self, ul_asset, type, strike, expiry, style)
        self.type = "call"

class Put(Option) :
    def __init__(self, ul_asset, strike, expiry, style) :
        Option.__init__(self, ul_asset, type, strike, expiry, style)
        self.type = "put"

model = {1:"Binomial", 2:"Black & Scholes", 3:"Monte Carlo"}
model = st.sidebar.selectbox(label="Model", options=list(model.keys()), index=1, format_func=lambda x: model[x])

if (model == 1) : # Binomial
    st.sidebar.header("Model Parameters")
    steps = st.sidebar.number_input(label="Steps", min_value=1, value=4)
    simulations = 0
elif (model == 2) : # Black & Scholes
    steps = 0
    simulations = 0
elif (model == 3) : # Monte Carlo
    st.sidebar.header("Model Parameters")
    steps = st.sidebar.number_input(label="Steps", min_value=1, value=100)
    simulations = st.sidebar.number_input(label="Simulations", min_value=1, max_value=100000, value=100000)

def user_input_features() :
    st.sidebar.header("Option")
    type = st.sidebar.selectbox(label="Type", options=["Call", "Put"])
    ul_asset = st.sidebar.text_input(label="Underlying Asset", value="EURUSD")
    spot = st.sidebar.number_input(label="Spot", min_value=0.0, value=1.1850, step=0.0005, format="%.4f")
    strike = st.sidebar.number_input(label="Strike", min_value=0.0, value=1.1650, step=0.0005, format="%.4f")
    expiry = st.sidebar.date_input(label="Expiry", value=datetime.date(2021, 12, 31))
    style = st.sidebar.selectbox(label="Style", options=["EU", "US"], index=0)

    st.sidebar.header("Market")
    riskfree = st.sidebar.slider(label="Riskfree Rate", min_value=0.0, max_value=10.0, value=1.0, step=0.05)
    dividend = st.sidebar.number_input(label="Dividend", min_value=0.0, value=0.0)
    volatility = st.sidebar.slider(label="Implied Volatility", min_value=0.0, max_value=1.0, value=0.2, step=0.0005)

    data = {
        "type" : type.lower(),
        "ul_asset" : ul_asset,
        "strike" : strike,
        "spot" : spot,
        "expiry" : expiry.strftime("%Y-%m-%d"),
        "style" : style,
        "riskfree" : riskfree,
        "dividend" : dividend,
        "volatility" : volatility
    }
    features = pd.DataFrame(data, index=[0])
    return features

st.header("User Input Parameters")
st.subheader("Option")
features = user_input_features()
st.write(features[['type', 'ul_asset', 'strike', 'spot', 'expiry', 'style']])
st.subheader("Market")
st.write(features[['riskfree', 'dividend', 'volatility']])

spot = features['spot'][0]
riskfree = features['riskfree'][0]
dividend = features['dividend'][0]
volatility = features['volatility'][0]

option = Option(
    ul_asset=features['ul_asset'][0],
    type=features['type'][0],
    strike=features['strike'][0],
    expiry=features['expiry'][0],
    style=features['style'][0]
)

st.header("Output")
payoff = {"payoff" : float(option.get_payoff(spot=spot))}
price = {"price" : float(option.get_price(model=model, spot=spot, riskfree=riskfree, dividend=dividend, volatility=volatility, steps=steps, simulations=simulations))}
greeks = option.get_greeks(spot=spot, riskfree=riskfree, dividend=dividend, volatility=volatility)
output = {**payoff, **price, **greeks}
df = pd.DataFrame(output, index=[0])
st.write(df)

def debug() :
    start = time.time()
    spot = 100.

    riskfree = .05
    dividend = 0.
    volatility = .2

    c = Call("INDEX", 99., "2020-12-31", "EU")

    p_bn = float(c.get_price(1, spot=spot, riskfree=riskfree, dividend=dividend, volatility=volatility, steps=4))
    t_bn = time.time() - start
    print(f"BN. {p_bn:.6f} ({t_bn:.6f} secs)")

    p_bs = float(c.get_price(2, spot=spot, riskfree=riskfree, dividend=dividend, volatility=volatility))
    t_bs = time.time() - start
    print(f"BS. {p_bs:.6f} ({t_bs:.6f} secs)")

    p_mc = float(c.get_price(3, spot=spot, riskfree=riskfree, dividend=dividend, volatility=volatility, steps=100, simulations=10000))
    t_mc = time.time() - start
    print(f"MC. {p_mc:.6f} ({t_mc:.6f} secs)")
    return

def main() :
    pass

if __name__ == "__main__" :
    main()


import numpy as np

def constitutive(E, nu, problem_type):
    """Calculate the constitutive matrix for the plane elasticity problem
    Inputs:
    1) E = Young's Modulus (N/m^2)
    2) nu = Poisson's ratio
    3) problem_type = type of problem, plane stress or plane strain
    problem_type = 0 (plane stress)
    problem_type = 1 (plane strain)

    Output:
    C = 3x3 constitutive matrix for the given material"""

    C = np.eye(3)
    if problem_type == 0:
        const = E/(1 - nu**2)
        C[0, 1] = nu
        C[2, 2] = (1-nu)/2
        C[1, 0] = nu

    else:
        const = E/((1+nu)*(1-2*nu))
        C[0, 0] = 1 - nu
        C[1, 1] = C[0, 0]
        C[0, 1] = nu
        C[1, 0] = C[0, 1]
        C[2, 2] = (1 - 2*nu)/2

    C = const * C
    return C


"""Methods based on multiplying the gradient by a diagonal definite-positive matrix"""
import numpy as np

from optimus.types import DirectionMethod
from optimus.types import Function

class DiagonalQuasiHessian(DirectionMethod):
    """Direction is gradient multiplied by an inverse diagonal-only Hessian."""

    def __call__(
        self, parameters: np.ndarray, objective_function: Function
    ) -> np.ndarray:
        gradient = objective_function.gradient(parameters)
        size = gradient.size
        self_second_partial_derivatives = np.array(
            [
                objective_function.partial_second_derivative(parameters, i, i)
                for i in range(size)
            ]
        )
        return gradient / self_second_partial_derivatives


# Run the blending process
# Martha Grover, July 6, 2017 (MATLAB)
# John Hedengren, July 14, 2017 (Python)

import numpy as np
from scipy.integrate import odeint

# Here is the playlist for the accompanying screencasts:
# https://www.youtube.com/playlist?list=PL4xAk5aclnUhb0tM6nypIATyxPRk0fB3L

# Following on the first screencast (Blending Process: Dynamic Simulation),
# here you can simulate the nonlinear coupled set of differential equations.
# As in the second screencast (Blending Process: Steady States),
# observe here how the mass fraction in the tank
# approaches the steady state value of xbar as the system approaches long
# time.  The volume does not have a unique steady state.  Since filling a
# tank is a integrating process, it may increase or decrease without bound,
# based on the difference between the inlet and outlet mass flow rates.

# Parameters
rho = 1000   # Density [kg/m^3]

# Here we will consider x1 and x2 to remain as constants
x1 = 0.1
x2 = 0

#######################################################################
############### Define the Nonlinear Model  ###########################
#######################################################################
# Nominal inputs:
# x1: Mass fraction of Species A in Stream 1 (unitless)
# w1: Mass flow rate in Stream 1 [kg/s]
# x2: Mass fraction of Species A in Stream 2 (unitless)
# w2: Mass flow rate in Stream 2 [kg/s]
# w:  Outlet mass flow [kg/s]

def blending(z,t,u):
    # Dynamic model of the blending process
    # State variables passed in as vector z:
    V = z[0]   # Volume [m3]
    x = z[1]   # Mass fraction of Species A in the tank (unitless)
    # Inputs passed in as vector u:
    w1 = u[0]  # Mass flow rate in Stream 1 [kg/s]
    w2 = u[1]  # Mass flow rate in Stream 2 [kg/s]
    w = u[2]   # Here we set the outlet flow equal to the total inlet flow

    # Dynamic equations
    dVdt = (1.0/rho)*(w1+w2-w)                     # Change in volume
    dxdt = (1.0/(rho*V))*(w1*(x1-x)+w2*(x2-x))     # Change in mass fraction

    # Assemble the two time derivatives back into a vector to pass back
    dzdt = [dVdt,dxdt]
    return dzdt

#######################################################################
############# Dynamic Simulation of the Nonlinear System ##############
#######################################################################

# Initial conditions
V0 = 10        # Initial volume in the tank [m^3]
x0 = 0.025     # Initial mass fraction of Species A in the tank (unitless)
# Note: these are currently set at their nominal steady-state values...
# But you can try changing them to other values.
z0 = [V0,x0]  # Initial condition vector for the system

# The flow rates will be the variables in u that may change over time
w1 = 1         # w1: Mass flow rate in Stream 1 [kg/s]
w2 = 3         # w2: Mass flow rate in Stream 2 [kg/s]
w = w1 + w2    # w:  Outlet mass flow [kg/s]
u = [w1,w2,w]  # Assemble these together in a column vector u

tf = 3600      # Final simulation time [s]
t = np.linspace(0,tf,100) # points to report solution

# Simulate the blending process
z = odeint(blending,z0,t,args=(u,))

# plotting results
import matplotlib.pyplot as plt

# Plot the blending process under steady operation
plt.figure(1)
plt.subplot(2,1,1)
plt.plot(t,z[:,0])
plt.xlabel('time t [s]')
plt.ylabel(r'$V \; [m^3]$')
plt.title('Blending process under constant inputs')
plt.subplot(2,1,2)
plt.plot(t,z[:,1])
plt.xlabel('time t [s]')
plt.ylabel('x')

# Calculate the steady-state value for x
xbar = (w1*x1 + w2*x2)/(w1+w2)
# Check to see if this matches the long-term value of x on the plot
# Since V does not have a unique steady state, specify a desired operating value
# Here it is set equal to the initial volume
Vbar = V0  # volume [m^3]

# Define ubar as the set of inputs to achieve this steady state
ubar = np.copy(u)

# Next simulate the system for the higher value of w1 = 1.1 (0.1 higher)
dw1 = 0.1
u[0] = ubar[0] + dw1

zs = odeint(blending,z0,t,args=(u,))

# Plot the blending process under a step change in w1
plt.figure(2)
plt.subplot(2,1,1)
plt.plot(t,zs[:,0])
plt.xlabel('time t [s]')
plt.ylabel(r'$V \; [m^3]$')
plt.title(r'Blending process under a step input to $w_1$')
plt.subplot(2,1,2)
plt.plot(t,zs[:,1])
plt.xlabel('time t [s]')
plt.ylabel('x')

#######################################################################
###################### Linear Approximate Model #######################
#######################################################################

# Formulate the linear approximation as a state-space system using
# deviation variables (See screencast on Blending Process: Deviation
# Variables)

# Dynamic state x: V' and x'

# Inputs u: w1', w2', w'

# Measurements y: w1', V', x'

# Define the matrices A, B, C, and D for the linearized system
# dxdt = A*x + B*u'
# y = C*x + D*u'
# See the screencasts on Linearization and State Space

# Dynamic equation: dx/dt = Ax + Bu
A = np.array([[0,0], \
              [0,1.0/(rho*Vbar)*(-w1-w2)]])
B = np.array([[1.0/rho,1.0/rho,-1.0/rho], \
              [1.0/(rho*Vbar)*(x1-xbar),1.0/(rho*Vbar)*(x2-xbar),0]])
# Measurement equation: y = Cx + Du
C = np.array([[0,0], \
              [1,0], \
              [0,1]])        # Measuring the states V and x directly
D = np.array([[1,0,0], \
              [0,0,0], \
              [0,0,0]])      # Measuring the input w directly

#######################################################################
############### Define the Linear Model ###############################
#######################################################################
def blending_linear(x,t,u):
    # State space version of the linearized model for the blending process,
    # using deviation variables
    # dx/dt = A*x + B*u
    # The measurement equation of y = C*x + D*u is not included here, since
    # it is an algebraic equation that does not need to be solved by odeint.

    # Dynamic state x
    Vp = x[0]      # V' = deviation in volume
    xp = x[1]      # x' = deviation in mass fraction

    # Input vector u
    w1p = u[0]     # w1' = deviation in mass flow rate in inlet Stream 1
    w2p = u[1]     # w2' = deviation in mass flow rate in inlet Stream 2
    wp = u[2]      # w' = deviation in mass fraction in outlet stream

    # dx/dt = Ax + Bu
    dxdt = np.dot(A,x) + np.dot(B,u)
    return dxdt

# Define input in deviation variables u'
up = np.array(u) - np.array(ubar)
# Define the deviation in initial state
# Here we will continue to use z for the state vector, to avoid confusion
# with the mass fraction of Species A which is called x
zbar = np.array([Vbar,xbar])
zp0 = z0 - zbar   # Note: We set z0 = zbar earlier, so this should be zero
# Simulate the linearized model of the blending process
zp = odeint(blending_linear,zp0,t,args=(up,))

# Plot the comparison between the nonlinear system and the linearized
# system, for a step change of 0.1 in w1
plt.figure(3)
plt.subplot(2,1,1)
plt.plot(t,zs[:,0],'r-',linewidth=2)
plt.plot(t,zp[:,0]+Vbar,'b--',linewidth=2)
plt.legend(['Nonlinear','Linearized'])
plt.xlabel('time t [s]')
plt.ylabel(r'$V \; [m^3]$')
plt.title(r'Comparison of nonlinear and linear models for a step change in $w_1$')
plt.subplot(2,1,2)
plt.plot(t,zs[:,1],'k-',linewidth=2)
plt.plot(t,zp[:,1]+xbar,'g:',linewidth=2)
plt.legend(['Nonlinear','Linearized'])
plt.xlabel('time t [s]')
plt.ylabel('mass fraction x')

# In this example, the linear model agrees pretty well with the nonlinear
# model.  The equation for volume V is linear and does not depend on the
# mass fraction x, so it agrees perfectly with the nonlinear model.
# The mass fraction prediction is not perfect, but because the step change
# is "small" (10%) the agreement is still pretty good.

# Steady-state gain of the system
K = np.dot(np.dot(C,np.linalg.pinv(-A)),B)+D

# Note: It is not possible to calculate this since A is not invertible
# This makes sense because there is no unique steady-state value for
# volume V

# Note that we did not actually use C and D in this example.  We can
# evaluate the measurements y' at each time point of our ode solution:
yp = np.zeros((np.size(ubar),np.size(t)))
yp = np.dot(C,zp.T)
for i in range(np.size(t)):
    yp[:,i] = yp[:,i] + np.dot(D,up)

# show plots
plt.show()


# Exponential distribution is used for describing time till next event e.g. failure or success etc.
# it has two parameters
# scale - inverse of rate (see lam in poisson distribution) defaults to 1.0.
# size - the shape of the returned array.
from numpy import random
import matplotlib.pyplot as plt
import seaborn as sns

arr1 = random.exponential(scale=3, size=10)         # show time can take between 2 events when mean time is 3.
print(arr1)

sns.distplot(arr1, hist=False)
plt.show()
# poisson deals with number of occurrence of event in a time period
# whereas exponential distribution deals with time between these events

Python/Numpy/numpy 26 - exponential distribution.py


import numpy as np
import theano.tensor as T
import matplotlib.pyplot as plt

# MY CODE

temperature = 0.01
logits = np.linspace(-2, 2, 10).reshape([1, -1])

def softmax(x):
    """Compute softmax values for each sets of scores in x."""
    e_x = np.exp(x - np.max(x))
    return e_x / e_x.sum(axis=0)

def sample_gumbel(shape, eps=1e-20):
    """ Sample from Gumbel(0, 1) """
    U = np.random.uniform(size=shape, low=0, high=1)
    return -np.log(-np.log(U + eps) + eps)

def sample_gumbel_softmax(logits, temperature):
    """ Sample from Gumbel-Softmax distribution """
    y = logits + sample_gumbel(logits.shape)
    return softmax(y / temperature)

plt.title('gumbel-softmax samples')
for i in range(100):
    plt.plot(
        range(10),
        sample_gumbel_softmax(logits,temperature=temperature),
        marker='o',
        alpha=0.25
    )

plt.ylim(0,1)
plt.show()

gsm_samples = [sample_gumbel_softmax(logits,temperature=temperature) for _ in range(500)]
plt.title('average over samples')
plt.plot(
    range(10),
    np.mean(gsm_samples, axis=0)[0],
    marker='o',
    label='gumbel-softmax average'
)
plt.plot(
    softmax(sample_gumbel_softmax(logits,temperature=temperature)[0]),
    marker='+',
    label='regular softmax'
)
plt.legend(loc='best')
plt.show()

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

# THEIR CODE
temperature = 0.01
logits = np.linspace(-2, 2, 10)

def softmax(x):
    e_x = np.exp(x - np.max(x))
    return e_x / e_x.sum(axis=0)

def GumbelSoftmax(logits, temperature):
    uniform = np.random.uniform(size=logits.shape,low=0,high=1)
    gumbel = -np.log(-np.log(uniform + 1e-20) + 1e-20)
    return softmax((logits + gumbel) / temperature)

plt.title('gumbel-softmax samples')
for i in range(100):
    plt.plot(
        range(10),
        GumbelSoftmax(logits, temperature),
        marker='o',
        alpha=0.25
    )

plt.ylim(0,1)
plt.show()

gsm_samples = [sample_gumbel_softmax(logits,temperature=temperature) for _ in range(500)]
plt.title('average over samples')
plt.plot(
    range(10),
    np.mean(gsm_samples, axis=0)[0],
    marker='o',
    label='gumbel-softmax average'
)
plt.plot(
    softmax(sample_gumbel_softmax(logits,temperature=temperature)[0]),
    marker='+',
    label='regular softmax'
)
plt.legend(loc='best')
plt.show()


import dataload
import matplotlib.pyplot as plt
import numpy as np
from random import seed, randrange
import os, sys, glob
from abc import abstractmethod, ABC

class LINEAR_REGRESSION(object):
    def __init__(self, xs, ys):
        self.xs = xs
        self.ys = ys
        self.size = len(xs)
        if (self.size == 0):
            print("ERROR: Data size cannot be zero")
            sys.exit()
        elif (len(xs) != len(ys)):
            print("ERROR: Independent and dependent variable length is unequal")
            sys.exit()

    def RegressionPlot(self, y_predict):
        pass

class LINEAR_RSQUARE(object):
    # TODO: Use super method
    def __init__(self, xs, ys):
        self.xs = xs
        self.ys = ys
        self.size = len(xs)
        if (self.size == 0):
            print("ERROR: Data size cannot be zero")
            sys.exit()
        elif (len(xs) != len(ys)):
            print("ERROR: Independent and dependent variable length is unequal")
            sys.exit()

    def slope_intercept(self):
        n = self.size
        S_x  = sum( self.xs ); S_y  = sum( self.ys )
        S_xx = sum( self.xs**2 ); S_xy = sum( self.xs*self.ys )
        # S_yy = sum( ys**2 )

        m = (n*S_xy - S_x*S_y) / (n*S_xx - S_x**2)
        b = S_y/n - m*(S_x/n)
        return m, b

    def squared_error(self, original, estimation):
        sum_sqr_err = 0.0
        for i in range( len(original) ):
            sqr_err = (estimation[i] - original[i])**2
            sum_sqr_err += sqr_err
        return sum_sqr_err

    def rsquared(self):
        ys_original  = list(self.ys)
        m_est, b_est = self.slope_intercept()

        ys_estimation = [m_est * x + b_est for x in self.xs]
        ys_mean_line  = [np.mean(self.ys) for y in ys_original]
        SS_tot = self.squared_error(ys_original, ys_mean_line)
        SS_res = self.squared_error(ys_original, ys_estimation)
        return (1.0 - (SS_res/SS_tot))

class LINEAR_RMSE(object):
    def __init__(self, xs, ys):
        self.xs = xs
        self.ys = ys

    def predict(self, row, coeff):
        # Coefficient predicitions
        y_hat = coeff[0]
        for i in range (len(row)-1):
            y_hat += coeff[i+1] * row[i]
        return y_hat

    def SGD_coeff(self, n_epoch=10, l_rate=0.001):
        # Estimate linear regression coefficients using SGD
        train_set = np.concatenate( (self.xs, self.ys) )
        train_set = np.reshape(train_set, (len(self.xs),2), order='F')

        coef = np.zeros( len(train_set[0]) )
        for _ in range(n_epoch):
            sum_error = 0.0

            for row in train_set:
                yhat       = self.predict(row, coef)
                error      = yhat - row[-1]
                sum_error += error**2
                coef[0]   -= l_rate * error

                for i in range(len(row)-1):
                    coef[i + 1] -= l_rate * error * row[i]
            # print('>> epoch={}, lrate={}, error={}'.format(epoch, l_rate,
            # sum_error))
        m = np.array( [coef[1]] ); b = np.array( [coef[0]] )
        return m, b

    def RMSE(self, y_original, y_estimation):
        sum_error = 0.0
        for i in range(0, len(y_original)):
            error = y_estimation[i] - y_original[i]
            sum_error += error**2
        mean_error = sum_error/float( len(y_original) )
        return mean_error

if __name__ == '__main__':
    snow_data = '../data/snow/snow.csv'
    x_snow, y_snow = dataload.loadCSV(snow_data)

    linear_reg_01 = LINEAR_RSQUARE(x_snow, y_snow)
    m_snow, b_snow = linear_reg_01.slope_intercept()
    regression_line = [m_snow * x + b_snow for x in x_snow]
    rsqr = linear_reg_01.rsquared()

    print("Slope and Intercept: {} and {}".format(m_snow, b_snow) )
    print("R-square: {}".format(rsqr))
    """ Use bool flag to display graph
    plt.scatter(x_snow, y_snow, color='red')
    plt.plot(x_snow, regression_line, color='blue')
    plt.title('Plot of Snow vs Yield using Statistical Analysis')
    plt.xlabel('Snow')
    plt.ylabel('Yield')
    plt.show()
    """

    linear_reg_02 = LINEAR_RMSE(x_snow, y_snow)
    m, b = linear_reg_02.SGD_coeff(1000, 0.001)
    regressionline_02 = m * x_snow + b
    rmse = linear_reg_02.RMSE(y_snow, regressionline_02)
    print("Slope and Intercept: {} and {}".format(m, b) )
    print("RMSE: {}".format(rmse))

    """ Use bool flag to display graph
    plt.scatter(x_snow, y_snow, color='red')
    plt.plot(x_snow, regressionline_02, color='blue')
    plt.title('Plot of Snow vs Yield using Machine Learning Analysis')
    plt.xlabel('Snow')
    plt.ylabel('Yield')
    plt.show()
    """


# python3
"""Z-Y dcomposition of a unitary U."""

import cmath

from absl import app
import numpy as np
import scipy.stats

from src.lib import ops

# The "Z-Y decomposition for a single qubit" shows that
# any unitary U can be decomposed into Rz and Ry rotations
# with 4 parameters alpha, beta, gamma, delta as follows:
#
#   U = e^(i*alpha) * Rz(beta) * Ry(gamma) * Rz(delta)
#
# The question is how to find the 4 parameters for
# a given U?
#
# One answer was provided here - it solves correctly for alpha and gamma:
#    https://threeplusone.com/pubs/on_gates.pdf
#
# The approach from this paper can be found in code, here:
#    https://github.com/gecrooks/quantumflow-dev/blob/master/quantumflow/decompositions.py
#
# Another publication solves correctly for beta and delta:
#    https://quantumcomputing.stackexchange.com/questions/\
#    16256/what-is-the-procedure-of-finding-z-y-decomposition-of-unitary-matrices
#
# Let's try and implement this here!

def make_u(alpha, beta, gamma, delta):
  """Construct unitary from the 4 parameters."""

  return ((ops.RotationZ(beta) @
           ops.RotationY(gamma) @
           ops.RotationZ(delta)) *
          cmath.exp(1.0j * alpha))

def zy_decompose(umat):
  """Perform Z-Y decomposition of unitary operator in SU(2)."""

  a = umat[0][0]
  b = umat[0][1]
  c = umat[1][0]

  det = np.linalg.det(umat)
  alpha = 0.5 * np.arctan2(det.imag, det.real)

  if a >= b:
    gamma = 2 * np.arccos(abs(a))
  else:
    gamma = 2 * np.arcsin(abs(b))

  # TODO(rhundt): Handle cases with gamma very close to 0 or Pi

  beta = cmath.phase(c) - cmath.phase(a)
  delta = cmath.phase(-b) - cmath.phase(a)

  return alpha, beta, gamma, delta

def main(argv):
  if len(argv) > 1:
    raise app.UsageError('Too many command-line arguments.')

  iterations = 10000
  print(f'Perform {iterations} random Z-Y decompositions.')

  for i in range(iterations):
    #
    # Construct a random unitary operator and put into SU(2).
    #
    u = scipy.stats.unitary_group.rvs(2)
    umat = np.sqrt(1 / np.linalg.det(u)) * u

    #
    # Now decompose this operator and find the four parameters.
    #
    alpha, beta, gamma, delta = zy_decompose(umat)

    #
    # Construct another operator from these newly found
    # parameters and make sure that the resulting
    # operator matches the one from above.
    #
    unew = make_u(alpha, beta, gamma, delta)

    if not np.allclose(umat, unew, atol=1e-4):
      print(f'decomp : {i:2d}: {alpha:.3f} {beta:.3f} {gamma:.3f} {delta:.3f}')
      raise AssertionError('Z-Y decomposition failed')

  print('Success')

if __name__ == '__main__':
  app.run(main)


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

import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import matrix_power
from termcolor import colored
import timeit
plt.style.use('seaborn')

def transition_matrix(N, mu_a, mu_A,
                      f, g):
     '''
    N -- population size
    mu_a, mu_A are mutation rates
    and f, g are fitnesses for
    allele a and allele A respectively.
    '''
    P = np.zeros((N+1,N+1))
    for j in range(1,N):
        sa = f*j/(f*j + g*(N-j))   # Prob of selecting an allele a
        sA = 1 - sa   # Prob of selecting an allele A
        P[j][j+1] = (sa*(1 - mu_a) + (sA*mu_A))*(N - j)/N   # Prob of birth for allele a
        P[j][j-1] = (sa*mu_a + sA*(1 - mu_A))*j/N   # Prob of death for allele a
        P[j][j] = 1 - P[j][j+1] - P[j][j-1]
    P[0][1] = mu_A
    P[N][N-1] = mu_a
    P[0][0] = 1 - P[0][1]
    P[N][N] = 1 - P[N][N-1]
    return P

def fixation_prob(N, f, g, x0, k):
    '''
    Returns the probability of
    fixation at state N, starting at x0.
    '''
    P = transition_matrix(N, 0, 0, f, g)
    estimate_prob = matrix_power(P,k)[x0][N]
    return estimate_prob

def time_to_fixation(N, f, g, x0):
    '''
    Returns mean time to
    fixation at either state 0 or N,
    starting at x0.
    '''
    P = transition_matrix(N, 0, 0, f, g)
    Q = P[1:N,1:N]
    J = np.ones(N-1)
    I = np.identity(N-1)
    A = np.dot(np.linalg.inv(I-Q),J)
    mean_time = A[x0]
    return mean_time

def fixation_plots(pop_vec, pows, fit_vec, x0):
    fig, ax = plt.subplots(len(pop_vec), len(fit_vec), figsize=(12,8))
    col = ['cornflowerblue','orange','orchid']
    for i, (N,k) in enumerate(zip(pop_vec, pows)):
        for j, (f,g) in enumerate(fit_vec):
            mean_time = time_to_fixation(N, f, g, x0)
            trans_prob = []
            for iteration in range(k):
                p = fixation_prob(N, f, g, x0, iteration)
                trans_prob.append(p)
            ax[i,j].plot(np.linspace(1,k,k), trans_prob, color=col[i])
            ax[0,j].set_title('(f,g)={}'.format((f,g)), fontsize=12)
            ax[-1,j].set_xlabel('steps(k)', fontsize=12)
            ax[i,0].set_ylabel('N={}'.format(N), fontsize=14)
            ax[i,j].legend(['$Prob[X_k={}|x_0=1]$'.format(N)], fontsize=10)
            if i==0:
                ax[i,j].text(200,0.1,'Mean time to fixtaion\n= %1.1f' %mean_time, fontsize=9)
            elif i==1:
                ax[i,j].text(400,0.07,'Mean time to fixtaion\n= %1.1f' %mean_time, fontsize=9)
            else:
                ax[i,j].text(1000,0.03,'Mean time to fixtaion\n=  %1.1f' %mean_time, fontsize=9)
            ax[i,j].set_ylim([0,1/N + 0.01])
            ax[i,j].set_yticks(np.linspace(0,1/N,5))
            plt.suptitle('First Plot: $Prob[X_{k}=N | x_{0}=1]$ versus'\
                         ' $k\,(steps)$ for different values of $N$',y=1.05)
            plt.tight_layout()

def stationary_distribution(N, mu_a, mu_A,
                            f, g, k):
    P = transition_matrix(N, mu_a, mu_A, f, g)
    steady_state_approx = matrix_power(P, k)[0,:]
    return steady_state_approx

def stationary_plots(N, mut_vec, pows, fit_vec):
    fig, ax = plt.subplots(len(mut_vec), len(fit_vec), figsize=(12,8))
    samples = 1000
    mutations = zip(mut_vec, pows)
    for i,((mu_a, mu_A), k) in enumerate(mutations):
        for j, (f,g) in enumerate(fit_vec):
            P = transition_matrix(N, mu_a, mu_A, f, g)
            steady_state_approx = stationary_distribution(N, mu_a, mu_A,
                                                          f, g, k)
            state_frequency = steady_state_approx * samples
            mean_state = np.dot(state_frequency, np.arange(N+1))/samples
            ax[i,j].bar(np.arange(N+1), state_frequency)
            ax[i,j].axvline(x=mean_state, ymin=0, ymax=0.95, linestyle='dashed', color ='green', label='Mean')
            ax[0,j].set_title('(f,g)={}'.format((f,g)), fontsize=12)
            ax[-1,j].set_xlabel('states', fontsize=12)
            ax[i,0].set_ylabel('$\mu_a$=$\mu_A$={}'.format(mu_a), fontsize=12)
            ax[i,j].legend()
            ax[i,j].set_ylim([0,max(state_frequency)+30])
            plt.tight_layout()
            plt.suptitle('Second Plot: Frequncy of states at stationary for N=20'\
                         ' in 1000 samples' ,y=1.05)

start = timeit.default_timer()

# Plot the fixation probabilities
pop_vec = [5, 10, 20]
pows = [500, 1000, 2000]
fit_vec = [(1,1), (1,1.1), (1,1.2)]
x0 = 1
fixation_plots(pop_vec, pows, fit_vec, x0)

# Plot the stationary distributions
N = 20
mut_vec = [(0.005,0.005), (0.05,0.05), (0.5,0.5)]
pows = [50000, 20000, 5000]
fit_vec = [(1,1), (1,1.1), (1,1.2)]
stationary_plots(N, mut_vec, pows, fit_vec)

# timing
end = timeit.default_timer()
print('run time = %1.2f sec.'%(end-start))


import numpy as np

class Regularizer(object):
    def __call__(self, w):
        return self.forward(w)

    def forward(self, w):
        pass

    def backward(self, w):
        """
        Computes the gradient of the loss with respect to w
        """
        pass

class L1(Regularizer):
    """
    L1 regularization, also known as Lasso regularization

    Computed as l1 * sum(abs(w))
    """

    def __init__(self, l1=0.01):
        self.l1 = l1

    def forward(self, w):
        """
        Note: you have to divide the result by m, the batch size, if you don't want l1 to depend on m
        """

        J = self.l1 * np.sum(np.abs(w))
        return J

    def backward(self, w):
        """
        Note: you have to divide the result by m, the batch size, if you don't want l1 to depend on m
        """

        # dw = (w > 0).astype(np.int) * 2 - 1
        # dw[w == 0] = 0
        dJ_dw = self.l1 * np.sign(w)
        return dJ_dw

class L2(Regularizer):
    """
    L2 regularization, also known as Ridge regularization

    Computed as l2 * sum(square(w))
    """

    def __init__(self, l2=0.01):
        self.l2 = l2

    def forward(self, w):
        """
        Note: you have to divide the result by m, the batch size, if you don't want l2 to depend on m
        """

        J = self.l2 * np.sum(np.square(w))
        return J

    def backward(self, w):
        """
        Note: you have to divide the result by m, the batch size, if you don't want l2 to depend on m
        """

        dJ_dw = self.l2 * 2 * w
        return dJ_dw

class L1L2(Regularizer):
    """
    Applies both L1 and L2 regularization

    Computed as l1 * sum(abs(w)) + l2 * sum(square(w))
    """

    def __init__(self, l1=0.0, l2=0.0):
        self.l1 = l1
        self.l2 = l2

        self.l1_regularizer = L1(l1)
        self.l2_regularizer = L2(l2)

    def forward(self, w):
        """
        Note: you have to divide the result by m, the batch size, if you don't want l1 and l2 to depend on m
        """

        self.l1_regularizer.l1, self.l2_regularizer.l2 = self.l1, self.l2

        J = self.l1_regularizer(w) + self.l2_regularizer(w)
        return J

    def backward(self, w):
        """
        Note: you have to divide the result by m, the batch size, if you don't want l1 and l2 to depend on m
        """

        self.l1_regularizer.l1, self.l2_regularizer.l2 = self.l1, self.l2

        dJ_dw = self.l1_regularizer.backward(w) + self.l2_regularizer.backward(w)
        return dJ_dw