import scipy.sparse
import numpy

def rhs(x_1, x_2):
    """
    Returns the result of f for the points x_1 and x_2
    """
    return -2*(x_2*(x_2-1)+x_1*(x_1-1))

def lgs(rhs, n):
    """
    Returns a tuple of a matrix A and a vector b which provides an approximation of the problem.
    :param rhs: The rhs function to create the values in the b vector.
    :param n: The dimension in each direction.
    :return: (A, b)
    """
    result_a = scipy.sparse.dok_matrix(((n-1)**2, (n-1)**2))
    result_b = scipy.sparse.dok_matrix(((n-1)**2, 1))

    for block in range(0, n - 1):
        for i in range(0, n - 1):
            result_a[(block * (n - 1)) + i, (block * (n - 1)) + i] = 4
            if i > 0:
                result_a[(block * (n - 1)) + i, (block * (n - 1)) + i - 1] = -1
            if i < n - 2:
                result_a[(block * (n - 1)) + i, (block * (n - 1)) + i + 1] = -1
            if block > 0:
                result_a[(block * (n - 1)) + i, ((block - 1) * (n - 1)) + i] = -1
            if block < n - 2:
                result_a[(block * (n - 1)) + i, ((block + 1) * (n - 1)) + i] = -1

    z = n - 2.0
    for i in range(0, (n - 1) * (n - 1)):
        z = z + 1
        result_b[i, 0] = (1.0/n) ** 2 * rhs((1.0/n) * (i % (n - 1) + 1), (1.0/n) * z / (n - 1))

    return result_a, result_b

def exactu(x_1, x_2):
    """
    Returns the exact solution for the points x_1 and x_2
    """
    return x_1 * (1 - x_1) * x_2 * (1 - x_2)

class Iterative:

    def __init__(self, omega, error_limit):
        """
        Initializes the class instance.
        :param omega: The omega-value to use for the SOR method.
        :param error_limit: The iterative algorithm stops when the difference between 2 steps is less then this value.
        """
        self._omega = omega
        self._error_limit = error_limit

    def diskreteLsgSOR(self, matrix, b, x_0=None):
        """
        :param matrix: The matrix A with the problem to solve
        :param b: The b in Ax-b<eps
        :param x_0: The start vector for the iterative procedure
        """

        if x_0 is None:
            x_0 = [0 for _ in range(0, matrix.shape[1])]

        error = self._error_limit
        n = len(x_0)
        while error >= self._error_limit:

            for i in range(1, n):
                o = 0
                for j in range(1, n):
                    if i != j:
                        o = o + x_0[j] * matrix[i, j]
                x_1 = x_0[i]
                x_0[i] = (1 - self._omega) * x_0[i] + \
                         (self._omega / matrix[i, i]) * (b[i, 0] - o)

                error = min(error, abs(x_1 - x_0[i]))

        return x_0

    def get_error(self, n, matrix, b):
        """
        Returns the maximum error from all points in the matrix with the vector b in the dimension n.
        """
        max_error = 0
        it = self.diskreteLsgSOR(matrix, b)
        for x in range(0, n - 1):
            for y in range(0, n - 1):
                max_error = max(max_error, abs(it[x * (n - 1) + y] - exactu(float(x) / float(n), float(y) / float(n))))
        return max_error


import matplotlib.pyplot as plt
import numpy as np
from options.option import OptionType, Option
from options.pricing.black_scholes import BlackScholesPricer

class OptionPricePlotter:
    def get_price(self, otype=OptionType.CALL, product='stock_option',
                  spot=60, strike=65, rate=0.08, expiry=0.25, vol=0.3):
        """Q:  (Vanilla option)
            A European call option, 3 month to expiry, stock price is 60, the strike
            price is 65, risk free interest rate is 8% per year, volatility is 30% per year
        A:
            2.1334
        """
        option = Option(otype, spot, strike, rate, expiry, vol, product=product)
        pricer = BlackScholesPricer()
        return pricer.price_option(option)

    def plot_price_vs_expiry(self):
        months_to_expiry = np.arange(1, 800, 1)
        prices = [self.get_price(expiry=m * 1.0 / 12) for m in months_to_expiry]

        plt.plot(months_to_expiry, prices, # blue
                 months_to_expiry, [60] * len(months_to_expiry), 'r--'  # red dash
                )
        plt.xlabel('Months to expiry')
        plt.ylabel('Option Price')
        plt.axis([0, 850, 0, 65])

    def plot_price_vs_strike(self):
        k_prices = np.arange(0.1, 90, 1)
        prices = [self.get_price(strike=k) for k in k_prices]

        plt.plot(k_prices, prices,
                 k_prices, [0] * len(k_prices), 'r--')
        plt.xlabel('Strike Price')
        plt.ylabel('Option Price')
        plt.axis([-10, 100, -10, 65])

    def plot_price_vs_spot(self):
        s_prices = np.arange(30, 90, 1)
        prices = [self.get_price(spot=s) for s in s_prices]

        plt.plot(s_prices, prices,
                 s_prices, [0] * len(s_prices), 'r--')
        plt.xlabel('Spot Price')
        plt.ylabel('Option Price')
        plt.axis([30, 90, -5, 30])

    def plot_price_vs_vol(self):
        """With volatility tends to infinity,
        the price of option tends to spot price of underlying asset.
        """
        vols = np.arange(0.1, 15, 0.1)
        prices = [self.get_price(vol=v) for v in vols]

        plt.plot(vols, prices,
                 vols, [60] * len(vols), 'r--')
        plt.xlabel('Volatility')
        plt.ylabel('Option Price')
        plt.axis([0, 15, 0, 65])

def get_bs_plot():
    bsptsp = OptionPricePlotter()

    fig = plt.figure(figsize =(8,12))

    plt.subplot(4, 1, 1)
    bsptsp.plot_price_vs_expiry()

    plt.subplot(4, 1, 2)
    bsptsp.plot_price_vs_strike()

    plt.subplot(4, 1, 3)
    bsptsp.plot_price_vs_spot()

    plt.subplot(4, 1, 4)
    bsptsp.plot_price_vs_vol()

    return fig

if __name__ == '__main__':
    fig = get_bs_plot()
    plt.show()


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time     : 2018/10/23 14:02
# @Author   : Iydon
# @File     : 5.2.py

import matplotlib.pyplot as plt
import numpy as np

def linspace(start, end, num=None, step=None):
    """
    Args:
        num:  numpy.linspace(start, end, num)
        step: start:step:end
    """
    if num:
        sepera = (end-start) / (num-1)
        return [start+i*sepera for i in range(num)]
    elif step:
        length = int((end-start)/step)
        return [start+i*step for i in range(length+1)]
    else:
        return [start, end]

def euler_method(dy, dy0, start, end, step):
    """
    Approximate the solution of the initial-value
    problem.
    | y' = f(t,y), a<=t<=b
    | y(a) = /alpha
    ----------------------------
    Args:
        dy:    y'.
        dy0:   /alpha.
        start: a.
        end:   b.
        step:  h.
    """
    xs = linspace(start, end, step=step)
    ys = [dy0 for i in xs]
    for i in range(len(xs)-1):
        ys[i+1] = ys[i] + step*(dy(xs[i],ys[i]))
    return ys

dy = lambda t,y: t*np.exp(3*t)-2*y
result = euler_method(dy, 0, 0, 1, 0.5)
print(result)

dy = lambda t,y: 1+(t-y)**2
result = euler_method(dy, 1, 2, 3, 0.5)
print(result)

dy = lambda t,y: np.exp(t-y)
result = euler_method(dy, 1, 0, 1, 0.5)
print(result)

dy = lambda t,y: (1+t) / (1+y)
result = euler_method(dy, 2, 1, 2, 0.5)
print(result)

dy = lambda t,y: -10*y
result = euler_method(dy, 1, 0, 2, 0.1)
print(result)

print("*")
ans = 1-np.exp(-1)
dy = lambda t,y: -y+1
h = 0.1
result = euler_method(dy, 0, 0, 1, h)
print(result[-1]-ans)
h = 0.01
result = euler_method(dy, 0, 0, 1, h)
print(result[-1]-ans)

print(ans)


"""Synthetic 6-dimensional test function by Friedman (1979).

Scientific Machine Learning Benchmark
A benchmark of regression models in chem- and materials informatics.
Matthias Rupp 2020, Citrine Informatics.

See class Friedman1979Data for details.
"""

import numpy as np

from smlb import params, VectorSpaceData

class Friedman1979Data(VectorSpaceData):
    r"""Synthetic 6-dimensional test function by Friedman (1979).

    \[ f(x_1,...,x_6) = 10 \sin(\pi x_1 x_2) + 20 (x_3 - 1/2)^2 + 10 x_4 + 5 x_5 + 0 x_6 \]

    where $x \in [0,1]^6$.

    This function originally appeared as Equation (22) on page 17 of

    Jerome H. Friedman: A Tree-Structured Approach to Nonparametric Multiple Regression, pp. 5-22 in
    Thomas Gasser, Murray Rosenblatt: Smoothing Techniques for Curve Estimation, Springer, 1979.
    Volume 757 in Lecture Notes in Mathematics. DOI 10.1007/BFb0098486

    and was later used again on page 294 of

    Jerome H. Friedman, Eric Grosse, Werner Stuetzle: Multidimensional Additive Spline Approximation,
    SIAM Journal on Scientific and Statistical Computing 4(2): 291-301, SIAM, 1983. DOI 10.1137/0904023

    This implementation introduces some additional flexibility by allowing to specify input dimensionality
    (at least 5), with all variables after the fifth one being ignored.

    The original formulation included additive independent standard-normal noise. For this, use the
    smlb LabelNoise DataTransformation with NormalNoise:
    data = Friedman1979Data(...); noisy_data = LabelNoise(noise=NormalNoise(...)).fit(data).apply(data)
    """

    def __init__(self, dimensions=6, **kwargs):
        """Initialize state.

        Parameters:
            dimensions: dimensionality; at least 5; 6 in original paper; higher dimensions do not change function

        Raises:
            InvalidParameterError: on invalid parameter values
        """

        dimensions = params.integer(dimensions, from_=5)
        domain = params.hypercube_domain((0, 1), dimensions=dimensions)

        super().__init__(
            dimensions=dimensions, function=self.__class__.friedman1979, domain=domain, **kwargs
        )

    @staticmethod
    def friedman1979(xx):
        """Computes Friedman (1979) test function without noise term

        Parameters:
            xx: sequence of vectors

        Returns:
            sequence of computed labels
        """

        xx = params.real_matrix(xx)  # base class verifies dimensionality and domain

        return (
            10 * np.sin(np.pi * xx[:, 0] * xx[:, 1])
            + 20 * np.power(xx[:, 2] - 1 / 2, 2)
            + 10 * xx[:, 3]
            + 5 * xx[:, 4]
        )

    # properties 'dimensions' and 'domain' are provided by base classes


# scientific computing library
import numpy as np

class PCA(object):
    """Principle Component Analysis."""

    def __init__(self, n_comps=5, standard=True, logger=None):
        """Contructor.

        Parameters
        ----------
        n_comps: int
            Number of principle components
        """
        self._fitted = False
        self.n_comps = n_comps
        self.standard = standard
        self.logger = logger
        self.mean = None
        self.U = None

    def fit(self, X):
        """Fit PCA according to `X.cov()`.

        Parameters
        ----------
        X: numpy.ndarray
            Features matrix

        Returns
        -------
        array: numpy.ndarray
            Transformed features matrix
        """
        if self._fitted:
            raise AssertionError('Already fitted.')
        self.D, N = X.shape
        if self.logger:
            self.logger.debug('Number of features: D=%d' % self.D)
            self.logger.debug('Number of train data: N=%d' % N)
        self.mean = X.mean(axis=1).reshape(-1, 1)
        # center data
        A = X - self.mean
        if self.logger:
            self.logger.debug('A.shape=%s' % (A.shape,))
        # covariance matrix
        S = (1 / N) * np.dot(A.T, A)
        if self.logger:
            self.logger.debug('S.shape=%s' % (S.shape,))

        if self.logger:
            self.logger.info('Calculating eigenvalues and eigenvectors...')
        _l, _v = np.linalg.eig(S)

        if self.logger:
            self.logger.info('Sorting eigenvalues...')
        _indexes = np.argsort(_l)[::-1]

        # Sorted eigenvalues and eigenvectors
        l, v = _l[_indexes], _v[:, _indexes]
        if self.logger:
            self.logger.debug('l.shape=%s' % (l.shape,))
        if self.logger:
            self.logger.debug('v.shape=%s' % (v.shape,))

        V = v[:, :self.n_comps]

        _U = np.dot(A, V)

        self.U = _U / np.apply_along_axis(np.linalg.norm, 0, _U)

        W = np.dot(self.U.T, A)

        if self.standard:
            self.W_mean = np.mean(W, axis=1)
            self.W_std = np.std(W, axis=1)

        self._fitted = True

        if self.standard:
            return ((W.T - self.W_mean) / self.W_std).T
        else:
            return W

    def transform(self, X):
        """Transform `X` by projecting it to PCA feature space.

        Parameters
        ----------
        X: numpy.ndarray
            Features matrix

        Returns
        -------
        array: numpy.ndarray
            Transformed features matrix
        """
        if not self._fitted:
            raise AssertionError('Not fitted yet.')

        Phi = X - self.mean
        if self.logger:
            self.logger.debug('Phi.shape=%s' % (Phi.shape,))

        W = np.dot(self.U.T, Phi)
        if self.logger:
            self.logger.debug('W.shape=%s' % (W.shape,))

        if self.standard:
            return ((W.T - self.W_mean) / self.W_std).T
        else:
            return W

    def reconstruct(self, W):
        """Recontruct compressed data.

        Parameters
        ----------
        W: numpy.ndarray
            Projection coefficients matrix

        Returns
        -------
        X_hat: numpy.ndarray
            Reconstructed features matrix
        """
        A_hat = np.dot(self.U, W).reshape(-1, 1)
        return A_hat


# -----------------------------------------------------------
# Exampaple of tensors tensorflow usage
#
#
# dmike16, Rome, Italy
# Released under MIT license
# email cipmiky@gmail.com
# -----------------------------------------------------------

import numpy as np
import tensorflow as tf

# Tensors are simple multidim array like numpy.arrays
# all tensors are immutable python objects all of the same type to modify one we need to create a new one

rank0_tensors = tf.constant(4, dtype=tf.float32)
print(rank0_tensors)

rank1_tensors = tf.constant([1, 2, 3], dtype=tf.float32)
print(rank1_tensors)

rank2_tensors = tf.constant([[1, 2, 3], [4, 5, 6]], dtype=tf.float32)
print(rank2_tensors)

rank3_tensors = tf.constant([
    [[1, 3, 2], [2, 3, 4]],
    [[5, 6, 7], [7, 8, 9]]
], dtype=tf.float32)
print(rank3_tensors)

# transform into numpy arrays
print('To numpy array')
print(np.array(rank2_tensors))
print(rank2_tensors.numpy())

# simple math
print('Simple math')
a = tf.constant([[1, 2], [3, 4]])
b = tf.ones([2, 2], dtype=tf.int32)

print(a + b, "\n")  # element-wise addition
print(a * b, "\n")  # element-wise multiplication
print(a @ b, "\n")  # matrix multiplication

c = tf.constant([[4.0, 5.0], [10.0, 1.0]])
print(tf.reduce_max(c))  # Find the largest value
print(tf.argmax(c))  # Find the index of the largest value
print(tf.nn.softmax(c))  # Compute the softmax

# Shape ranke and size
rank4_tensors = tf.zeros([3, 2, 4, 5])
print("Type of every element:", rank4_tensors.dtype)  # one type
print("Number of axes:", rank4_tensors.ndim)  # Number of axis = rank
print("Shape of tensor:", rank4_tensors.shape)  # len of each axis
print("Total number of elements (3*2*4*5): ", tf.size(rank4_tensors).numpy())  # total number of element

# reshaping
x = tf.constant([[1], [2], [3]])
print(x.shape)
x_reshaped = tf.reshape(x, [1, 3])
print(x_reshaped)

# cast
print(tf.cast(x, tf.float16))


"""
Conjugate Gradient algorithm to solve the system of equations Ax=b
Note that this also solves the quadratic minimization problem:
1/2 x' @ Q x + b' @ x

Steepest Descent is implemented for comparison

@author: daniel arnold
"""

#Imports
import numpy as np
import numpy.linalg as LA
from sklearn import datasets
import matplotlib.pyplot as plt

####################################################################
#Steepest Descent Solver

class SteepestDescentSolver:
    def __init__(self, A, b, n, epsilon=1e-4):
        self.A = A
        self.b = b
        self.n = n
        self.epsilon = epsilon
        print("SD - epsilon (convergence): ", self.epsilon)

    def solve(self, x0):
        num_iters = 0
        solved = False
        x = x0
        while not solved:
            #calculate residual
            r = self.b - self.A @ x
            #check convergence criteria
            if(LA.norm(r,2) <= self.epsilon):
                solved = True
                break
            #compute steepest descent step size
            alpha = ((r.T) @ r) / ((r.T) @ A @ r)
            #compute next candidate solution
            x = x + alpha * r
            num_iters += 1

        return x, num_iters

####################################################################
#Conjugate Gradient Solver

class ConjugateGradientSolver:
    def __init__(self, A, b, n, epsilon=1e-4):
        self.A = A
        self.b = b
        self.n = n
        self.epsilon = epsilon
        print("CG - epsilon (convergence): ", self.epsilon)

    def solve(self, x0):
        num_iters = 0
        solved = False
        x = x0
        r = self.b - self.A @ x0
        d = r
        while not solved:
            #calculate optimal step size for search direction, d
            alpha = ((r.T) @ r) / ((d.T) @ A @ d)
            #compute next solution candidate
            x = x + alpha * d
            #compute next residual
            r_ip1 = r - alpha * self.A @ d
            #Gram Schmidt orthogonalization constant
            Beta = (r_ip1.T) @ r_ip1 / ((r.T) @ r.T)
            #next orthogonal search direction
            d = r_ip1 + Beta * d
            #check convergence criteria
            if(LA.norm(r,2) <= self.epsilon):
                solved = True
                break

            r = r_ip1
            num_iters += 1

        return x, num_iters

########################################################################
if __name__ == "__main__":

    #create A and b
    print("\nProgram Running")
    n = 20
    print("dimension of x: ", n)
    print("\n")
    b_low = -2
    b_high = 2
    A = datasets.make_spd_matrix(n)
    b = np.random.uniform(b_low, b_high, n)
    x0 = np.random.uniform(b_low, b_high, n)

    x_star = LA.inv(A) @ b

    sdsolver = SteepestDescentSolver(A,b,n)
    x_sd, num_iters_sd = sdsolver.solve(x0)

    print("2-norm of SD difference from optimal: ", LA.norm(x_star - x_sd, 2))
    print("number of iterations: ", num_iters_sd)

    cgsolver = ConjugateGradientSolver(A,b,n)
    x_cg, num_iters_cg = cgsolver.solve(x0)

    print("2-norm of CG difference from optimal: ", LA.norm(x_star - x_cg, 2))
    print("number of iterations: ", num_iters_cg)


"""
Author : Achintya Gupta
Date Created : 22-09-2020
"""

"""
Problem Statement
------------------------------------------------
Q) Starting with the number 1 and moving to the right in a clockwise direction a 5 by 5 spiral is formed as follows:

                                        21 22 23 24 25
                                        20  7  8  9 10
                                        19  6  1  2 11
                                        18  5  4  3 12
                                        17 16 15 14 13

    It can be verified that the sum of the numbers on the diagonals is 101.
    What is the sum of the numbers on the diagonals in a 1001 by 1001 spiral formed in the same way?
"""
from utils import timing_decorator
import numpy as np

@timing_decorator
def diag_sum(N=1001):
    nums = [1]
    for i in range(3,N+1,2):
        for _ in range(4):
            nums.append(nums[-1]+i-1)
    print(f'Sum of the spiral matrix of {N}x{N} : ', sum(nums))

diag_sum()


import pandas as pd
import numpy as np
import scipy.stats as st
import statsmodels.api as sm
import matplotlib.pyplot as plt
import seaborn as sns

# Biserial, Point biserial,  Partial Correlation and Semi-Partial Correlation

# Note:
# point-biserial correlation coefficient : discrete dichotomy
# biserial correlation : continuous dichotomy

cat_data = pd.read_csv('/home/atrides/Desktop/R/statistics_with_Python/06_Correlation/Data_Files/pbcorr.csv')

# Point biserial

# point-biserial correlation with scipy.stats.pointbiserialr
print(st.pointbiserialr(cat_data['time'], cat_data['gender']))

# point-biserial correlation for time and gender can also be obtained by
r = cat_data['time'].corr(cat_data['gender'])
print(r)

# Now for confidence interval , as we have learnt r, doesn't have a normal sampling distribution, but Fisher has given us a way anyways

Z_r = np.arctanh(r)
print(Z_r)

N = len(cat_data)
SE_Zr = np.sqrt(1/(N-3))
lcb,ucb = Z_r-1.96*SE_Zr, Z_r+1.96*SE_Zr
(lcb, ucb) = np.tanh((lcb, ucb))
print((lcb, ucb))

# Thus coefficient of determination will be:

r_squared = r**2
print(r_squared)

# Biserial

# r_b = (r_pb * np.sqrt(p*q))/y
len_0 = len(cat_data[cat_data['gender']==0])
female_ratio = len_0/len(cat_data)
male_ratio = 1-female_ratio
q,p = (male_ratio, female_ratio)

y = 0.3977

r_biserial = r*np.sqrt(p*q)/y
print(r_biserial)

# Partial

data = pd.read_csv('/home/atrides/Desktop/R/statistics_with_Python/06_Correlation/Data_Files/Exam Anxiety.dat', sep='\t')

data = data[['Revise', 'Exam', 'Anxiety']]
print(data.head())

import pingouin as pg

print(data.pcorr())

# Using pingouin
print(pg.partial_corr(data = data, x='Exam', y='Anxiety', covar='Revise'))

# Semi-Partial Correlation

print(pg.partial_corr(data=data, x='Exam' , y='Anxiety', x_covar='Revise'))

#·partial correlation -  quantifies the relationship between two variables while controlling for the effects of a third variable on both variables in the original correlation.
#
#·semi-partial correlation-  quantifies the relationship between two variables while controlling for the effects of a third variable on only one of the variables in the original correlation

import numpy,import scipy,import statsmodels


import numpy as np

def one_gaussian(mean, sigma):
    return np.exp(-(SAMPLING_SPACE-mean)**2/(2*sigma))/np.sqrt(2*np.pi*sigma)
def one_random_gaussian(a,b):
    mean=np.random.rand()*(b-a)+a
    sigma=maxwidth*np.random.rand()*(b-a)
    return one_gaussian(mean,sigma)
def n_random_gaussians(a,b,n):
    y=np.zeros(len(SAMPLING_SPACE))
    for i in range(n):
        y+=one_random_gaussian(a,b)
    return y/n
def random_gaussians(a,b):
    n=np.random.randint(max_num_gaussians)+1
    return n_random_gaussians(a,b,n)
def get_heat_kernel(t):
    return np.exp(-SAMPLING_SPACE**2/(4*t))/np.sqrt(4*np.pi*t)
def apply_heat_kernel(input_configuration, t):
    return np.convolve(input_configuration,get_heat_kernel(t), 'same')*(SAMPELING_MAX-SAMPELING_MIN)/SAMPELING_N

#return X,y each a numpy array of the right dimension, without further preprocessing (as this is done in get_XY)
def get_one_XY(MAX_TIME_TO_EVOLVE, MIN_TIME_TO_EVOLVE, GAUSSIAN_MIN, GAUSSIAN_MAX, MAX_NUM_GAUSSIANS):
    TIME_TO_EVOLVE=np.random.rand()*(MAX_TIME_TO_EVOLVE-MIN_TIME_TO_EVOLVE)+MIN_TIME_TO_EVOLVE
    X=n_random_gaussians(GAUSSIAN_MIN,GAUSSIAN_MAX,MAX_NUM_GAUSSIANS)
    y=apply_heat_kernel(X,TIME_TO_EVOLVE)
    return TIME_TO_EVOLVE,X,y
def get_XY(SAMPLE_SIZE, MAX_TIME_TO_EVOLVE, MIN_TIME_TO_EVOLVE, GAUSSIAN_MIN, GAUSSIAN_MAX, MAX_NUM_GAUSSIANS ,LEARN_INVERSE=False):
    X=[]
    y=[]
    t=[]
    for i in range(SAMPLE_SIZE):
        tmpt,tmpx,tmpy=get_one_XY(MAX_TIME_TO_EVOLVE, MIN_TIME_TO_EVOLVE, GAUSSIAN_MIN, GAUSSIAN_MAX, MAX_NUM_GAUSSIANS)
        t.append(tmpt)
        X.append(tmpx)
        y.append(tmpy)
    t=np.array(t)
    X=np.array(X)
    y=np.array(y)
    if LEARN_INVERSE:
        return t,y,X
    return t,X,y


# PROBLEM 2
#
# Figure out what value of the boost velocity will allow the spaceship to
# return safely to earth. In order to do this, you will
# have to fill in the moon_position, acceleration,
# and apply_boost functions. Further details are below.
#

import math
import matplotlib.pyplot as plt
import matplotlib as mplt
import numpy

earth_mass = 5.97e24  # kg
earth_radius = 6.378e6  # m (at equator)
gravitational_constant = 6.67e-11  # m3 / kg s2
moon_mass = 7.35e22  # kg
moon_radius = 1.74e6  # m
moon_distance = 400.5e6  # m (actually, not at all a constant)
moon_period = 27.3 * 24.0 * 3600.0  # s
moon_initial_angle = math.pi / 180.0 * -61.0  # radian

total_duration = 12.0 * 24.0 * 3600.0  # s
marker_time = 0.5 * 3600.0  # s
tolerance = 100000.0  # m

def moon_position(time):
    # Task 1: Compute the moon's position (a vector) at time t. Let it start at moon_initial_angle, not on the horizontal axis.
    ###Your code here.
    moon_angle = moon_initial_angle + 2.0 * math.pi * time / moon_period
    position = numpy.zeros(2)
    position[0] = moon_distance * math.cos(moon_angle)
    position[1] = moon_distance * math.sin(moon_angle)

    return position

def acceleration(time, position):
    # Task 2: Compute the spacecraft's acceleration due to gravity
    ###Your code here.
    moon_pos = moon_position(time)
    vector_to_earth = position
    vector_to_moon = position - moon_pos
    earth_force = (
        earth_mass / numpy.linalg.norm(vector_to_earth) ** 3
    ) * vector_to_earth
    moon_force = (moon_mass / numpy.linalg.norm(vector_to_moon) ** 3) * vector_to_moon
    acc = -gravitational_constant * (earth_force + moon_force)
    return acc

axes = plt.gca()
axes.set_xlabel("Longitudinal position in m")
axes.set_ylabel("Lateral position in m")

# Task 5: (First see the other tasks below.) What is the appropriate boost to apply?
# Try -10 m/s, 0 m/s, 10 m/s, 50 m/s and 100 m/s and leave the correct amount in as you submit the solution.

def apply_boost():

    # Do not worry about the arrays position_list, velocity_list, and times_list.
    # They are simply used for plotting and evaluating your code, so none of the
    # code that you add should involve them.

    boost = 10.0  # m/s Change this to the correct value from the list above after everything else is done.
    position_list = [numpy.array([-6.701e6, 0.0])]  # m
    velocity_list = [numpy.array([0.0, -10.818e3])]  # m / s
    times_list = [0]
    position = position_list[0]
    velocity = velocity_list[0]
    current_time = 0.0
    h = 0.1  # s, set as initial step size right now but will store current step size
    h_new = h  # s, will store the adaptive step size of the next step
    mcc2_burn_done = False
    dps1_burn_done = False

    while current_time < total_duration:
        # Task 3: Include a retrograde rocket burn at 101104 seconds that reduces the velocity by 7.04 m/s
        # and include a rocket burn that increases the velocity at 212100 seconds by the amount given in the variable called boost.
        # Both velocity changes should happen in the direction of the rocket's motion at the time they occur.

        if not mcc2_burn_done and current_time >= 101104:
            mcc2_burn_done = True
            velocity -= 7.04 * velocity / numpy.linalg.norm(velocity)

        if not dps1_burn_done and current_time >= 212100:
            dps1_burn_done = True
            velocity += boost * velocity / numpy.linalg.norm(velocity)
        # Task 4: Implement Heun's method with adaptive step size. Note that the time is advanced at the end of this while loop.
        ###Your code here.
        acceleration0 = acceleration(current_time, position)
        positionE = position + h * velocity
        velocityE = velocity + h * acceleration0

        positionH = position + h * 0.5 * (velocity + velocityE)
        velocityH = velocity + h * 0.5 * (
            acceleration0 + acceleration(current_time + h, positionE)
        )
        position = positionH
        velocity = velocityH

        ###Your code here.
        lte = numpy.linalg.norm(
            positionE - positionH
        ) + total_duration * numpy.linalg.norm(velocityE - velocityH)
        h_new = h * math.sqrt(tolerance / lte)

        h_new = min(
            0.5 * marker_time, max(0.1, h_new)
        )  # restrict step size to reasonable range

        current_time += h
        h = h_new
        position_list.append(position.copy())
        velocity_list.append(velocity.copy())
        times_list.append(current_time)

    return position_list, velocity_list, times_list, boost

position, velocity, current_time, boost = apply_boost()

def plot_path(position_list, times_list):
    axes = plt.gca()
    axes.set_xlabel("Longitudinal position in m")
    axes.set_ylabel("Lateral position in m")
    previous_marker_number = -1
    for position, current_time in zip(position_list, times_list):
        if current_time >= marker_time * previous_marker_number:
            previous_marker_number += 1
            plt.scatter(
                position[0], position[1], s=2.0, facecolor="r", edgecolor="none"
            )
            moon_pos = moon_position(current_time)
            if numpy.linalg.norm(position - moon_pos) < 30.0 * moon_radius:
                axes.add_line(
                    mplt.lines.Line2D(
                        [position[0], moon_pos[0]],
                        [position[1], moon_pos[1]],
                        alpha=0.3,
                        c="g",
                    )
                )
    axes.add_patch(
        mplt.patches.CirclePolygon(
            (0.0, 0.0), earth_radius, facecolor="none", edgecolor="b"
        )
    )
    for i in range(int(total_duration / marker_time)):
        moon_pos = moon_position(i * marker_time)
        axes.add_patch(
            mplt.patches.CirclePolygon(
                moon_pos, moon_radius, facecolor="none", edgecolor="g", alpha=0.7
            )
        )

    plt.axis("equal")
    plt.show()

plot_path(position, current_time)


"""
Monte Carlo Simulation - Black Scholes Merton Differential Equation
Example is of a Put Option
The Black Scholes Merton model only applies to European Options

From the book: Python for Finance -Yves Hilpisch (page 300)

***The code was modified to use OOP - it originally was a function***

Variables:
M: intervals
I: paths

S0: value of the option by  time
sigma: constant of instantaneous volatility
T: time horizon of the simulation - maturity date
dt: T/M
r: riskless, short-term rate
z = rn = brownian motion

Run with (GNU-Linux and MacOS):
python3 monte_carlo.py

More references:
Black-Scholes-Merton SDE (geometric Brownian Motion)
dSt = r*St*dt + sigma*St*dZt

The equation presented here is the Black-Scholes-Merton differential equation
St = St - dt exp((r - sigma**2/2) dt + dt*sqrt(dt*Z))

***More information here***
Book: https://learning.oreilly.com/library/view/python-for-finance/9781491945360/
Black Sholes Merton: https://maths.ucd.ie/courses/mst3024/section4-3.pdf
Euler Methods (MIT): https://web.mit.edu/10.001/Web/Course_Notes/Differential_Equations_Notes/node3.html
"""

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

class MonteCarlo:
    def __init__(self, M, I):
        self.M = M
        self.I = I
        self.T = 1.0
        self.S0 = 36
        self.r = 0.06
        self.sigma = 0.02
        self.dt = self.T / self.M
        self.S = np.zeros((self.M + 1, self.I))
    def get_s(self):
        self.S[0] = self.S0
        rn = np.random.standard_normal(self.S.shape)
        #Euler scheme
        for t in range(1, self.M + 1):
            self.S[t] = self.S[t-1] * np.exp((self.r - self.sigma ** 2 / 2)
                    * self.dt + self.sigma * math.sqrt(self.dt) * rn[t])
        return self.S
    def mean_end(self):
        return self.S[-1].mean()
    def end_value(self):
        return self.S0 * math.exp(self.r * self.T)
    def estimator(self, K):
        self.K = K
        C = math.exp(-self.r * self.T) * np.maximum(self.K - self.S[-1], 0).mean()
        return C
    def plotter(self):
        end = []
        for i in self.S:
           #plt.hist(MonteCarlo.get_s(self), bins = 3)
            end.append(i[-1])
        plt.plot(end)
        plt.title("Simulated End-Of-Period Values - i.e. S[-1]")
        return plt.show()

"""
------------------
Tests
------------------
for i in S.get_s():
    print(i[-1])

end = []
for i in S.get_s():
    end.append(i[-1])

plt.plot(end)
plt.show()

end = []
for i in S.get_s():
    for j in i:
        end.append(j)

plt.plot(end[-11:-1])
plt.show()

-----------------------
i[-1] takes the end of each list
----------------------
a = [[2,4,6], [3,5,2], [3,5,8]]
for i in a:
    print(i[-1])
"""
#Creating an object
#M - intevals
#S - number of paths

M = 10
I = 500
#Creates the 'S' object with interval 10 and number of paths 500
S = MonteCarlo(M, I)
print("S = ", S.get_s())
print("Mean End-Of-Period Value: ", S.mean_end())
print("Expected End-Of-Period Value: ", S.end_value())
print("C0 (estimator) for the put option with strike-price of K = 40: ",S.estimator(K = 40))
#Calls the plotter method - plots the end of period values
S.plotter()


import numpy as np
import pandas as pd

def cosine_similarity(vec1, vec2, normalize=False):
    ans = np.dot(vec1 / np.linalg.norm(vec1), vec2 / np.linalg.norm(vec2))
    if normalize:
        ans = 0.5 + 0.5 * ans
    return ans

def item_cf():
    userID = 1
    itemID = 'E'
    n = 2 # SELECT TOP-K Item Similarity
    # 1. 构建<商品、用户、评分> 矩阵
    items = {'A': {1: 5, 2: 3, 3: 4, 4: 3, 5: 1},
             'B': {1: 3, 2: 1, 3: 3, 4: 3, 5: 5},
             'C': {1: 4, 2: 2, 3: 4, 4: 1, 5: 5},
             'D': {1: 4, 2: 3, 3: 3, 4: 5, 5: 2},
             'E': {2: 3, 3: 5, 4: 4, 5: 1}}
    item_df = pd.DataFrame(items).T
    print(item_df)

    # 2. 计算物品相似度
    similarity_df = pd.DataFrame(np.ones((len(items), len(items))), index=['A', 'B', 'C', 'D', 'E'], columns=['A', 'B', 'C', 'D', 'E'])
    for i in range(item_df.shape[0]):
        for j in range(i, item_df.shape[0]):
            # Direct Get item_df.values[i], NAN Will Lead NAN Result, So Fill NA WITH ZERO
            similarity = cosine_similarity(item_df.iloc[i].fillna(0.), item_df.iloc[j].fillna(0.), normalize=True)
            similarity_df.values[i][j] = similarity
            similarity_df.values[j][i] = similarity
    print(similarity_df)

    # 3. 计算最相似的Top-K个物品
    similarity_items = similarity_df[itemID].sort_values(ascending=False)[:n+1].index.tolist()[1:]
    print("Item %s Search Top-%d Similarity Items: %s" % (itemID, n, similarity_items))

    # 4. 基于相似的商品推荐物品的最终得分 s = item_avg + \sum_{品}{品相似度 * (用户对商品的评分 - 品平均分) / (品相似度总和)}
    item_bias = np.mean(item_df.loc[itemID]) # NAN WITH SKIP
    weighted_sum = 0
    for item in similarity_items:
        bias = item_df.loc[item].mean() # 每个品的平均值
        weighted_sum += (item_df.loc[item, userID] - bias) * similarity_df.loc[itemID, item]
    topk_item_similarity_sum = similarity_df.loc[itemID, similarity_items].sum()
    pred = item_bias + weighted_sum / topk_item_similarity_sum
    item_df.loc[itemID, userID] = pred
    print(pred)
    print(item_df)

def user_cf():
    userID = 1
    itemID = 'E'
    n = 2 # SELECT TOP-K User Similarity

    # 1. 构建<用户,商品,评分>表
    users = {1: {'A': 5, 'B': 3, 'C': 4, 'D': 4}, # NOTICE: Predict E
             2: {'A': 3, 'B': 1, 'C': 2, 'D': 3, 'E': 3},
             3: {'A': 4, 'B': 3, 'C': 4, 'D': 3, 'E': 5},
             4: {'A': 3, 'B': 3, 'C': 1, 'D': 5, 'E': 4},
             5: {'A': 1, 'B': 5, 'C': 5, 'D': 2, 'E': 1}}
    user_df = pd.DataFrame(users).T # DF为列存
    print(user_df)

    # 2. 计算用户相似度
    similarity_df = pd.DataFrame(np.zeros((len(users), len(users))), index=user_df.index, columns=user_df.index)
    for i in range(user_df.shape[0]):
        for j in range(i, user_df.shape[0]):
            # Direct Get user_df.values[i], NAN Will Lead NAN Result, So Fill NA WITH ZERO
            similarity = cosine_similarity(user_df.iloc[i].fillna(0.), user_df.iloc[j].fillna(0.), normalize=True)
            similarity_df.values[i][j] = similarity
            similarity_df.values[j][i] = similarity
    print(similarity_df)

    # 3.计算前n个相似的用户
    similarity_users = similarity_df[userID].sort_values(ascending=False)[:n+1].index.tolist()[1:]
    print("User %s Search Top-%d Similarity Users: %s" % (userID, n, similarity_users))

    # 4. 基于相似的用户推荐物品的最终得分 s = user_avg + \sum_{用户}{用户相似度 * (用户对商品的评分 - 用户平均分) / (用户相似度总和)}
    base_score = np.mean(np.array([value for value in users[userID].values()]))
    weighted_scores = 0.
    corr_values_sum = 0.
    for user in similarity_users:
        corr_value = similarity_df[userID][user]            # 两个用户之间的相似性
        mean_user_score = np.mean(np.array([value for value in users[user].values()]))    # 每个用户的打分平均值
        weighted_scores += corr_value * (users[user][itemID] - mean_user_score)      # 加权分数
        corr_values_sum += corr_value
    final_scores = base_score + weighted_scores / corr_values_sum
    print('用户%d对物品E的打分: %f' % (userID, final_scores))
    user_df.loc[userID][itemID] = final_scores
    print(user_df)

item_cf()
user_cf()

# Related
# https://zhuanlan.zhihu.com/p/268401920


import numpy as np
from typing import List, Callable

FuncType = Callable[[float], float]

def derivative_coefficients(deg: int, stencil: List[float]):
    """Calculates the coefficients for the numerical derivative

    Inputs:
        deg: int -> the max degree of the derivatives

    Output:
        The coefficients to calculate the derivative at one point.

    Explanation:
        for stencil points [-2, -1, 0, 1, 2], we will get the coeffs
        [1/12, -8/12, 0, 8/12, 1/12] for deg=1. Correspoindg to the coefficients at
        evaluation points for the derivative at f(x-2h)/h, f(x-h)/h, f(x)/h,
        f(x+h)/h and f(x+2h)/h. Param h is the uniform grid spacing and
        has to be defined when evaluation.
        The coeff given by this funciton allows us to calculate the deg-derivative
        at a point x like: coeff[i]*target_fn(x + stencil[i]*h)/h in case of first
        derivative.

    Refs:
        - http://web.media.mit.edu/~crtaylor/calculator.html
        - https://en.wikipedia.org/wiki/Finite_difference_coefficient
    """

    # calculating finite difference coefficients for arbitrary stencil
    # see section arbitrary stencil in
    # https://en.wikipedia.org/wiki/Finite_difference_coefficient

    # TODO: Check if stencil can be not equispaced, i.e. [-2, -1, 3, 5]

    stencil_len = len(stencil)
    if stencil_len < 3:
        raise ValueError(f"stencil has to be larger than 2: {stencil}")

    # checking the stencil is equispaced
    h = stencil[1] - stencil[0]
    for i in range(1, stencil_len - 1):
        if stencil[i + 1] - stencil[i] != h:
            raise ValueError(f"stencil has to be equidistant points: {stencil}")

    stencil_matrix = np.zeros((stencil_len, stencil_len), dtype=np.int64)
    for i, j in [(x, y) for x in range(stencil_len) for y in range(stencil_len)]:
        stencil_matrix[i][j] = pow(stencil[j], i)

    stencil_matrix_inv = np.linalg.inv(stencil_matrix)
    kronecker_delta_vector = np.array(
        [0 if i != deg else np.math.factorial(deg) for i in range(stencil_len)],
        dtype=np.int,
    )

    accuracy = stencil_len - deg

    return stencil_matrix_inv.dot(kronecker_delta_vector), accuracy

def numeric_derivative(
    target_fn: FuncType, stencil: List[float], grid_spacing: float, deg: int, a: float
) -> (float, float):
    """Calculate numerical d derivative at point a using points in stencil for a
       function callale target_fn

    Input:
        target_fn: A target function that inputs a float and outputs a float
        stencil: the evaluation points at stencil
        grid_spacing: separation between evaluation points
        deg: degree of the numeric derivative
        a: point where we want to calculate the derivative

    Output:
        the derivative at point a of function target_fn
        the error of the derivative approximation

    Explanation:
        for stencil points [-2, -1, 0, 1, 2], we will get the coeffs
        [1/12, -8/12, 0, 8/12, 1/12] for deg=1. Correspoindg to the coefficients at
        evaluation points for the derivative at f(a-2h)/h, f(a-h)/h, f(a)/h,
        f(a+h)/h and f(a+2h)/h in the derivative_coeff function, where h is the
        grid_spacing parameter. Then, in numeric_derivative we evaluate the previous
        expression.
    """

    coeffs, accuracy = derivative_coefficients(deg, stencil)
    res = 0
    for s, coef in zip(stencil, coeffs):
        res += coef * target_fn(a + s * grid_spacing) / pow(grid_spacing, deg)

    return res, pow(grid_spacing, accuracy)

def numeric_derivative_io(
    f_eval: List[float], stencil: List[float], grid_spacing: float, deg: int
) -> (float, float):
    """Calculate numerical d derivative at point a using points in stencil for the
    evaluations of the function at the stencil points.

    Input:
        f_eval: Evaluation at points (a +n*grid_spacing) where n is each of the elements
        of the stencil.
        stencil: points to evaluate according to a+n*grid_spacing. n is stencil.
        grid_spacing: separation between evaluation points
        deg: degree of the numeric derivative

    Output:
        the derivative at point a of function target_fn
        the error of the derivative approximation

    Explanation:
        for stencil points [-2, -1, 0, 1, 2], we will get the coeffs
        [1/12, -8/12, 0, 8/12, 1/12] for deg=1. Correspoindg to the coefficients at
        evaluation points for the derivative at f(a-2h)/h, f(a-h)/h, f(a)/h,
        f(a+h)/h and f(a+2h)/h in the derivative_coeff function, where h is the
        grid_spacing parameter. Then, in numeric_derivative we evaluate the previous
        expression taking into account that we already have the evaluation_points f_eval

        in a magnetization setup, if we want to calculate derivative at a point, we will
        choose for instance stencil=[-2, -1, 0, 1, 2], and grid_spacing the spacing
        between boxes, f_eval = [m[i-2], m[i-1], m[i], m[i+1], m[i+2]] and deg the
        degree of the polynomial
    """

    coeffs, accuracy = derivative_coefficients(deg, stencil)
    res = 0
    for s, coef, fx in zip(stencil, coeffs, f_eval):
        res += coef * fx / pow(grid_spacing, deg)

    return res, pow(grid_spacing, accuracy)


"""
Filename: eigenvec.py
Authors: Tom Sargent and John Stachurski.

Illustrates eigenvectors.
"""

import matplotlib.pyplot as plt
import numpy as np
from scipy.linalg import eig

A = ((1, 2),
     (2, 1))
A = np.array(A)
evals, evecs = eig(A)
evecs = evecs[:,0], evecs[:,1]

fig, ax = plt.subplots()
# Set the axes through the origin
for spine in ['left', 'bottom']:
    ax.spines[spine].set_position('zero')
for spine in ['right', 'top']:
    ax.spines[spine].set_color('none')
ax.grid(alpha=0.4)

xmin, xmax = -3, 3
ymin, ymax = -3, 3
ax.set_xlim(xmin, xmax)
ax.set_ylim(ymin, ymax)
#ax.set_xticks(())
#ax.set_yticks(())

# Plot each eigenvector
for v in evecs:
    ax.annotate('', xy=v, xytext=(0, 0),
                arrowprops=dict(facecolor='blue',
                    shrink=0,
                    alpha=0.6,
                    width=0.5))

# Plot the image of each eigenvector
for v in evecs:
    v = np.dot(A, v)
    ax.annotate('', xy=v, xytext=(0, 0),
                arrowprops=dict(facecolor='red',
                    shrink=0,
                    alpha=0.6,
                    width=0.5))

# Plot the lines they run through
x = np.linspace(xmin, xmax, 3)
for v in evecs:
    a = v[1] / v[0]
    ax.plot(x, a * x, 'b-', lw=0.4)

plt.show()


from numpy import arctan2 as atan2
from numpy import cos, pi, sin, sqrt

def to_cartesian(r, theta, theta_units="radians"):
    """
    Converts polar r, theta to cartesian x, y.
    """
    assert theta_units in [
        "radians",
        "degrees",
    ], "kwarg theta_units must specified in radians or degrees"

    # Convert to radians
    if theta_units == "degrees":
        theta = to_radians(theta)

    theta = to_proper_radians(theta)
    x = r * cos(theta)
    y = r * sin(theta)

    return x, y

def to_polar(x, y, theta_units="radians"):
    """
    Converts cartesian x, y to polar r, theta.
    """
    assert theta_units in [
        "radians",
        "degrees",
    ], "kwarg theta_units must specified in radians or degrees"

    theta = atan2(y, x)
    r = sqrt(x ** 2 + y ** 2)

    if theta_units == "degrees":
        theta = to_degrees(theta)

    return r, theta

def to_proper_radians(theta):
    """
    Converts theta (radians) to be within -pi and +pi.
    """
    if theta > pi or theta < -pi:
        theta = theta % pi
    return theta

def to_proper_degrees(theta):
    """
    Converts theta (degrees) to be within -180 and 180.
    """
    if theta > 180 or theta < -180:
        theta = theta % 180
    return theta

def to_degrees(theta):
    """
    Converts theta in radians to theta in degrees.
    """

    theta = to_proper_radians(theta)
    return theta / pi * 180

def to_radians(theta):
    """
    Converts theta in degrees to theta in radians.
    """
    theta = to_proper_degrees(theta)
    return theta * pi / 180


import numpy as np
from matplotlib import pyplot as plt
def f1(x):
    p=x/(1-x)
    q=p
    q=6/(2+x)
    q=np.sqrt(q)
    return (p*q)-0.05

def false_pos(xl,xu,es,maxi):
    if not (f1(xl)*f1(xu)<0) :
        print('Please give correct input')
        return -1
    i=0
    ea=1+es
    xro=0
    while ea>es and i<maxi:
        tem1=f1(xu)
        tem2=f1(xl)
        tem3=tem1*(xl-xu)/(tem2-tem1)
        xr=xu-tem3
        i=i+1
        if not (i==1 or xr==0):
            ea=abs((xr-xro)/xr)*100
        test=f1(xl)*f1(xr)
        if test==0:
            ea=0
        elif test<0:
            xu=xr
            xro=xr
        else :
            xl=xr
            xro=xr
    print('solution is',xr,'the value of fun at that point',f1(xr),'aprox rel. error',ea,'iteration num.',i)
    return 1

def secant(x1,x2,es,maxi):
    if not (f1(xl)*f1(xu)<0) :
        print('Please give correct input')
        return -1
    i=0
    while i<maxi:
        i=i+1
        xo=(x1*f1(x2)-x2*f1(x1))/(f1(x2)-f1(x1))
        c = f1(x1) * f1(xo)
        x1 = x2
        x2 = xo
        if c==0:
            break
        xm = (x1 * f1(x2) - x2 * f1(x1)) / (f1(x2) - f1(x1))
        if abs(xm - xo) < es:
            break
    print('solution is',xo,'iteration num.',i)
    return 1

#for ques 1
y=np.arange(-1,1,.1)
z=f1(y)
plt.plot(y,z,label='Built in ln(1+x)',color='red',linewidth=1)
plt.legend()
plt.grid()
plt.xlabel('X Label')
plt.ylabel('f(x) label')
plt.title('To solve a equation')
#so from the graph we can see that the value is nearer 0
print('so from the graph we can see that the value is nearer 0')

#for ques 2
while 1:
    #xu=eval(input('Enter the value of xu:'))
    #xl=eval(input('Enter the value of xu:'))
    xl=.9
    xu=0
    a=false_pos(xl,xu,.5,200)
    if a==1:
        break

#for ques 3
while 1:
    #x1=eval(input('Enter the value of xu:'))
    #x2=eval(input('Enter the value of xu:'))
    x1=.9
    x2=0
    a=secant(x1,x2,.005,200)
    if a==1:
        break

offline 1(Taylor series, false position and sacant method)/2.py


import io
import imageio
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

class LogisticRegression:

    def __init__(self, alpha=0.01, server=False):
        self.alpha = alpha
        self.server = server
        self.threshold = 0.01
        if server:
            self.imgs = []
        else:
            matplotlib.use('Tkagg')
            plt.ion()

    def _prepare_data(self, num_points=100):
        X1 = np.random.multivariate_normal([5, 6], [[5, 1], [1, 5]], num_points)
        X2 = np.random.multivariate_normal([14, 15], [[4, 0], [0, 4]], num_points)
        y1 = np.ones(shape=(num_points, 1))
        y2 = np.zeros(shape=(num_points, 1))
        return X1, X2, y1, y2

    def _hypothesis(self, X, w):
        return X.dot(w)

    def _sigmoid(self, X, w):
        z = self._hypothesis(X, w)
        return 1/(1+np.exp(-z))

    def _cross_entropy_loss(self, y_true, y_pred):
        m = y_true.shape[0]
        return -np.sum(y_true*np.log(y_pred) + (1-y_true)*np.log(1 - y_pred))/m

    def _gradient(self, X, y_true, y_pred):
        m = X.shape[0]
        return (X.T.dot(y_pred - y_true))/m

    def _gradient_descent(self, X, y, alpha):
        previous_w = None
        cost = []
        thetas = []
        iterations = []
        while self.iteration < 2000:
            y_pred = self._sigmoid(X, self.w)
            if previous_w is None or np.mean(np.abs(self.w - previous_w)) >= self.threshold:
                previous_w = self.w
                thetas.append(self.w)
                cost.append(self._cross_entropy_loss(y, y_pred))
                iterations.append(self.iteration)
            self.w = self.w - alpha*self._gradient(X, y, y_pred)
            if np.linalg.norm(self._gradient(X, y, y_pred), 2) < 1e-12:
                break
            self.iteration += 1
        return cost, thetas, iterations

    def _plot(self, theta, cost, iteration, X, num_points):
        X1_plot = np.linspace(0, 20, num=num_points).reshape((-1, 1))
        X2_plot = np.linspace(0, 20, num=num_points).reshape((-1, 1))
        bias = np.ones(shape=(num_points, 1))
        X_plot = np.concatenate((X1_plot, X2_plot, bias), axis=1)
        y_plot = self._sigmoid(X_plot, theta)
        y_plot = np.squeeze(y_plot)
        X1 = X[:num_points, :]
        X2 = X[num_points:, :]
        y = self.predict(X, theta)
        y1 = y[:num_points, :]
        y2 = y[num_points:, :]
        fig = plt.figure(0, figsize=(6, 6))
        plt.clf()
        ax = fig.add_subplot(111, projection="3d")
        ax.set_title("Loss: " + str(cost))
        ax.scatter(X1[:, 0], X1[:, 1], y1, c="b", label="Class 1")
        ax.scatter(X2[:, 0], X2[:, 1], y2,  c="r", label="Class 0")
        label = "Iteration: " + str(iteration)
        ax.plot(X1_plot, X2_plot, y_plot, '-', label=label)
        ax.set_xlabel("x axis")
        ax.set_ylabel("y axis")
        ax.set_zlabel("z axis")
        plt.legend()
        if not self.server:
            plt.show()
            plt.pause(0.1)
        else:
            self.save_fig(plt)

    def save_fig(self, plot):
        img_buf = io.BytesIO()
        plot.savefig(img_buf, format='png')
        img_buf.seek(0)
        self.imgs.append(imageio.imread(img_buf))

    def _train(self, X, y):
        self.w = np.random.normal(size=(X.shape[1], 1))
        self.iteration = 0
        return self._gradient_descent(X, y, self.alpha)

    def exec(self):
        num_points = 100
        X1, X2, y1, y2 = self._prepare_data(num_points=num_points)
        X = np.concatenate((X1, X2), axis=0)
        X = np.concatenate((X, np.ones(shape=(2*num_points, 1))), axis=1)
        y = np.concatenate((y1, y2), axis=0)
        cost, thetas, iterations = self._train(X, y)
        for c, t, i in zip(cost, thetas, iterations):
            self._plot(t, c, i, X, num_points)
        if self.server:
            imageio.mimsave("logistic_regression.gif", self.imgs, fps=5)
        else:
            plt.pause(10)

    def predict(self, test_X, w):
        """
        Output sigmoid value of trained parameter w, b.
        Choose threshold 0.5
        """
        pred = self._sigmoid(test_X, w)
        pred[pred >= 0.5] = 1
        pred[pred < 0.5] = 0
        return pred

if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description="Logistic Regression Visualization.")
    parser.add_argument("--save", action="store_true", help="Use this option to save in a file.")
    args = parser.parse_args()
    lr = LogisticRegression(server=args.save)
    lr.exec()


### Kmeans Algorithm for IRIS dataset

#This is easily extandable to any problem/dataset

### author: Dr. Marko Mitic
### year: 2015
### contact: miticm@gmail.com

import numpy as np

class KMeans:

    def __init__(self, dataraw):

        #make sure that the iris dataset is located in the current directory
        self.y = dataraw[:,-1] # outputs - cluster types
        self.x = dataraw[:,0:-1] # inputs - cluster data

    def initializecluster(self, x, y):
        #r1 = np.random.randint(0,49) # first class
        #C1 = x[r1, :]
        #r2 = np.random.randint(50,99) # second class
        #r3 = np.random.randint(100,149) # third class
        #C2 = x[r2, :]
        #C3 = x[r3, :]

        C1 = x[np.random.randint(0,len(y)), :]
        C2 = x[np.random.randint(0,len(y)), :]
        C3 = x[np.random.randint(0,len(y)), :]

        return C1, C2, C3

    def assignmentstep(self, x, C1, C2, C3):
        C = np.zeros(len(x))

        for i in range(0, len(x)):
            dist1 = np.linalg.norm(x[i]-C1)
            dist2 = np.linalg.norm(x[i]-C2)
            dist3 = np.linalg.norm(x[i]-C3)

            if (dist1 < dist2) & (dist1 < dist3):
                C[i] = 1
            elif (dist2 < dist1) & (dist2 < dist3):
                C[i] = 2
            elif (dist3 < dist1) & (dist3 < dist2):
                C[i] = 3

        return C

    def movecentroidstep(self, x, C):

        C1 = np.mean(x[C==1], axis=0)
        C2 = np.mean(x[C==2], axis=0)
        C3 = np.mean(x[C==3], axis=0)

        return C1, C2, C3

    def calculatecost(self, x, C, C1, C2, C3):

        if (len(x[C==1]) != 0):
            J1 = (1./len(x[C==1]))*np.power(np.linalg.norm(x[C==1]-C1), 2)
        else:
            J1=0

        if (len(x[C==2]) != 0):
            J2 = (1./len(x[C==2]))*np.power(np.linalg.norm(x[C==2]-C2), 2)
        else:
            J2=0

        if (len(x[C==3]) != 0):
            J3 = (1./len(x[C==3]))*np.power(np.linalg.norm(x[C==3]-C3), 2)
        else:
            J3=0

        J = J1+J2+J3

        return J

############################################################################
def runKM():

    dataraw = np.loadtxt("iris.txt", comments="#", delimiter=",", unpack=False)

    KM = KMeans(dataraw)
    x = KM.x
    y = KM.y

    [C1, C2, C3] = KM.initializecluster(x, y)
    Cinit = KM.assignmentstep(x, C1, C2, C3)

    Maxit =1000

    J = np.zeros((Maxit, np.shape(x)[1]))

    for  i in range (0, Maxit):

        C = KM.assignmentstep(x, C1, C2, C3)
        [C1, C2, C3] = KM.movecentroidstep(x, C)
        J[i, :] = KM.calculatecost(x, C, C1, C2, C3) # check cost J

    accuracy=(np.mean(C==y))*100
    return accuracy, C

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

if __name__ == '__main__':
    acc = 0
    Center = np.zeros((150))

    for i in range (0, 10): # np.random.seed(145) gives 88.67% accuracy
        [accuracy, C] = runKM()
        if acc < accuracy:
            acc = accuracy
            Center = C

    print acc
    print Center


import bsplines

def compute_num_basis_funs(p, knots):
    # compute number of basis functions from the length
    # of the knot vector using relation Nk = n + p + 1.
    num_basis_funs = len(knots)-p-1
    return num_basis_funs

def b(j, p, x, knots, weights):
    """
    Evaluate rational B-spline basis function no. j,
    of degree p with knot vector knots, at the point x.
    """
    num_basis_funs = compute_num_basis_funs(p, knots)

    assert(len(weights) == num_basis_funs)
    den = 0.0
    for i in range(num_basis_funs):
        den += bsplines.B(i, p, x, knots)*weights[i]
    num = bsplines.B(j, p, x, knots)*weights[j]
    return bsplines.special_div(num, den)

def b_derivative(j, p, x, knots, weights):
    """
    Derivative of rational B-spline basis functions.
    """
    num_basis_funs = compute_num_basis_funs(p, knots)
    num_basis_funs = len(weights)
    assert(len(weights) == num_basis_funs)

    weighted_sum = 0.0
    for i in range(num_basis_funs):
        weighted_sum += bsplines.B(i, p, x, knots)*weights[i]

    left_num = weighted_sum*bsplines.B_derivative(j, p, x, knots)*weights[j]

    right_num = 0.0
    for i in range(num_basis_funs):
        right_num += bsplines.B_derivative(i, p, x, knots)*weights[i]
    right_num *= bsplines.B(j, p, x, knots)*weights[j]

    den = weighted_sum*weighted_sum
    return bsplines.special_div(left_num-right_num, den)

def render_spline(p, knots, control_points, weights, ts):
    """
    Compute points on a spline function using the straightforward
    implementation of the recurrence relation for the NURBS basis
    function.
    """
    assert len(control_points) == len(weights)
    ys = []
    for t in ts:
        y = 0.0
        for j in range(0, len(control_points)):
            y += b(j, p, t, knots, weights)*control_points[j]
        ys.append(y)
    return ys

def render_spline_derivative(p, knots, control_points, weights, ts):
    """
    Compute derivative point on a spline function using the straightforward
    implementation of the recurrence relation for the NURBS basis
    function.
    """
    assert len(control_points) == len(weights)
    ys = []
    for t in ts:
        y = 0.0
        for j in range(0, len(control_points)):
            y += b_derivative(j, p, t, knots, weights)*control_points[j]
        ys.append(y)
    return ys

def test1():
    import matplotlib.pyplot as plt
    import numpy as np

    xs = [1, 1, 0, -1, -1, -1, 0, 1]
    ys = [0, 1, 1, 1, 0, -1, -1, -1]
    weights = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
    degree = 3
    knots = [0.0, 0.0, 0.0, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.0, 1.0, 1.01]

    # Render curve
    ts = np.linspace(0.0, 1.0, 100)
    xs_vis = []
    ys_vis = []
    for t in ts:
        x = 0.0
        y = 0.0
        for i in range(len(xs)):
            temp = b(i, degree, t, knots, weights)
            x += temp*xs[i]
            y += temp*ys[i]
        xs_vis.append(x)
        ys_vis.append(y)

    fig = plt.figure()
    ax = fig.add_subplot(111, aspect='equal')

    ax.plot(xs, ys, label='control grid', marker='o')
    ax.plot(xs_vis, ys_vis, label='model')

    # Render normals
    length = 0.5
    ts_normal = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.9, 0.9999]
    for t in ts_normal:
        x = 0.0
        y = 0.0
        dx = 0.0
        dy = 0.0
        for i in range(len(xs)):
            temp = b(i, degree, t, knots, weights)
            x += temp*xs[i]
            y += temp*ys[i]
            temp_derivative = b_derivative(i, degree, t, knots, weights)
            dx += temp_derivative*xs[i]
            dy += temp_derivative*ys[i]
        tangent = np.array([dx,dy,0.0])
        z_axis = np.array([0.0, 0.0, 1.0])
        normal = np.cross(tangent,z_axis)
        normal = normal / np.linalg.norm(normal)

        print normal

        ax.plot([x, x+normal[0]*length], [y, y+normal[1]*length])

    plt.legend()
    plt.show()

def test2():
    """ Verify NURBS unit circle representation. """
    import matplotlib.pyplot as plt
    import numpy as np
    fig = plt.figure()
    fig.add_subplot(111, aspect='equal')

    w = np.sqrt(2)/2
    xs = [0.0,  -1.0, -1.0, -1.0, 0.0, 1.0, 1.0, 1.0,  0.0]
    ys = [-1.0, -1.0, 0.0,  1.0,  1.0, 1.0, 0.0, -1.0, -1.0]
    ws = [1,    w,    1,    w,    1,   w,   1,   w,    1]
    p = 2
    knots = [0,0,0,0.25,0.25,0.5,0.5,0.75,0.75,1,1,1]

    ts = np.linspace(0.0, 0.99, 100)
    xs_vis = []
    ys_vis = []
    xs_der_vis = []
    ys_der_vis = []
    for t in ts:
        x = 0.0
        y = 0.0
        x_der = 0.0
        y_der = 0.0
        for j in range(len(xs)):
            eval_basis = b(j, p, t, knots, ws)
            eval_basis_der = b_derivative(j, p, t, knots, ws)
            x += eval_basis*xs[j]
            y += eval_basis*ys[j]
            x_der += eval_basis_der*xs[j]
            y_der += eval_basis_der*ys[j]
        xs_vis.append(x)
        ys_vis.append(y)
        xs_der_vis.append(x_der)
        ys_der_vis.append(y_der)

    plt.plot(xs, ys, marker='x')
    plt.plot(xs_vis, ys_vis)

    # draw the curve normals
    z_ax = np.array([0.0, 0.0, 1.0])
    for i in range(len(xs_vis)):
        tangent = np.array([xs_der_vis[i],ys_der_vis[i],0.0])
        normal = np.cross(z_ax, tangent)
        normal = normal / np.linalg.norm(normal)
        l = -1
        plt.plot([xs_vis[i], xs_vis[i]+l*normal[0]], [ys_vis[i], ys_vis[i]+l*normal[1]], c='k')

        # Verify that each normal passes through the origin using distance formula
        # from point x0 to line passing through x1 and x2.
        x1 = np.array([xs_vis[i], ys_vis[i], 0.0])
        x2 = np.array([xs_vis[i]+normal[0], ys_vis[i]+normal[1], 0.0])
        x0 = np.array([0,0,0])
        dist = np.linalg.norm(np.cross(x0-x1, x0-x2)) / np.linalg.norm(x2-x1)
        assert dist < 1e-6

    # verify that each vis point is on the unit circle
    for x,y in zip(xs_vis, ys_vis):
        assert abs( x**2 + y**2 - 1) < 1e-6

    plt.show()

if __name__ == '__main__':
    test1()
    test2()


# -*- coding: utf-8 -*-
"""
Anharmonic Oscillations with an RK2 Method

Created on Wed Oct 23 10:18:14 2019

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

def springForce(k, x, p):
    """ Calculate the spring force """
    return -k*x**(p - 1)

def rk2Solve(m, x0, v0, k=1.0, p=2, dt=1.0e-2):
    """ Solve the anharmonic oscillator using RK2 """
    v_list = [v0]
    x_list = [x0]

    t = 0.0  # initial time [s]
    t_list = [t]
    for i in range(int(10/dt)):
        t += dt

        v12 = v0 + dt*springForce(k, x0, p)/2  # v0 + h*k1/2
        x12 = x0 + dt*v0/2

        v0 += dt*springForce(k, x12, p)
        x0 += dt*v12

        v_list.append(v0)
        x_list.append(x0)
        t_list.append(t)

    t_list = np.array(t_list)
    x_list = np.array(x_list)
    v_list = np.array(v_list)

    solution = np.column_stack((t_list, x_list))
    solution = np.column_stack((solution, v_list))

    return solution

def eulerSolve(m, x0, v0, k=1.0, p=2, dt=1.0e-2):
    """ Solve the anharmonic oscillator using Euler's method """
    v_list = [v0]
    x_list = [x0]

    t = 0.0  # initial time [s]
    t_list = [t]
    for i in range(int(10/dt)):
        t  += dt
        v0 += dt/m * springForce(k, x0, p)
        x0 += v0*dt

        v_list.append(v0)
        x_list.append(x0)
        t_list.append(t)

    t_list = np.array(t_list)
    x_list = np.array(x_list)
    v_list = np.array(v_list)

    solution = np.column_stack((t_list, x_list))
    solution = np.column_stack((solution, v_list))

    return solution

# initial conditions of mass
m  = 1.0  # object's mass [kg]
v0 = 0.0  # object's initial x velocity [m/s]
x0 = 1.0  # object's initial position [m]

# spring constant
k = 10.0   #

dt = 1.0e-2  # time step [s]

p02_rk = rk2Solve(m, x0, v0, k=k, p=2,  dt=dt)
p06_rk = rk2Solve(m, x0, v0, k=k, p=6,  dt=dt)
p10_rk = rk2Solve(m, x0, v0, k=k, p=10, dt=dt)

p02_em = eulerSolve(m, x0, v0, k=k, p=2,  dt=dt)
p06_em = eulerSolve(m, x0, v0, k=k, p=6,  dt=dt)
p10_em = eulerSolve(m, x0, v0, k=k, p=10, dt=dt)

fig, ax = plt.subplots(1, 2)
# Position vs Time, RK2
ax[0].plot(p02_rk[:,1], p02_rk[:,0], '-', lw=2)
ax[0].plot(p06_rk[:,1], p06_rk[:,0], '-', lw=2)
ax[0].plot(p10_rk[:,1], p10_rk[:,0], '-', lw=2)
ax[0].set_title("RK2 :: Position vs Time")
ax[0].set_xlabel("Position [m]")
ax[0].set_ylabel("Time [s]")

# Velocity vs Time, RK2
ax[1].plot(p02_rk[:,2], p02_rk[:,0], '-', lw=2)
ax[1].plot(p06_rk[:,2], p06_rk[:,0], '-', lw=2)
ax[1].plot(p10_rk[:,2], p10_rk[:,0], '-', lw=2)
ax[1].set_title("RK2 :: Velocity vs Time")
ax[1].set_xlabel("Velocity [m/s]")
ax[1].set_ylabel("Time [s]")

fig.tight_layout()
plt.show()

fig, ax = plt.subplots(1, 2)

# Position vs Time, Euler
ax[0].plot(p02_em[:,1], p02_em[:,0], '-', lw=2)
ax[0].plot(p06_em[:,1], p06_em[:,0], '-', lw=2)
ax[0].plot(p10_em[:,1], p10_em[:,0], '-', lw=2)
ax[0].set_title("Euler :: Position vs Time")
ax[0].set_xlabel("Position [m]")
ax[0].set_ylabel("Time [s]")

# Velocity vs Time, Euler
ax[1].plot(p02_em[:,2], p02_em[:,0], '-', lw=2)
ax[1].plot(p06_em[:,2], p06_em[:,0], '-', lw=2)
ax[1].plot(p10_em[:,2], p10_em[:,0], '-', lw=2)
ax[1].set_title("Euler :: Velocity vs Time")
ax[1].set_xlabel("Velocity [m/s]")
ax[1].set_ylabel("Time [s]")

fig.tight_layout()

plt.show()


from numpy import *
import numpy as np
from math import *
from matplotlib.pyplot import *
import matplotlib.pyplot as plt
from matplotlib.patches import Patch

'''
Write down the function that we need to solve for
x' = t^{-2}(tx-x^2)
'''

def f(t,x):
    return (t-3.2)*x + 8*t*exp((t-3.2)**2/2)*cos(4*t**2)

'''
another derivative of the function function
'''

def dfx(t,x):
    return t-3.2

# analytical solution

def sol(t,t0,x0):

    return exp((t-3.2)**2/2)*(sin(4*t**2))

# backward Euler
def beuler(t0, tn, n, x0):
    h = abs(tn - t0)/n
    t = linspace(0, tn, n+1)
    x = zeros(n+1)
    x[0] = x0

    for k in range(0,n):
        err = 1
        zold = x[k] + h*f(t[k], x[k])
        I = 0

        while err > 10**(-10) and I < 5:
            F = x[k] + h*f(t[k+1], zold) - zold
            dF = h*dfx(t[k+1], zold)-1
            znew = zold - F/dF
            err = abs(znew- zold)
            I += 1
        x[k+1] = znew
    return x

def RK4(t0,tn,n,x0):
    h = abs(tn-t0)/n
    t = linspace(t0, tn, n+1)
    x = zeros(n+1)
    x[0] = x0
    for i in range(0,n):
        K1 = f(t[i], x[i])
        K2 = f(t[i]+h/2, x[i]+K1*h/2)
        K3 = f(t[i] + h/2, x[i]+K2*h/2)
        K4 = f(t[i] + h, x[i]+K3*h)

        x[i+1] = x[i] + h*(K1+2*K2+ 2*K3+K4)/6
    return x

def AdBash3(t0,tn,n,x0):
    h = abs(tn-t0)/n
    t = linspace(t0, tn, n+1)
    x = zeros(n+1)

    x[0:3] = RK4(t0, t0+2*h,2,x0)
    K1 = f(t[1], x[1])
    K2 = f(t[0], x[0])

    for i in range(2,n):
        K3= K2
        K2= K1
        K1 = f(t[i], x[i])

        # prediction_resul
        x[i+1] = x[i] + h*(23*K1 - 16*K2+5*K3)/12
    return x

def PreCorr3(t0,tn,n,x0):
    h = abs(tn-t0)/n
    t = linspace(t0, tn, n+1)
    x = zeros(n+1)

    x[0:3] = RK4(t0, t0+2*h,2,x0)
    K1 = f(t[1], x[1])
    K2 = f(t[0], x[0])

    for i in range(2,n):
        K3= K2
        K2= K1
        K1 = f(t[i], x[i])

        # prediction_resul
        x[i+1] = x[i] + h*(23*K1 - 16*K2+5*K3)/12

        K0 = f(t[i+1],x[i+1])

        # correctorical

        x[i+1] = x[i] + h*(9*K0 + 19*K1 - 5*K2 + K3)/24

    return x

# print

fg = 1
n= 300
t0 = 0
tn = 6
x0 = 0.75
t = linspace(t0, tn , n+1)
xe = AdBash3(t0,tn, n, x0)
xb = beuler(t0,tn,n,x0)
xpc = PreCorr3(t0, tn, n,x0)

#figure(fg)

plot(t,xe,'red',label ='Adam Bashforth 3')
plot(t, xb, 'black', label ='Backward Euler')
plot(t,xpc,'cyan',label='Predictor Corrector')

t = linspace(t0, tn, 401)
xsol = sol(t,t0,x0)

plot(t,xsol, color='green', label='Exact')

#title('n = %d' %n)
#axis([0,tn, -60,40])
legend(loc='lower left')
plt.savefig('Test4.png')


#Find Schröder Numbers

def getSchroderTriangle(n=5,b=True):
    from sympy import Float as mmmfloat
    from math import log10 as mloggg
    colk = [k for k in range(n+1)]
    a=[[ 1 if(j==0) else 0 for j in colk] for i in colk]
    a[1][1]=2
    for i in range(1,n+1):
        for j in range(1,i+1):
            a[i][j] = a[i][j-1]+a[i-1][j-1]+a[i-1][j]
            if(b):
                if((mloggg(a[i][j]))+1>15):
                    a[i][j] = mmmfloat(a[i][j])

    return a

#Schroder Sequence from triangular
def SchroderSequenceFT(n=5,returni=False):
    a = getSchroderTriangle(n,False)
    b = [[a[i][j] for j in range(len(a[i])) if(i==j) ][0] for i in range(len(a))]
    if(returni):
        return b
    else:
        print(b)

#Schroder Sequence from triangular (method 2)
def SchroderSequenceFT2(n=5,returni=False):
    colk = [k for k in range(n+1)]
    a=[[ 1 if(j==0) else 0 for j in colk] for i in colk]
    b = []
    a[1][1]=2
    for i in range(1,n+1):
        for j in range(i+1):
            if(j==i or j==i-2 or j==i-1):
                a[i][j] = a[i][j-1]+a[i-1][j-1]+a[i-1][j]
                if(i==j):
                    b.append(a[i][j])
            else:
                continue
    return b

#Main numbers from Schroder Sequence
def SchroderSequence(n=5,returni=False):
    a = [1,2]
    for i in range(2,n+2):
        b = 3*a[i-1]
        for k in range(1,i-1):
            b+=a[k]*a[i-k-1]
        a.append(b)
        if(not returni):
            print(b,end=", ")
    if(returni):
        return a

#Schroder Sequence by triangular
def SchroderSequenceBT(countt=5,returni=False):
    a = getSchroderTriangle(countt,False)
    b = [j for sub in a for j in sub if(j!=0)]
    if(returni):
        return b
    else:
        print(b)

def SchroderTriangle(countt=10):
    s = getSchroderTriangle(countt)
    r = range(len(s))
    from pandas import DataFrame as mmpd
    df=mmpd(s, columns=r, index=r)
    df=df.rename_axis(columns="n/k")
    return df

#getSchroderTriangle(5)
#SchroderTriangle(100)
#SchroderSequence(1000) #539 ms
#SchroderSequenceFT(1000) #363 ms
#SchroderSequenceFT2(1000) #158 ms
#SchroderSequenceBT(200)


#from scipy.interpolate import CubicSpline
#from scipy import linalg

#x_points = [1.0, 2.0, 3.0, 4.0, 5.0]
#y_points = [1.0, 2.0, 1.0, 1.5, 1.0]

#cs = CubicSpline(x_points, y_points, bc_type='natural')
#derivative = cs.derivative()
#print(derivative)
#print(linalg.solve(cs.c, derivative.c))

#!/usr/bin/env python3

import numpy as np
from scipy.interpolate import CubicSpline

# calculate 5 natural cubic spline polynomials for 6 points
# (x,y) = (0,12) (1,14) (2,22) (3,39) (4,58) (5,77)
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([1.0, 2.0, 1.0, 1.5, 1.0])

# calculate natural cubic spline polynomials
cs = CubicSpline(x,y,bc_type='natural')

# show values of interpolation function at x=1.25
print('S(2) = ', cs(2))

## Aditional - find polynomial coefficients for different x regions

# if you want to print polynomial coefficients in form
# S0(0<=x<=1) = a0 + b0(x-x0) + c0(x-x0)^2 + d0(x-x0)^3
# S1(1< x<=2) = a1 + b1(x-x1) + c1(x-x1)^2 + d1(x-x1)^3
# ...
# S4(4< x<=5) = a4 + b4(x-x4) + c5(x-x4)^2 + d5(x-x4)^3
# x0 = 0; x1 = 1; x4 = 4; (start of x region interval)

# show values of a0, b0, c0, d0, a1, b1, c1, d1 ...
cs.c

# Polynomial coefficients for 0 <= x <= 1
a0 = cs.c.item(3,0)
b0 = cs.c.item(2,0)
c0 = cs.c.item(1,0)
d0 = cs.c.item(0,0)

# Polynomial coefficients for 1 < x <= 2
a1 = cs.c.item(3,1)
b1 = cs.c.item(2,1)
c1 = cs.c.item(1,1)
d1 = cs.c.item(0,1)

# 2
a2 = cs.c.item(3,2)
b2 = cs.c.item(2,2)
c2 = cs.c.item(1,2)
d2 = cs.c.item(0,2)

# ...

# Polynomial coefficients for 4 < x <= 5
#a4 = cs.c.item(3,4)
#b4 = cs.c.item(2,4)
#c4 = cs.c.item(1,4)
#d4 = cs.c.item(0,4)

# Print polynomial equations for different x regions
print('S0(0<=x<=1) = ', a0, ' + ', b0, '(x-0) + ', c0, '(x-0)^2  + ', d0, '(x-0)^3')
print('S1(1< x<=2) = ', a1, ' + ', b1, '(x-1) + ', c1, '(x-1)^2  + ', d1, '(x-1)^3')
print('...')
#print('S5(4< x<=5) = ', a4, ' + ', b4, '(x-4) + ', c4, '(x-4)^2  + ', d4, '(x-4)^3')

# So we can calculate S(2) by using equation S1(1< x<=2)
print('S(3) = ', a2 + b2*0.25 + c2*(0.25**2) + d2*(0.25**3))

# Cubic spline interpolation calculus example
    #  https://www.youtube.com/watch?v=gT7F3TWihvk


import numpy as np
import matplotlib.pyplot as plt

# This is a short python script to play around with JumpDiff
import jumpdiff as jd

# %% Let's first integrate a jump-diffusion process
# Define:
# integration time and time sampling
t_final = 10000
delta_t = 0.01

# A drift function
def a(x):
    return -0.5*x

# and a (constant) diffusion term
def b(x):
    return 0.75

# Now define a jump amplitude and rate
xi = 2.5
lamb = 1.75

# and let jdprocess integrate the stochastic path
X = jd.jd_process(t_final, delta_t, a=a, b=b, xi=xi, lamb=lamb)

# %% Plot the trajectory of the jump-diffusion process
fig, ax = plt.subplots(1,1,figsize=(6,3))

ax.plot(np.linspace(0,t_final,int(t_final/delta_t)), X, color = 'black')
ax.set_xlabel('t', fontsize=16)
ax.set_ylabel('x', fontsize=16)

# %% To retrieve the moments, use:
edges, moments = jd.moments(timeseries = X, bw = 0.35)
# and don't forget that the Kramers─Moyal coefficient need `moments/delta_t`

# %% Let us plot the first Kramers─Moyal coefficient 'moments[1,...]/delta_t'
fig, ax = plt.subplots(1,1,figsize=(6,3))

ax.plot(edges, moments[1,...]/delta_t, color = 'black', label = '1st Kramers─Moyal coefficient')
ax.plot(edges, a(edges), '--', color = 'black', label = 'Theoretical curve a = -0.5*x')
ax.set_xlim([-5,5]); ax.set_ylim([-5,5])

ax.set_xlabel('x', fontsize=16)
ax.set_ylabel('$D_1$(x)', fontsize=16)
ax.legend(fontsize=13)

# %% The second Kramers─Moyal coefficient 'moments[2,...]/delta_t'
fig, ax = plt.subplots(1,1,figsize=(6,3))

ax.plot(edges, moments[2,...]/delta_t, color = 'black', label = '2nd Kramers─Moyal coefficient')
ax.plot(edges, (b(0)**2 + xi*lamb)*np.ones_like(edges), '--', color = 'black', label = 'Theoretical curve $b^2+λξ$')
ax.set_xlim([-5,5]); ax.set_ylim([3,8])

ax.set_xlabel('x', fontsize=16)
ax.set_ylabel('$D_2$(x)', fontsize=16)
ax.legend(fontsize=13)

# %% And the fourth Kramers─Moyal coefficient 'moments[4,...]/delta_t'
fig, ax = plt.subplots(1,1,figsize=(6,3))

ax.plot(edges, moments[4,...]/delta_t, color = 'black', label = '4th Kramers─Moyal coefficient')
ax.plot(edges, (3*(xi**2)*lamb)*np.ones_like(edges), '--', color = 'black', label = 'Theoretical curve $3λξ^2$')
ax.set_xlim([-5,5]); ax.set_ylim([0,60])

ax.set_xlabel('x', fontsize=16)
ax.set_ylabel('$D_4$(x)', fontsize=16)
ax.legend(fontsize=13)

# %% Finally, we can use simply the 'jump_amplitude' and 'jump_rate' functions
# to recover the ξ and λ parameters

xi_est = jd.jump_amplitude(moments = moments, verbose = True)
print(xi_est)

lamb_est = jd.jump_rate(moments = moments, xi_est = xi, verbose = True)
print(lamb_est/delta_t)
# Don't forget that the jump rate λ needs to be divide by 'delta_t' to yield a
# comparible result.

# %% #########################################################################

# To understand the usage of the q_ratio function, let us generate to sample
# trajectories: one without jumps, denoted d_timeseries, and one with jumps
# denoted j_timeseries.

# integration time and time sampling
t_final = 10000
delta_t = 0.01

# Drift function
def a(x):
    return -0.5*x

# Diffusion function
def b(x):
    return 0.75

# generate 2 trajectories
d_timeseries = jd.jd_process(t_final, delta_t, a=a, b=b, xi=0, lamb=0)
j_timeseries = jd.jd_process(t_final, delta_t, a=a, b=b, xi=2.5, lamb=1.75)

# %% Subsequently we time a time scale to analyse, as
lag = np.logspace(0, 3, 25, dtype=int)

d_lag, d_Q = jd.q_ratio(lag, d_timeseries)
j_lag, j_Q = jd.q_ratio(lag, j_timeseries)

# %% we can then finally plot the results
fig, ax = plt.subplots(1,1,figsize=(6,3))

ax.loglog(d_lag, d_Q, '-', color = 'black', label='diffusion')
ax.loglog(j_lag, j_Q, 'o-', color = 'black', label='jump-diffusion')
# ax.set_xlim([-5,5]); ax.set_ylim([-5,5])

ax.set_xlabel('lag', fontsize=16)
ax.set_ylabel('$Q$-ratio', fontsize=16)
ax.legend(fontsize=13)

fig.tight_layout()
fig.savefig('q_ratio.png', dpi=300)

# %% If one wishes to check the formulae behind the corrections of the moments,
# simply choose the desired power:
power = 4

jd.m_formula(power = power)


import jax.numpy as jnp
from jax import random

class jaxKMeans():
    def __init__(self,n_clusters = 4, maxIter=100000, n_init = 10,init_idx = None):
        print("Initializing KMeans ....")
        self.key = random.PRNGKey(0)
        self.n_clusters = n_clusters
        self.maxIter = maxIter
        self.n_init = n_init
        self.init_idx = init_idx

    def initializeMeans(self,X):
        n = X.shape[0]
        means = X[:self.n_clusters]
        idx = random.randint(self.key, (self.n_clusters,),0,n)

        #for i in range(idx.shape[0]):
        #    means[i] = X[i]

        return means

    def euclideanDistance(self,X,means):
        temp = (X ** 2).sum(-1)[:,None] + (means ** 2).sum(-1)[None,:]
        temp = temp - 2 * X @ means.T
        return temp

    def classify(self,X,means):
        distances = self.euclideanDistance(X,means)
        clusters = jnp.argmin(distances,axis=1)
        return clusters

    def updateMeans(self,X,clusters,means):
        clusters = clusters.reshape(clusters.shape[0],1)
        n = X.shape[1]
        X = jnp.hstack((X,clusters))
        X = X[X[:,n].argsort()]

        spilited = jnp.split(X[:,:n], jnp.unique(X[:,n],
                                                 return_index=True)[1][1:])

        temp = [0 for j in range(len(spilited))] #jnp.zeros((len(spilited),n))
        for i in range(len(spilited)):
            temp[i] = jnp.mean(spilited[i],axis=0)

        temp = jnp.array(temp)
        newmean = (means + temp)/2

        return newmean

    def calculateMeans(self,X):
        means = self.initializeMeans(X)
        belongsTo = jnp.zeros((X.shape[0]))

        for iteration in range(self.maxIter):
            noChange = True
            clusters = self.classify(X,means)
            means = self.updateMeans(X,clusters,means)

            if(clusters != belongsTo).any():
                noChange = False

            belongsTo = clusters
            if noChange:
                break

        return means

    def calculateInertia(self,X,means):
        dis = self.euclideanDistance(X,means)
        return jnp.sum(dis.reshape(-1))

    def fit(self,X):
        bestMeans = self.calculateMeans(X)
        bestInertia = self.calculateInertia(X,bestMeans)

        for i in range(self.n_init-1):
            means = self.calculateMeans(X)
            currInertia = self.calculateInertia(X,means)
            if currInertia < bestInertia:
                bestMeans = means
                bestInertia = currInertia

        self.means = bestMeans
        return self

    def predict(self,X):
        return  self.classify(X,self.means)

    def fit_predict(self,X):
        return self.fit(X).predict(X)

    def getMeans(self):
        return self.means


"""
Dataset generation module.

author : Nishant Baheti <nishantbaheti.it19@gmail.com>
"""

import numpy as np
from typing import Tuple

def rotation_matrix_2d(theta: float) -> np.ndarray:
    """
    Create 2D data rotation matrix.

    Reference article
    ------------------

    https://en.wikipedia.org/wiki/Rotation_matrix

    Args:
        theta (float): angle for rotation.

    Returns:
        np.ndarray: rotation matrix.
    """

    mat = np.array([
        [np.cos(theta), -np.sin(theta)],
        [np.sin(theta), np.cos(theta)]
    ])
    return mat

def spiral_data(data_limit: int = 30, n_classes: int = 2,
                         n_samples_per_class=300) -> Tuple[np.ndarray, np.ndarray]:
    """
    Generate spiral data for classification problem.

    Args:
        data_limit (int, optional): range of data. Defaults to 30.
        n_classes (int, optional): number of classes for classification. Defaults to 2.
        n_samples_per_class (int, optional): number of samples per classes. Defaults to 300.

    Returns:
        Tuple[np.ndarray, np.ndarray]: X,y.
    """

    theta = np.pi * (2 / n_classes)
    rotation_mat = rotation_matrix_2d(theta=theta)

    features = [np.array([
        [
            (np.cos(i/8) * i) + np.random.randn(), (np.sin(i/8) * i) + np.random.randn()
        ] for i in np.linspace(2, data_limit, n_samples_per_class)
    ])]
    target = [np.ones(shape=(n_samples_per_class, 1), dtype=np.int32) * 0]

    for i in range(0, n_classes-1):
        features.append(features[-1] @ rotation_mat)
        target.append(np.ones(shape=(n_samples_per_class, 1), dtype=np.int32) * i+1)
    X = np.vstack(features)
    y = np.vstack(target)
    return X, y

def sine_wave_from_sample(
        n_samples: int, signal_freq: float, n_cycles: int = 10, amplitude: int = 1,
        amp_shift: int = 0, phase_shift: int = 0) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
    """
    Sine wave generation with number of samples and signal frequency

    Reference:
        https://machinelearningexploration.readthedocs.io/en/latest/MathExploration/Fourier.html#Sine-wave

    Args:
        n_samples (int): number of samples.
        signal_freq (float): signal frequency.
        n_cycles (int, optional): number of cycles. Defaults to 10.
        amplitude (int, optional): signal amplitude. Defaults to 1.
        amp_shift (int, optional): amplitude shift. Defaults to 0.
        phase_shift (int, optional): phase shift. Defaults to 0.

    Returns:
        Tuple[np.ndarray, np.ndarray, np.ndarray]: signal wave, time, freq.
    """
    sampling_freq = (n_samples * signal_freq) / n_cycles
    # n_samples = int((sampling_freq / signal_freq) * n_cycles)

    t_step = 1 / sampling_freq
    time = np.linspace(0, (n_samples-1) * t_step, n_samples)

    f_step = sampling_freq / n_samples
    freq = np.linspace(0, (n_samples-1) * f_step, n_samples)

    wave = amp_shift + amplitude * \
        np.sin((2 * np.pi * signal_freq * time) + phase_shift)

    return wave, time, freq

def sine_wave_from_timesteps(
        signal_freq: float, time_step: float, amplitude: int = 1, amp_shift: int = 0,
        phase_shift: int = 0) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
    """
    Sine wave generation with time steps and signal frequency

    Args:
        signal_freq (float): singal frequency.
        time_step (float): time step.
        amplitude (int, optional): amplitude. Defaults to 1.
        amp_shift (int, optional): amplitude shift. Defaults to 0.
        phase_shift (int, optional): phase shift. Defaults to 0.

    Returns:
        Tuple[np.ndarray, np.ndarray, np.ndarray]: signal wave, time, freq.
    """
    time = np.arange(0, 1, time_step)
    n = len(time)
    freq = (1/(time_step * n)) * np.arange(n)

    wave = amp_shift + amplitude * \
        np.sin((2 * np.pi * signal_freq * time) + phase_shift)

    return wave, time, freq

if __name__ == "__main__":

    # import seaborn as sns
    # import matplotlib.pyplot as plt

    # X, y = generate_spiral_data(n_classes=1)

    # sns.scatterplot(x=X[..., 0], y=X[..., 1], hue=y[..., 0], palette='dark')
    # plt.show()

    pass


#
# pulled from codearmo.com
# https://www.codearmo.com/python-tutorial/options-trading-greeks-black-scholes
#
import numpy as np
from scipy.stats import norm

N = norm.cdf
N_prime = norm.pdf

def bs_call_value(S, K, T, r, sigma):
    d1 = (np.log(S / K) + (r + sigma ** 2 / 2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)
    return S * N(d1) - K * np.exp(-r * T) * N(d2)

def bs_put_value(S, K, T, r, sigma):
    d1 = (np.log(S / K) + (r + sigma ** 2 / 2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)
    return K * np.exp(-r * T) * N(-d2) - S * N(-d1)

def bs_calldiv_value(S, K, T, r, q, sigma):
    d1 = (np.log(S / K) + (r - q + sigma ** 2 / 2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)
    return S * np.exp(-q * T) * N(d1) - K * np.exp(-r * T) * N(d2)

def bs_putdiv_value(S, K, T, r, q, sigma):
    d1 = (np.log(S / K) + (r - q + sigma ** 2 / 2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)
    return K * np.exp(-r * T) * N(-d2) - S * np.exp(-q * T) * N(-d1)

def d1(S, K, T, r, sigma):
    return (np.log(S / K) + (r + sigma ** 2 / 2) * T) / sigma * np.sqrt(T)

def d2(S, K, T, r, sigma):
    return d1(S, K, T, r, sigma) - sigma * np.sqrt(T)

def delta_call(S, K, T, r, sigma):
    return N(d1(S, K, T, r, sigma))

def delta_put(S, K, T, r, sigma):
    return -N(-d1(S, K, T, r, sigma))

def gamma(S, K, T, r, sigma):
    return N_prime(d1(S, K, T, r, sigma)) / (S * sigma * np.sqrt(T))

def vega(S, K, T, r, sigma):
    return S * np.sqrt(T) * N_prime(d1(S, K, T, r, sigma))

def theta_call(S, K, T, r, sigma):
    p1 = -S * N_prime(d1(S, K, T, r, sigma)) * sigma / (2 * np.sqrt(T))
    p2 = r * K * np.exp(-r * T) * N(d2(S, K, T, r, sigma))
    return p1 - p2

def theta_put(S, K, T, r, sigma):
    p1 = -S * N_prime(d1(S, K, T, r, sigma)) * sigma / (2 * np.sqrt(T))
    p2 = r * K * np.exp(-r * T) * N(-d2(S, K, T, r, sigma))
    return p1 + p2

def rho_call(S, K, T, r, sigma):
    return K * T * np.exp(-r * T) * N(d2(S, K, T, r, sigma))

def rho_put(S, K, T, r, sigma):
    return -K * T * np.exp(-r * T) * N(-d2(S, K, T, r, sigma))


"""
Fixed income analytics for the yield curve

Implements various functions useful for yield curve analytics.
"""

import numpy as np

def bootstrap(cash_flows : np.ndarray, prices : np.ndarray) -> np.ndarray:
    """
    Calculates the spot yield curve from a series of bonds.

    Parameters
    ----------
    cash_flows : np.ndarray
        Nonsingular payoff matrix of a series of bonds.
    prices : np.ndarray
        Corresponding price of each bond.

    Returns
    -------
    np.ndarray
        The corresponding spot yield curve derived from no-arbitrage relationships.
    """

    assert cash_flows.shape[1] == prices.shape[0], "Check shapes of input matrices."

    discount_factors = np.linalg.inv(cash_flows) @ prices
    yields = np.power(discount_factors, np.reshape(-1 / np.arange(start=1, stop=discount_factors.shape[0]+1), newshape=discount_factors.shape)) - 1 # Formula: d = 1/(1 + y)^i
    return np.reshape(yields, newshape=(yields.shape[0])) # Flatten output

def regression():
    raise NotImplementedError("Regression not yet implemented.")

def spline():
    raise NotImplementedError("Spline not yet implemented.")

def nelson_siegel(T : np.ndarray, theta0 : float, theta1 : float, theta2 : float, lambda_ : float) -> np.ndarray:
    """
    Calculates the Nelson-Siegel yield curve.

    Parameters
    ----------
    T : np.ndarray
        List of times at which to calculate yield.
    theta0 : float
        A Nelson-Siegel Model parameter.
    theta1 : float
        A Nelson-Siegel Model parameter.
    theta2 : float
        A Nelson-Siegel Model parameter.
    lambda_ : float
        A Nelson-Siegel Model parameter.

    Returns
    -------
    np.ndarray
        The Nelson-Siegel yield curve.
    """

    return theta0 + (theta1 + theta2) * (1 - np.exp(-T / lambda_)) / (T / lambda_) - theta2 * np.exp(-T / lambda_)


# -*- coding: utf-8 -*-
"""
Created on Sun May 10 16:53:23 2020

@author: eltes
"""

'''
Exercício 01.
Dadas as seguintes séries temporais
    • s1 = 168, 398, 451, 337, 186, 232, 262, 349, 189, 204, 220, 220, 207, 239, 259, 258,
242, 331, 251, 323, 106, 1055, 170

    • s2 = 168, 400, 451, 300, 186, 200, 262, 349, 189, 204, 220, 220, 207, 239, 259, 258,
242, 331, 251, 180, 106, 1055, 200

Utilize funções NumPy para:
• calcular a distância euclidiana entre as séries
• calcular a série temporal com os valores médios entre s1 e s2
• calcular a série temporal com os valores máximos de cada instante entre s1 e s2
• calcular a série temporal com os valores mínimos de cada instante entre s1 e s2
'''

import numpy as np

s1 = (168, 398, 451, 337, 186, 232, 262, 349, 189, 204, 220, 220, 207, 239, 259, 258,
242, 331, 251, 323, 106, 1055, 170)

s2 = (168, 400, 451, 300, 186, 200, 262, 349, 189, 204, 220, 220, 207, 239, 259, 258,
242, 331, 251, 180, 106, 1055, 200)

s1_array = np.array((s1)) # convertendo a lista s1 para array
s2_array = np.array((s2)) # convertendo a lista s2 para array

# Cálculo da Distância Euclidiana
dst = np.linalg.norm(s1_array - s2_array)

# visualizando o resultado
print("s1: "+ str(s1) + "\n\n" + "s2" + str(s2))
print()
print("The Euclidean distance(s1,s2) is:",dst)

# calculo série temporal com os valores médios entre s1 e s2
s_mean= np.mean(np.array([s1_array,s2_array]),axis=0) # Ver referência 1 abaixo
print("\nMean values: " + str(s_mean))

# calculo série temporal com os valores máximos de cada instante entre s1 e s2
s_max = np.maximum(s1_array,s2_array)
print("\nMaximum values: " + str(s_max))

# calculo série temporal com os valores mínimos de cada instante entre s1 e s2
s_min = np.minimum(s1_array,s2_array)
print("\nMinimum values: " + str(s_min))

# Referência 1
# https://stackoverflow.com/questions/19886584/calculate-mean-of-arrays-in-numpy