import numpy as np
import data_reader
import sys

def newton_interpolation(x_values:list,y_values:list,x:float):
	nor = len(x_values) #nor - number of rows

	#DT - Difference Table
	#DT[i,i] = f[x_i]
	#DT[i,j] = f[x_i,x_(i+1),...,x_j] for j > i

	DT = np.zeros((nor,nor),dtype=np.float64)

	###############[calculate the kth divided difference]###############
	for i in range(0,nor):
		DT[i,i] = y_values[i]
	for m in range(1,nor):
		for j in range(0,nor-m):
			DT[j,j+m] = (DT[j+1,j+m] - DT[j,j+m-1])/(x_values[j+m]-x_values[j])

	#print(DT) #for debugging purposes only.

	##############[evaluate the interpolating polynomial at x]##########
	p = np.zeros(nor,dtype=np.float64)
	p[0] = y_values[0]
	for k in range(1,nor):
		p[k] = p[k-1]
		g = 1
		for i in range(0,k):
			g *= (x - x_values[i])
		g *= DT[0,k]
		p[k] += g

	return p[nor-1]

if __name__ == '__main__':
	help_message = f"""
	Usage: python3.7 {sys.argv[0]} <filename> x
	* the first option is for the filename
	* the second option is the point you want to evaluate the interpolating polynomial.
	"""

	if len(sys.argv) != 3:
		print(help_message)
		exit(1)

	f = data_reader.InterpolationData(sys.argv[1])
	data = f.get_data_in_two_lists()
	x = float(sys.argv[2])

	print(newton_interpolation(data[0],data[1],x))


import numpy as np

def get_rotation_matrix(angle):

    thetha = (angle/180.) * np.pi
    rotation_matrix = np.array([
                            [np.cos(thetha), -np.sin(thetha)],
                            [np.sin(thetha), np.cos(thetha) ]
                            ])
    return rotation_matrix

def rotate_90_clockwise(vector):
    """
    vector:tuple
    """
    v = np.array(vector,dtype= np.float)

    m = get_rotation_matrix(-90)

    r = np.matmul(m,v)

    r = r.astype('int')

    return r

def rotate_90_counterclockwise(vector):
    """
    vector:tuple
    """
    v = np.array(vector)

    m = get_rotation_matrix(90)

    r = np.matmul(m,v)
    r = r.astype('int')
    return r

if __name__ == "__main__":
    l  = (-1,0)
    up  = (0,1)
    r = (1,0)
    down = (0,-1)

    r0 = rotate_90_clockwise(l)

    print("Rotate clockwise l {} must give up {}, r={} ".format(l,up, r0))

    r0 = rotate_90_clockwise(up)

    print("Rotate clockwise up {} must give r {}, r={} ".format(up,r, r0))

    r0 = rotate_90_clockwise(r)

    print("Rotate clockwise r {} must give down {}, r={} ".format(r,down, r0))

    r0 = rotate_90_clockwise(down)

    print("Rotate clockwise down {} must give l {}, r={} ".format(down,l, r0))

    print("\n\n")
    ### COUNTERCLOCKWISE

    r0 = rotate_90_counterclockwise(l)

    print("Rotate counterclockwise l {} must give down {}, r={} ".format(l,down, r0))

    r0 = rotate_90_counterclockwise(up)

    print("Rotate clockwise up {} must give l {}, r={} ".format(up,l, r0))

    r0 = rotate_90_counterclockwise(r)

    print("Rotate clockwise r {} must give up {}, r={} ".format(r,up, r0))

    r0 = rotate_90_counterclockwise(down)

    print("Rotate clockwise down {} must give r {}, r={} ".format(down,r, r0))


import numpy as np

def Gauss(n, A):
    X = np.zeros(n,dtype=float)
    L = np.arange(n,dtype=int)   #index vector
    S = np.zeros(n,dtype=float)
    for i in range(0, n):
        L[i] = i
        smax = 0
        for j in range(0, n):
            smax = max(smax, np.abs(A[i][j]))
        S[i] = smax
    for k in range(0, n-1):
        rmax = 0
        for i in range(k, n):
            r = np.abs(A[L[i]][k]/S[L[i]])
            if r > rmax:
                rmax = r
                j = i
        temp = L[j]
        L[j] = L[k]
        L[k] = temp
        for i in range(k+1, n):
            xmult = A[L[i]][k]/A[L[k]][k]
            A[L[i]][k] = xmult
            for j in range (k+1, n):
                A[L[i]][j] = A[L[i]][j] - (xmult*A[L[k]][j])
    return X,A,L

def Solve(n,A,L,B,X):
    for k in range(0, n-1):
        for i in range(k+1, n):
            B[L[i]] = B[L[i]]-(A[L[i]][k]*B[L[k]])
    X[n-1] = B[L[n-1]]/A[L[n-1]][n-1]
    for i in range(n-1, -1, -1):
        sum1 = B[L[i]]
        for j in range(i+1, n):
            sum1 = sum1-A[L[i]][j]*X[j]
        X[i] = sum1/A[L[i]][i]
    return X

def FullGauss(n,A,B):
    X,A,L = Gauss(n, A)
    X = Solve(n,A,L,B,X)
    return X

#Example
A = np.array([[3.0, 4, 3],
              [1, 5, -1],
              [6, 3, 7]])
B = np.array([10.0, 7, 15])
print(A, "\n")
print(B, "\n")

n = 3
X,A,L = Gauss(n,A)
X = Solve(n,A,L,B,X)
print("Solution ", X)
#solution [2,1,0]


import numpy as np
import math

"""
:A: square matrix (np.ndarray)
:returns: determinant of A
"""
def det(A: np.ndarray):
    if A.shape[0] < 2 or A.shape[0] != A.shape[1]:
        raise Exception('Wrong matrix dimensions for determinant')

    n = A.shape[0]

    if n == 2:
        return A[0][0]*A[1][1] - A[0][1]*A[1][0]

    a = np.copy(A)
    s = 0

    for i in range(n):
        s += (-1 if i%2!=0 else 1) * a[0][i] * det(np.delete(np.delete(a, 0, 0), i, 1))
        a = np.copy(A)

    return s

"""
:returns: matrix A with chess table rule applied
"""
def chess_table_rule(A: np.ndarray):
    if A.shape[0] < 2 or A.shape[0] != A.shape[1]:
        raise Exception('Wrong matrix dimensions for chess table rule')

    a = np.copy(A)
    n = len(A)
    c = 0

    for i in range(n):
        for j in range(n):
            if c%2!=0:
                a[i][j] *= -1
            c += 1

    return a

"""
:returns: subdeterminant of matrix A (minor matrix)
"""
def subdet(A: np.ndarray):
    if A.shape[0] < 3 or A.shape[0] != A.shape[1]:
        raise Exception('Wrong matrix dimensions for adjungate')

    n = len(A.shape)
    a = np.copy(A)
    na = []

    for i in range(n + 1):
        row = []
        for j in range(n + 1):
           row.append(det(np.delete(np.delete(a, i, 0), j, 1)))
        na.append(row)

    return np.array(na)

"""
:A: square matrix (np.ndarray)
:returns: adjungate of A
"""
def adj(A: np.ndarray):
    return chess_table_rule(subdet(A)).T

def inv(A: np.ndarray):
    d = det(A)
    if d == 0:
        raise Exception('Matrix cannot be inverted')
    return adj(A) / d

"""
Convert data from cartesian coorinates to polar coordinates.
:returns: New X and Y values
"""
def to_polar(X: np.ndarray, Y: np.ndarray):
    nX, nY = [], []

    for x, y in zip(X, Y):
        nX.append((x**2 + y**2)**0.5)
        if x != 0:
            nY.append(math.degrees(math.atan(y / x)))
        else:
            nY.append(0)

    """
    # For visual testing
    import matplotlib.pyplot as plt

    plt.scatter(X, Y, c="red")
    plt.scatter(nX, nY, c="green")
    plt.show()
    """
    return np.array(nX), np.array(nY)

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

if __name__ == '__main__':
    import random

    print('Testing', __file__)

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

    print(det(A))

    B = np.array([
        [1, -2, 0],
        [2, -1, 1],
        [-1, 0, -3]
    ])

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

    # Test data
    X = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
    y = np.array([random.randint(10, 100) for _ in range(10)])

    print(chess_table_rule(C))
    print(adj(B))
    print(inv(B))

    print(X, y)
    print(to_polar(X, y))


import numpy as np
from scipy.optimize import curve_fit

###############################################################
# Standard functions
def linear_func(x, a, b):
    """a * x + b"""
    return a * x + b

def quad_func(x, a, b, c):
    """ a*x**2 + b*x + c """
    return a*x**2 + b*x + c
def quad_func2(x, a, b, c):
    """a*(x-b)**2 + c"""
    return a*(x-b)**2 + c

def power_func(x, a, b):
    """a * x ** b"""
    return a * x ** b
def power_func2(x, x0, a, b):
    """a * (x-x0) ** b"""
    return a * (x-x0) ** b

def exp(x, a, b):
    """a * np.exp(-b * x)"""
    return a * np.exp(-b * x)

def exp_func(x, a, b, x0):
    """a * np.exp(-b * (x-x0)) + c"""
    return a * np.exp(-b * (x-x0))

def gaussian(x, a, x0, sigma, b):
    """ a * np.exp(- (x - x0) ** 2. / (2. * sigma ** 2.)) + b"""
    return a * np.exp(- (x - x0) ** 2. / (2. * sigma ** 2.)) + b

def gaussian_norm(x, x0, sigma):
    """ 1. / (np.sqrt(2 * np.pi * sigma ** 2.)) * np.exp(- (x - x0) ** 2. / (2. * sigma ** 2.)) """
    return 1. / (np.sqrt(2 * np.pi * sigma ** 2.)) * np.exp(- (x - x0) ** 2. / (2. * sigma ** 2.))

def double_gaussian(x, a1, x1, sigma1, b1, a2, x2, sigma2, b2):
    """a1 * np.exp(- (x - x1) ** 2. / (2. * sigma1)) + b1 + a2 * np.exp(- (x - x2) ** 2. / (2. * sigma2)) + b2"""
    return a1 * np.exp(- (x - x1) ** 2. / (2. * sigma1)) + b1 + a2 * np.exp(- (x - x2) ** 2. / (2. * sigma2)) + b2

def lorentzian(x, x0, gamma, alpha):
    """alpha * gamma / ((x-x0)**2 + gamma ** 2)"""
    return alpha * gamma / ((x-x0)**2 + gamma ** 2)

def lorentzian_norm(x, x0, gamma):
    """1. / np.pi * gamma / ((x-x0)**2 + gamma ** 2)"""
    return 1. / np.pi * gamma / ((x-x0)**2 + gamma ** 2)

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

def fit(func, xdata, ydata, **kwargs):
    if func is None:
        popt, pcov = curve_fit(linear_func, xdata, ydata, **kwargs)
    else:
        popt, pcov = curve_fit(func, xdata, ydata, **kwargs)
    return popt, pcov


import numpy as np

from typing import Union, List

def complex_sinusoid(w: float, t: Union[np.ndarray, float]) -> np.ndarray:
    """ This function evaluates a complex sinusoid.

    Parameters
    ----------

    w : float
        The angular frequency.

    t : np.ndarray
        The instances to evaluated at.

    Returns
    -------

    np.ndarray
        A complex sinusoid.

    """

    return np.exp(1j * w * t)

def steering_vector(theta: float, n_sensors: int, d: float = 0.5) -> np.ndarray:
    """ This function returns a steering vector pointing at direction `theta`.

    Parameters
    ----------

    theta : float
        The direction of arrival in degrees

    n_sensors : int
        The number of recievers

    d : float
        Antenna spacing in number of wavelengths

    Returns
    -------

    a : np.ndarray
        The steering vector

    """

    s = d * np.arange(n_sensors)
    w = 2 * np.pi * np.sin(np.pi * theta / 180)
    a = np.exp(-1j * w * s)
    return a

def steering_matrix(thetas: Union[np.ndarray, List], n_sensors: int, d: float = 0.5) -> np.ndarray:
    """ This function returns the steering matrix of an array.

    Parameters
    ----------
    thetas : Union[np.ndarray, List]
        A list with the direction of arrivals.

    n_sensors : int
        Then number of sensors

    d : float
        The array spacing in wavelengths.

    Returns
    -------
    np.ndarray
        The steering matrix of shape (n_sensors, n_doas).

    """

    return np.array([steering_vector(theta, n_sensors, d) for theta in thetas]).T

def single_radar_target(theta: float, n_sensors: int, s: np.ndarray = None, d: float=0.5, rnd_phase: bool=True) -> np.ndarray:
    """ This function measures a single incoming radar target

    Parameters
    ----------
    s : np.ndarray
        The source signal

    theta : float
        The direction of arrival

    n_sensors : int
        The number of sensors

    d : float
        The element spacing in number of wavelengths

    rnd_phase : bool
        If true, adds a random phase shift to the signal at each snapshot

    Returns
    -------
    np.ndarray
        The measured source

    """

    if s is None:
        s = np.random.randn(32).astype(np.complex128)

    if rnd_phase:
        s *= np.exp(1j * 2 * np.pi * np.random.rand(1))

    a = steering_vector(theta, n_sensors, d=d)
    return np.outer(a, s)

def wideband_steering_vector(theta1, theta2, n_sensors, d=0.5):
    s = d * np.arange(n_sensors)

    wa = 2 * np.pi * np.sin(np.pi * theta1 / 180)
    wb = 2 * np.pi * np.sin(np.pi * theta2 / 180)

    a = (np.exp(1j * wb * s) - np.exp(-1j * wa * s)) / (1j * 2 * np.pi * s)
    return a


import numpy as np
import matplotlib.pyplot as mpl
from scipy.optimize import fmin_powell as fmin
from scipy.odr import *
from scipy.stats import chi2

t 		= np.asfarray([ 352 , 701 , 1048 , 1398 , 1751 , 2099 , 2446 , 2805 ])

t_err	= np.asfarray([ 5 , 9 , 9 , 9 , 9 , 15 , 15 , 15 ])

dT 		= np.asfarray([ 10.0 , 19.7 , 30.2 , 40.4 , 49.9 , 60.5 , 70.4 , 80.0 ])

dT_err	= np.asfarray([ 0.1 , 0.2 , 0.2 , 0.2 , 0.3 , 0.3 , 0.4 , 0.4 ])

U		= 12
I		= 10
m		= 1000.0

RCFbound	= 2.0/(np.sum(np.power(m/(t_err*U*I),2.0)*(np.power(dT,2.0)+np.power(dT_err,2.0))))

def t_value_odr(C,delta_T):
	U		= 12
	I		= 10
	m		= 1000.0
	return (m*delta_T*C[0])/(U*I)
model	= Model(t_value_odr)
data	= RealData(dT, t, sx=dT_err, sy=t_err)

odrfit	= ODR(data, model, beta0=[1.0])

odrfit.set_job(fit_type=2)
output1	= odrfit.run()
C_val1	= output1.beta[0]
chisq1	= output1.sum_square
pval1	= chi2.cdf(chisq1,1)
C_err1	= output1.sd_beta[0]

odrfit.set_job(fit_type=0)
output2	= odrfit.run()
C_val2	= output2.beta[0]
chisq2	= output2.sum_square
pval2	= chi2.cdf(chisq2,1)
C_err2	= output2.sd_beta[0]

# I wrote the commented sections of code to make sure the odrfit matches with least squares code written by me. It does.
"""
def t_value(C,delta_T):
	U		= 12
	I		= 10
	m		= 1000.0
	return (m*delta_T*C)/(U*I)

def chisquare(t_obs, sigma_t, C, delta_T):
	t_exp	= t_value(C,delta_T)
	return	np.sum(np.power((t_obs-t_exp)/sigma_t, 2.0))
C_val_old, chisq_old = fmin(lambda x: chisquare(t, t_err, x, dT), np.asfarray([1.0]), full_output=True, disp=False)[0:2]
C_err_old = np.abs(C_val_old - fmin(lambda x: np.power(chisquare(t, t_err, x, dT)-chisq_old-1,2.0), np.asfarray([C_val_old]),disp=False))

print 'Difference between manual least squares minimization and ODR-packages:',C_val_old-C_val1
"""

print 'Least squares with t-errors only:'
print 'C:',C_val1, ' sigma_C:', C_err1,' Chi2:', chisq1, ' P-value:',pval1
print 'Least squares with both errors:'
print 'C:',C_val2, ' sigma_C:', C_err2,' Chi2:', chisq2, ' P-value:',pval2
print 'RFC-bound for std:',np.sqrt(RCFbound)

Statistical Methods 2014 - Home exam/Code/exam_p04.py


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

# Name: Baylee Mumma, Christine Outlaw
# Email: mumma103@mail.chapman.edu
# Course: PHYS220/MATH220/CPSC220 Fall 2017
# Assignment: CLASSWORK 12

import numpy as np
import matplotlib.pyplot as plt

def y_dot(t,y,x,nu,F):
    """y_dot(t,y,x,nu,F)
    The differential equation given for the dot derivative of y.
    """
    return -(nu*y)+x-(x**3)+(F*np.cos(t))

def x_dot(y):
    """x_dot(y)
    The differential equation given for the dot derivative of x.
    """
    return y

def rk4(a, b, x0, y0, nu=0, F=0, xdot = x_dot, ydot = y_dot):
    """rk(a, b, x0, y0, nu=0, F=0, xdot = x_dot, ydot = y_dot)

    Args:
        a  (float) : Lower bound, t = a*2*pi
        b  (float) : Upper bound, t = b*2*pi
        x0 (float) : Initial position of ball
        y0 (float) : Initial velocity of ball
        nu (float) : Constant damping coefficient
        F  (float) : Constant force amplitude coefficient
        xdot (function) : Part of the differential equation
        ydot (function) : Part of the differential equation

    Returns:
        t (array) : Array over the time interval with equal dt = .001
        x (array) : Array containing the position of the ball at each time in the time array
        y (array) : Array containing the velocity of the ball at each time in the time array
    """
    dt = 0.001
    start = 2*a*np.pi
    end = 2*b*np.pi
    n = int(np.ceil((end-start)/dt))
    t = np.linspace(start,end,n)
    x = np.zeros(n)
    y = np.zeros(n)
    x_dot_vec = np.zeros(n)
    y_dot_vec = np.zeros(n)
    x[0] = x0
    y[0] = y0
    for k in range(n):
        x_dot_vec[k] = x_dot(y[k])
        y_dot_vec[k] = ydot(t[k],y[k],x[k],nu,F)
        if k == n-1:
            break
        else:
            k1y = dt*ydot(t[k],y[k],x[k],nu,F)
            k2y = dt*ydot((t[k]+dt/2),(y[k]+k1y/2),x[k],nu,F)
            k3y = dt*ydot((t[k]+dt/2),(y[k]+k2y/2),x[k],nu,F)
            k4y = dt*ydot((t[k]+dt),(y[k]+k3y),x[k],nu,F)
            rky = (k1y+(2*k2y)+(2*k3y)+k4y)/6
            y[k+1] = y[k]+rky
            k1x = dt*xdot(y[k])
            k2x = dt*xdot(y[k]+k1x/2)
            k3x = dt*xdot(y[k]+k2x/2)
            k4x = dt*xdot(y[k]+k3x)
            rkx = (k1x+(2*k2x)+(2*k3x)+k4x)/6
            x[k+1] = x[k]+rkx
    return (t,x,y)

def plot(t,x,title=""):
    """plot(x,t,title='')
    Generate a plot of a time-valued function.

    Args:
        t (array) : Array of time domain
        x (array) : Array of values representing position
        title (string) : Title of the plot

    Returns:
        A plot of a function with respect to time.
        """
    plt.plot(t,x)
    plt.xlabel('t')
    plt.ylabel('x')
    plt.title(title, fontsize = 20)
    plt.show()

def parametric(x,y,title = ''):
    """parametric(x,y,title = '')
    Generate a parametric plot of velocity with respect to position.

    Args:
        x (array) : Postion of ball with respect to time
        y (array) : Velocity of ball with respect to time
        title (array) : Title of plot

    Returns:
        A parametric plot.
        """
    plt.plot(x,y)
    plt.xlabel('x')
    plt.ylabel('$\dot{x}$')
    plt.title(title, fontsize = 20)
    plt.show()

def scatter(x,y,n,title = ''):
    """scatter(x,y,n,title = '')
    Generate a Poincare section of the parametric curve.

   Args:
        x (array) : Position with respect to time
        y (array) : Velocity with respect to time
        n (int)   : Number of points in scatter plot
        title (string) : Title of plot

   Returns:
       A scatter plot with points at every integer multiple of 2*pi*n for n[0,50].
       """
    ax = plt.subplot
    plt.title(title, fontsize = 20)
    plt.xlabel('x')
    plt.ylabel('$\dot{x}$')
    for k in range(n):
        plt.scatter(x[6*k],y[6*k])
    plt.show()


import sympy as sp
x, y, z = sp.symbols('x y z')
sp.init_printing()

# Here we simply give the input needed as The Following:
# ( X0 ) & ( X1 ) & ( X2 )
# ( Fx ) is the equation of the function
# ( n ) is the number of Iterations needed

x0 = 4.5

x1 = 5.5

x2 = 5

Fx = x**3 - 13*x - 12

n = 3

print("____________________________________________________________________________________________________________\n  "
      "Iteration |    X3    |    H0   |    H1    |    D0    |    D1   |    A    |    B    |    C    |   Error  "
      "\n------------------------------------------------------------------------------------------------------------")
for i in range(n):
    # Finding F(x0) & F(x1) & F(x2)
    fx0 = Fx.subs(x, x0).evalf(); fx1 = Fx.subs(x, x1).evalf(); fx2 = Fx.subs(x, x2).evalf();
    # Finding H 0 & 1
    H0 = x1 - x0; H1 = x2 - x1;
    # Finding Delta 0 & 1
    d0 = (fx1 - fx0)/(x1 - x0); d1 = (fx2 - fx1)/(x2 - x1);
    # Finding A & B & C
    A = (d1 - d0)/(H1 + H0); B = A*H1 + d1; C = fx2;
    # To Calculate X3 we have two solutions one is when delta is positive and the other is when its negative
    DeltaPos = (B + sp.sqrt(B**2 - (4*A*C)))
    DeltaNeg = (B - sp.sqrt(B**2 - (4*A*C)))

    if (abs(DeltaPos) > abs(DeltaNeg)): x3 = x2 + ((- 2*C)/DeltaPos)
    else: x3 = x2 + ((- 2*C)/DeltaNeg)
    Error = abs(((x3 - x2)/x3)*100)
    print("     {0:2d}     |  {1:.5f} | {2:.5f} | {3:.5f} | {4:.5f} | {5:.4f} | {6:.4f} | {7:.4f} | {8:.4f} | {9:.6f} \n"
      .format(i+1, x3, H0, H1, d0, d1, A, B, C, Error))
    # Changing Variables for The Next Iteration
    x0 = x1; x1 = x2; x2 = x3;

# Finally displaying the output with the value of every rule that was needed in order to get the final answer and the percentage of error after each iteration


# Decision Tree

given dataset $D=\left\{(x^{(i)},y^{(i)})\right\}$

decision tree is trying to pick $(feature, value)$ that partition the dataset to subsets

after that partition, elements in each subsets is similar in total, i.e we gain certainty.

continue the process, until we get subset that is very pure or partition too many times.

we thus create a tree called the decision tree.

when predicting, find leaf subset of that sample, then use typical value of leaf as prediction.

## information gain

we use entropy to measure the uncertainty of data.

for classfication problem, assume $y_{(i)} \in \left\{1,...,k\right\}$, we have the entropy of dataset $D$:

$$H(D) = E(-log\ p_{i}) = -\sum_{i=1}^{k}p_{i}log\ p_{i}$$

$p_{i}$ is the frequency of i-th class, it defines the uncertainty of $D$.

suppose we partition $D$ according to feature $A$ into $D_{1},...,D_{n}$, we have:

$$H(D|A)=\sum_{i=1}^{n}\frac{\#D_{i}}{\#D}H(D_{i})$$

that is: the uncertainty of $D$ after knowing $A$.

information gain is uncertainty loss:

$$g(D,A) = H(D) - H(D|A)$$

decision tree ID3 choose feature $A$ that maximize $g(D,A)$ until:

1. subset is empty
2. information gain $g(D,A)\le\epsilon$

## information gain ratio

if use information gain, we prefer feature $A$ such that $\#A$ is large.

more precisely, we prefer features that is uncertain

$$H_{A}(D) =-\sum_{i=1}^{n}\frac{\#D_{i}}{\#D}log\ \frac{\#D_{i}}{\#D}$$

defines that uncertainty, it is the entropy of viewing category of $A$ as labels.

to fix that problem, we define the information gain ratio:

$$g_{R}(D,A)=\frac{g(D,A)}{H_{A}(D)}=\frac{H(D)-H(D|A)}{H_{A}(D)}$$

algorithm that uses $g_{R}(D,A)$ is C4.5

## pruning

we need to pruning the decision tree $\Rightarrow $ lower model's complexity $\Rightarrow $ mitigate overfit

suppose now we have a decision tree $T$, use $\left | T \right | $ to denote the number of leaves of $T$, and these leaves are $T_{1},...,T_{\left | T \right | }$.

then entropy of leaf $t$: $H(T_{t})$

total entropy of these leaves:

$$C(T) = \sum_{t=1}^{\left | T \right |} \left | T_{t} \right |H(T_{t})$$

we want these minimize this entropy, and at the same time limit model's complexity, give rise to the loss function:

$$C_{\alpha}(T) = C(T) + \alpha\left | T \right |$$

in practice, pruning is from leaves to root.

if pruning a node result in a decrease of the loss function, the operate this pruning.

## CART-classification and regression tree

CART can solve both the classification and regression problem.

CART simply uses different strategies for them.

for regression problem, we try to find feature $j$ and cutting point $s$ that minimize the square error:

$$\underset{j,s}{min}\left[\underset{c_{1}}{min}\sum_{x_{i} \in R_{1}(j, s)}(y_{i} - c_{1})^{2} + \underset{c_{2}}{min}\sum_{x_{i} \in R_{2}(j, s)}(y_{i} - c_{2})^{2}\right]$$

rather than optimizing information gain or information gain ratio.

CART optimize Gini-index when facing a classification problem:

$$Gini(D) = E(1 - p_{i}) = \sum_{i=1}^{k}p_{i}(1 - p_{i})$$

here, rather than self-information $-log\ p_{i}$ uses in entropy, we use $1 - p_{i}$ to indicate the information of event with probability $p_{i}$.

## Practice using sklearn

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier

iris = load_iris()
X = iris.data[:, 2:]  # petal length and width
y = iris.target

tree_clf = DecisionTreeClassifier(max_depth=2)
tree_clf.fit(X, y)

"""visualize using graphviz, need 1.pip install graphviz, 2.brew install graphviz"""
from graphviz import Source
from sklearn.tree import export_graphviz

export_graphviz(tree_clf,
                out_file="iris_tree.dot",
                feature_names=iris.feature_names[2:],
                class_names=iris.target_names,
                rounded=True,
                filled=True
               )

Source.from_file("iris_tree.dot")

tree_clf.predict_proba([[5, 1.5]]), tree_clf.predict([[5, 1.5]])

"""criterion can switch from gini to entropy"""
entropy_tree_clf = DecisionTreeClassifier(criterion="entropy", max_depth=3)

"""hyper-parameters for regularization"""
regularized_tree_clf = DecisionTreeClassifier(max_depth=5,  # maximum depth of that tree
                                              max_leaf_nodes=20,  # maximum number of leaf nodes
                                              max_features=8,  # maximum number of features when splitting each node
                                              min_samples_split=10,  # min number of samples of a node before it can split
                                              min_samples_leaf=4,  # min number of samples of a leaf node
                                              min_weight_fraction_leaf=0.01  # same as min_samples_leaf, but by weight frac
                                             )

"""CART(sklearn uses) can also regression"""
from sklearn.tree import DecisionTreeRegressor

tree_reg = DecisionTreeRegressor(max_depth=3)

### moon dataset

"""make moon dataset"""
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split

X, y = make_moons(n_samples=10000, noise=0.4)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

"""grid search"""
from sklearn.model_selection import GridSearchCV

param_grid = [{"max_leaf_nodes": [2, 5, 10, 20], "min_samples_split": [3, 4]}]

tree_clf = DecisionTreeClassifier()
grid_search = GridSearchCV(tree_clf, param_grid, cv=3, verbose=3)
grid_search.fit(X_train, y_train)

"""using best estimator to predict"""
from sklearn.metrics import accuracy_score

y_predict = grid_search.predict(X_test)
accuracy_score(y_true=y_test, y_pred=y_predict)

### using multiple trees

"""generate 1000 subsets, each 100 instances"""
from sklearn.model_selection import ShuffleSplit

n_trees = 1000
n_instances = 100

mini_sets = []

rs = ShuffleSplit(n_splits=n_trees, test_size=len(X_train) - n_instances, random_state=42)
# make train_size = len(X_train) - (len(X_train) - n_instances) = n_instances

for mini_train_index, mini_test_index in rs.split(X_train):
    X_mini_train = X_train[mini_train_index]
    y_mini_train = y_train[mini_train_index]
    mini_sets.append((X_mini_train, y_mini_train))

"""train each subset on grid_search.best_estimator_"""
from sklearn.base import clone
import numpy as np

forest = [clone(grid_search.best_estimator_) for _ in range(n_trees)]

accuracy_scores = []

for tree, (X_mini_train, y_mini_train) in zip(forest, mini_sets):
    tree.fit(X_mini_train, y_mini_train)

    y_pred = tree.predict(X_test)
    accuracy_scores.append(accuracy_score(y_test, y_pred))

np.mean(accuracy_scores)

"""save all predictions"""
Y_pred = np.empty([n_trees, len(X_test)], dtype=np.uint8)

for tree_index, tree in enumerate(forest):
    Y_pred[tree_index] = tree.predict(X_test)

"""use majority vote, improve performance"""
from scipy.stats import mode

y_pred_majority_votes, n_votes = mode(Y_pred, axis=0)
accuracy_score(y_test, y_pred_majority_votes.reshape(-1))


#
#	Solved Problems in Geostatistics
#
# ------------------------------------------------
#	This file includes some general statistics
#	functions, which are needed for the problems
# ------------------------------------------------
#
#

from numpy import *

# Standartize the array
def stand(z, mean, st_dev):
	z = (z - mean) / st_dev
	return z

# Calculate weighted variance
def w_var(weights, data, w_mean):
	var = 0.0
	weights = norm(weights)
	for i in xrange(len(data)):
		var = var + weights[i] * (data[i]-w_mean)**2
	var = sqrt(var/weights.sum())
	return var

# Calculate weighted mean
def w_mean(weights, data):
	z_1 = 0.0
	z = 0.0
	for i in xrange(len(data)):
		z = z + weights[i]*data[i]
		z_1 = z_1 + weights[i]
	z = z/z_1
	return z

# Calculate standard deviation (sqrt[var])
def calc_quadr_var(array,mean):
	var = 0.0
	for i in xrange(len(array)):
		var = var + ((array[i]-mean)**2)/len(array)
	var = sqrt(var)
	return var

# Calculate mean
def calc_mean_array(array):
	size = len(array)
	sum = array.sum() / size
	return sum

# Normalize array
def norm(array):
	sum = array.sum()
	for i in xrange(len(array)):
		array[i] = array[i]/sum
	return array

# Calculate corellation coefficient
def corr_coef(x,y):
	coef = 0.0
	mean_x = x.mean()
	var_x = calc_quadr_var(x,mean_x)
	mean_y = y.mean()
	var_y = calc_quadr_var(y,mean_y)
	var = var_x * var_y
	for i in xrange(len(x)):
		coef = coef + x[i]*y[i]
	coef = (coef - len(x)*mean_x*mean_y) / ((len(x)-1)* var)
	return coef

# Make random array from existing with same values
def rand_arrays(array1, array2, n):
	array1_rand = zeros( (n), dtype = float)
	array2_rand = zeros( (n), dtype = float)
	for i in xrange(n):
		value = random.randint(len(array1))
		array1_rand[i] = array1[value]
		array2_rand[i] = array2[value]
	return [array1_rand, array2_rand]

# Calculate weighted covariance
def calc_cov(x, y, w):
	cov = 0.0
	weigths = 0.0
	for i in xrange(len(x)):
		cov = cov + w[i] * (x[i] - w_mean(w,x)) * (y[i] - w_mean(w,y))
		weigths = weigths + w[i]
	cov = cov / weigths
	return cov

# Calculate weighted correlation coefficient
def w_corr_coef(x, y, w):
	w_coef = calc_cov(x, y, w) / sqrt(calc_cov(x, x, w) * calc_cov(y, y, w))
	return w_coef

# Calculate distance between points
def calc_distance(x1,y1,x2,y2):
	h = sqrt((x2-x1)**2+(y2-y1)**2)
	return h

def calc_distance_3d(x1, y1, z1, x2, y2, z2):
	h = sqrt((x2 - x1)**2 + (y2 - y1)**2 + (z1 - z2)**2)
	return h

from numpy import mean, std, sum, sqrt, sort, corrcoef, tanh, arctanh
from numpy.random import randint

def bootstrap_correlation(x,y):
	idx = randint(len(x),size=(1000,len(x)))
	bx = x[idx]
	by = y[idx]
	mx = mean(bx,1)
	my = mean(by,1)
	sx = std(bx,1)
	sy = std(by,1)
	r = sort(sum( (bx - mx.repeat(len(x),0).reshape(bx.shape)) *
	(by - my.repeat(len(y),0).reshape(by.shape)), 1)
	/ ((len(x)-1)*sx*sy))
#bootstrap confidence interval (NB! biased)
	conf_interval = (r[25],r[975])
#bootstrap standard error using Fisher's z-transform (NB! biased)
	std_err = tanh(std(arctanh(r))*(len(r)/(len(r)-1.0)))
	return (std_err, conf_interval)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Aug  1 16:27:03 2018

@author: shivap
"""

import numpy as np

# =============================================================================
# Rosenbrock Function
# https://www.sfu.ca/~ssurjano/rosen.html
# =============================================================================
def myrosenbrock(X):
    X=np.asarray(X)
    X = X.reshape((-1,2))
    if len(X.shape)==1:# one observation
        x1=X[0]
        x2=X[1]
    else:# multiple observations
        x1=X[:,0]
        x2=X[:,1]
    fx = 100*(x2-x1**2)**2 + (x1-1)**2
    return fx.reshape(-1,1)

# =============================================================================
#  Six-hump Camel Function
#  https://www.sfu.ca/~ssurjano/camel6.html
# =============================================================================
def mysixhumpcamp(X):
    X=np.asarray(X)
    X = np.reshape(X,(-1,2))
    if len(X.shape)==1:
        x1=X[0]
        x2=X[1]
    else:
        x1=X[:,0]
        x2=X[:,1]
    term1 = (4-2.1*x1**2+(x1**4)/3) * x1**2
    term2 = x1*x2
    term3 = (-4+4*x2**2) * x2**2
    fval = term1 + term2 + term3
    return fval.reshape(-1,1)

# =============================================================================
# Beale function
# https://www.sfu.ca/~ssurjano/beale.html
# =============================================================================
def mybeale(X):
    X=np.asarray(X)
    X = X.reshape((-1,2))
    if len(X.shape)==1:
        x1=X[0]
        x2=X[1]
    else:
        x1=X[:,0]
        x2=X[:,1]
    fval = (1.5-x1+x1*x2)**2+(2.25-x1+x1*x2**2)**2+(2.625-x1+x1*x2**3)**2
    return fval.reshape(-1,1)

def func(ht,X):
    # ht is a categorical index
    # X is a continuous variable

    if ht==0: #rosenbrock
        return myrosenbrock(X)
    elif ht==1: # six hump
        return mysixhumpcamp(X)
    elif ht==2: # beale
        return mybeale(X)


import numpy as np

def inverse_truncated_modal(M, num_modes, svd=None):
	'''Invert `M` with `num_modes` modes.

	Modes are given by a singular value decomposition of the input matrix.
	If `svd` is given, it is used instead. Modes are ordered in descending
	order by their singular values.

	Parameters
	----------
	M : ndarray
		The matrix to invert. This matrix must be two-dimensional.
	num_modes : integer
		The number of modes to use for the inversion. Higher-order modes
		are ignored.
	svd : SVD object
		A precalculated singular value decomposition object. This will
		be used if supplied, to avoid recalculation of an SVD.

	Returns
	-------
	ndarray
		The inverted matrix.
	'''
	if svd is None:
		from .singular_value_decomposition import SVD
		svd = SVD(M, num_modes)

	U, S, Vt = svd.svd
	return (Vt.T / S).dot(U.T)

def inverse_truncated(M, rcond=1e-15, svd=None):
	'''Invert `M` truncating the number of modes.

	Modes are given by a singular value decomposition of the input matrix.
	If `svd` is given, it is used instead. Modes are ordered in descending
	order by their singular values. All modes with a singular value lower than
	`rcond` times the maximum singular value, will be ignored.

	Parameters
	----------
	M : ndarray
		The matrix to invert. This matrix must be two-dimensional.
	rcond : scalar
		The relative condition number of the highest-order mode that must
		be used for inversion.
	svd : SVD object
		A precalculated singular value decomposition object. This will
		be used if supplied, to avoid recalculation of an SVD.

	Returns
	-------
	ndarray
		The inverted matrix.
	'''
	if svd is None:
		from .singular_value_decomposition import SVD
		svd = SVD(M)

	U, S, Vt = svd.svd
	S_inv = np.array([1/s if abs(s) > (rcond * S.max()) else 0 for s in S])

	return (Vt.T * S_inv).dot(U.T)

def inverse_tikhonov(M, rcond=1e-15, svd=None):
	'''Invert `M` using Tikhonov regularization.

	Tikhonov regularization will be an identity matrix, with strength
	`rcond` * the maximum singular value of the matrix.

	Parameters
	----------
	M : ndarray
		The matrix to invert. This matrix must be two-dimensional.
	rcond : scalar
		The relative strength of the regularization. An identity matrix
		will be used for the regularization.
	svd : SVD object
		A precalculated singular value decomposition object. This will
		be used if supplied, to avoid recalculation of an SVD.

	Returns
	-------
	ndarray
		The inverted matrix.
	'''
	if svd is None:
		from .singular_value_decomposition import SVD
		svd = SVD(M)

	U, S, Vt = svd.svd
	S_inv = S / (S**2 + (rcond * S.max())**2)

	return (Vt.T * S_inv).dot(U.T)


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

"""
二维离散傅里叶(Fourier)变换
"""

from .fourier import fft
from .fourier import ifft
import numpy as np

def dft2d(fxy:np.matrix):
    """二维离散傅里叶变换

    :Parameters:
        - fxy: 二维离散序列

    :Returns: 二维频谱序列
    """
    M,N = fxy.shape
    m = np.arange(M).reshape(M, 1)
    n = np.arange(N).reshape(N, 1)
    wm = np.exp((-2j * np.pi / M) * np.dot(m, m.T))
    wn = np.exp((-2j * np.pi / N) * np.dot(n, n.T))
    fuv = np.dot(np.dot(wm, fxy), wn)   # wm和wn为对称矩阵，不用提心转置问题
    return fuv

def idft2d(fuv:np.matrix):
    """二维离散傅里叶逆变换

    :Parameters:
        - fuv: 二维频谱序列

    :Returns: 二维离散序列
    """
    M,N = fuv.shape
    m = np.arange(M).reshape(M, 1)
    n = np.arange(N).reshape(N, 1)
    wm = np.exp((2j * np.pi / M) * np.dot(m, m.T))
    wn = np.exp((2j * np.pi / N) * np.dot(n, n.T))
    fxy = np.dot(np.dot(wm, fuv), wn) / (M * N)  # wm和wn为对称矩阵，不用提心转置问题
    return fxy

def fft2d_shift(img:np.matrix):
    """平移二维序列

    :Parameters:
        - img: 二维序列

    :Returns: 平移后的序列
    """
    M,N = img.shape
    s = np.zeros((M, N), dtype=img.dtype)
    mu = int(np.ceil(M / 2))
    md = int(np.trunc(M / 2))
    nu = int(np.ceil(N / 2))
    nd = int(np.trunc(N / 2))
    s[:md, :nd] = img[mu:, nu:]
    s[:md, nd:] = img[mu:, :nu]
    s[md:, :nd] = img[:mu, nu:]
    s[md:, nd:] = img[:mu, :nu]
    return s

def fft2d(fxy:np.matrix):
    """二维离散傅里叶变换

    基于一维fft计算太慢，可以考虑使用原位计算优化。
    """
    # raise Exception('Not implementation')
    M,N = fxy.shape
    fuv = np.zeros((M, N), dtype=np.complex)
    for k in np.arange(M):
        fuv[k, :] = fft(fxy[k, :])
    for k in np.arange(N):
        fuv[:, k] = fft(fuv[:, k])
    return fuv

def ifft2d(fuv:np.matrix):
    """二维离散傅里叶逆变换
    """
    # raise Exception('Not implementation')
    M,N = fuv.shape
    fxy = np.zeros((M, N), dtype=np.complex)
    for k in np.arange(M):
        fxy[k, :] = ifft(fuv[k, :])
    for k in np.arange(N):
        fxy[:, k] = ifft(fxy[:, k])
    return fxy


""" Orbital Mechanics for Engineering Students Problem 1.2
Question:
Given four vectors A, B, C, and D and the identities from Problem 1.1, show
    (A x B) . (C x D) = (A . C)(B . D) - (A . D)(B. C)
Written by: J.X.J. Bannwarth
"""
from sympy.vector import CoordSys3D
from sympy.vector import Vector
from sympy import symbols
from sympy import simplify

# Title
print("Orbital Mechanics for Engineering Students Problem 1.2")

# Coordinate system
N = CoordSys3D('N')
i, j, k = N.base_vectors()

# Define vectors
ax, ay, az = symbols("ax ay az")
bx, by, bz = symbols("bx by bz")
cx, cy, cz = symbols("cx cy cz")
dx, dy, dz = symbols("dx dy dz")
A = ax * i + ay * j + az * k
B = bx * i + by * j + bz * k
C = cx * i + cy * j + cz * k
D = dx * i + dy * j + dz * k

# Analytical
print("(1) Answer")
print("(A x B) . (C x D)")
print("A . [B x (C x D)] - interchangeability")
print("A . [C(B . D) - D(B . C)] - bac-cab")
print("(A . C)(B . D) - (A . D)(B . C) - expand")

# Check the equations work out
print("\n(2) Check")
LHS = simplify((A.cross(B)).dot(C.cross(D)))
RHS = simplify(A.dot(C) * B.dot(D) - A.dot(D) * B.dot(C))
print("(A x B) . (C x D) =", LHS)
print("(A . C)(B . D) - (A . D)(B . C) =", RHS)
if simplify(LHS - RHS) == 0:
    print("(A x B) . (C x D) == (A . C)(B . D) - (A . D)(B. C)")


# Assignemnt on 2 sample T test

import numpy as np

"""
1.Two sets of ten students selected at random from a college were taken:One set was given memory test as they were and the other was given the memory test after two weeks of training and the scores are given below:

Set A	10	8	7	9	8	10	9	6	7	8
Set B	12	8	8	10	8	11	9	8	9	9

Do you think there is a significant effect due to training ?
"""
print("Assignment 1")

sample1=np.array([10,8,7,9,8,10,9,6,7,8])
sample2=np.array([12,8,8,10,8,11,9,8,9,9])
#print(len(sample1),len(sample2))

from scipy.stats import ttest_ind

tstatistics,pvalue=ttest_ind(sample1,sample2)
print("T Statistics:",tstatistics)
print("pvalue:",pvalue)

if pvalue<0.05:
    print("Reject the Null Hypothesis")
    print("Significant Effect due to Training")
else:
    print("Fails to Reject the Null Hypothesis")
    print("No Significant Effect due to Training")
print("\n")

"""
2.A group of 5 patients treated with medicine A weigh 42,39,48,60 and 41 kgs; a second group of 7 patients from the same hospital treated with medicine B weigh 38,42,56,64,68,69 and 62 kgs. Do you agree with the claim that medicine B increases weight significantly.
"""
print("Assignment 2")

sample1=np.array([42,39,48,60,41])
sample2=np.array([8,42,56,64,68,69,62])

tstatistics,pvalue=ttest_ind(sample1,sample2)
print("T Statistics:",tstatistics)
print("pvalue:",pvalue)

if pvalue<0.05:
    print("Reject the Null Hypothesis")
    print("Medicine B increase weight significantly")
else:
    print("Fails to Reject the Null Hypothesis")
    print("Medicine B does not increase weight significantly")
print("\n")

"""
3.Samples of two types of electric bulbs were tested for length of life and the following data were obtained

	Type I	Type II
No of Samples	8	7
Mean of the Samples (in hrs.)	1134	1024
SD of the samples (in hrs.)	35	40

Test at 5 percent level, whether the difference in sample means is significant
"""
print("Assignment 3")
ns1=8
ns2=7
means1=1134
means2=1024
sds1=35
sds2=40

from scipy.stats import ttest_ind_from_stats

tstatistics,pvalue=ttest_ind_from_stats(\
    mean1=means1,std1=sds1,nobs1=ns1,\
    mean2=means2,std2=sds1,nobs2=ns2)
print("T Statistics:",tstatistics)
print("pvalue:",pvalue)

if pvalue<0.05:
    print("Reject the Null Hypothesis")
    print("Two types of bulbs differ significantly with respect to theri mean life")
else:
    print("Fails to Reject the Null Hypothesis")
    print("Two types of bulbs differ significantly with respect to theri mean life")
print("\n")


import numpy as np
import matplotlib.pyplot as plt
"""
Y = ((Y_(i+1) - Y_i)/(X_(i+1) - X_i))*(X - X_i) +Y_i

Programación

1. Cargar dato:
X = []
Y = []

2. Def Interpolación Lineal: (X[],Y[]):
for(i=0, len(X[])-1):
    if(x >= xi and x =< X_(i+1) ):
        calcule m, b, y
        return y
"""

datos = np.loadtxt("datos.dat")
x_list = []
y_list = []

for i in range(0,datos.shape[0]):
    x_list.append(datos[i][0])
    y_list.append(datos[i][1])

def intPLineal(x_list, y_list,x):
    for i in range(0, len(x_list)):
        if(x >= x_list[i] and x <= x_list[i+1]):
            x_prev = x_list[i] #X_i
            y_prev  = y_list[i] #  Y_i
            x_next = x_list[i+1] #X_i+1
            y_next = y_list[i+1]#Y_i+1

            y = (y_next - y_prev)/(x_next - x_prev)*(x - x_prev) + y_prev
            return y

x_interpol = np.linspace(min(x_list), max(x_list),100)
y_interpol = []

for i in range(0,len(x_interpol)):
    y_interpol.append(intPLineal(x_list,y_list,x_interpol[i]))

fig = plt.figure()
ax = plt.axes()
ax.plot(x_list, y_list,'*',markersize='10', label='Datos Discretos')
ax.plot(x_interpol, y_interpol,'.', label='Puntos interpolados')
ax.plot(x_interpol, np.sin(x_interpol), label='sin(x)')
ax.legend()
plt.show()
#print(intPLineal(x_list,y_list,0.5))


"""
Module for calculating and caching Chebyshev polynomials, as well as
  some helper functions regarding polynomial manipulation.
"""

from sympy import Poly
from sympy.abc import x

"""
Caching for the computed Chebyshev polynomials.
"""
computed_polynomials = [Poly(1, x), Poly(x, x)]

def get_nth_chebyshev_polynomial(polynomial_degree: int) -> Poly:
    """
    Calculates the nth Chebyshev polynomial using the recursive relation:

        T_n = 2x * T_{n - 1} - T_{n - 2}

    Caches the result in the computed_polynomials list.

    :param polynomial_degree: degree of the Chebyshev polynomial
    :return: the nth Chebyshev polynomial
    :rtype: Poly
    """
    if (len(computed_polynomials) - 1) >= polynomial_degree:
        return computed_polynomials[polynomial_degree]

    # T_n = 2x * T_{n - 1} - T_{n - 2}
    T_n_1 = get_nth_chebyshev_polynomial(polynomial_degree - 1)
    T_n_2 = get_nth_chebyshev_polynomial(polynomial_degree - 2)

    T_n = 2 * x * T_n_1 - T_n_2

    computed_polynomials.append(T_n)

    return T_n

def normalise_polynomial(polynomial: Poly) -> Poly:
    """
    Normalises polynomial by dividing it by its leading coefficient.

    :param polynomial: polynomial to normalise
    :return: normalised polynomial
    :rtype: Poly
    """

    return polynomial / polynomial.LC()

def get_normalised_nth_chebyshev_polynomial(polynomial_degree: int) -> Poly:
    """
    A helper function to return the normalised nth Chebyshev polynomial.

    :param polynomial_degree: degree of the Chebyshev polynomial
    :return: normalised Chebyshev polynomial
    :rtype: Poly
    """

    return normalise_polynomial(get_nth_chebyshev_polynomial(polynomial_degree))

def lower_degree_to(polynomial: Poly,
                    max_polynomial_degree: int) -> Poly:
    """
    Lowers the degree of the polynomial by using Chebyshev polynomials.

    :param polynomial: polynomial to lower the degree of
    :param max_polynomial_degree: maximum polynomial degree to lower to
    :return: polynomial with the degree less than or equal to `max_polynomial_degree`
    :rtype: Poly
    """

    while polynomial.degree() > max_polynomial_degree:
        normalised_chebyshev_polynomial = get_normalised_nth_chebyshev_polynomial(polynomial.degree())

        polynomial -= normalised_chebyshev_polynomial * polynomial.LC()

    return polynomial


import numpy as np

def linear_interpolation(x_data, y_data, point):
    if len(x_data) != len(y_data):
        raise Exception("X and Y vectors must have equal number of elements.")

    if x_data.size < 2:
        raise Exception("X and Y vectors have to contain at least 2 elements.")

    def _interpolate(x1, x2, y1, y2, point):
        return ((y2 - y1) * point + x2 * y1 - x1 * y2) / (x2 - x1)

    for index, x in np.ndenumerate(x_data[:-1]):
        i = index[0]
        if point >= x and point <= x_data[i + 1]:
            x1 = x
            x2 = x_data[i + 1]
            y1 = y_data[i]
            y2 = y_data[i + 1]
            return _interpolate(x1, x2, y1, y2, point)


"""Lower-Upper (LU) Decomposition."""

# lower–upper (LU) decomposition - https://en.wikipedia.org/wiki/LU_decomposition
import numpy

def LUDecompose(table):
    # Table that contains our data
    # Table has to be a square array so we need to check first
    rows, columns = numpy.shape(table)
    L = numpy.zeros((rows, columns))
    U = numpy.zeros((rows, columns))
    if rows != columns:
        return []
    for i in range(columns):
        for j in range(i - 1):
            sum = 0
            for k in range(j - 1):
                sum += L[i][k] * U[k][j]
            L[i][j] = (table[i][j] - sum) / U[j][j]
        L[i][i] = 1
        for j in range(i - 1, columns):
            sum1 = 0
            for k in range(i - 1):
                sum1 += L[i][k] * U[k][j]
            U[i][j] = table[i][j] - sum1
    return L, U

if __name__ == "__main__":
    matrix = numpy.array([[2, -2, 1], [0, 1, 2], [5, 3, 1]])
    L, U = LUDecompose(matrix)
    print(L)
    print(U)


# Finding the minimum for the function:
# f(x,y) = -log(1-x-y)-log(x)-log(y)
# Domain x + y < 1, x > 0, y > 0
# Using Gradient Descent

# Import Required Libraries
import numpy
import matplotlib.pyplot as plt

# Functions
# Initial Guess
def Initalisation():
    x = numpy.random.uniform(0, 0.5)
    y = numpy.random.uniform(0, 0.5)
    return numpy.array([[x, y]])

# Calculates Gradient of the given Function
def Gradient(x, y):
    g1 = (-2 * x - y + 1) / (x ** 2 + y * x - x)
    g2 = (-x - 2 * y + 1) / (x * y + y ** 2 - 1)
    return numpy.array([g1, g2])

# Evaluates the value of the function at the given point
def Eval_Func(x, y):
    return -numpy.log(1-x-y)-numpy.log(x)-numpy.log(y)

# Update the points based on the Gradient Descent Algorithm
def Update_Weights(x, y, eta):
    return numpy.array([x, y]) - eta*Gradient(x, y)

# Actual Loop where Gradient Descent Algo runs until optimal point is reached
def GD(max_iter, tol, eta):
    iterations = 0
    F = numpy.array([])  # Stores the values of the function
    Epoch = numpy.array([])
    while iterations < max_iter:
        if iterations == 0:
            # Generate Initial Guess and Book Keeping
            if numpy.DataSource().exists('InitialGuess.txt'):
                W = numpy.loadtxt('InitialGuess.txt')  # Load the Initial Weights
            else:
                W = Initalisation()
                numpy.savetxt('InitialGuess.txt', W)  # Generate the Weights and save them
            W = numpy.reshape(W, (1, 2))
            f_temp = Eval_Func(W[-1, 0], W[-1, 1])
            F = numpy.concatenate((F, [f_temp]), axis=0)
            Epoch = numpy.concatenate((Epoch, [iterations]), axis=0)
            print('No. of Iterations: ', iterations, ' Points: ', W[-1], ' Function Value: ', F[-1], '\n')
            iterations += 1
        else:
            # Run The Gradient Descent Algorithm
            w_temp = Update_Weights(W[-1, 0], W[-1, 1], eta)
            f_temp = Eval_Func(W[-1, 0], W[-1, 1])
            # Book Keeping
            W = numpy.concatenate((W, [w_temp]), axis=0)
            F = numpy.concatenate((F, [f_temp]), axis=0)
            Epoch = numpy.concatenate((Epoch, [iterations]), axis=0)
            print('No. of Iterations: ', iterations, ' Points: ', W[-1], ' Function Value: ', F[-1], '\n')
            # Check for Close Weights
            if (W[-1] - W[-2]).all() < tol:
                print('Optimal Value Reached')
                break
            else:
                iterations += 1
    return Epoch, W, F

# Parameters
max_iter = 100000 # Maximum Iterations to reach the optimal value
tol = 1.0e-6 # Tolerance
eta = 0.05 # Learning Rate

# Main Loop
Epoch, W, F = GD(max_iter, tol, eta)

# Plot the results
# Plot 1
fig, ax1 = plt.subplots()
ax1.plot(W[:, 0], W[:, 1], 'rx:', label='Points After Every Iterations')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Trajectory Followed by the Points at each Iteration')
plt.legend()
# Plot 2
fig, ax2 = plt.subplots()
ax2.plot(Epoch, F, 'b', label='Energy')
plt.xlabel('Epoch')
plt.ylabel('Function Value')
plt.title('Value of the Function -log(1-x-y)-log(x)-log(y) at each iteration')
fig.text(0.39, 0.03, r'Learning Rate $\eta = 0.05$', ha='center')
plt.legend()
plt.tight_layout()
plt.show()


import numpy as np

def sigmoid(vector: np.array) -> np.array:
    """fungsi sigmoid digunakan untuk mendapatkan output berupa non-linear

    Args:
        vector (np.array): Nilai input berupa vektor

    Returns:
        np.array: Nilai sigmoid dari vektor yang diinputkan

    >>> sigmoid(np.array([-1.0, 1.0, 2.0]))
    array([0.26894142, 0.73105858, 0.88079708])
    >>> sigmoid(np.array([0.0]))
    array([0.5])
    """
    return 1 / (1 + np.exp(-vector))


import time
import numpy as np

class Knapsack:
    # A class to solve Knapsack problems presented in Coursera, Discrete Optimisation, week 2

    def __init__(self, values, weights):
        self.diagnose = False
        self.v = values
        self.w = weights
        self.method_names = {1: "DP",
                             2: "DP (Branch & Bound)",
                             3: "DP (Branch & Bound, fractional item)"
                             }

    def solve(self, capacity, method):
        self.count = 0
        self.currentBest = 0
        self.K = capacity
        self.method = method
        start_time = time.time()

        if method == 1:
            self.value = self.DP(self.K, self.v.size, self.v, self.w)
        elif method == 2:
            self.value = self.DP_BB1(self.K, self.v.size, self.v, self.w)

        self.time_taken = (time.time() * 1000 - start_time * 1000)

    def print(self):
        print("Capacity of this knapsack problem:", self.K)
        print("Optimal value:", self.value)
        print("Method used is:", self.method_names[method])
        print("Time taken: %s ms" % round(self.time_taken, 0))
        print("The function has been called: %i times." % self.count)

    def DP(self, k, j, v, w):
        self.count += 1
        if self.diagnose:
            print(f"count={self.count} | k={k} | j={j} | v={v} | w={w}")
        if j == 0:
            return 0
        elif w[j - 1] <= k:
            return max(self.DP(k, j - 1, v, w), v[j - 1] + self.DP(k - w[j - 1], j - 1, v, w))
        else:
            return self.DP(k, j - 1, v, w)

    def DP_BB1(self, k, j, v, w):
        self.count += 1
        if self.diagnose:
            print(f"count={self.count} | k={k} | j={j} | v={v} | w={w}")

        if j == 0 or v.dot(w) < self.currentBest:
            return 0
        elif w[j - 1] <= k:
            value = max(self.DP(k, j - 1, v, w), v[j - 1] + self.DP(k - w[j - 1], j - 1, v, w))
            if value > self.currentBest:
                self.currentBest = value
            return value
        else:
            return self.DP(k, j - 1, v, w)

v1 = np.array([16, 19, 23, 28, 18, 24, 5, 15, 17, 37, 21, 14, 9, 24, 11, 58, 28, 22, 18,
               13, 33, 16, 19, 23, 28, 18, 24, 5, 15, 17, 37, 21, 14, 9, 24, 11, 58, 28, 22, 18, 13, 33,
               16, 19, 23, 28, 18, 24, 5, 15, 17, 37, 21, 13, 33, 16, 19, 23, 28, 18, 24, 5, 15, 17])

w2 = np.array([2, 3, 4, 5, 3, 4, 1, 2, 2, 6, 4, 1, 1, 4, 1, 7, 5, 4, 3, 2, 6, 2, 3, 4, 5, 3, 4, 1, 2, 2, 6,
               4, 1, 1, 4, 1, 7, 5, 4, 3, 2, 6, 2, 3, 4, 5, 3, 4, 1, 2, 2, 6, 4,
               1, 1, 4, 1, 7, 5, 4, 3, 2, 6, 2, 3, 4, 5, 3, 4, 1, 2, 2])

v2 = np.array([45, 48, 35])
w2 = np.array([5, 8, 3])

knapsack1 = Knapsack(v2, w2)
knapsack1.diagnose = False

K = 10
method = 2
knapsack1.solve(K, method)
knapsack1.print()


from __future__ import division
from sympy import sin, cos, Symbol, lambdify, Number, Expr, S
from common import function
from math import sqrt, pi
import numpy as np

SQRT_PI = sqrt(pi)
SQRT_2PI = sqrt(2*pi)

def fourier_basis(N, symbol='x'):
    '''
    Consider a Fourier series

    \sum k\in[0, N]a_k cos(k x)/sqrt(pi) + \sum k\in[1, N]b_k sin(kx)/sqrt(pi).

    Here these 2*N + 1 basis functions are returned. Basis functions are
    normalized to have the L^2 norm over [0, 2*pi] equal to 1. The N can be
    understood as the highest wavenumber.
    '''
    x = Symbol(symbol)
    return [S(1)/SQRT_2PI] +\
           [cos(k*x)/SQRT_PI for k in range(1, N+1)] +\
           [-sin(k*x)/SQRT_PI for k in range(1, N+1)]

def fourier_function(F):
    '''
    Return a linear combination of len(F_vec) Fourier basis functions with
    coefficients given by F_vec.
    '''
    if len(F.shape) == 1:
        basis = fourier_basis(F.shape[0]//2, 'x')
        return function(basis, F)
    else:
        raise NotImplementedError('2d, 3d not implemented yet.')

def fourier_eval(N, f):
    '''
    Let N the highest wavenumber to be considered in the Fourier series for f.
    In order to get Fourier coefficients of f with some accuracy the function
    must be avaluated in a least 2*N points.
    '''
    n_points = 2*N
    points = np.linspace(0, 2*pi, n_points, endpoint=False)

    if isinstance(f, (Number, int, float)):
        f_values = float(f)*np.ones(len(points))
    # Symbolic functions
    elif isinstance(f, Expr):
        x = Symbol('x')
        assert x in f.atoms() or isinstance(f, Number)
        f = lambdify(x, f, 'numpy')
        # Lambdify makes it fast if we feed as arrays the x y z comps
        # of points
        f_values = f(points)
    # Python functions/lambdas
    else:
        # For (lambda)function I can only check the argcount
        assert f.func_code.co_argcount == 1
        f_values = np.array([f(*(p.tolist())) for p in points])

    return f_values

def fft(f_vec):
    '''
    If f was sapled in 2*N points we can construct a series with highest
    frequency N that has 2*N+1 terms. To get its coefficients we take a
    DFFT of f_vec this is N+1 complex values. The real part is proportional to
    the N+1 coeffs for cosines, while the imaginary part is related to the N
    coefficients of sines.
    '''
    F_vec = np.fft.rfft(f_vec)
    # These are the coefficient values
    n_points = len(f_vec)
    F_vec[0] *= SQRT_2PI/n_points
    F_vec[1:] *= 2*SQRT_PI/n_points
    F_vec = np.r_[F_vec.real, F_vec.imag[1:]]

    return F_vec

def ifft(F_vec):
    '''
    To get values of f in control points back, the coefficients must be rescaled
    and collapsed to complex vector.
    '''
    n_points = len(F_vec) - 1
    F_vec = F_vec.copy()
    F_vec[0] /= SQRT_2PI/n_points
    F_vec[1:] /= 2*SQRT_PI/n_points
    end_real = n_points/2 + 1
    F_vec = F_vec[:end_real] + 1j*np.r_[0, F_vec[end_real:]]
    f_vec = np.fft.irfft(F_vec)

    return f_vec

def mass_matrix(N):
    '''
    2N+1 x 2N+1 matrix with entries corresponding to \int_{0}^{2pi} u v where
    u, v are from fourier basis N is a diagonal matrix. Return the diagonal
    '''
    # This is here just for completeness
    return np.ones(2*N + 1)

def stiffness_matrix(N):
    '''
    2N+1 x 2N+1 matrix with entries corresponding to \int_{0}^{2pi} -u'' v where
    u, v are from fourier basis N is a diagonal matrix. Return the diagonal.
    '''
    # This is here just
    k_ = np.array([k**2 for k in range(1, N+1)])
    return np.r_[0, k_, k_]

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

if __name__ == '__main__':
    from sympy.mpmath import quad
    from sympy import lambdify
    from random import random

    N = 15
    tol = 1E-13

    x = Symbol('x')
    f = sum(random()*cos(k*x) + random()*sin(k*x) for k in range(N))

    # Computing fourier series coefficients by FFT
    f_vec = fourier_eval(N, f)
    F_vec = fft(f_vec)

    # Compare with analytical coefficients values
    basis = fourier_basis(N)
    for i, v in enumerate(basis):
         assert abs(quad(lambdify(x, v*f), [0, 2*np.pi]) - F_vec[i]) < 1E-14

    # Comming back
    f_vec_ = ifft(F_vec)
    assert np.allclose(f_vec, f_vec_)

    N = 6
    basis = fourier_basis(N)

    # Check mass matrix
    M = np.diag(mass_matrix(N))
    M_ = np.zeros_like(M, dtype='double')
    for i, v in enumerate(basis):
        M_[i, i] = quad(lambdify(x, v**2), [0, 2*pi])
        for j, u in enumerate(basis[i+1:], i+1):
            M_[i, j] = quad(lambdify(x, v*u), [0, 2*pi])
            M_[j, i] = M_[i, j]
    assert np.allclose(M, M_)

    # Check stiffness matrix
    A = np.diag(stiffness_matrix(N))
    A_ = np.zeros_like(A, dtype='double')
    for i, v in enumerate(basis):
        A_[i, i] = quad(lambdify(x, -v*v.diff(x, 2)), [0, 2*pi])
        for j, u in enumerate(basis[i+1:], i+1):
            A_[i, j] = quad(lambdify(x, -v*u.diff(x, 2)), [0, 2*pi])
            A_[j, i] = A_[i, j]
    assert np.allclose(A, A_)


import numpy as np
from numpy import *
import matplotlib.pyplot as plt
import math as m
from matplotlib.pyplot import figure, show

## we arue using the cholesky method to solve Ax=b

def facto_dense(A, n):
    T = np.zeros(shape=(n,n))
    for i in range(n):
        for k in range(i+1):
            tmp_sum = sum(np.fromiter((T[i][j] * T[k][j] for j in range(k)),float))

            if (i == k):
                T[i][k] = np.sqrt(A[i][i] - tmp_sum)
            else:
                T[i][k] = (A[i][k] - tmp_sum)/(T[k][k])
    return T

## finding Y in the method

def descente(T,n,B):
    Y = np.zeros(shape=(n, 1))
    Y[0]= B[0]/T[0][0]
    for i in range(1,n):
        s = 0
        for j in range(i):
            s += T[i][j]*Y[j]
        Y[i] = (B[i] - s)/T[i][i]
    return Y

## finding X in the method

def remontee(T,n,Y):
    X = np.zeros(shape=(n, 1))
    X[n-1] = Y[n-1]/T[n-1][n-1]
    for i in range(n-2,-1,-1):
        s = 0
        for j in range(i+1,n):
            s += T[i][j] * X[j]
        X[i] = (Y[i] -s)/T[i][i]
    return X

#final resolution of Ax=b

def resolution_cholesky(A,B,n):
    T = facto_dense(-A,n**2)
    Y = descente(T,n**2,-B)
    X = remontee(T.T, n**2, Y)
    return X

# second method reolution with gradient

def conjgrad(A, b,N):
    x=np.zeros(shape=(N**2,1))
    r=b-np.dot(A,x)
    p=r
    rsold=np.dot((np.conj(r).T),r)[0][0]

    for i in range(1, 10**6):
        Ap=np.dot(A,p)
        alpha=rsold/(np.dot(np.conj(p).T,Ap)[0][0])
        x=x+np.dot(alpha,p)
        r=r-np.dot(alpha,Ap)
        rsnew=np.dot((np.conj(r).T),r)[0][0]
        if np.sqrt(rsnew) < 10**(-10):
            break
        p=r+(rsnew/rsold)*p
        rsold=rsnew
    return x

# generate the derivative operator matrix

def generermatA(N):

    Matrix = np.zeros(shape=(N**2,N**2))
    for i in range(N**2):
        Matrix[i][i] = -4
        for j in range(N**2):
            if (j == i+1 and j%N != 0):
                Matrix[i][j] = 1
            if (i == j+1 and j%N != N-1):
                Matrix[i][j] = 1
            if (j == i+N):
                Matrix[i][j] = 1
            if (i == j+N):
                Matrix[i][j] = 1

    return Matrix

#generate f(x,y) <=> B

def genererB(f,N):
    B = np.zeros(shape=(N**2, 1))
    for i in range(N):
        for j in range(N):
            B[i*N+j] = f(i,j,N)
    return B
#function for center radiator

def radiateur_centre(i,j,N):
    if (i > N/2-5 and i < N/2+5 and j > N/2-5 and j < N/2+5):
        return -25
    return 0
#function tjat generate a north wall

def mur_nord(i,j,N):
    if (i > N-2):
        return -25
    return 0
#generate solotion according to the methode chosen

def gen_x(N, fonction, methode):
    A = generermatA(N)
    B = genererB(fonction,N)
    if (methode == "numpy"):
        x = np.linalg.solve(A,B)
    if (methode == "gradient"):
        x = conjgrad(A,B,N)
    if (methode == "cholesky"):
        x = resolution_cholesky(A,B,N)
    return x

#tranform a vector into a matrix

def vect_to_mat(x,N):
    T = np.zeros(shape=(N,N))
    for i in range(N):
        for j in range(N):
            T[i][j] = x[i*N+j][0]
    return T

def Eqchaleur(fonction, N, methode):
    return vect_to_mat(gen_x(N, fonction, methode), N)

def afficher(fonction, N, p, methode):
    fig=figure()
    pc = plt.pcolormesh(Eqchaleur(fonction, N, methode), cmap='hot' , shading='bilinear')
    fig.colorbar(pc)
    plt.xticks([x for x in range(0,N-1,int(N/10))]+[N-1], [i/10 for i in range(10)]+[1.0])
    plt.yticks([x for x in range(0,N-1,int(N/10))]+[N-1], [i/10 for i in range(10)]+[1.0])

    plt.show()

#afficher(mur_nord, 80, 0, "gradient" )
#afficher(radiateur_centre,80,1, "gradient")
#afficher(radiateur_centre, 40, 1, "cholesky" )

def calculer_ec_rel(fonction, N, methode):

    norme_numpy = np.linalg.norm(Eqchaleur(fonction, N, "numpy"))
    norme_fonction = np.linalg.norm(Eqchaleur(fonction, N, methode))

    ecart = abs(norme_fonction - norme_numpy)/norme_numpy

    return ecart


import numpy as np
import copy
import scipy
import scipy.linalg
import sys

def CalcularMatrices(n = 4): #intentar con n = 2,3,4,5 y ver que onda
    A = [[(i + j)**2 for i in range (1,n+1)] for j in range (1, n+1)]
    B = [0 for _ in range (n) ]
    bi = 0
    for i in range(0,n):
        for j in range (0,n-1):
            bi += A[i][j]
            print(bi)
        B[i] = bi
        bi = 0

    return A, B

def swap(v,i,j):
    if len(v.shape) == 1:
        v[i],v[j] = v[j],v[i]
    else:
        temp = copy.deepcopy(v[i])
        v[i] = v[j]
        v[j] = temp
    return v

def gaussPivoteo(a,b, tol = 1.0e-12):
    L = [[0 for i in range(len(a))]for j in range(len(a))] #inicializar matriz de ceros para la trinagular inferior

    n = len(b)

    s = np.zeros(n)
    for i in range(n):
        s[i] = max(abs(a[i,:]))

    # permutaciones
    vp = np.array(range(n))

    for k in range(0,n-1):
        p = np.argmax(abs(a[k:n , k])/s[k:n]) + k
        if abs(a[p,k]) < tol:
            print(f"La matriz es una matrix singular :c")
            input("Presione una tecla para salir")
            sys.exit()

        if p != k:
            swap(a,k,p)
            swap(b,k,p)
            swap(s,k,p)
            swap(vp,k,p)
            print(f"Intercambie {k} y {p}")

# Eliminación
        for i in range(k+1,n): # renglones
                lam = a[i,k]/a[k,k]
                L[i][k] = lam
                a[i,k:n] = a[i,k:n] - lam*a[k,k:n]
                b[i] = b[i] - lam*b[k]

    if abs(a[n-1,n-1]) < tol:
        print(f"Matrix singular :c")
        input("Oprime un tecla para continuar")
        sys.exit()

    # Sustitución regresiva
    for i in range(n-1,-1,-1):
        b[i] = (b[i] - np.dot(a[i,i+1:n],b[i+1:n]))/a[i,i]
    return b, vp

def Imprime(M):
    for l in M:
        print(l)
    print("\n")

if __name__ == "__main__":
    a  = np.array([[3.,-13., 9., 3.],[-6., 4., 1., -18.],[6., -2., 2., 4.],[12., -8., 6, 10.]])
    b  = np.array([-19., -34., 16., 26.])[np.newaxis]
    # a = np.array([[0.143, 0.357, 2.01],[-1.31, 0.911, 1.99],[11.2, -4.30, -0.605]])
    # b = np.array([-5.17, -5.46, 4.42])[np.newaxis]
    # a = np.array([[4,1,2,-3,5], [-3,3,-1,4,-2], [-1,2,5,1,3], [5,4,3,-1,2],[1,-2,3,-4,5.]])
    a_copy = copy.deepcopy(a)

    # b = np.array ([-16, 20, -4, -10, 3.])[np.newaxis]
    b = b.T
    b_copy = copy.deepcopy(b)

    L = []

    x, a = gaussPivoteo(a,b)

    print (f"El vertor de permutaciones es: \n")
    Imprime(a)

    print ("El vector b original", "\n",b_copy)
    print(f"\n")
    print("La solucion al sistema: ","\n", x, "\n")

    print(f"Ax = b {np.dot(a_copy,x)} \n")
    print (f"la comprobacion del sistema es: \n {np.linalg.solve(a_copy,b_copy)}")


import numpy as np
from fractions import Fraction
from kerala_math.jyatable import MST

_k = [0 for i in range(24)]
_b = [0 for i in range(24)]

# First two accurate jyas
_b[0] = MST(224, 50, 22)
_b[1] = MST(448, 42, 58)

# tattajya recurrence
for i in range(2,24):
    _b[i] = ((_b[i-1])**2 - (_b[0])**2)/_b[i-2]

# Pindajyas
_k[0] = _b[0]
for i in range(1,24):
    _k[i] = _b[i] - _b[i-1]

def khandajya(k: int):
    """
    Return the kth khandajya computed by the tattajya recurrence

    Inputs:
      k (int) : index from 0 to 23
    Outputs:
      int : kth khandajya
    """
    assert ((k>=0) & (k<24)), f"Input must be between 0 and 23 inclusive, got {k}"
    return _k[k]

def pindajya(k: int):
    """
    Return the kth pindajya computed by the tattajya recurrence

    Inputs:
      k (int) : index from 0 to 23
    Outputs:
      int : kth pindajya
    """
    assert ((k>=0) & (k<24)), f"Input must be between 0 and 23 inclusive, got {k}"
    return _b[k]


import numpy as np
from distributionLib import Dist

binom = Dist.binomialDist
xBar = Dist.expt
var = Dist.var
coolPrint = Dist.coolPrint

# test-1
#A fair coin tossed 6 times. The probability of head coming is as follow
print('test-1')
n   = 6
p   = 0.5
P   = binom(n,p,plot=True)
coolPrint(P)
print('-'*80)

'''
test-2
https://www.statisticshowto.com/probability-and-statistics/binomial-theorem/binomial-distribution-formula/
Example-3
60% of people who purchase sports cars are men.  If 10 sports car owners are randomly
selected, find the probability that exactly 7 are men.
'''
print('test-2')
n = 10
p = 0.6
k = 7
prob = binom(10,0.6,7)
print('Answer = {}'.format(prob))

P = binom(10,0.6,plot=True)
coolPrint(P)

print('-'*80)


import numpy as np
import matplotlib.pyplot as plt

def get_points():
    x_start = float(input())
    x = list(map(float, input().split()))
    y = list(map(float, input().split()))

    return x_start, x, y

def find_good_range_idx(x_start, x):
    k = 0
    for i, j in zip(x, x[1:]):
        if i <= x_start <= j:
            break
        k += 1

    return k

def calc_first_deriv(x, y, x_start):
    good_idx = find_good_range_idx(x_start, x)

    num1 = (y[good_idx + 1] - y[good_idx]) / (x[good_idx + 1] - x[good_idx])
    num2 = (y[good_idx + 2] - y[good_idx + 1]) / (x[good_idx + 2] - x[good_idx + 1]) - num1
    num2 = num2 / (x[good_idx + 2] - x[good_idx])

    return num1 + num2 * (2 * x_start - x[good_idx] - x[good_idx + 1])

def calc_second_deriv(x, y, x_start):
    good_idx = find_good_range_idx(x_start, x)
    num1 = (y[good_idx + 2] - y[good_idx + 1]) / (x[good_idx + 2] - x[good_idx + 1])
    num2 = (y[good_idx + 1] - y[good_idx]) / (x[good_idx + 1] - x[good_idx])

    return 2 * (num1 - num2) / (x[good_idx + 2] - x[good_idx])

def main():
    x_start, x, y = get_points()

    first_der = calc_first_deriv(x, y, x_start)
    second_der = calc_second_deriv(x, y, x_start)

    print(f'y\'(x) = {first_der}')
    print(f'y\"(x) = {second_der}')

main()


#!/usr/bin/python

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

def main():
    args = sys.argv
    a, b = args[1], args[2]
    t = integra_mc(func, 0, 5.5)
    print(t)

def func (x) :
    return -(x**2)+ 5*x + 5

#version numpy
def integra_mc(func, a, b, num_puntos = 100):
    puntos = np.linspace(a,b,num_puntos)
    m = max(func(puntos))
    fxpuntos = func(puntos)
    ypuntos = np.random.uniform(0, m, [num_puntos])
    menores = ypuntos < fxpuntos
    por_debajo = sum(menores)
    plt.plot(puntos, func(puntos), label="function")
    plt.plot(puntos,ypuntos,ls = 'None', marker = 'x', c = 'r', label="rand generated numbers")
    plt.legend(loc='upper left')
    ax = plt.gca() # gca stands for 'get current axis'
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    ax.xaxis.set_ticks_position('bottom')
    ax.spines['bottom'].set_position(('data',0))
    ax.yaxis.set_ticks_position('left')
    ax.spines['left'].set_position(('data',0))
    plt.show()
    return (por_debajo / num_puntos)*(b-a)*m

#-----------------------------------------funciones añadidas--------------------------------------------#

def main1():
    args = sys.argv
    a, b = args[1], args[2]
    t = integra_mc1(func, 0, 5.5)
    print(t)

def main2():
    from scipy import integrate
    x2 = lambda x: func (x)
    t = integrate.quad(x2, 0, 5.5)
    print(t)

#version iterativa
def integra_mc1(func, a, b, num_puntos = 1000000):

    punto_f = func(a)
    por_debajo = 0

    for num in range(num_puntos):
        aux = a + (b-a)*num/num_puntos
        aux_f = func(aux)

        if aux_f > punto_f:
            punto_f = aux_f

    for num in range(num_puntos):
        fx = func(random.randrange(a,int(b)))
        y = random.randrange(int(punto_f))

        if y < fx:
            por_debajo = por_debajo + 1

    return (por_debajo / num_puntos)*(b-a)*punto_f

main() # 379 µs ± 12.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

main1() # 2 s ± 4.79 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

main2() # 10.7 µs ± 22.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)


#import skfuzzy
import numpy as np
from math import pi
from scipy.special import erf
import matplotlib.pylab as plt

##______________________S-shaped transfer functions_______________________

def s1(x):

    s1=1 / (1 + np.exp(-2*x))

    return s1

def s2(x):
    s2 = 1 / (1 + np.exp(-x))
    return s2
# s2 is called logistic function and can be imported using scipy.special.expit(x) library

def s3(x):
    s3=1 / (1 + np.exp(-x/3))
    return s3

def s4(x):
    s4=1 / (1 + np.exp(-x/2))
    return s4

x = np.arange(-8, 8, 0.1)
# x is used inside this script and will be replaced by a binary individual (1-d binary vector)
#when the transfer function is called or imported in the optimizers scripts

#____________


#!/usr/bin/env python
import numpy as np

#!/usr/bin/env python
def slopes(x,y):
  """
  SLOPES calculate the slope y'(x) Given data vectors X and Y SLOPES
  calculates Y'(X), i.e the slope of a curve Y(X). The slope is
  estimated using the slope obtained from that of a parabola through
  any three consecutive points.
  This method should be superior to that described in the appendix
  of A CONSISTENTLY WELL BEHAVED METHOD OF INTERPOLATION by Russel
  W. Stineman (Creative Computing July 1980) in at least one aspect:
  Circles for interpolation demand a known aspect ratio between x-
  and y-values.  For many functions, however, the abscissa are given
  in different dimensions, so an aspect ratio is completely
  arbitrary.

  The parabola method gives very similar results to the circle
  method for most regular cases but behaves much better in special
  cases
  Norbert Nemec, Institute of Theoretical Physics, University or
  Regensburg, April 2006 Norbert.Nemec at physik.uni-regensburg.de
  (inspired by a original implementation by Halldor Bjornsson,
  Icelandic Meteorological Office, March 2006 halldor at vedur.is)
  """
  x=np.asarray(x, np.float64)
  y=np.asarray(y, np.float64)

  yp=np.zeros(y.shape, np.float64)

  dx=x[1:] - x[:-1]
  dy=y[1:] - y[:-1]
  dydx = dy/dx
  yp[1:-1] = (dydx[:-1] * dx[1:] + dydx[1:] * dx[:-1])/(dx[1:] + dx[:-1])
  yp[0] = 2.0 * dy[0]/dx[0] - yp[1]
  yp[-1] = 2.0 * dy[-1]/dx[-1] - yp[-2]
  return yp

def stineman_interp(xi,x,y,yp=None):
  """
  STINEMAN_INTERP Well behaved data interpolation.  Given data
  vectors X and Y, the slope vector YP and a new abscissa vector XI
  the function stineman_interp(xi,x,y,yp) uses Stineman
  interpolation to calculate a vector YI corresponding to XI.
  Here's an example that generates a coarse sine curve, then
  interpolates over a finer abscissa:
    x = linspace(0,2*pi,20);  y = sin(x); yp = cos(x)
    xi = linspace(0,2*pi,40);
    yi = stineman_interp(xi,x,y,yp);
    plot(x,y,'o',xi,yi)
  The interpolation method is described in the article A
  CONSISTENTLY WELL BEHAVED METHOD OF INTERPOLATION by Russell
  W. Stineman. The article appeared in the July 1980 issue of
  Creative computing with a note from the editor stating that while
  they were
    not an academic journal but once in a while something serious
    and original comes in adding that this was
    "apparently a real solution" to a well known problem.

  For yp=None, the routine automatically determines the slopes using
  the "slopes" routine.
  X is assumed to be sorted in increasing order
  For values xi[j] < x[0] or xi[j] > x[-1], the routine tries a
  extrapolation.  The relevance of the data obtained from this, of
  course, questionable...
  original implementation by Halldor Bjornsson, Icelandic
  Meteorolocial Office, March 2006 halldor at vedur.is
  completely reworked and optimized for Python by Norbert Nemec,
  Institute of Theoretical Physics, University or Regensburg, April
  2006 Norbert.Nemec at physik.uni-regensburg.de
  """
  # Cast key variables as float.
  x=np.asarray(x, np.float64)
  y=np.asarray(y, np.float64)
  assert x.shape == y.shape
  N=len(y)

  if yp is None:
      yp = slopes(x,y)
  else:
      yp=np.asarray(yp, np.float64)

  xi=np.asarray(xi, np.float64)
  yi=np.zeros(xi.shape, np.float64)

  # calculate linear slopes
  dx = x[1:] - x[:-1]
  dy = y[1:] - y[:-1]
  s = dy/dx  #note length of s is N-1 so last element is #N-2

  # find the segment each xi is in
  # this line actually is the key to the efficiency of this implementation
  idx = np.searchsorted(x[1:-1], xi)

  # now we have generally: x[idx[j]] <= xi[j] <= x[idx[j]+1]
  # except at the boundaries, where it may be that xi[j] < x[0] or xi[j] > x[-1]

  # the y-values that would come out from a linear interpolation:
  sidx = np.take(s, idx)
  xidx = np.take(x, idx)
  yidx = np.take(y, idx)
  xidxp1 = np.take(x, idx+1)
  yo = yidx + sidx * (xi - xidx)

  # the difference that comes when using the slopes given in yp
  dy1 = (np.take(yp, idx)- sidx) * (xi - xidx)       # using the yp slope of the left point
  dy2 = (np.take(yp, idx+1)-sidx) * (xi - xidxp1) # using the yp slope of the right point

  dy1dy2 = dy1*dy2
  # The following is optimized for Python. The solution actually
  # does more calculations than necessary but exploiting the power
  # of numpy, this is far more efficient than coding a loop by hand
  # in Python
  yi = yo + dy1dy2 * np.choose(np.array(np.sign(dy1dy2), np.int32)+1,
                               ((2*xi-xidx-xidxp1)/((dy1-dy2)*(xidxp1-xidx)),
                                0.0,
                                1/(dy1+dy2),))

  return yi


from math import factorial
import numpy as np

def _poch(d, n):
    """
    Returns
    -------
    d * (d - 1) * (d - 2) * ... * (d - n + 1) : float
    """
    return np.prod([d - k for k in range(n)])

def get_coefs(d, n_terms):
    """
    Compute coefficients of fracdiff operator explicitly (but inefficiently)
    and return the sequence of them as `numpy.array`.

    Parameters
    ----------
    - d : float
        Order of fracdiff.
    - n_terms : int
        Number of coefficients to compute.
    """
    return np.array([
        (-1) ** k * _poch(d, k) / factorial(k) for k in range(n_terms)
    ])


import math
import numpy as np

# DCG
def dcg(r, k=None):
    """The Burges et al. (2005) version of DCG.

    This is what everyone uses (except trec_eval)
    :param r: results
    :param k: cut-off
    :return: sum (2^ y_i - 1) / log (i +2)
    """
    result = sum([(pow(2, rel) - 1) / math.log(rank + 2, 2) for rank, rel in enumerate(r[:k])])
    return result

def dcg_trec(r, k=None):
    """The `trec_eval` version of DCG

    :param r: results
    :param k: cut-off
    :return: sum rel_i / log(i + 2)
    """
    result = sum([rel / math.log(rank + 2, 2) for rank, rel in enumerate(r[:k])])
    return result

# nDCG
def ndcg(x, k=None, dcg=dcg):
    """
    Args:
        k: cutoff
        dcg_func: set to `dcg` or `dcg_trec`
    """
    ideal = dcg(sorted(x, reverse=True), k)
    if ideal == 0:
        return 0
    result = dcg(x, k) / ideal
    return result

def err(x, k, g_max):
    res = 0
    p = 1
    norm = pow(2, g_max)
    for i, g in enumerate(x[:k], 1):
        R = float(pow(2, g) - 1) / norm
        res += p * R / i
        p *= (1 - R)
    return res

def patk(labels, k):
    """We assume an array with 0's and 1's
        If there are no relevant documents (all zeroes) will return zero
    """
    return (0. + np.sum(labels[0:k])) / k

def mean_ap(labels, k=None, n_rel=None):
    """We assume an array with 0's and 1's
        If there are no relevant documents (all zeroes) will return zero
    """
    if n_rel is None:
        n_rel = np.sum(labels[0:k])
    if n_rel == 0:
        return 0

    idx = np.nonzero(labels[0:k])[0]
    score = np.sum((np.arange(idx.size) + 1.0) / (idx + 1.0))
    return score / n_rel

def print_trec_eval(groups):
    resfile = open('run.res', 'w')
    relfile = open('run.rel', 'w')

    qid = 0
    for s, l in groups:
        qid += 1
        new_l = [x for (y, x) in sorted(zip(s, l), key=lambda pair: pair[0], reverse=True)]
        new_s = sorted(s, reverse=True)
        for j in range(len(new_s)):
            resfile.write("Q%i Q0 Q%iD%i %i %f RUN\n" % (qid, qid, j+1, j+1, new_s[j]))
            relfile.write("Q%i 0 Q%iD%i %i\n" % (qid, qid, j+1, new_l[j]))
    relfile.close()
    resfile.close()

def ndcg_one(scores, labels):
    a = [x for (y, x) in sorted(zip(scores, labels), key=lambda pair: pair[0], reverse=True)]
    return ndcg(a, len(a))

def test_ndcg(scores, labels, query_ids, average=True):
    labels = np.maximum(labels, 0)
    groups, _ = group_per_query(scores, labels, query_ids)
    ndcg_scores = []
    for s, l in groups:
        idx = np.argsort(s)
        a = l[idx[::-1]]
        ndcg_scores.append(ndcg(a, len(a)))
    if average:
        return sum(ndcg_scores) / len(ndcg_scores)
    else:
        return ndcg_scores

def test_map(scores, labels, query_ids, average=True):
    labels = np.maximum(labels, 0)
    groups, _ = group_per_query(scores, labels, query_ids)
    map_scores = []
    for s, l in groups:
        idx = np.argsort(s)
        a = l[idx[::-1]]
        binary = [int(v > 0) for v in a]
        map_scores.append(mean_ap(binary))
    if average:
        return sum(map_scores) / len(map_scores)
    else:
        return map_scores

def group_per_query(pred, y, query_groups):
    # offsets, qids = group_offsets(query_groups, return_values=True)
    # return [(pred[a:b], y[a:b]) for a, b in offsets], qids

    qid = query_groups[0]
    ly = list()
    lpred = list()
    groups = list()
    unique_ids = [qid]

    for i in range(len(query_groups)):
        if qid != query_groups[i]:  # new query
            yarray = np.array(ly)
            predarray = np.array(lpred)
            groups.append((predarray, yarray))
            qid = query_groups[i]
            unique_ids.append(qid)
            ly = list()
            lpred = list()
        lpred.append(pred[i])
        ly.append(y[i])
    #groups.append((predarray, yarray))
    groups.append((np.array(lpred), np.array(ly)))
    return groups, unique_ids

def test_all(scores, labels, query_ids, rel=0, relcount={}, average=True):
    from collections import defaultdict
    max_grade = int(np.max(labels))
    labels = np.maximum(labels, 0)
    groups, qids = group_per_query(scores, labels, query_ids)
    # metrics = {"map": 0, "ndcg@5": 0, "ndcg@10": 0, "ndcg@20": 0, "dcg@5": 0, "dcg@10": 0,
    #            "dcg@20": 0, "err": 0,
    #            "p@1": 0, "p@2": 0, "p@5": 0, "p@10": 0, "p@20": 0, "dcg": 0, "ndcg": 0}

    if average:
        metrics = defaultdict(float)
    else:
        metrics = {k: [] for k in ('p@1', 'p@2', 'p@5', 'p@10', 'p@20', 'err@5', 'err@10', 'err@20',
                                   'dcg@5', 'dcg@10', 'dcg@20', 'ndcg@5', 'ndcg@10', 'ndcg@20',
                                   'map', 'err', 'dcg', 'ndcg')}

    # for (s, l) in groups:
    #     # sorts x using y as a key
    #     # a = [x for (y, x) in sorted(zip(s, l), key=lambda pair: pair[0], reverse=True)]
    #     idx = np.argsort(s)
    #     a = l[idx[::-1]]
    #     # print("scores %s labels %s array %s" %(s,l,a))
    #     # binary = map(lambda x: 1 if x > rel  else  0, a)
    #     binary = [int(v > 0) for v in a]

        # shallow metrics
    if average:
        for (s, l), qid in zip(groups, qids):
            idx = np.argsort(s)
            a = l[idx[::-1]]
            binary = [int(v > 0) for v in a]

            metrics["p@1"] += patk(binary, 1)
            metrics["p@2"] += patk(binary, 2)
            metrics["p@5"] += patk(binary, 5)
            metrics["p@10"] += patk(binary, 10)
            metrics["p@20"] += patk(binary, 20)
            metrics["err@5"] += err(a, 5, max_grade)
            metrics["err@10"] += err(a, 10, max_grade)
            metrics["err@20"] += err(a, 20, max_grade)
            metrics["dcg@5"] += dcg(a, 5)
            metrics["dcg@10"] += dcg(a, 10)
            metrics["dcg@20"] += dcg(a, 20)
            metrics["ndcg@5"] += ndcg(a, 5)
            metrics["ndcg@10"] += ndcg(a, 10)
            metrics["ndcg@20"] += ndcg(a, 20)

            # deep metrics
            metrics["map"] += mean_ap(binary, n_rel=relcount.get(qid, None))
            metrics["err"] += err(a, None, max_grade)
            metrics["dcg"] += dcg(a)
            metrics["ndcg"] += ndcg(a)

        for k in metrics.keys():
            metrics[k] /= len(groups) + 0.
        return metrics
    else:
        for (s, l), qid in zip(groups, qids):
            idx = np.argsort(s)
            a = l[idx[::-1]]
            binary = [int(v > 0) for v in a]

            metrics["p@1"].append(patk(binary, 1))
            metrics["p@2"].append(patk(binary, 2))
            metrics["p@5"].append(patk(binary, 5))
            metrics["p@10"].append(patk(binary, 10))
            metrics["p@20"].append(patk(binary, 20))
            metrics["err@5"].append(err(a, 5, max_grade))
            metrics["err@10"].append(err(a, 10, max_grade))
            metrics["err@20"].append(err(a, 20, max_grade))
            metrics["dcg@5"].append(dcg(a, 5))
            metrics["dcg@10"].append(dcg(a, 10))
            metrics["dcg@20"].append(dcg(a, 20))
            metrics["ndcg@5"].append(ndcg(a, 5))
            metrics["ndcg@10"].append(ndcg(a, 10))
            metrics["ndcg@20"].append(ndcg(a, 20))

            # deep metrics
            metrics["map"].append(mean_ap(binary, n_rel=relcount.get(qid, None)))
            metrics["err"].append(err(a, None, max_grade))
            metrics["dcg"].append(dcg(a))
            metrics["ndcg"].append(ndcg(a))

        return metrics


import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from scipy.special import erf

# gelu/swish/softplus 对 relu 的光滑逼近

def psi(x):
    return 0.5 * (1 + erf(x / np.sqrt(2)))

def swish(x, a=1.1702):
    return x / (1 + np.exp(-a * x))

def relu(x):
    return np.maximum(x, 0.0)

def gelu(x):
    return 0.5 * x * (1 + erf(x / np.sqrt(2)))

def softplus(x, a=3):
    return 1 / a * np.log(1 + np.exp(a * x))

def plot_activations():
    x = np.linspace(-4, 4, 1000)
    plt.plot(x, psi(x), label="psi(x)")
    plt.plot(x, relu(x), label="relu")
    plt.plot(x, swish(x), label="swish")
    plt.plot(x, gelu(x), label="gelu")
    plt.plot(x, softplus(x), label="softplus")
    plt.legend(loc="upper right")
    plt.show()

def swish_psi_err(a):
    x = np.arange(0, 5, 0.001)
    e = np.abs(swish(x, a) - psi(x) * x)
    return np.max(e)

# 计算 swish 的参数 a
options = {"xtol": 1e-10, "ftol": 1e-10, "maxiter": 100000}
result = minimize(swish_psi_err, 0, method="Powell", options=options)
print(result.x)

if __name__ == "__main__":
    plot_activations()


import numpy as np
import matplotlib.pyplot as plt

# System Parameters
x_init = 0
xDot_init = 0

mass = 5
damp = 10
spring = 50

omega = 2
forceMagnit = 1

timeStart = 0
timeStop = 10
stepTime = 0.001
time = np.arange(timeStart, timeStop, stepTime, dtype = float)

# Initial Condition
y = np.array([[x_init], [xDot_init]], dtype = float)

# Reserve data
totalData = np.size(time)
position = np.zeros(totalData, dtype = float)
velocity = np.zeros(totalData, dtype = float)
acceleration = np.zeros(totalData, dtype = float)

positionRK = np.zeros(totalData, dtype = float)
velocityRK = np.zeros(totalData, dtype = float)
accelerationRK = np.zeros(totalData, dtype = float)

#Euler Method
systemFunction = lambda t, y: (forceMagnit*np.sin(omega*t)-damp*float(y[1])-spring*float(y[0]))/mass
#
for i in range(totalData):
    eulerMeth = systemFunction(time[i], y)
    y = y + stepTime*np.array([y[1], [eulerMeth]], dtype = float)

    position[i] = (y[0])
    velocity[i] = (y[1])
    acceleration[i] = eulerMeth

#Runge Kutta 4-5
#systemFunction = lambda t, y: (forceMagnit*np.sin(omega*t)-damp*float(y[1])-spring*float(y[0]))/mass
y = np.array([[x_init], [xDot_init]], dtype = float)

for i in range(totalData):
    t1 = time[i]
    f_1 = systemFunction(t1, y)
    k1 = np.array([y[1], [f_1]], dtype = float)

    t2 = time[i]+0.5*stepTime
    y2 = y + 0.5*k1*stepTime
    f_2 = systemFunction(t2, y2)
    k2 = np.array([y2[1], [f_2]], dtype = float)

    t3 = time[i]+0.5*stepTime
    y3 = y + 0.5*k2*stepTime
    f_3 = systemFunction(t3, y3)
    k3 = np.array([y3[1], [f_3]], dtype = float)

    t4 = time[i]+stepTime
    y4 = y + k3*stepTime
    f_4 = systemFunction(t4, y4)
    k4 = np.array([y4[1], [f_4]], dtype = float)

    RKFunct = (k1 + 2*k2 + 2*k3 + k4)/6
    y = y + stepTime*RKFunct

    positionRK[i] = (y[0])
    velocityRK[i] = (y[1])
    accelerationRK[i] = RKFunct[1]

plt.figure(1)
plt.plot(time, position)
plt.plot(time, positionRK)
title = "position plot [step time = %1.6f s]" % stepTime
plt.title(title)
plt.ylabel('displacement [m]')
plt.xlabel('time [s]')
plt.grid(True)
plt.legend(["euler", "RK"])

plt.figure(2)
plt.plot(time, velocity)
plt.plot(time, velocityRK)
title = "velocity plot [step time = %1.6f s]" % stepTime
plt.title(title)
plt.ylabel('velocity [m/s]')
plt.xlabel('time [s]')
plt.grid(True)
plt.legend(["euler", "RK"])

plt.figure(3)
plt.plot(time, acceleration)
plt.plot(time, accelerationRK)
title = "Accleration plot [step time = %1.6f s]" % stepTime
plt.title(title)
plt.ylabel('Acceleration [m/s/s]')
plt.xlabel('time [s]')
plt.grid(True)
plt.legend(["euler", "RK"])
plt.show()


# !/usr/bin/python

__author__ = 'fjanoos'

from optparse import OptionParser
from pylab import *
from numpy import linalg

# acceptable error
eps = 1e-4  #finfo(float).eps

def test_model( num_list, verb_flg):
	lhs_matrix =  matrix( [num_list[:-1], [double(1) for x in num_list[:-1]] ] ).transpose();

	rhs_matrix = matrix( num_list[1:]).transpose();

	# do a least squares solve
	coeffs = linalg.solve( lhs_matrix.transpose()*lhs_matrix, lhs_matrix.transpose()*rhs_matrix)

	if coeffs[0] > 1 and verb_flg:
		print( 'warning: This is not a well conditioned recursion (K > 1) -- might fail giving a result.' )

	# compute residuals
	r = rhs_matrix - lhs_matrix*coeffs

	sse = ( r.transpose()*r ) / len(r)

	if  verb_flg:
		print ( coeffs, sse)

	if sse < eps :
		return coeffs
	else:
		return None

if __name__ == "__main__":
	usage = \
		'''  %prog [options] [0,1] num_1 ... num_n
				   Prints K,L for a_i = K a_{i-1} + L ''';
	option_parser = OptionParser( usage )
	option_parser.add_option( "-v", "--verbose", action = "store_true", dest = "verbose", default = False );
	(options, args) = option_parser.parse_args( )

	verb_flg = options.verbose;

	if len( args ) <= 1 or (int(args[0]) !=1 and int(args[0]) !=2 ):
		option_parser.error( "incorrect arguments" )
		option_parser.print_help( )
		sys.exit( )

	type = int(args[0])
	num_list = [];
	for ii in range( 1, len( args ) ):
		num_list.append( double(args[ii]) )

	if  verb_flg:
		print 'processing '+str( num_list)

	try:
		coefs = test_model(num_list, verb_flg)
		if coefs != None:
			if type == 1:
				print '%.2f %.2f'%(coefs[0], coefs[1])
			else:
				print 'true'
		else:
			print 'false'
	except LinAlgError:
		print 'false'

# else:
# 	type = 1
# 	a0 = 4;
# 	K = 0.5;
# 	L = 2.77
# 	num_list = [a0]
# 	a_i = a0;
# 	for i in range( 1, 1000 ):
# 		a_i = a_i * K + L
# 		num_list.append( a_i )


# Code for solving du/dt = ddu/ddx on a rectangular grid
# of size L x (T*dt),
# with with L = 1, u(x,0) = g(x), u(0,t) = u(L,t) = 0
#

import numpy,math
import sys

def forward_step(alpha,u,uPrev,N):
    """
    Steps forward-euler algo one step ahead.
    Implemented in separate function for code-reuse from crank_nicolson()
    """

    for x in xrange(1,N+1): #loop from i=1 to i=N
        u[x] = alpha*uPrev[x-1] + (1.0-2*alpha)*uPrev[x] + alpha*uPrev[x+1]

def forward_euler(alpha,u,N,T):
    """
    Implements forward euler sheme, results saved to
    array u
    """

    #Skip boundary elements
    for t in xrange(1,T):
        forward_step(alpha,u[t],u[t-1],N)

def tridiag(alpha,u,N):
    """
    Tridiagonal gaus-eliminator, specialized to diagonal = 1+2*alpha,
    super- and sub- diagonal = - alpha
    """
    d = numpy.zeros(N) + (1+2*alpha)
    b = numpy.zeros(N-1) - alpha

    #Forward eliminate
    for i in xrange(1,N):
        #Normalize row i (i in u convention):
        b[i-1] /= d[i-1];
        u[i] /= d[i-1] #Note: row i in u = row i-1 in the matrix
        d[i-1] = 1.0
        #Eliminate
        u[i+1] += u[i]*alpha
        d[i] += b[i-1]*alpha
    #Normalize bottom row
    u[N] /= d[N-1]
    d[N-1] = 1.0

    #Backward substitute
    for i in xrange(N,1,-1): #loop from i=N to i=2
        u[i-1] -= u[i]*b[i-2]
        #b[i-2] = 0.0 #This is never read, why bother...

def backward_euler(alpha,u,N,T):
    """
    Implements backward euler scheme by gaus-elimination of tridiagonal matrix.
    Results are saved to u.
    """
    for t in xrange(1,T):
        u[t] = u[t-1].copy()
        tridiag(alpha,u[t],N) #Note: Passing a pointer to row t, which is modified in-place

def crank_nicolson(alpha,u,N,T):
    """
    Implents crank-nicolson scheme, reusing code from forward- and backward euler
    """
    for t in xrange(1,T):
        forward_step(alpha/2,u[t],u[t-1],N)
        tridiag(alpha/2,u[t],N)

def g(x):
    """Initial condition u(x,0) = g(x), x \in [0,1]"""
    return numpy.sin(math.pi*x)

#Initialize
if len(sys.argv) == 6:
    N       =   int(sys.argv[1])
    dt      = float(sys.argv[2])
    T       =   int(sys.argv[3])
    method  =   int(sys.argv[4])
    outfile =   str(sys.argv[5])
else:
    print "Usage:", sys.argv[0], "N dt T method"
    print "\t N:       Number of inner meshpoints"
    print "\t dt:      Length of timestep"
    print "\t T:       Number of timesteps"
    print "\t method:  Method selector:"
    print "\t          1 => Forward Euler"
    print "\t          2 => Backward Euler"
    print "\t          3 => Crank-Nicolson"
    print "\t outfile: Name of file to write to"
    sys.exit(0)

ofile = open(outfile,'w')

#dx = 1/float(N+1)
u = numpy.zeros((T,N+2),numpy.double)
(x,dx) = numpy.linspace (0,1,N+2, retstep=True)
alpha = dt/(dx**2)

#Initial codition
u[0,:] = g(x)
u[0,0] = u[0,N+1] = 0.0 #Implement boundaries rigidly

if   method == 1:
    forward_euler(alpha,u,N,T)
elif method == 2:
    backward_euler(alpha,u,N,T)
elif method == 3:
    crank_nicolson(alpha,u,N,T)
else:
    print "Please select method 1,2, or 3!"
    import sys
    sys.exit(0)

#Output
ostring = "%16.8E "*(N+2) + "\n";
for t in xrange(T):
    ofile.write(ostring % tuple(u[t,:]))
ofile.close()


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

# # normal method
# position = 0
# walk = [position]
# steps = 1000
# for i in range(steps):
#     step = 1 if random.randint(0, 1) else -1
#     position += step
#     walk.append(position)
# x = np.linspace(0, 1000, 1001)
# plt.figure()
# plt.ylim((-15, 15))
# plt.xlim((0, 100))
# plt.title('Random walk with +1/-1 steps')
# plt.plot(x, walk)
# plt.show()

# Use NumPy
nsteps = 1000
draws = np.random.randint(0, 2, size=nsteps)
steps = np.where(draws > 0, 1, -1)
walk = steps.cumsum() # cumulative sum of the steps

print('the minium of steps : ', walk.min())
print('the maxinum of steps : ', walk.max())

x = np.linspace(0, nsteps, nsteps)
plt.xlim((0, 100))
plt.ylim((-15, 15))
plt.title('Random walk with +1/-1 steps')
plt.plot(x, walk)
plt.show()


# Copyright 2017 Battelle Energy Alliance, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#***************************************
#* Simple analytic test ExternalModule *
#***************************************
# This test is used to compute the global sensitivities:
# The analytic solution for 5 input variables is:
# mean = 1.0, variance = 0.728
# S1 = S2 = S3 = 0.2747
# S12 = S23 = S31 = 0.0549
# S123 = 0.0110
#
# input variables are distributed as y ~ [0,1]
# from: Bruno Sudret, Global Sensitivity Analysis using Polynomial Chaos Expansion, Reliability Engineering and System Safety, 2008

import numpy as np

def evaluate(inp):
  return 1.0/(2.0**len(inp))*np.prod(list(1.+3.0*n**2 for n in inp))

def run(self,Input):
  self.ans  = evaluate(Input.values())

#
#  This model has analytic mean and variance and is documented in raven/docs/tests
#


import numpy as np

def spherical_coords(theta, phi):
    """
    given theta and phi, returns the corresponding Cartesian vector """
    theta *= 2*np.pi/360
    phi *= 2*np.pi/360
    r=1
    x=r*np.sin(theta)*np.cos(phi)
    y=r*np.sin(theta)*np.sin(phi)
    z=r*np.cos(theta)
    r = np.array([x,y,z])
    return r

def find_orthog(u1, u2):
    """
    Given two Cartesian vectors, find the vector that is orthogonal to both
    Arguments:
        u1: vector 1 [x,y,z]
        u2: vector 2 [x,y,z]
    Returns:
        theta, phi (oxford magnet basis)"""
    u3 = np.cross(u1, u2)
    theta = np.arccos(u3[2])/np.linalg.norm(u3)
    phi = np.arctan(u3[1]/u3[0])
    return theta, phi


## 1. The Range ##

import pandas as pd
houses = pd.read_table('AmesHousing_1.txt')

def range(distribution):
    range = max(distribution) - min(distribution)

    return range

range_by_year = {}
for year in houses['Yr Sold'].unique():
    data_by_year = houses[houses['Yr Sold'] == year]
    range_by_year[year] = range(data_by_year['SalePrice'])

print(range_by_year)

one = False
two = True

## 2. The Average Distance ##

C = [1,1,1,1,1,1,1,1,1,21]

def average_distance(array):
    reference_point = sum(array) / len(array)
    distances = []

    for value in array:
        distance = value - reference_point
        distances.append(distance)

    return sum(distances) / len(distances)

avg_distance = average_distance(C)
print(avg_distance)

## 3. Mean Absolute Deviation ##

C = [1,1,1,1,1,1,1,1,1,21]

def mean_absolute_deviation(array):
    reference_point =  sum(array) / len(array)

    distances = []

    for value in array:
        absolute_distance = abs(value - reference_point)
        distances.append(absolute_distance)

    return sum(distances)/len(distances)

mad = mean_absolute_deviation(C)
print(mad)

## 4. Variance ##

C = [1,1,1,1,1,1,1,1,1,21]

def variance(array):
    reference_point = sum(array) / len(array)

    distances = []

    for value in array:
        squared_distance =  (value - reference_point) ** 2
        distances.append(squared_distance)

    return sum(distances) / len(distances)

variance_C =  variance(C)
print(variance_C)

## 5. Standard Deviation ##

from math import sqrt
C = [1,1,1,1,1,1,1,1,1,21]

def standard_deviation(array):
    reference_point = sum(array) / len(array)

    distances = []

    for value in array:
        squared_distance = (value -  reference_point) ** 2
        distances.append(squared_distance)

    return sqrt(sum(distances)/len(distances))

standard_deviation_C = standard_deviation(C)
print(standard_deviation_C)

## 6. Average Variability Around the Mean ##

def standard_deviation(array):
    reference_point = sum(array) / len(array)

    distances = []
    for value in array:
        squared_distance = (value - reference_point)**2
        distances.append(squared_distance)

    variance = sum(distances) / len(distances)

    return sqrt(variance)

# Measure first the variability for each year
years = {}

for year in houses['Yr Sold'].unique():
    year_segment = houses[houses['Yr Sold']==year]
    st_dev = standard_deviation(year_segment['SalePrice'])
    years[year] =st_dev

# Get years of max and min variability
greatest_variability = max(years, key = years.get)
lowest_variability = min(years, key = years.get)
print(years)
print(greatest_variability)
print(lowest_variability)

## 7. A Measure of Spread ##

sample1 = houses['Year Built'].sample(50, random_state = 1)
sample2 = houses['Year Built'].sample(50, random_state = 2)

def standard_deviation(array):
    reference_point = sum(array) / len(array)

    distances = []
    for value in array:
        squared_distance = (value - reference_point)**2
        distances.append(squared_distance)

    variance = sum(distances) / len(distances)

    return sqrt(variance)

bigger_spread = 'sample 2'

st_dev1 = standard_deviation(sample1)
st_dev2 = standard_deviation(sample2)
print(st_dev1)
print(st_dev2)

## 8. The Sample Standard Deviation ##

def standard_deviation(array):
    reference_point = sum(array) / len(array)

    distances = []
    for value in array:
        squared_distance = (value - reference_point)**2
        distances.append(squared_distance)

    variance = sum(distances) / len(distances)

    return sqrt(variance)

import matplotlib.pyplot as plt
st_devs = []

for i in range(5000):
    sample = houses['SalePrice'].sample(10, random_state = i)
    st_dev = standard_deviation(sample)
    st_devs.append(st_dev)

plt.hist(st_devs)
plt.axvline(standard_deviation(houses['SalePrice']))

## 9. Bessel's Correction ##

from math import sqrt
def standard_deviation(array):
    reference_point = sum(array) / len(array)

    distances = []
    for value in array:
        squared_distance = (value - reference_point)**2
        distances.append(squared_distance)

    variance = sum(distances) / (len(distances)-1)

    return sqrt(variance)

import matplotlib.pyplot as plt
st_devs = []

for i in range(5000):
    sample = houses['SalePrice'].sample(10, random_state = i)
    st_dev = standard_deviation(sample)
    st_devs.append(st_dev)

plt.hist(st_devs)
plt.axvline(pop_stdev)  # pop_stdev is pre-saved from the last screen

## 10. Standard Notation ##

sample = houses.sample(100, random_state = 1)
from numpy import std, var

pandas_stdev = sample['SalePrice'].std(ddof = 1)
print(pandas_stdev)
numpy_stdev = std(sample['SalePrice'],ddof=1)
print(numpy_stdev)
equal_stdevs = pandas_stdev == numpy_stdev
print(equal_stdevs)

pandas_var = sample['SalePrice'].var(ddof = 1) # default ddof = 1
numpy_var = var(sample['SalePrice'], ddof = 1) #default ddof = 0
equal_vars = pandas_var == numpy_var

## 11. Sample Variance — Unbiased Estimator ##

population = [0, 3, 6]

samples = [[0,3], [0,6],
           [3,0], [3,6],
           [6,0], [6,3]
          ]

from numpy import var, std

pop_var = var(population, ddof = 0)
pop_std = std(population, ddof = 0)

st_devs = []
variances = []

for sample in samples:
    st_devs.append(std(sample, ddof = 1))
    variances.append(var(sample, ddof = 1))

mean_std = sum(st_devs) / len(st_devs)
mean_var = sum(variances) / len(variances)

equal_stdev = pop_std == mean_std
equal_var = pop_var == mean_var

5. Probability and Statistics/statistics-intermediate/Measures of Variability-308.py