"""
Peng-robinson equation of state calculator.

As used: https://www.poppyi.com/app_design_form/public_render/peng%20robinson%20eq%20of%20state
"""
import numpy as np

R = 8.31446  # Pa.m3/K

def validate_numeric(form_data, key):
    try:
        return float(form_data[key])
    except ValueError:
        raise Warning('Numeric input required for: {}'.format(key))

def main(form_data):
    temperature_kelvin = validate_numeric(form_data, 'temp_kelvin')
    pressure_pascal = validate_numeric(form_data, 'pressure_pascal')
    temperature_critical = validate_numeric(form_data, 'critical_temp_kelvin')
    pressure_critical = validate_numeric(form_data, 'critical_pressure_pa')
    acentric_factor = validate_numeric(form_data, 'acentric_factor')

    temperature_critical = float(temperature_critical)
    pressure_critical = float(pressure_critical)
    acentric_factor = float(acentric_factor)

    a = (0.457235 * (R * temperature_critical)**2) / pressure_critical
    b = 0.077796 * R * temperature_critical / pressure_critical

    if acentric_factor <= 0.49:
        kappa = 0.37464 + 1.54226 * acentric_factor - 0.26992 * acentric_factor**2
    else:
        kappa = 0.379642 + 1.48503 * acentric_factor - 0.164423 * acentric_factor**2 + 0.0166666 * acentric_factor**3

    reduced_temp = temperature_kelvin / temperature_critical

    alpha = (1 + kappa * (1 - reduced_temp**0.5))**2

    A = alpha * a * pressure_pascal / (R * temperature_kelvin)**2
    B = b * pressure_pascal / (R * temperature_kelvin)

    k3 = 1
    k2 = 1 - B
    k1 = A - 2 * B - 3 * B**2
    k0 = A * B - B**2 - B**3

    z_roots = np.roots([k3, -k2, k1, -k0])

    z = z_roots.real[z_roots.imag < 1e-5]

    z_filtered = [float(z_) for z_ in z if z_ >= 1e-3]

    if len(z_filtered) == 0:
        raise Warning('peng robinson eq of state error: no solutions found (no roots)')

    z_str = [str(i) for i in z_filtered]
    return {
        'compressibility_max': {
            'action': 'update',
            'value': max(z_filtered)
        },
        'compressibility_min': {
            'action': 'update',
            'value': min(z_filtered)
        },
        'peng_calc_output': {
            'action': 'update'
        },
        'debug_outputs': {
            'action': 'update'
        },
        'critical_temp': {
            'action': 'update',
            'value': temperature_critical
        },
        'critical_pressure': {
            'action': 'update',
            'value': pressure_critical
        },
        'acentric_factor': {
            'action': 'update',
            'value': acentric_factor
        },
        'reduced_temp': {
            'action': 'update',
            'value': reduced_temp
        },
        'a': {
            'action': 'update',
            'value': a
        },
        'b': {
            'action': 'update',
            'value': b
        },
        'k': {
            'action': 'update',
            'value': kappa
        },
        'alpha': {
            'action': 'update',
            'value': alpha
        },
        'A': {
            'action': 'update',
            'value': A
        },
        'B': {
            'action': 'update',
            'value': B
        },
    }


# -*- coding: utf-8 -*-
"""Copy of Forward-Backward-and-Central-Differentiation (1).ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1G7csGz574pv_wAA3j5TQgERYRnA56S_4

Before you turn this problem in, make sure everything runs as expected. First, **restart the kernel** (in the menubar, select Kernel$\rightarrow$Restart) and then **run all cells** (in the menubar, select Cell$\rightarrow$Run All).

Make sure you fill in any place that says `YOUR CODE HERE` or "YOUR ANSWER HERE", as well as your name and collaborators below:
"""

NAME = "Prabal CHowdhury"
COLLABORATORS = ""

"""---

# Differentiation: Forward, Backward, And Central
---

## Task 1: Differentiation

We have already learnt about *forward differentiation*, *backward diferentiation* and *central differentiation*. In this part of the assignment we will write methods to calculate this values and check how they perform.

The equations are as follows,

\begin{align}
\text{forward differentiation}, f^\prime(x) \simeq \frac{f(x+h)-f(x)}{h} \tag{4.6} \\
\text{backward differentiation}, f^\prime(x) \simeq \frac{f(x)-f(x-h)}{h} \tag{4.7} \\
\text{central differentiation}, f^\prime(x) \simeq \frac{f(x+h)-f(x-h)}{2h} \tag{4.8}
\end{align}

## Importing libraries
"""

import numpy as np
import matplotlib.pyplot as plt
from numpy.polynomial import Polynomial

"""Here, `forward_diff(f, h, x)`, `backward_diff(f, h, x)`, and `central_diff(f, h, x)` calculates the *forward differentiation*, *backward differentiation* and *central differentiation* respectively. finally the `error(f, f_prime, h, x)` method calculates the different values for various $h$ and returns the errors.

Later we will run some code to test out performance. The first one is done for you.
"""

def forward_diff(f, h, x):
    return (f(x+h) - f(x)) / h

def backward_diff(f, h, x):
    # --------------------------------------------
    # YOUR CODE HERE
    return (f(x-h) - f(x)) / h
    # --------------------------------------------

def central_diff(f, h, x):
    # --------------------------------------------
    # YOUR CODE HERE
    return (f(x+h) - f(x-h)) / (2*h)
    # --------------------------------------------

def error(f, f_prime, h, x):
    Y_correct = f_prime(x)
    f_error = np.array([])
    b_error = np.array([])
    c_error = np.array([])

    for h_i in h:
        # for different values of h (h_i)
        # calculate the error at the point x for  (i) forward method
        #                                         (ii) backward method
        #                                         (ii) central method
        # the first one is done for you
        f_error_h_i = forward_diff(f, h_i, x) - Y_correct
        f_error = np.append(f_error, f_error_h_i)

        b_error_h_i = backward_diff(f, h_i, x) - Y_correct
        b_error = np.append(b_error, b_error_h_i)

        c_error_h_i = central_diff(f, h_i, x) - Y_correct
        c_error = np.append(c_error, c_error_h_i)

    return f_error, b_error, c_error

"""## Plot1
Polynomial and Actual Derivative Function
"""

fig, ax = plt.subplots()
ax.axhline(y=0, color='k')

p = Polynomial([2.0, 1.0, -6.0, -2.0, 2.5, 1.0])
data = p.linspace(domain=[-2.4, 1.5])
ax.plot(data[0], data[1], label='Function')

p_prime = p.deriv(1)
data2 = p_prime.linspace(domain=[-2.4, 1.5])
ax.plot(data2[0], data2[1], label='Derivative')

ax.legend()

h = 1
fig, bx = plt.subplots()
bx.axhline(y=0, color='k')

x = np.linspace(-2.0, 1.3, 50, endpoint=True)
y = forward_diff(p, h, x)
bx.plot(x, y, label='Forward; h=1')
y = backward_diff(p, h, x)
bx.plot(x, y, label='Backward; h=1')
y = central_diff(p, h, x)
bx.plot(x, y, label='Central; h=1')

data2 = p_prime.linspace(domain=[-2.0, 1.3])
bx.plot(data2[0], data2[1], label='actual')

bx.legend()

h = 0.1
fig, bx = plt.subplots()
bx.axhline(y=0, color='k')

x = np.linspace(-2.2, 1.3, 50, endpoint=True)
y = forward_diff(p, h, x)
bx.plot(x, y, label='Forward; h=0.1')
y = backward_diff(p, h, x)
bx.plot(x, y, label='Backward; h=0.1')
y = central_diff(p, h, x)
bx.plot(x, y, label='Central; h=0.1')

data2 = p_prime.linspace(domain=[-2.2, 1.3])
bx.plot(data2[0], data2[1], label='actual')

bx.legend()

h = 0.01
fig, bx = plt.subplots()
bx.axhline(y=0, color='k')

x = np.linspace(-2.2, 1.3, 50, endpoint=True)
y = forward_diff(p, h, x)
bx.plot(x, y, label='Forward; h=0.01')
y = backward_diff(p, h, x)
bx.plot(x, y, label='Backward; h=0.01')
y = central_diff(p, h, x)
bx.plot(x, y, label='Central; h=0.01')

data2 = p_prime.linspace(domain=[-2.2, 1.3])
bx.plot(data2[0], data2[1], label='actual')

bx.legend()

fig, bx = plt.subplots()
bx.axhline(y=0, color='k')

h = np.array([1., 0.55, 0.3, .17, 0.1, 0.055, 0.03, 0.017, 0.01])
err = error(p, p_prime, h, 2.0)

bx.plot(h, err[0], label='Forward')
bx.plot(h, err[1], label='Backward')
bx.plot(h, err[2], label='Central')
bx.legend()


import numpy as np

#import numpy on your virtual environment

def add(matrix1, matrix2):
    matrix = [[0,0],[0,0]]

    for i in range(len(matrix1)):
        for j in range(len(matrix1[0])):
            matrix[i][j] = matrix1[i][j] + matrix2[i][j]
    return matrix

def add_python_way(matrix1, matrix2):
    return [[matrix1[i][j] + matrix2[i][j]  for j in range(len(matrix1[0]))] for i in range(len(matrix1))]

def print_array(array):
    for line in array:
        print('  '.join(map(str, line)))

def main():
    matrix1 = np.array([[1, -2],[-3, 4]])
    matrix2 = np.array([[2, -1],[0, -1]])

    print('matrix1:')
    print_array(matrix1)
    print()

    print('matrix2:')
    print_array(matrix2)
    print()

    print('matrix 1 + matrix2:')
    print_array(add(matrix1, matrix2))
    print()

    print('matrix 1 + matrix2 with pythonic list compreehension:')
    print_array(add_python_way(matrix1, matrix2))

if __name__ == "__main__":
    main()


import numpy as np
import pandas as pd

itr_limit = 1000
conv_crit = 0.0000001

def stop_cond(A, b, x):
    n = len(b)
    res = (A @ x - b)
    magnitude = (res @ res) ** 0.5

    if magnitude < conv_crit:
        return True
    else:
        return False

def GS(A, b, N=-1, x=None):
    n = len(b)
    itr = 0
    converged = False
    if x is None:
        x = np.zeros(n)

    while not converged and itr < itr_limit and itr != N:

        for i in range(n):
            dot = 0
            for j in range(n):
                if (i != j):
                    dot += A[i, j] * x[j]

            x[i] = (b[i] - dot) / A[i, i]

        itr += 1
        converged = stop_cond(A, b, x)

    if not converged:
        print("Iteration limit reached without convergence.")

    return x

Ni = 10
Nj = 10
dx = 0.1  # in m
dy = 0.1  # in m
K = 384.1  # Conductivity in W/mK
Su = 0  # Source in W/m^3
Sp = 0  # Source in W/(K.m^3)

Tw = 2500  # Temperatures in K
Ts = 400
Tn = 300
Te = 200
qw = 0  # Fluxes in W/m^2
qs = 0
qn = 0
qe = 0

def pad(x, i, j):
    if j < 0 or j >= x.shape[1]:
        return 0
    else:
        return x[i,j]

def diffusion_steady():
    n = Ni * Nj
    A = np.zeros((n,n))
    b = np.full(n, Su * dx * dy, dtype="double")

    for i in range(n):
        if i < Nj:
            A[i,i] += 2 * K * (dy / dx)
            b[i] += 2 * K * Tw * (dy / dx) + (qw * dy)
        else:
            A[i, i-Nj] -= K * dy / dx

        if i >= n - Nj:
            A[i,i] += 2 * K * (dy / dx)
            b[i] += 2 * K * Te * (dy / dx) + (qe * dy)
        else:
            A[i, i+Nj] -= K * dy / dx

        if i % Nj == 0:
            if i != 0 and i != (n-Nj):
                A[i,i] += 2 * K * (dx / dy)
                b[i] += 2 * K * Ts * (dx / dy) + (qs * dx)
        else:
            A[i, i-1] -= K * dx / dy

        if (i + 1) % Nj == 0:
            if i != (Nj-1) and i != (n-1):
                A[i,i] += 2 * K * (dx / dy)
                b[i] += 2 * K * Tn * (dx / dy) + (qn * dx)
        else:
            A[i, i+1] -= K * dx / dy

        A[i,i] -= pad(A,i,i-Nj) + pad(A,i,i-1) + pad(A,i,i+1) + pad(A,i,i+Nj) + Sp * dx * dy
    df1 = pd.DataFrame(A)
    df2 = pd.DataFrame(b)
    with pd.ExcelWriter('data.xlsx') as writer:
        df1.to_excel(writer, sheet_name='Sheet1')
        df2.to_excel(writer, sheet_name='Sheet2')
    return GS(A,b)

print(diffusion_steady())


import numpy as np

def get_cov_ellipsoid(cov, mu=np.zeros((3)), nstd=3):
    """
    Return the 3d points representing the covariance matrix
    cov centred at mu and scaled by the factor nstd.

    Plot on your favourite 3d axis.
    Example 1:  ax.plot_wireframe(X,Y,Z,alpha=0.1)
    Example 2:  ax.plot_surface(X,Y,Z,alpha=0.1)
    """
    assert cov.shape==(3,3)

    # Find and sort eigenvalues to correspond to the covariance matrix
    eigvals, eigvecs = np.linalg.eigh(cov)
    idx = np.sum(cov,axis=0).argsort()
    eigvals_temp = eigvals[idx]
    idx = eigvals_temp.argsort()
    eigvals = eigvals[idx]
    eigvecs = eigvecs[:,idx]

    # Set of all spherical angles to draw our ellipsoid
    n_points = 100
    theta = np.linspace(0, 2*np.pi, n_points)
    phi = np.linspace(0, np.pi, n_points)

    # Width, height and depth of ellipsoid
    rx, ry, rz = nstd * np.sqrt(eigvals)

    # Get the xyz points for plotting
    # Cartesian coordinates that correspond to the spherical angles:
    X = rx * np.outer(np.cos(theta), np.sin(phi))
    Y = ry * np.outer(np.sin(theta), np.sin(phi))
    Z = rz * np.outer(np.ones_like(theta), np.cos(phi))

    # Rotate ellipsoid for off axis alignment
    old_shape = X.shape
    # Flatten to vectorise rotation
    X,Y,Z = X.flatten(), Y.flatten(), Z.flatten()
    X,Y,Z = np.matmul(eigvecs, np.array([X,Y,Z]))
    X,Y,Z = X.reshape(old_shape), Y.reshape(old_shape), Z.reshape(old_shape)

    # Add in offsets for the mean
    X = X + mu[0]
    Y = Y + mu[1]
    Z = Z + mu[2]

    return X,Y,Z

#########################################################
## Testing some data
#########################################################
if __name__=='__main__':
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D

    # Setup the plot
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    plt.xlabel('x')
    plt.ylabel('y')
    # ax.set_aspect(1.0)
    # ax.set_xlim3d(-3,10)
    # ax.set_ylim3d(-3,10)
    # ax.set_zlim3d(-3,10)
    # Generate random 3d data points for 2 different offsets

    #########################################################
    ## Generate datasets s1 and s2
    #########################################################
    # s1
    mu1 = np.random.random((3)) * 5
    cov1 = np.array([            # Using an off-axis alignment for s1
        [2.5, 0.75, 0.175],
        [0.75, 0.70, 0.135],
        [0.175, 01.35, 0.43]
    ])
    s1 = np.random.multivariate_normal(mu1, cov1, (200))
    ax.scatter(s1[:,0],s1[:,1],s1[:,2], c='r')

    # s2
    mu2 = np.random.random((3)) * 5 + 4
    cov2 = np.diag((1,3,5))
    s2 = np.random.multivariate_normal(mu2, cov2, (200))
    ax.scatter(s2[:,0],s2[:,1],s2[:,2], c='b')

    #########################################################
    ## Process data and plot ellipsoid
    #########################################################
    nstd = 2    # 95% confidence interval
    # s1
    mu1_ = np.mean(s1, axis=0)
    cov1_ = np.cov(s1.T)
    X1,Y1,Z1 = get_cov_ellipsoid(cov1_, mu1_, nstd)
    ax.plot_wireframe(X1,Y1,Z1, color='r', alpha=0.1)

    # s2
    mu2_ = np.mean(s2, axis=0)
    cov2_ = np.cov(s2.T)
    X2,Y2,Z2 = get_cov_ellipsoid(cov2_, mu2_, nstd)
    ax.plot_wireframe(X2,Y2,Z2, color='b', alpha=0.1)

    plt.show()


import numpy as np

# Write a function that takes as input a list of numbers, and returns
# the list of values given by the softmax function.
def softmax(L):
    results = []
    sum = 0
    #Sum all exponentials
    for i in range(len(L)):
        sum = sum + np.exp(L[i])
    #Divide each exponential by the sum of all exponentials
    for i in range(len(L)):
        results.append(np.exp(L[i])/sum)
    return results

Documentation/Curs Neural Networks/Softmax function/softmax.py


import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
import random
import math
import datetime

## GENETIC ALGORITHM

MUTATE_RATE = 0.1
#keep pop size a multiple of 4
POP_SIZE = 100
NUM_GENS = 100
CROSS_RATE = 0.5
GENOME_SIZE = 2
MUTATE_BOUND = [-2.5,2.5]
WINDOW = [0,50]
NUM_ELITES = 1

def get_fitness(genome):
#    return np.sum(genome)
#    return -3*genome[0]**8 + 7*genome[1]**7 - 1*genome[2]**6 + 4*genome[3]**5 - 3*genome[4]**4 + 11*genome[5]**3 - 5.5*genome[6]**2 + 2*genome[7] + genome[8]
#    return 3*math.exp(-((genome[0]+1)**2+(genome[1]+1)**2))
    x = genome[0]
    y = genome[1]
    return math.exp(-(math.cos(x/2)+math.cos(y/4))) + math.cos(x)

def select(genomes):
    random.shuffle(genomes)
    fittest = []
    for i in range(int(POP_SIZE/2)):
        p1 = genomes[i]
        p2 = genomes[2*i]
        if get_fitness(p1) >= get_fitness(p2):
            fittest.append(p1)
        else:
            fittest.append(p2)
    return fittest

def crossover(fittest):
    offspring = []
    elite = sorted(fittest.copy(), key=get_fitness, reverse=True)[0:NUM_ELITES]
    while len(offspring) < POP_SIZE:
        random.shuffle(fittest)
        females = fittest[0:int(len(fittest)/2)]
        males = fittest[int(len(fittest)/2):len(fittest)]
        for i in range(len(males)):
            mom = females[i]
            dad = males[i]
            if np.random.rand() < CROSS_RATE:
                child = []
                for i in range(len(dad)):
                    if np.random.rand() < 0.5:
                        child.append(dad[i])
                    else:
                        child.append(mom[i])
                offspring.append(child)
            else:
                #clone both parents
                offspring.append(dad)
                offspring.append(mom)

    return [*elite,*random.sample(offspring,POP_SIZE-NUM_ELITES)]

def mutate(offspring, gen_num):
    for child in offspring:
        for gene in range(GENOME_SIZE):
            if np.random.rand() < get_mutation_rate(gen_num) and (WINDOW[0] <= child[gene] + np.random.uniform(*MUTATE_BOUND) <= WINDOW[1]):
                child[gene] = child[gene] + np.random.uniform(*MUTATE_BOUND)

#initialize population all at starting point
genomes = POP_SIZE*[[12.5,25]]
#for i in range(POP_SIZE):
#    genomes.append(random.sample(range(0,10), GENOME_SIZE))
#    genomes.append([0 for _ in range(GENOME_SIZE)])

def get_mutation_rate(gen_num):
    #use 0.03 for ~80-120
    return MUTATE_RATE*math.exp(-(MUTATE_RATE/2)*gen_num)

rounds = []
for i in range(NUM_GENS):
    points = []
    top = select(genomes)
    offspring = crossover(top)
    mutate(offspring, i)
    genomes = offspring
    top = sorted(genomes.copy(), key=get_fitness, reverse=True)
    if i % 10 == 0:
        print(get_fitness(top[0]),top[0])
    for g in top:
        points.append((g[0], g[1]))
    rounds.append(points)

    #stop condition
#    if get_fitness(top[0]) > 8.3728:
#        break

def fun(x, y):
  return math.exp(-(math.cos(x/2)+math.cos(y/4))) + math.cos(x)

delta = 0.05
x = np.arange(0, 20, delta)
y = np.arange(0, 50, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
zs = np.array([fun(x,y) for x,y in zip(np.ravel(X), np.ravel(Y))])
Z = zs.reshape(X.shape)

norm = cm.colors.Normalize(vmax=abs(Z).max(), vmin=-abs(Z).max())
cmap = cm.PRGn

levels = np.arange(0, 10, 2)

filenames = []
for i,points in enumerate(rounds):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.contourf(X, Y, Z, levels,
                cmap=cm.get_cmap(cmap, len(levels)-1),
                norm=norm)
    ax.autoscale(False) # To avoid that the scatter changes limits

    ax.scatter(*zip(*points), color='red')
    #plt.show()
    if i % 2 == 0:
        file = 'plot'+ str(i) +'.png'
        fig.savefig(file)
        filenames.append(file)
    plt.close(fig)

import imageio
images = []
for filename in filenames:
    images.append(imageio.imread(filename))

st = datetime.datetime.now().strftime('%Y%m%d%H%M')
imageio.mimsave('climber_'+ st +'.gif', images)


import numpy as np
import scipy.linalg as linalg
import contextlib

def create_hilbert(n):
    A = np.zeros((n,n))
    for i in range(n):
        for j in range(n):
            A[i][j] = 1/(i+j+1)
    return A

def pivot_change(A,i,P):
    maxindex = i
    for j in range (i,len(A)):
        if (abs(A[j][i]) > abs(A[maxindex][i])):
            maxindex = j
    a = np.copy(A[i])
    A[i] = A[maxindex]
    A[maxindex] = a
    if (i != maxindex):
        P_ = np.zeros((len(A),len(A)))
        for fi in range(len(A)):
            for fj in range(len(A)):
                if (fi == fj):
                    P_[fi][fj] = 1
        P_[i][i] = 0
        P_[maxindex][maxindex] = 0
        P_[i][maxindex] = 1
        P_[maxindex][i] = 1
        P[:][:] = P_.dot(P)

def lu_decomposition (A) :
    P = np.zeros((len(A),len(A)))
    for i in range(len(A)):
        for j in range(len(A)):
            if (i == j) :
                P[i][j] = 1
    for i in range(len(A)):
        pivot_change(A,i,P)
        u_ii = A[i][i]
        for j in range(i+1,len(A)):
            A[j][i] = A[j][i] / u_ii
            for k in range(i+1,len(A)):
                A[j][k] = - A[j][i] * A[i][k] + A[j][k]
    L = np.zeros((len(A),len(A)))
    for i in range(len(A)):
        for j in range(len(A)):
            if (i == j) :
                L[i][j] = 1
            elif (i > j):
                L[i][j] = A[i][j]
    U = np.zeros((len(A),len(A)))
    for i in range(len(A)):
        for j in range(len(A)):
            if (i == j) :
                U[i][j] = A[i][j]
            elif (i < j) :
                U[i][j] = A[i][j]
    return (L, U, P)

if __name__ == "__main__" :
    A = create_hilbert(6)
    L,U,P = lu_decomposition(A)
    np.set_printoptions(formatter={'float': '{: 0.5f}'.format})
    print("L = ")
    print(L)
    print("U = ")
    print(U)
    print("P = ")
    print(P)
    print("PA = ")
    print(P.dot(create_hilbert(6)))
    print("LU = ")
    print(L.dot(U))


import numpy as np

def simplex_coordinates1 ( m ):

#*****************************************************************************80
#
## SIMPLEX_COORDINATES1 computes the Cartesian coordinates of simplex vertices.
#
#  Discussion:
#
#    The simplex will have its centroid at 0
#
#    The sum of the vertices will be zero.
#
#    The distance of each vertex from the origin will be 1.
#
#    The length of each edge will be constant.
#
#    The dot product of the vectors defining any two vertices will be - 1 / M.
#    This also means the angle subtended by the vectors from the origin
#    to any two distinct vertices will be arccos ( - 1 / M ).
#
#  Licensing:
#
#    This code is distributed under the GNU LGPL license.
#
#  Modified:
#
#    28 June 2015
#
#  Author:
#
#    John Burkardt
#
#  Parameters:
#
#    Input, integer M, the spatial dimension.
#
#    Output, real X(M,M+1), the coordinates of the vertices
#    of a simplex in M dimensions.
#

  x = np.zeros ( [ m, m + 1 ] )

  for k in range ( 0, m ):
#
#  Set X(K,K) so that sum ( X(1:K,K)^2 ) = 1.
#
    s = 0.0
    for i in range ( 0, k ):
      s = s + x[i,k] ** 2

    x[k,k] = np.sqrt ( 1.0 - s )
#
#  Set X(K,J) for J = K+1 to M+1 by using the fact that XK dot XJ = - 1 / M.
#
    for j in range ( k + 1, m + 1 ):
      s = 0.0
      for i in range ( 0, k ):
        s = s + x[i,k] * x[i,j]

      x[k,j] = ( - 1.0 / float ( m ) - s ) / x[k,k]

  return x


"""
Inferring two binomial proportions using PyMC.
"""
from __future__ import division
import matplotlib.pyplot as plt
plt.style.use('seaborn-darkgrid')
import numpy as np
import pymc3 as pm

# Generate the data
y1 = np.array([1, 1, 1, 1, 1, 0, 0])  # 5 heads and 2 tails
y2 = np.array([1, 1, 0, 0, 0, 0, 0])  # 2 heads and 5 tails

with pm.Model() as model:
    # define the prior
    theta1 = pm.Beta('theta1', 3, 3)  # prior
    theta2 = pm.Beta('theta2', 3, 3)  # prior
    # define the likelihood
    y1 = pm.Bernoulli('y1', p=theta1, observed=y1)
    y2 = pm.Bernoulli('y2', p=theta2, observed=y2)

    # Generate a MCMC chain
    trace = pm.sample(1000)

# create an array with the posterior sample
theta1_sample = trace['theta1']
theta2_sample = trace['theta2']

# Plot the trajectory of the last 500 sampled values.
plt.plot(theta1_sample[:-500], theta2_sample[:-500], marker='o',  color='skyblue')
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.xlabel(r'$\theta1$')
plt.ylabel(r'$\theta2$')

# Display means in plot.
plt.plot(0, label='M = %.3f, %.3f' % (np.mean(theta1_sample), np.mean(theta2_sample)), alpha=0.0)

plt.legend(loc='upper left')
plt.savefig('Figure_8.6.png')

# Plot a histogram of the posterior differences of theta values.
theta_diff = theta1_sample - theta2_sample
pm.plot_posterior(theta_diff, ref_val=0.0, bins=30, color='skyblue')
plt.xlabel(r'$\theta_1 - \theta_2$')
plt.savefig('Figure_8.8.png')

# For Exercise 8.5:
# Posterior prediction. For each step in the chain, use the posterior thetas
# to flip the coins.
chain_len = len(theta1_sample)
# Create matrix to hold results of simulated flips:
y_pred = np.zeros((2, chain_len))
for step_idx in range(chain_len):  # step through the chain
    # flip the first coin:
    p_head1 = theta1_sample[step_idx]
    y_pred[0, step_idx] = np.random.choice([0,1], p=[1-p_head1, p_head1])
    # flip the second coin:
    p_head2 = theta2_sample[step_idx]
    y_pred[1, step_idx] = np.random.choice([0,1], p=[1-p_head2, p_head2])

# Now determine the proportion of times that y1==1 and y2==0
pY1eq1andY2eq0 = sum((y_pred[0] ==1) & (y_pred[1] == 0)) / chain_len

print(pY1eq1andY2eq0)
plt.show()


#!/usr/bin/env python

import numpy as np

def normalizeRows(x):
    """ Row normalization function

    Implement a function that normalizes each row of a matrix to have
    unit length.
    """
    N = x.shape[0]
    x /= np.sqrt(np.sum(x**2, axis=1)).reshape((N,1)) + 1e-30
    return x

def softmax(x):
    """Compute the softmax function for each row of the input x.
    It is crucial that this function is optimized for speed because
    it will be used frequently in later code.

    Arguments:
    x -- A D dimensional vector or N x D dimensional numpy matrix.
    Return:
    x -- You are allowed to modify x in-place
    """
    orig_shape = x.shape

    if len(x.shape) > 1:
        # Matrix
        tmp = np.max(x, axis=1)
        x -= tmp.reshape((x.shape[0], 1))
        x = np.exp(x)
        tmp = np.sum(x, axis=1)
        x /= tmp.reshape((x.shape[0], 1))
    else:
        # Vector
        tmp = np.max(x)
        x -= tmp
        x = np.exp(x)
        tmp = np.sum(x)
        x /= tmp

    assert x.shape == orig_shape
    return x


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

import numpy as np
a = np.array([1, 2, 3, 4])
b = np.array([4, 2, 2, 4])
print(a == b)
print(a > b)
a = np.array([1, 2, 3, 4])
b = np.array([4, 2, 2, 4])
c = np.array([1, 2, 3, 4])
np.array_equal(a, b)
np.array_equal(a, c)
a = np.array([1, 1, 0, 0], dtype=bool)
b = np.array([1, 0, 1, 0], dtype=bool)
print(np.logical_or(a, b))
print(np.logical_and(a, b))
a = np.arange(5)
print(np.sin(a))
print(np.log(a))
print(np.exp(a))
a = np.arange(4)
try:
    a + np.array([1, 2])
except ValueError as ve:
    print(ve)
# see help(np.triu)
a = np.triu(np.ones((3, 3)), 1)
print(a)
print(a.T)
a = np.arange(9).reshape(3, 3)
a.T[0, 2] = 999
print(a.T)
print(a)
print(np.allclose([1e10,1e-7],
                  [1.00001e10,1e-8]))
print(np.allclose([1e10,1e-8],
                  [1.00001e10,1e-9]))
print(np.allclose([1e10,1e-8],
                  [1.0001e10,1e-9]))
print(np.allclose([1.0, np.nan],
                  [1.0, np.nan]))
print(np.allclose([1.0, np.nan],
                  [1.0, np.nan],
                  equal_nan=True))


import numpy as np
import tqdm
import sklearn.metrics
import warnings
import pdb
from p_tqdm import p_umap

RESAMPLE_FAILED_WARNING = "Resampling distrubution for estimator {} failed because of : {}"
CONFIDENCE_INTERVAL_EXCEPTION = "Cannot calculate confidence interval. Sampled {} times for found {} (target {}) valid samples."

def confidence_interval(emperical_distribution, confidence_interval=0.95, num_resamples=5000, estimator=np.mean, clusters=None):
    '''
    Estimates confidence interval of the mean of emperical_distribution
    using emperical bootstrap. Method details are available at:

    https://ocw.mit.edu/courses/mathematics/18-05-introduction-to-probability-and-statistics-spring-2014/readings/MIT18_05S14_Reading24.pdf

    -emperical_distribution: Emperical distributions for which we want to
    estimate the confidence interval of the mean
    -confidence_interval: Amount of probability mass interval should cover.
    -num_resamples: Amount of trails to use to estimate confidence interval.
    Should as large as computationally feasiable.

    if Clusters is not none, perform two stage bootstrap.
    '''
    emp_mean = estimator(emperical_distribution)
    num_samples = len(emperical_distribution)
    deltas = []
    num_tries = 0
    if clusters is not None:
        cluster_to_inds = {}
        for ind, cluster in enumerate(clusters):
            if cluster not in cluster_to_inds:
                cluster_to_inds[cluster] = []
            cluster_to_inds[cluster].append(ind)
        num_clusters = len(cluster_to_inds)
        cluster_ids = list(cluster_to_inds.keys())

    def get_delta(dummy_ind):
        if clusters is None:
            resample_ind = np.random.choice(a=range(len(emperical_distribution)),
                                    size=num_samples,
                                    replace=True
                                    )
        else:
            resample_clusters = np.random.choice(a=cluster_ids,
                                                size=num_clusters,
                                                replace=True)
            resample_ind = []
            for cluster in resample_clusters:
                resampled_inds_for_cluster = np.random.choice(a=cluster_to_inds[cluster],
                                                            size=len(cluster_to_inds[cluster]),
                                                            replace=True)
                resample_ind.extend(resampled_inds_for_cluster)

        resample_dist = [ emperical_distribution[ind] for ind in resample_ind]
        delta = estimator(resample_dist) - emp_mean
        return delta

    deltas = p_umap(get_delta, range(num_resamples))
    lower_bound, upper_bound = get_ci_bounds(emp_mean, deltas, confidence_interval, num_resamples)

    return emp_mean, (lower_bound, upper_bound)

def get_ci_bounds(mean, deltas, confidence_interval, num_resamples):
    '''
    Returns the lower and upper bounds of the confidence interval.
    mean : the empirical mean
    deltas : deltas from the empirical mean from different samples
    '''
    deltas = np.sort(deltas)
    index_offset = int((1 - confidence_interval)/2. * num_resamples)
    lower_delta, upper_delta = deltas[index_offset], deltas[-index_offset]
    lower_bound, upper_bound = mean - upper_delta, mean - lower_delta
    return lower_bound, upper_bound


## module gaussQuad2
''' I = gaussQuad2(f,xc,yc,m).
    Gauss-Legendre integration of f(x,y) over a
    quadrilateral using integration order m.
    {xc},{yc} are the corner coordinates of the quadrilateral.
'''
from gaussNodes import *
import numpy as np
def gaussQuad2(f,x,y,m):

    def jac(x,y,s,t):
        J = np.zeros((2,2))
        J[0,0] = -(1.0 - t)*x[0] + (1.0 - t)*x[1]  \
                + (1.0 + t)*x[2] - (1.0 + t)*x[3]
        J[0,1] = -(1.0 - t)*y[0] + (1.0 - t)*y[1]  \
                + (1.0 + t)*y[2] - (1.0 + t)*y[3]
        J[1,0] = -(1.0 - s)*x[0] - (1.0 + s)*x[1]  \
                + (1.0 + s)*x[2] + (1.0 - s)*x[3]
        J[1,1] = -(1.0 - s)*y[0] - (1.0 + s)*y[1]  \
                + (1.0 + s)*y[2] + (1.0 - s)*y[3]
        return (J[0,0]*J[1,1] - J[0,1]*J[1,0])/16.0

    def map(x,y,s,t):
        N = np.zeros(4)
        N[0] = (1.0 - s)*(1.0 - t)/4.0
        N[1] = (1.0 + s)*(1.0 - t)/4.0
        N[2] = (1.0 + s)*(1.0 + t)/4.0
        N[3] = (1.0 - s)*(1.0 + t)/4.0
        xCoord = np.dot(N,x)
        yCoord = np.dot(N,y)
        return xCoord,yCoord

    s,A = gaussNodes(m)
    sum = 0.0
    for i in range(m):
        for j in range(m):
            xCoord,yCoord = map(x,y,s[i],s[j])
            sum = sum + A[i]*A[j]*jac(x,y,s[i],s[j])  \
                       *f(xCoord,yCoord)
    return sum


import numpy as np

def poisson(lam, k):
    """
    Possion Function (lambda^k)*(e^-lambda)/(k!)
    :param lam:
    :param k:
    :return:
    """
    # The exponential part, pretty much a direct translation from eqn. to code
    exponent_part = np.float64(np.exp(-1. * lam))
    first_part = np.float64(lam ** k)
    # Factorial part....
    fact = np.float64(1)
    for i in range(1, np.int64(k + 1)):
        fact *= i

    final_result = np.float64((first_part * exponent_part) / fact)
    return final_result

import sys
sys.stdout = open('1a.txt', 'w')
print("The Poisson value for $\lambda$ = {} and k = {} is: {} ".format(1, 0, poisson(1, 0)))
print("The Poisson value for $\lambda$ = {} and k = {} is: {} ".format(5, 10, poisson(5, 10)))
print("The Poisson value for $\lambda$ = {} and k = {} is: {} ".format(3, 21, poisson(2.6, 40)))


import math
import pandas as pd
import numpy as np
import sys

class MultiLayerPerceptron:
    def __init__(self, batch_size, learning_rate, num_epochs):
        self.batch_size = batch_size
        self.learning_rate = learning_rate
        self.num_epochs = num_epochs

        # Layer 1: weight, bias
        # w: 512 * (28*28)
        # x: (28*28) * 1
        # b: 512 * 1
        # r: 512 * 1
        # Layer 2: weight, bias
        # w: 256 * 512
        # x: 512 * 1
        # b: 256 * 1
        # r: 256 * 1
        # Layer 3: weight, bias
        # w: 10 * 256
        # x: 256 * 1
        # b: 10 * 1
        # r: 10 * 1
        self.params = {
            'W1': np.random.randn(512, 784) * np.sqrt(1.0 / 784),
            'b1': np.random.randn(512, 1) * np.sqrt(1.0 / 748),
            'W2': np.random.randn(256, 512) * np.sqrt(1.0 / 512),
            'b2': np.random.randn(256, 1) * np.sqrt(1.0 / 512),
            'W3': np.random.randn(10, 256) * np.sqrt(1.0 / 256),
            'b3': np.random.randn(10, 1) * np.sqrt(1.0 / 256)
        }

    def start(self):

        if len(sys.argv) > 3:
            trainX = pd.read_csv(sys.argv[1], header=None)
            trainY = pd.read_csv(sys.argv[2], header=None)
            testX = pd.read_csv(sys.argv[3], header=None)
        else:
            trainX = pd.read_csv('train_image.csv', header=None)
            trainY = pd.read_csv('train_label.csv', header=None)
            testX = pd.read_csv('test_image.csv', header=None)

        # Transpose
        trainX = trainX.T
        trainY = trainY.T
        testX = testX.T

        # pd to np
        trainX = trainX.values
        trainY = trainY.values
        testX = testX.values

        # categorical encoding
        onehotY = np.zeros((trainY.size, 10))
        onehotY[np.arange(trainY.size), trainY] = 1
        onehotY = onehotY.T

        return trainX, onehotY, testX

    # e^x/1+e^x
    def sigmoid(self, x):
        x = np.clip(x, -500, 500)
        return 1.0 / (1.0 + np.exp(-x))

    # v * s * 1 - s
    def sigmoid_backward(self, dA, Z):
        sig = self.sigmoid(Z)
        return dA * sig * (1 - sig)

    # 10 labels
    def softmax(self, x):
        exps = np.exp(x - x.max())
        return exps / np.sum(exps, axis=0)

    def get_mini_batches(self, X, y, batch_size):
        n = X.shape[1]
        mini_batches = list()

        for i in range(0, math.floor(n / batch_size)):
            mx = X[:, i * batch_size: (i + 1) * batch_size]
            my = y[:, i * batch_size: (i + 1) * batch_size]
            mini_batch = (mx, my)
            mini_batches.append(mini_batch)

        if n % batch_size != 0:
            mx = X[:, batch_size * math.floor(n / batch_size): n]
            my = y[:, batch_size * math.floor(n / batch_size): n]
            mini_batch = (mx, my)
            mini_batches.append(mini_batch)

        return mini_batches

    # sigmoid(w*x + b)
    # last layer: softmax(w*x + b)
    def forward_pass(self, X):
        cache = dict()

        cache['Z1'] = np.dot(self.params['W1'], X) + self.params['b1']
        cache['A1'] = self.sigmoid(cache['Z1'])
        cache['Z2'] = np.dot(self.params['W2'], cache['A1']) + self.params['b2']
        cache['A2'] = self.sigmoid(cache['Z2'])
        cache['Z3'] = np.dot(self.params['W3'], cache['A2']) + self.params['b3']
        cache['A3'] = self.softmax(cache['Z3'])

        return cache

    # backward pass
    def backward_pass(self, X, Y, cache):
        m = X.shape[1]

        dZ3 = cache['A3'] - Y

        dW3 = np.dot(dZ3, cache["A2"].T) / m
        db3 = np.sum(dZ3, axis=1, keepdims=True) / m

        dA2 = np.dot(self.params['W3'].T, dZ3)
        dZ2 = self.sigmoid_backward(dA2, cache['Z2'])

        dW2 = np.dot(dZ2, cache['A1'].T) / m
        db2 = np.sum(dZ2, axis=1, keepdims=True) / m

        dA1 = np.dot(self.params['W2'].T, dZ2)
        dZ1 = self.sigmoid_backward(dA1, cache['Z1'])

        dW1 = np.dot(dZ1, X.T) / m
        db1 = np.sum(dZ1, axis=1, keepdims=True) / m

        return {'dW3': dW3, 'db3': db3, 'dW2': dW2, 'db2': db2, 'dW1': dW1, 'db1': db1}

    def train(self, X, y):
        # i = 0
        for i in range(0, self.num_epochs):
            # j = 0
            random = np.arange(len(X[1]))
            np.random.shuffle(random)
            X_shuffle = X[:, random]
            y_shuffle = y[:, random]

            mini_batches = self.get_mini_batches(X_shuffle, y_shuffle, self.batch_size)

            for mini_batch in mini_batches:
                mx, my = mini_batch
                cache = self.forward_pass(mx)
                grads = self.backward_pass(mx, my, cache)

                self.params['W1'] = self.params['W1'] - (self.learning_rate * grads['dW1'])
                self.params['b1'] = self.params['b1'] - (self.learning_rate * grads['db1'])
                self.params['W2'] = self.params['W2'] - (self.learning_rate * grads['dW2'])
                self.params['b2'] = self.params['b2'] - (self.learning_rate * grads['db2'])
                self.params['W3'] = self.params['W3'] - (self.learning_rate * grads['dW3'])
                self.params['b3'] = self.params['b3'] - (self.learning_rate * grads['db3'])
                # print('Over {},{}'.format(i, j))
                # j += 1
            # i += 1

# network
nn = MultiLayerPerceptron(batch_size=32, learning_rate=0.01, num_epochs=80)
trainX, onehotY, testX = nn.start()
nn.train(trainX, onehotY)
out = nn.forward_pass(testX)
output = out['A3']
pred = np.argmax(output, axis=0)
pd.DataFrame(pred).to_csv('test_predictions.csv', header=None, index=None)


"""
Methods for fitting a beta binomial model, to be used for skills measurement and
A/B test analysis.
"""
import numpy as np
import scipy.stats as scs

def beta_values(alpha, beta, numpoints=1000):
    domain = np.linspace(0, 1, numpoints)
    dist = scs.beta.pdf(domain, alpha, beta)
    return (domain, dist,)

def fit_beta_prior(data):
    """
    Fit the parameters of a beta prior given probability data.
    Arguments:
        data (numpy array):
            Values ranging 0 to 1, representing the population level data.

    Returns:
        List of beta distribution parameters
    """
    alpha, beta, _, _ = scs.beta.fit(data, floc=0, fscale=1)
    return (alpha, beta,)

def beta_posterior_values(successes, trials, alpha, beta, numpoints=1000):
    failures = trials - successes
    return beta_values(alpha + successes, beta + failures, numpoints)

def beta_expected_value(alpha, beta):
    return alpha / (alpha + beta)

def compare_beta_distros(alpha_sa, beta_sa, alpha_sb, beta_sb):
    """
    Evaluate the probability that a random sample of the beta distribution from
    sample a is greater than a random sample from the beta distribution of sample b.
    This gives a good measure of whether sample a is *better* than sample b.
    """
    sa_samples = np.random.beta(alpha_sa, beta_sa, 100000)
    sb_samples = np.random.beta(alpha_sb, beta_sb, 100000)
    return np.sum(sa_samples > sb_samples) / len(sa_samples)


import numpy as np
import multiplyingMartices as mm
def inverse2x2(matrix1):
    diff = (matrix1[1][1] * matrix1[0][0])-  (matrix1[1][0] * matrix1[0][1])
    final =  np.array([
        [matrix1[1][1]/diff, (-1 * matrix1[0][1]) / diff],
        [(-1 * matrix1[1][0]) / diff, (1 * matrix1[0][0]) / diff],
    ])

    result = mm.martixMultiply(matrix1,final)

    id = np.array([[1,0],[0,1]])
    if(np.array_equal(id, result)):
        return final
    else:
        return False


from math import sqrt
import numpy as np

'''
Gradient Descent Algorithm for Linear Regression
    feature_matrix: matrix whose rows are samples and columns are features
    output: vector containing actual value
    initial_weights: vector containing intial weight values
    step_size: scalar value for step size
    tolerance: scalar value to test convergence
'''
def regression_gradient_descent(feature_matrix, output, initial_weights, step_size, tolerance):
    converged = False
    weights = np.array(initial_weights)

    while not converged:
        predictions = predict_output(feature_matrix, weights)
        errors = predictions - output
        gradient_sum_squares = 0

        # update each feature's weight
        for i in range(len(weights)):
            derivative = feature_derivative(errors, feature_matrix[:,i])
            gradient_sum_squares += derivative * derivative
            weights[i] = weights[i] - step_size * derivative

        gradient_magnitude = sqrt(gradient_sum_squares)

        if gradient_magnitude < tolerance:
            converged = True

    return(weights)

def feature_derivative(errors, feature):
    derivative = 2 * np.dot(errors, feature)
    return(derivative)

def predict_output(feature_matrix, weights):
    predictions = np.dot(feature_matrix, weights)
    return(predictions)


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

import numpy as np
from matplotlib.pyplot import *

def value_iteration(P, r, gamma = 0., policy = None, iter_no = None):
    '''Value iteration for finite state and action spaces'''

    actions_no, states_no = np.shape(P)[0:2]

    # A simple heuristic to set the number of iterations
    iter_no = min(1000, int(20./(1-gamma)))

    Q = np.zeros((states_no,actions_no))
    Q_new = Q

    if policy is None:
        Bellman_optimality = True
    else:
        Bellman_optimality = False

    for m in range(iter_no):
        Q = Q_new
        for s in range(states_no):
            for a in range(actions_no):

                value_next = 0

                # This loop could be optimized using numpy
                for s_next in range(states_no):
                    if Bellman_optimality:
                        value_next += P[a,s,s_next] * max(Q[s_next]) #
                    else:
                        value_next += P[a,s,s_next] * Q[s_next,policy[s_next]]

                Q_new[s,a] = r[s,a] + gamma* value_next

    return Q

P = np.array( [ [[0, 1.], [0., 1.0]],
     [ [1.,0 ], [1.0,0.0 ] ] ] )

r = np.array( [ [-1., 1.0], [0.0, 5.]] )
gamma = 0.9

pol_1 = np.array([0, 0]) # Saving policy
pol_2 = np.array([1,1]) # Spending policy

Q = value_iteration(P,r, gamma) #, policy=pol_2)
print 'Q:', Q
print 'Optimal policy:', np.argmax(Q,axis = 1)

# Varying discount factor (gamma) and computing the optimal action-value and value function, and policy
gamma_set = np.linspace(0,0.99,100)
Q_res = []
V_res = []
pi_res = []
for gamma in gamma_set:
    Q = value_iteration(P,r, gamma) #, policy=pol_2)
    V = np.max(Q,axis = 1)
    pi_greedy = np.argmax(Q,axis = 1)

    Q_res.append(Q*(1. - gamma))
    V_res.append(V*(1. - gamma))
    pi_res.append(pi_greedy)

subplot(1,2,1)
plot(gamma_set, np.array(pi_res)[:,0],'o')
xlabel('$\gamma$')
ylabel('Policy at state $s_1$')
ylim((-0.05,1.05))
subplot(1,2,2)
plot(gamma_set, np.array(pi_res)[:,1],'o')
ylim((-0.05,1.05))
xlabel('$\gamma$')
ylabel('Policy at state $s_2$')
figure()
plot(gamma_set, V_res)
legend(['State 1', 'State 2'])
xlabel('$\gamma$')
ylabel('(Normalized) optimal value function')


import numpy as np
from sigmoid import *

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

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

    h = sigmoid(np.dot(X,theta))

    mt = 1e-7
    cost = (1 / m) * np.sum(-y * np.log(h + mt) - (1 - y) * np.log(-h + 1 + mt), 0)

    grad = (1 / m) * np.dot(X.T, (h - y))

    # ===================== Your Code Here =====================
    # Instructions : Compute the cost of a particular choice of theta
    #                You should set cost and grad correctly.
    #

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

    return cost, grad


import numpy as np

def bootstrapped_correlation(x, y, perc=5, N=1000):
    assert (len(x) == len(y))
    corrs = []
    for i in range(N):
        indices = np.random.choice(len(x), replace=True, size=len(x))
        corr = np.corrcoef(x[indices], y[indices])[0, 1]
        corrs.append(corr)
    corrs = np.array(corrs)
    meancorr = np.corrcoef(x, y)[0, 1]
    upper = np.percentile(corrs, q=100 - perc)
    lower = np.percentile(corrs, q=perc)

    return meancorr, lower, upper

def bootstrapped_correlation_difference(x1,y1,x2,y2, perc=5, N=1000):
    """ compute the difference between corr(x1,y1) and corr (x2,y2) plus
    bands [perc,100-perc] of the differecne in  correlation, estimated via bootstrpaping.
    This method is useful when the uncertainty between the two correlations is not independent.
    x1,y1,x2,y2 must all have the same length"""
    assert (len(x1) == len(y1))
    assert (len(x1) == len(y2))
    assert (len(x2) == len(x1))
    n_samples = len(x1)
    diff_corrs = []
    # we use the same indices both for sample 1 and sample 2, and then compute the difference in correlation
    for i in range(N):
        indices = np.random.choice(n_samples, replace=True, size=n_samples)
        corr1 = np.corrcoef(x1[indices], y1[indices])[0, 1]
        corr2 = np.corrcoef(x2[indices], y2[indices])[0, 1]
        diff_corrs.append(corr1-corr2)
    corrs = np.array(diff_corrs)
    meancorrdiff = np.corrcoef(x1, y1)[0, 1] - np.corrcoef(x2, y2)[0, 1]
    upper = np.percentile(corrs, q=100 - perc)
    lower = np.percentile(corrs, q=perc)
    assert(upper>=lower)
    return meancorrdiff, lower, upper

def bootstrapped_rmse_difference(x1,x2, perc=5, N=1000):
    """ compute difference between x1 and x2 plus uncertainty, when x1 and x2 are either rmse or standarddeviation

    """
    assert(len(x1)==len(x2))
    n_samples = len(x1)
    means = []
    for i in range(N):
        indices = np.random.choice(n_samples, replace=True, size=n_samples)
        # now compute difference in  RMSE on this subsample
        mm = np.sqrt(np.mean(x1[indices]**2)) - np.sqrt(np.mean(x2[indices]**2))
        means.append(mm)
    means = np.array(means)
    mmean = np.sqrt(np.mean(x1**2)) - np.sqrt(np.mean(x2**2))
    upper = np.percentile(means, q=100 - perc)
    lower = np.percentile(means, q=perc)
    # assert (upper >= lower) # we deactivate this check here because if one or both of x1 and x2
    # concist only of repreated values, then numerical inaccuracis can lead to
    # lower being a tiny little larger than upper (even though they should be the same in this case)
    return np.array([mmean, lower, upper])


import scipy.stats as st
import numpy as np
import pandas as pd

class CI:
    def one_proportion(self, n, phat, conf):
        z_val = st.norm.ppf(1 - (1 - conf) / 2) # this is two-side
        # z_val = st.norm.ppf(1 - (1 - conf)) # this is one-side
        se = np.sqrt(phat*(1-phat)/n)
        print('z-value=', z_val, "se=", se)
        ci = (phat - z_val * se, phat + z_val * se)
        print(ci)

    def one_proportion_conserv(self, n, phat, conf):
        # we center at phat, and try to estimate the margin of errors
        # use normal-dist (z-value)
        z_val = st.norm.ppf(1 - (1 - conf) / 2) # this is two-side
        # z_val = st.norm.ppf(1 - (1 - conf)) # this is one-side

        se = 1 / (2 * np.sqrt(n))
        print('z-value=', z_val, "se=", se)
        ci = (phat - z_val * se, phat + z_val * se)
        print(ci)

    def two_proportions(self, pos_num1, pos_num2, total_num1, total_num2, conf):
        m1, m2 = pos_num1, pos_num2 # positive numbers
        n1, n2 = total_num1, total_num2 # total numbers

        p1, p2 = m1 / n1, m2 / n2
        phat = p1 - p2
        # phat *= -1
        z_val = st.norm.ppf(1 - (1 - conf) / 2) # this is two-side
        se = np.sqrt(p1 * (1 - p1) / n1 + p2 * (1 - p2) / n2)
        print('z-value=', z_val, "se=", se)
        print(f'{phat} +/- {z_val * se}')
        ci = (phat - z_val * se, phat + z_val * se)
        print(ci)

    def one_mean(self, mu, n, sd, conf):
        dof = n - 1
        se = sd / np.sqrt(n)
        t = st.t.ppf(1 - (1 - conf) / 2, df = dof)

        print('t-value=', t, "se=", se)
        print(f'{mu} +/- {t * se}')
        ci = (mu - t * se, mu + t * se)
        print(ci)

    def two_mean_paired(self, mu_diff, sd, n, conf):
        dof = n - 1
        mu = mu_diff
        se = sd / np.sqrt(n)
        t = st.t.ppf(1 - (1 - conf) / 2, df = dof)
        print('t-value=', t, "se=", se)
        print(f'{mu} +/- {t * se}')
        ci = (mu - t * se, mu + t * se)
        print(ci)

        if ci[0] <= 0 <= ci[1]:
            print('0 is included. maybe no difference')
        else:
            print('0 is NOT included. some difference')

    def two_means_independent_unpooled(self, mu1, mu2, sd1, sd2, n1, n2, conf):
        dof = np.min([n1 - 1, n2 - 1])
        mu_hat = mu1 - mu2
        se = np.sqrt(sd1**2 / n1 + sd2**2 / n2)
        t = st.t.ppf(1 - (1 - conf) / 2, df = dof)
        print('DOF=', dof)
        print('t-value=', t, "se=", se)

        print(f'{mu_hat} +/- {t * se}')
        ci = (mu_hat - t * se, mu_hat + t * se)
        print(ci)

    def two_means_independent_pooled(self, mu1, mu2, sd1, sd2, n1, n2, conf):
        dof = n1 + n2 - 2
        mu_hat = mu1 - mu2
        se = np.sqrt(((n1 - 1) * sd1**2 + (n2 - 1) * sd2**2)/ (n1 + n2 - 2)) * np.sqrt(1/n1 + 1/n2)
        t = st.t.ppf(1 - (1 - conf) / 2, df = dof)
        print('DOF=', dof)
        print('t-value=', t, "se=", se)

        print(f'{mu_hat} +/- {t * se}')
        ci = (mu_hat - t * se, mu_hat + t * se)
        print(ci)

class HT:
    def one_proportion_two_sides(self, p0, phat, n, alpha):
        # check for assumption
        if (n * p0 >= 10 and n * (1 - p0) >= 10):
            print('sample size is large enough')
        else:
            print('sample size is NOT large enough')

        se = np.sqrt(p0 * (1 - p0) / n)
        z = abs(phat - p0) / se
        print(f'z-value is {z}')
        print(f'which means our observed sample proportion is {z} null SE above our hypothesized population proportion ABS value')
        p_val = (1 - st.norm.cdf(z)) * 2
        print(f'p-value is {p_val}')

        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')

    def one_proportion_phat_larger(self, p0, phat, n, alpha):
        # check for assumption
        if (n * p0 >= 10 and n * (1 - p0) >= 10):
            print('sample size is large enough')
        else:
            print('sample size is NOT large enough')

        se = np.sqrt(p0 * (1 - p0) / n)
        z = (phat - p0) / se
        print(f'z-value is {z}')
        print(f'which means our observed sample proportion is {z} null SE above our hypothesized population proportion')
        p_val = 1 - st.norm.cdf(z)
        print(f'p-value is {p_val}')

        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')

    def one_proportion_phat_smaller(self, p0, phat, n, alpha):
        # check for assumption
        if (n * p0 >= 10 and n * (1 - p0) >= 10):
            print('sample size is large enough')
        else:
            print('sample size is NOT large enough')

        se = np.sqrt(p0 * (1 - p0) / n)
        z = (p0 - phat) / se
        print(f'z-value is {z}')
        print(f'which means our observed sample proportion is {z} null SE above our hypothesized population proportion')
        p_val = 1 - st.norm.cdf(z)
        print(f'p-value is {p_val}')

        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')

    def two_proportion_two_sides(self, pos1_num, pos2_num, n1, n2, alpha):
        m1, m2 = pos1_num, pos2_num # positive numbers
        # check for assumption
        phat = (m1 + m2) / (n1 + n2)
        print('phat=', phat)
        if (n1 * phat >= 10 and n1 * (1 - phat) >= 10 and n2 * phat >= 10 and n2 * (1 - phat) >= 10):
            print('sample size is large enough')
        else:
            print('sample size is NOT large enough, should not use this method')

        p1, p2 = m1 / n1, m2 / n2
        se = np.sqrt(phat * (1 - phat) * (1 / n1 + 1 / n2))
        z = (p1 - p2 - 0) / se
        print(f'z-stat is {z}')

        p_val = (1 - st.norm.cdf(abs(z))) * 2
        print(f'p-value is {p_val}')

        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')

    def two_proportion_pos1_larger(self, pos1_num, pos2_num, n1, n2, alpha):
        m1, m2 = pos1_num, pos2_num # positive numbers
        # check for assumption
        phat = (m1 + m2) / (n1 + n2)
        print('phat=', phat)
        if (n1 * phat >= 10 and n1 * (1 - phat) >= 10 and n2 * phat >= 10 and n2 * (1 - phat) >= 10):
            print('sample size is large enough')
        else:
            print('sample size is NOT large enough, should not use this method')

        # p1, p2 = m1 / n1, m2 / n2
        p1, p2 = 0.52, 0.35
        # se = np.sqrt(phat * (1 - phat) * (1 / n1 + 1 / n2))
        se = 0.0338
        z = (p1 - p2 - 0) / se
        print(f'p1={p1} and p2={p2}')
        print(f'z-stat is {z}')
        # assert z > 0, "p1 > p2"

        p_val = (1 - st.norm.cdf(abs(z)))
        print(f'p-value is {p_val}')

        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')

    def two_proportion_pos1_smaller(self, pos1_num, pos2_num, n1, n2, alpha):
        m1, m2 = pos1_num, pos2_num # positive numbers
        # check for assumption
        phat = (m1 + m2) / (n1 + n2)
        print('phat=', phat)
        if (n1 * phat >= 10 and n1 * (1 - phat) >= 10 and n2 * phat >= 10 and n2 * (1 - phat) >= 10):
            print('sample size is large enough')
        else:
            print('sample size is NOT large enough, should not use this method')

        p1, p2 = m1 / n1, m2 / n2
        se = np.sqrt(phat * (1 - phat) * (1 / n1 + 1 / n2))
        z = (p2 - p1 - 0) / se
        print(f'p1={p1} and p2={p2}')
        print(f'z-stat is {z}')
        # assert z > 0, "p1 > p2"

        p_val = (1 - st.norm.cdf(abs(z)))
        print(f'p-value is {p_val}')

        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')

    def one_mean_two_sides(self, mu0, mu_hat, n, sd, alpha):
        dof = n - 1
        se = sd / np.sqrt(n)
        t = (mu_hat - mu0) / se
        print(f't-stat is {t}')
        p_val = (1 - st.t.cdf(abs(t), df = dof)) * 2
        print(f'p-value is {p_val}')

        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')

        # confidence
        conf = 1 - alpha
        t_conf = st.t.ppf(1 - (1 - conf) / 2, df=dof)
        ci = (mu_hat - t_conf * se, mu_hat + t_conf * se)
        print('0 exist in the CI?')
        print(f'CI with {conf} confidence level = ', ci)

    def one_mean_mu_hat_larger(self, mu0, mu_hat, n, sd, alpha):
        dof = n - 1
        se = sd / np.sqrt(n)
        t = (mu_hat - mu0) / se
        print(f't-stat is {t}')
        p_val = (1 - st.t.cdf(abs(t), df = dof)) * 1
        print(f'p-value is {p_val}')

        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')

        # confidence
        conf = 1 - alpha
        t_conf = st.t.ppf(1 - (1 - conf), df=dof)
        ci = (mu_hat - t_conf * se, mu_hat + t_conf * se)
        print('0 exist in the CI?')
        print(f'CI with {conf} confidence level = ', ci)

    def one_mean_mu_hat_smaller(self, mu0, mu_hat, n, sd, alpha):
        dof = n - 1
        se = sd / np.sqrt(n)
        t = (mu0 - mu_hat) / se
        print(f't-stat is {t}')
        p_val = (1 - st.t.cdf(abs(t), df = dof)) * 1
        print(f'p-value is {p_val}')

        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')

        # confidence
        conf = 1 - alpha
        t_conf = st.t.ppf(1 - (1 - conf), df=dof)
        ci = (mu_hat - t_conf * se, mu_hat + t_conf * se)
        print('0 exist in the CI?')
        print(f'CI with {conf} confidence level = ', ci)

    def two_means_paired_two_sides(self, mu, sd, n, alpha):
        dof = n - 1
        se = sd / np.sqrt(n)
        t = (mu - 0) / se
        p_val = (1 - st.t.cdf(t, df= dof)) * 2
        print(f't-val = ', t)
        print(f'Our observed mean difference is {t} (estimated) SE above our null value of 0')
        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')

        # confidence
        conf = 1 - alpha
        t_conf = st.t.ppf(1 - (1 - conf)/2, df=dof)
        ci = (mu - t_conf * se, mu + t_conf * se)
        print('0 exist in the CI?')
        print(f'CI with {conf} confidence level = ', ci)

    def two_means_independent_unpooled(self, mu1, mu2, sd1, sd2, n1, n2, alpha):
        dof = np.min([n1-1, n2-1])
        se = np.sqrt(sd1**2 / n1 + sd2**2 / n2)
        # se = 11.8831
        t = abs((mu1 - mu2) / se) # pay attention here
        print('dof=', dof)
        print('t-value=', t, 'se=', se)
        p_val = (1 - st.t.cdf(t, df = dof)) * 2 # if two sides
        # p_val = (1 - st.t.cdf(t, df = dof))  # if one sides
        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')

        # using CI (two side)
        conf = 1 - alpha
        t_conf = st.t.ppf(1 - (1 - conf)/2, df=dof)
        ci = (mu1 - mu2 - t_conf * se, mu1 - mu2 + t_conf * se)
        print('0 exist in the CI?')
        print(f'CI with {conf} confidence level = ', ci)

    def two_means_independent_pooled(self, mu1, mu2, sd1, sd2, n1, n2, alpha):
        dof = n1 + n2 - 2
        sp = np.sqrt(((n1 - 1) * sd1**2 + (n2 - 1) * sd2**2)/(n1 + n2 - 2))
        se = sp * np.sqrt(1/n1 + 1/n2)
        t = abs((mu1 - mu2) / se) # pay attention here
        print('dof=', dof)
        print('t-value=', t, 'se=', se)
        p_val = (1 - st.t.cdf(t, df = dof)) * 2 # if two sides
        # p_val = (1 - st.t.cdf(t, df = dof))  # if one sides
        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')

        # using CI (two side)
        conf = 1 - alpha
        t_conf = st.t.ppf(1 - (1 - conf)/2, df=dof)
        ci = (mu1 - mu2 - t_conf * se, mu1 - mu2 + t_conf * se)
        print('0 exist in the CI?')
        print(f'CI with {conf} confidence level = ', ci)

    def chi_squared_homogeneity(self, df, alpha):
        col_sum = df.sum(axis = 0)
        row_sum = df.sum(axis = 1)
        df_sum = df.values.sum()

        df_vis = df.copy()
        df_vis['total'] = row_sum
        df_vis.loc['total'] = col_sum
        df_vis.iloc[-1,-1] = df_sum
        # df_vis

        df_expected = df.copy()

        if 1 in df.shape:
            for i in range(df.shape[0]):
                for j in range(df.shape[1]):
                    df_expected.iloc[i,j] = df_sum / np.multiply(*df.shape)
        else:
            for i in range(df.shape[0]):
                for j in range(df.shape[1]):
                    # df_expected.iloc[i,j] = (row_sum[i] / df_sum) * (col_sum[j] / df_sum) * df_sum
                    df_expected.iloc[i,j] = (row_sum[i] / df_sum) * col_sum[j]

        # df_expected

        if np.all(df_expected.values.flatten() >= 5):
            print('assumption is ok: every expected value is at least 5')
        else:
            print('assumption is NOT ok')

        if 1 in df.shape:
            ddof = len(df.values.flatten()) - 1
        else:
            ddof = (df.shape[0] - 1) * (df.shape[1] - 1)
        df_e_flat = df_expected.values.flatten()
        df_flat = df.values.flatten()
        print(f'DOF = {ddof}')
        chi2 = np.sum((df_flat - df_e_flat) **2 / (df_e_flat))
        print(f'chi2 = {chi2}')

        p_val = 1 - st.chi2.cdf(chi2, df = ddof)
        print(f'p-value = {p_val}')

        print(f'reject if p_value {p_val} < alpha {alpha}')
        if p_val < alpha:
            print('Reject!')
        else:
            print('Cannot reject.')
        return {'vis': df_vis, 'expected': df_expected}


"""
Filename: riccati.py

Authors: Thomas Sargent, John Stachurski

Solves the discrete-time algebraic Riccati equation

"""

import numpy as np
from numpy import dot
from numpy.linalg import solve

def dare(A, B, R, Q, tolerance=1e-10, max_iter=150):
    """
    Solves the discrete-time algebraic Riccati equation

        X = A'XA - A'XB(B'XB + R)^{-1}B'XA + Q

    via the doubling algorithm.  An explanation of the algorithm can be
    found in "Optimal Filtering" by B.D.O. Anderson and J.B. Moore
    (Dover Publications, 2005, p. 159).

    Parameters
    ----------
    A : array_like(float, ndim=2)
        k x k array.
    B : array_like(float, ndim=2)
        k x n array
    R : array_like(float, ndim=2)
        n x n, should be symmetric and positive definite
    Q : array_like(float, ndim=2)
        k x k, should be symmetric and non-negative definite
    tolerance : scalar(int), optional(default=1e-10)
        The tolerance level for convergence
    max_iter : scalar(float), optional(default=150)
        The maximum number of iterations allowed

    Returns
    -------
    X : array_like(float, ndim=2)
        The fixed point of the Riccati equation; a  k x k array
        representing the approximate solution

    """
    # == Set up == #
    error = tolerance + 1
    fail_msg = "Convergence failed after {} iterations."
    # == Make sure that all arrays are two-dimensional == #
    A, B, Q, R = list(map(np.atleast_2d, (A, B, Q, R)))
    k = Q.shape[0]
    I = np.identity(k)

    # == Initial conditions == #
    a0 = A
    b0 = dot(B, solve(R, B.T))
    g0 = Q
    i = 1

    # == Main loop == #
    while error > tolerance:

        if i > max_iter:
            raise ValueError(fail_msg.format(i))

        else:

            a1 = dot(a0, solve(I + dot(b0, g0), a0))
            b1 = b0 + dot(a0, solve(I + dot(b0, g0), dot(b0, a0.T)))
            g1 = g0 + dot(dot(a0.T, g0), solve(I + dot(b0, g0), a0))

            error = np.max(np.abs(g1 - g0))

            a0 = a1
            b0 = b1
            g0 = g1

            i += 1

    return g1  # Return X

if __name__ == '__main__': ## Example of useage

    a = np.array([[0.1, 0.1, 0.0],
                  [0.1, 0.0, 0.1],
                  [0.0, 0.4, 0.0]])

    b = np.array([[1.0, 0.0],
                  [0.0, 0.0],
                  [0.0, 1.0]])

    r = np.array([[0.5, 0.0],
                  [0.0, 1.0]])

    q = np.array([[1, 0.0, 0.0],
                  [0.0, 1, 0.0],
                  [0.0, 0.0, 10.0]])

    x = dare(a, b, r, q)
    print(x)


import numpy as np

A = np.array([[3, -9], [2, 4]])
print(A)

B = np.array([4, 9])

Z = np.linalg.solve(A, B)

print(Z)


import numpy as np
import math
import matplotlib.pyplot as plt
'''
PART A:
Bernoulli distribution: We can generate samples from a bernoulli distribution with parameter p
by using uniform random variable generator in python by outputting 1 if number generated through
np.random.uniform() is less than parameter p and 0 if greater.
The above argument works because then the probability of generating 1 is (p-0)/1 = p and probability
of generating 0 is (1-p)/1 = 1-p
'''

def Bernoulli(p):
    z = np.random.uniform()
    if(z<=p):
        k = 1
    else:
        k = 0;
    return k

'''
PART B
Binomial distribution:We follow a similar approach in this, except that we need to have n inputs for this.
We shall store those n numbers in a list.
Binomial parameters : n, p
No. of sample : N
'''

def probab(n,r,p):
    x = nCr(n,r) * math.pow(p,r) * math.pow((1-p),n-r)
    return x

def nCr(n,r):
    f = math.factorial
    return (f(n) / (f(r)*f(n-r)))

def Binomial(N,n,p):
    l =[]
    Nl = []
    for i in range(0,N):
        l = []
        suml = 0
        for j in range(0,n):
            m = Bernoulli(p)
            l.append(m)
        suml = sum(l)
        Nl.append(suml)
    return Nl

# Generating random value based on bernoulli distribution
p = input("Enter the bernoulli parameter p:")
k = Bernoulli(p)
print("The random bernoulli value generated using uniform distribution is: " + str(k))

N = input("Enter the no. of samples:")
n = input("Enter the binomial parameter n:")
p = input("Enter the binomial parameter p:")

#Generating N random samples from binomial distribution
binom = Binomial(N,n,p)

# Plotting graph here
plt.figure(1)
al = list(xrange(n+1))
alp = []

for i in range(0,n+1):
    temp = probab(n,i,p)
    alp.append(temp*N)
# Red line indicates the expected probability distribution
plt.plot(al,alp,'r')
# Blue bars represent frequency of values obtained through experiment/sampling
plt.hist(binom,bins=n)
plt.title("Binomial distribution")
plt.xlabel("Values")
plt.ylabel("Frequency")

plt.show()


# coding: utf-8

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from scipy.constants import g

#
# Fandenpendel:
# $$ \ddot{\theta} = -k^2 \sin(\theta) $$
#
# Als Näherung:
# Harmonischer Oszillator:
# $$ \ddot{\theta} = -k^2 \theta  $$
#
# mit
# $$
# \theta(0) = \theta_0, \, \dot{\theta} = 0, \, k^2 = \frac{g}{l}
# $$

# Allgemeine Lösung des harmonischen Oszillators:
# $$
# \theta(t) = A e^{ikt} + B e^{-ikt}
# $$
# Anfandsbedinungen einsetzen:
# $$
# \theta(t) = \theta_0 \cos(kt)
# $$
# und
# $$
# \dot{\theta}(t) = - \theta_0 k \sin(kt)
# $$

steps = 1000 # [1]
T = 8.0 # [s]
t = np.linspace(0, T, steps) # [s]
v0 = 0.0 # [m/s]
l = 1.0 # [m]
k_sq = g / l
k = np.sqrt(k_sq)

def rhs(y, t):
    theta, v = y[0], y[1]
    a = - k_sq * np.sin(theta)
    return np.array([v, a])

def compare_harm_osc_and_pendulum(theta0_deg):
    theta0 = np.deg2rad(theta0_deg)

    theta_harm_osc = theta0 * np.cos(k * t)
    v_harm_osc = - theta0 * k * np.sin(k * t)

    y0 = np.array([theta0, v0])
    ys_pendel = odeint(rhs, y0, t)
    theta_pendel = ys_pendel[:, 0]
    v_pendel  = ys_pendel[:, 1]

    plt.subplot(2, 1, 1)
    plt.title(r"Harmonic Oscillator vs. Pendulum ($\theta_0 = %.2f^\circ$)" % theta0_deg)
    plt.plot(t, theta_harm_osc, "k", label="Harmonic Oscillator")
    plt.plot(t, theta_pendel, "--r", label="Pendulum")
    plt.plot(t, (theta_harm_osc - theta_pendel), "b", label="Signed Error")
    plt.grid()
    plt.xlabel("time t [s]")
    plt.ylabel(r"angle $\theta$ [rad]")
    plt.legend()

    plt.subplot(2, 1, 2)
    plt.plot(theta_harm_osc, v_harm_osc, "k", label="Harmonic Oscillator")
    plt.plot(theta_pendel, v_pendel, "r", label="Pendulum")
    plt.xlabel(r"$\theta$")
    plt.ylabel(r"$\dot{\theta}$")
    plt.grid()
    plt.legend()

    plt.tight_layout()

plt.figure(1, figsize=(8,8))
compare_harm_osc_and_pendulum(5)

plt.figure(2, figsize=(8,8))
compare_harm_osc_and_pendulum(60)

plt.figure(3, figsize=(8,8))
compare_harm_osc_and_pendulum(170)
plt.show()


#!/usr/bin/python3

"""
    The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

Find the sum of all the primes below two million.
"""

import numpy as np

def isprime(num: int) -> bool:
    for i in range(2, int(np.sqrt(num))+1):
        if num%i == 0:
            return False
    return True

def euler10() -> int:
    tot = 2
    i = 3
    while i < 2000000:
        if isprime(i):
            tot = tot + i
        i = i + 2
    return tot

tot = euler10()
print(tot)


import numpy as np

def f(x):

     s=x**2+x+1

     return s

def F(x):

   s=x**3/3+x**2/2+x

   return s

x=[0,0.5,1]

quad=(1/6)*(f(x[0])+4*f(x[1])+f(x[2]))

print('approximation with Trapezontial rule :', quad)
print('real solution of integration : ', F(1)-F(0))


'''
# Defining the sigmoid function for activations
def sigmoid(x):
    return 1/(1+np.exp(-x))

# Derivative of the sigmoid function
def sigmoid_prime(x):
    return sigmoid(x) * (1 - sigmoid(x))

# Input data
x = np.array([0.1, 0.3])
# Target
y = 0.2
# Input to output weights
weights = np.array([-0.8, 0.5])

# The learning rate, eta in the weight step equation
learnrate = 0.5

# The neural network output (y-hat)
nn_output = sigmoid(x[0]*weights[0] + x[1]*weights[1])
# or nn_output = sigmoid(np.dot(x, weights))

# output error (y - y-hat)
error = y - nn_output

# error term (lowercase delta)
error_term = error * sigmoid_prime(np.dot(x,weights))

# Gradient descent step
del_w = [ learnrate * error_term * x[0],
                 learnrate * error_term * x[1]]
# or del_w = learnrate * error_term * x
'''
import numpy as np

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

def sigmoid_prime(x):
    '''
    Derivative of the sigmoid function
    '''
    return sigmoid(x) * (1 - sigmoid(x))

learnrate = 0.5
x = np.array([1, 2])
y = np.array(0.5)

# Initial weights
w = np.array([0.5, -0.5])

# Calculate one gradient descent step for each weight
# TODO: Calculate output of neural network
nn_output = sigmoid(w.dot(x))

# TODO: Calculate error of neural network
error = y - nn_output

# TODO: Calculate change in weights
del_w = learnrate * error * x * sigmoid_prime(w.dot(x))

print('Neural Network output:')
print(nn_output)
print('Amount of Error:')
print(error)
print('Change in Weights:')
print(del_w)


from __future__ import print_function
from fenics import *
from mshr import *
import matplotlib.pyplot as plt
import numpy as np

# Create mesh
R = 1. # radius
N = 20 # mesh resolution
domain = Circle(Point(0., 0.), R)
mesh = generate_mesh(domain, N)
plot(mesh,linewidth=0.3)
plt.show()

#define function space
degreeElements = 1
FS = FunctionSpace(mesh, 'Lagrange', degreeElements)

#impose Dirichlet boundary conditions
def boundary(x, on_boundary):
    return on_boundary

bc = DirichletBC(FS, Constant(0.), boundary)

#define function u and test function v
u = Function(FS)
v = TestFunction(FS)

# weak formulation of the problem
Res = -dot(grad(u), grad(v))*dx + v*dx

# solve the problem
solve(Res == 0, u, bc)

# plot solution
c = plot(u,mode='color',title='$u$')
plt.colorbar(c)
plot(mesh,linewidth=0.3)
plt.show()

# exact solution
uExact=Expression('(1-x[0]*x[0]-x[1]*x[1])/4',degree=2)

# Compute error (L2 norm)
error_L2 = errornorm(uExact, u, 'L2')
print("Error = ",error_L2)

# evaluate function at several points
print("u(0,0) = ",u(0,0))
print("u(0.5,0.5) = ",u(0.5,0.5))
#print("u(2,0) = ",u(2,0)) #point outside domain
print("u(1,0) = ",u(1,0))
# print("u(0,1) = ",u(0,1)) #point outside the discretized domain

# plot solution
tol=1e-2;
x=np.linspace(-1+tol,1-tol,40)
points = [(x_, 0) for x_ in x]
u_line = np.array([u(point) for point in points])
plt.plot(x,u_line,'k-')
plt.plot(x,(1-x*x)/4,'r--')
plt.xlabel('$x$')
plt.ylabel('$u(x,0)$')
plt.legend(['FEM','exact'])
plt.show()


import numpy as np

class FuzzyKmeans():
    """
    Fuzzy Kmeans calculates cluster probabilities in regards to euclidian distance
    Equivalent to vanilla Kmeans if we assign a given point to the cluster with the highest fuzzy probability
    Parameters:
        X: numpy array() data matrix
        U: cluster probabilities
        centers: center values
        m: numeric, the degree of uncertainty, (fuzziness of cluster)
    """
    def __init__(self,X,m=2):
        self.X = X
        self.m = m
        self.U = None
        self.centers = None

    def calculate_centers(self,U,X):
        """
        Recalculates centers using a linear combination of fuzzy probs and X values
        Normalized by the sum of all the fuzzy probs.
        """
        m = self.m
        ones = np.ones(X.shape[0]).reshape((X.shape[0],1))
        denom = (1/(U**m).dot(ones)).reshape(U.shape[0],)
        diagonal = np.diag(denom)
        centers = diagonal.dot((U**m).dot(X))
        return centers

    def calculate_fuzzy(self,X,centers):
        m = self.m
        m = 2/(m-1)
        us = np.ones(shape=(centers.shape[0],1))
        ones = np.ones(shape=(1,centers.shape[0]))
        for i in range(X.shape[0]):
            row = X[i].reshape(X.shape[1],1)
            row = row.dot(ones).T - centers
            norms = np.linalg.norm(row,2,axis=1).reshape(centers.shape[0],1)
            norms = (norms.dot(1/norms.T))**m
            sums = 1/np.sum(norms,axis=1).reshape(norms.shape[0],1)
            us = np.column_stack((us,sums))

        return us[:,1:]

    def fit(self,k,exit=0.01,seed=1,maxiterations=100,argmax=False):
        """
        Main clustering function
            k is the number of clusters
            exit is the exit criteria
            set argmax = True for normal K-means
        """
        X = self.X
        np.random.seed(seed)
        U = np.random.uniform(0,1,size=(k,X.shape[0])) #initialize cluster probabilities
        centers = self.calculate_centers(U,X)
        newcenters = 2*centers
        count = 0
        while np.linalg.norm((centers - newcenters),2) >= exit and count <= maxiterations:
            newcenters = centers
            U = self.calculate_fuzzy(X,centers)
            centers = self.calculate_centers(U,X)
            count += 1
        self.U = U
        self.centers = centers

    def predict(self,X,argmax=False):

        U = self.calculate_fuzzy(X,self.centers)
        if argmax:
            return (np.argmax(U,axis=0).T).reshape(X.shape[0],)
        return U.T


import numpy as np
import matplotlib.pyplot as plt

def LagrangeInterpolation(xi, yi, points):
	m = points.size
	l = np.ones(xi.shape, dtype='double')
	ans = np.zeros(m)

	for j in range (0, m):
		for k in range(0, len(xi)):
			for i in range(0, len(xi)):
				if i != k:
					l[k] *= (points[j]-xi[i])/(xi[k]-xi[i])
		ans[j] = yi.dot(l)
		l = np.ones(xi.shape)

	return ans

values_x = np.array([-2,0,3,5], dtype='double')
values_y = np.array([3,-2,4,2], dtype='double')
points_x = np.linspace(-2, 5, num=41, endpoint=True)
points_y = LagrangeInterpolation(values_x, values_y, points_x)

plt.figure(figsize=(10,6),facecolor='white')
plt.plot(points_x,points_y,label = 'Interpolação de Lagrange',linewidth = 2)
plt.scatter(values_x,values_y,label = 'Pontos',linewidth = 2)
plt.xlabel('x',fontsize='large')
plt.ylabel('y',fontsize='large')
plt.title('')
plt.legend()
plt.show()


import numpy as np
import drawPlot as dp

def linearRegression(x, y):

    avgX, avgY = np.mean(x), np.mean(y)

    a = np.sum( y * (x - avgX) ) / np.sum((x - avgX) * (x - avgX))

    b = avgY - a * avgX

    return(a, b)

def main():
    x = np.array([40,  43,  139, 182,  240])
    y = np.array([149, 157, 350, 367,  423])

    f = linearRegression(x, y)
    print("f(x) = {}x  {}".format(f[0], f[1]))

    price = float(input("Price $: "))

    size = (price-f[1]) / f[0]
    print("Size {}".format(size))

    dp.drawPlot(x, y, f)

if __name__ == "__main__":
    main()


from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')

def derivatives(t, y, vaccine_rate, birth_rate=0.01):
    """Defines the system of differential equations that
    describe the epidemiology model.

    Args:
        t: a positive float
        y: a tuple of three integers
        vaccine_rate: a positive float <= 1
        birth_rate: a positive float <= 1

    Returns:
        A tuple containing dS, dI, and dR
    """
    infection_rate = 0.3
    recovery_rate = 0.02
    death_rate = 0.01
    S, I, R = y
    N = S + I + R
    dSdt = (
        -((infection_rate * S * I) / N)
        + ((1 - vaccine_rate) * birth_rate * N)
        - (death_rate * S)
    )
    dIdt = (
        ((infection_rate * S * I) / N)
        - (recovery_rate * I)
        - (death_rate * I)
    )
    dRdt = (
        (recovery_rate * I)
        - (death_rate * R)
        + (vaccine_rate * birth_rate * N)
    )
    return dSdt, dIdt, dRdt

def integrate_ode(
    derivative_function,
    t_span,
    y0=(2999, 1, 0),
    vaccine_rate=0.85,
    birth_rate=0.01,
):
    """Numerically solve the system of differential equations.

    Args:
        derivative_function: a function returning a tuple
                             of three floats
        t_span: endpoints oif the time range to integrate over
        y0: a tuple of three integers (default: (2999, 1, 0))
        vaccine_rate: a positive float <= 1 (default: 0.85)
        birth_rate: a positive float <= 1 (default: 0.01)

    Returns:
        A tuple of three arrays
    """
    sol = solve_ivp(
        derivative_function,
        t_span,
        y0,
        args=(vaccine_rate, birth_rate),
    )
    ts, S, I, R = sol.t, sol.y[0], sol.y[1], sol.y[2]
    return ts, S, I, R

t_span = [0, 730]
t, S, I, R = integrate_ode(derivatives, t_span, vaccine_rate=0.0)

fig, ax = plt.subplots(1, figsize=(10, 5))
ax.plot(t, S, label='Susceptible', c='black', linestyle='solid', linewidth=1.75)
ax.plot(t, I, label='Infected', c='black', linestyle='dotted', linewidth=1.75)
ax.plot(t, R, label='Recovered', c='black', linestyle='dashed', linewidth=1.75)
ax.legend(fontsize=14, frameon=True, ncol=3, bbox_to_anchor=(0.85, 1.13))
ax.set_xlabel('Time', fontsize=14)
ax.set_ylabel('People', fontsize=14)
fig.savefig("plot_no_vaccine.pdf")

t, S, I, R = integrate_ode(derivatives, t_span, vaccine_rate=0.85)

fig, ax = plt.subplots(1, figsize=(10, 5))
ax.plot(t, S, label='Susceptible', c='black', linestyle='solid', linewidth=1.75)
ax.plot(t, I, label='Infected', c='black', linestyle='dotted', linewidth=1.75)
ax.plot(t, R, label='Recovered', c='black', linestyle='dashed', linewidth=1.75)
ax.legend(fontsize=14, frameon=True, ncol=3, bbox_to_anchor=(0.85, 1.13))
ax.set_xlabel('Time', fontsize=14)
ax.set_ylabel('People', fontsize=14)
fig.savefig("plot_with_vaccine.pdf")


import numpy as np

def gini_coefficient(x: np.ndarray) -> float:
    """
    Calculate the Gini coefficient of a distribution.

    Parameters
    ----------
    x : np.ndarray
        Array of values.

    Returns
    -------
    float
        Gini coefficient.
    """
     # Mean absolute difference
    mad = np.abs(np.subtract.outer(x, x)).mean()
    # Relative mean absolute difference
    rmad = mad/np.mean(x)
    # Gini coefficient
    g = 0.5 * rmad
    return g


samples = 200

r = 0.83
r2 = 0.33
r3 = 0.56

# Generate pearson correlated data with approximately cor(X, Y) = r

import numpy as np

data = np.random.multivariate_normal([0, 0, 0 ], [[1, r, r2], [r, 1, r3], [r2, r3, 1] ], size=samples)

#X, Y = data[:,0], data[:,1]

X,Y,Z = data[:,0], data[:,1], data[:,2]

#X, Y = data[:,0], data[:,1]

# That's it! Now let's take a look at the actual correlation:

import scipy.stats as stats

print 'r=', stats.pearsonr(X, Y)[0]
print 'r2=', stats.pearsonr(X, Z)[0]
print 'r3=', stats.pearsonr(Y, Z)[0]


from math import gcd

from sage.all import GF
from sage.all import is_prime_power

def attack(outputs, modulus=None, multiplier=None, increment=None):
    """
    Recovers the parameters from a linear congruential generator.
    If no modulus is provided, attempts to recover the modulus from the outputs (may require many outputs).
    If no multiplier is provided, attempts to recover the multiplier from the outputs (requires at least 3 outputs).
    If no increment is provided, attempts to recover the increment from the outputs (requires at least 2 outputs).
    :param outputs: the sequential output values obtained from the LCG
    :param modulus: the modulus of the LCG (can be None)
    :param multiplier: the multiplier of the LCG (can be None)
    :param increment: the increment of the LCG (can be None)
    :return: a tuple containing the modulus, multiplier, and the increment
    """
    if modulus is None:
        assert len(outputs) >= 4, "At least 4 outputs are required to recover the modulus"
        for i in range(len(outputs) - 3):
            d0 = outputs[i + 1] - outputs[i]
            d1 = outputs[i + 2] - outputs[i + 1]
            d2 = outputs[i + 3] - outputs[i + 2]
            g = d2 * d0 - d1 * d1
            modulus = g if modulus is None else gcd(g, modulus)

        assert is_prime_power(modulus), "Modulus must be a prime power, try providing more outputs"

    gf = GF(modulus)
    if multiplier is None:
        assert len(outputs) >= 3, "At least 3 outputs are required to recover the multiplier"
        x0 = gf(outputs[0])
        x1 = gf(outputs[1])
        x2 = gf(outputs[2])
        multiplier = int((x2 - x1) / (x1 - x0))

    if increment is None:
        assert len(outputs) >= 2, "At least 2 outputs are required to recover the multiplier"
        x0 = gf(outputs[0])
        x1 = gf(outputs[1])
        increment = int(x1 - multiplier * x0)

    return modulus, multiplier, increment


import numpy as np
import torch

def cart2polar(x):
    """Transform Cartesian to Polar Coordinates

    x: torch.Tensor, [dims] x 2
    return rho, theta
    """
    rho = torch.norm(x, p=2, dim=-1).unsqueeze(-1)
    theta = torch.atan2(x[..., 1], x[..., 0]).unsqueeze(-1)
    theta = theta + (theta < 0).type_as(theta) * (2 * np.pi)

    return rho, theta


import numpy as np

#Series temporais como listas
s1 = [168, 398, 451, 337, 186, 232, 262, 349, 189, 204, 220, 220, 207, 239, 259, 258,242, 331, 251, 323, 106, 1055, 170]
s2= [168, 400, 451, 300, 186, 200, 262, 349, 189, 204, 220, 220, 207, 239, 259, 258,242, 331, 251, 180, 106, 1055, 200]

#criando arrays a partir das listas
a = np.array(s1)
b = np.array(s2)

#calculo distancia euclidiana

#subtraçao
subtracao = a - b
quadrado = subtracao**2
somatorio = np.sum(quadrado)
distancia = np.sqrt(somatorio)

print("A distância euclidiana entre as séries é:\n",distancia)

print()

#valores medios
media = (a+b) / 2
print("A matriz com os valores médios \n",media)

print()

#valores maximos
max =np.maximum(a, b)
print("Matriz com valores máximos:\n",max )

print()

#valores minimos
min =np.minimum(a, b)
print("Matriz com valores mínimos:\n",min )


# Elastic Net Regression
#----------------------------------
#
# This function shows how to use TensorFlow to
# solve elastic net regression.
# y = Ax + b
#
# We will use the iris data, specifically:
#  y = Sepal Length
#  x = Pedal Length, Petal Width, Sepal Width

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
from sklearn import datasets
from tensorflow.python.framework import ops
ops.reset_default_graph()

# Create graph
sess = tf.Session()

# Load the data
# iris.data = [(Sepal Length, Sepal Width, Petal Length, Petal Width)]
iris = datasets.load_iris()
x_vals = np.array([[x[1], x[2], x[3]] for x in iris.data])
y_vals = np.array([y[0] for y in iris.data])

# Declare batch size
batch_size = 50

# Initialize placeholders
x_data = tf.placeholder(shape=[None, 3], dtype=tf.float32)
y_target = tf.placeholder(shape=[None, 1], dtype=tf.float32)

# Create variables for linear regression
A = tf.Variable(tf.random_normal(shape=[3,1]))
b = tf.Variable(tf.random_normal(shape=[1,1]))

# Declare model operations
model_output = tf.add(tf.matmul(x_data, A), b)

# Declare the elastic net loss function
elastic_param1 = tf.constant(1.)
elastic_param2 = tf.constant(1.)
l1_a_loss = tf.reduce_mean(tf.abs(A))
l2_a_loss = tf.reduce_mean(tf.square(A))
e1_term = tf.multiply(elastic_param1, l1_a_loss)
e2_term = tf.multiply(elastic_param2, l2_a_loss)
loss = tf.expand_dims(tf.add(tf.add(tf.reduce_mean(tf.square(y_target - model_output)), e1_term), e2_term), 0)

# Declare optimizer
my_opt = tf.train.GradientDescentOptimizer(0.001)
train_step = my_opt.minimize(loss)

# Initialize variables
init = tf.global_variables_initializer()
sess.run(init)

# Training loop
loss_vec = []
for i in range(1000):
    rand_index = np.random.choice(len(x_vals), size=batch_size)
    rand_x = x_vals[rand_index]
    rand_y = np.transpose([y_vals[rand_index]])
    sess.run(train_step, feed_dict={x_data: rand_x, y_target: rand_y})
    temp_loss = sess.run(loss, feed_dict={x_data: rand_x, y_target: rand_y})
    loss_vec.append(temp_loss[0])
    if (i+1)%250==0:
        print('Step #' + str(i+1) + ' A = ' + str(sess.run(A)) + ' b = ' + str(sess.run(b)))
        print('Loss = ' + str(temp_loss))

# Get the optimal coefficients
[[sw_coef], [pl_coef], [pw_ceof]] = sess.run(A)
[y_intercept] = sess.run(b)

# Plot loss over time
plt.plot(loss_vec, 'k-')
plt.title('Loss per Generation')
plt.xlabel('Generation')
plt.ylabel('Loss')
plt.show()


import numpy as np

class Quaternion:

    def __init__(self, s=0, x=0, y=0, z=0):
        self.s = s
        self.x = x
        self.y = y
        self.z = z

    def __add__(self, other):
        res = Quaternion()
        res.x = self.x + other.x
        res.y = self.y + other.y
        res.z = self.z + other.z
        res.s = self.s + other.s
        return res

    def __sub__(self, other):
        res = Quaternion()
        res.x = self.x - other.x
        res.y = self.y - other.y
        res.z = self.z - other.z
        res.s = self.s - other.s
        return res

    def __mul__(self, other):
        res = Quaternion()
        if not isinstance(other, Quaternion):
            res.s = self.s * other
            res.x = self.x * other
            res.y = self.y * other
            res.z = self.z * other
        else:
            # doesn't satisfy commutative law.
            res.s = self.s * other.s - self.x * other.x - self.y * other.y - self.z * other.z
            res.x = self.s * other.x + self.x * other.s + self.y * other.z - self.z * other.y
            res.y = self.s * other.y - self.x * other.z + self.y * other.s + self.z * other.x
            res.z = self.s * other.z + self.x * other.y - self.y * other.x + self.z * other.s
        return res

    def __truediv__(self, other):
        if other == 0:
            raise ZeroDivisionError
        return self * (1. / other)

    def conjugate(self):
        res = Quaternion()
        res.s = self.s
        res.x = -self.x
        res.y = -self.y
        res.z = -self.z
        return res

    def normalize(self):
        return self / self.norm()

    def norm(self):
        return np.sqrt(self.s ** 2 + self.x ** 2 + self.y ** 2 + self.z ** 2)

    def inv(self):
        return self.conjugate() / self.norm() ** 2

    def dot(self, other):
        res = Quaternion()
        res.s = self.s * other.s
        res.x = self.x * other.x
        res.y = self.y * other.y
        res.z = self.z * other.z
        return res

    def rotate(self, p):
        return self * p * self.inv()

    def convert_to_rotation_matrix(self):
        R = np.array([
            [1 - 2 * self.y * self.y - 2 * self.z * self.z, 2 * self.x * self.y - 2 * self.s * self.z,
             2 * self.x * self.z + 2 * self.s * self.y],
            [2 * self.x * self.y + 2 * self.s * self.z, 1 - 2 * self.x * self.x - 2 * self.z * self.z,
             2 * self.y * self.z - 2 * self.s * self.x],
            [2 * self.x * self.z - 2 * self.s * self.y, 2 * self.y * self.z + 2 * self.s * self.x,
             1 - 2 * self.x * self.x - 2 * self.y * self.y]
        ])
        return R

    def load_from_rotation_matrix(self, R):
        self.s = np.sqrt(R.trace() + 1) / 2
        self.x = (R[1, 2] - R[2, 1]) / (self.s * 4)
        self.y = (R[2, 0] - R[0, 2]) / (self.s * 4)
        self.z = (R[0, 1] - R[1, 0]) / (self.s * 4)

    def load_from_axis_angle(self, theta, n):
        self.s = np.cos(theta / 2)
        n = n * np.sin(theta / 2)
        n = n.ravel()
        self.x = n[0]
        self.y = n[1]
        self.z = n[2]

    def convert_to_axis_angle(self):
        theta = 2 * np.arccos(self.s)
        n = np.array([self.x, self.y, self.z]) / np.sin(theta / 2)
        return theta, n

    def __str__(self):
        return f'[{self.s} {self.x} {self.y} {self.z}]'

if __name__ == '__main__':
    # "identity" quaternion can represent any rotation.
    R = np.array([
        [np.sqrt(2) / 2, -np.sqrt(2) / 2, 0.],
        [np.sqrt(2) / 2, np.sqrt(2) / 2, 0.],
        [0., 0., 1.]]
    )
    q = Quaternion()
    q.load_from_rotation_matrix(R)
    print('convert R to quaternion:', q)
    print('the norm of q:', q.norm())
    print('****take care：identity quaternion represent rotation, if norm(q)!=1, pls use norm.')
    res = q * q  # two time rotation, each time rotate 45 degree.
    theta, n = res.convert_to_axis_angle()
    print('q * q to axis angle:', np.rad2deg(theta), n)
    q2 = Quaternion()
    q2.load_from_axis_angle(theta, n)
    R2 = q2.convert_to_rotation_matrix()
    print('R2:\n', R2)
    print('q * inv(q):', q * q.inv())


import math
import matplotlib.pyplot as plt
import scipy.optimize as op
import numpy as np
np.set_printoptions(suppress=True)

from ex2 import hypothesis, plot_cost_history

def plot_classification(positive, negative, theta, title):
	#from https://towardsdatascience.com/andrew-ngs-machine-learning-course-in-python-regularized-logistic-regression-lasso-regression-721f311130fb
	def mapFeaturePlot(x1,x2,degree):
		"""
		take in numpy array of x1 and x2, return all polynomial terms up to the given degree
		"""
		out = np.ones(1)
		for i in range(1,degree+1):
			for j in range(i+1):
				terms= (x1**(i-j) * x2**j)
				out= np.hstack((out,terms))
		return out

	plt.clf()
	plt.title(title)
	plt.plot(positive[:,0], positive[:,1], 'b+', label = 'y = 1')
	plt.plot(negative[:,0], negative[:,1], 'rx', label = 'y = 0')

	# Plotting decision boundary
	u_vals = np.linspace(-1,1.5,50)
	v_vals = np.linspace(-1,1.5,50)
	z = np.zeros((len(u_vals),len(v_vals)))

	for i in range(len(u_vals)):
		for j in range(len(v_vals)):
			z[i,j] = mapFeaturePlot(u_vals[i],v_vals[j],6) @ theta

	plt.contour(u_vals,v_vals,z.T,0)
	plt.ylabel('Microchip Test 2')
	plt.xlabel('Microchip Test 1')
	plt.legend()
	plt.show()

# Import data
data = np.loadtxt("ex2data2.txt", delimiter=",")

positive = data[data[:,2] == 1][:,0:2]
negative = data[data[:,2] == 0][:,0:2]

# 2.1 Visualizing the data
plt.ylabel('Microchip Test 2')
plt.xlabel('Microchip Test 1')

plt.plot(positive[:,0], positive[:,1], 'b+', label = 'y = 1')
plt.plot(negative[:,0], negative[:,1], 'rx', label = 'y = 0')

plt.legend()
plt.show()

# 2.2 Feature mapping
def map_feature(x1, x2):
	degree = 6
	out = np.ones(x1.shape[0])

	for i in range(1, degree + 1):
		for j in range(i + 1):
			out = np.c_[out, (x1 ** (i - j)) * (x2 ** j)]

	return out

X = map_feature(data[:, 0], data[:, 1])

# 2.3 Cost function and gradient
def cost_function_reg(theta, X, y, Lambda):
	m = X.shape[0]

	h = hypothesis(theta, X)
	error = np.sum(-y * np.log(h) - (1 - y) * np.log(1 - h))

	error = error / m

	return error + ((Lambda / (2*m)) * np.sum(theta ** 2))

# Evaluation
theta = np.zeros(X.shape[1])
y = data[:, 2]

# Set regularization parameter lambda to 1
Lambda = 1

# You should see that the cost is about 0.693.
assert round(cost_function_reg(theta, X, y, Lambda), 3) == 0.693

def gradient(theta, X, y, Lambda):
	m = X.shape[0]

	h = hypothesis(theta, X)

	# for j = 0
	theta[0] = np.sum((h - y) * X[:, 0]) / m

	# for j ≥ 1
	for j in range(1, theta.shape[0]):
		theta[j] = (np.sum((h - y) * X[:, j]) / m) + ((Lambda / m) * theta[j])

	return theta

# There is no fminunc in scipy, so I have used gradient descent with manually tuned alpha and iterations.
for iterations in [100, 1000]:
	for Lambda in [0, 0.5]:
		theta = np.zeros(X.shape[1])
		alpha = 0.1
		cost_history = []

		m = X.shape[0]

		for i in range(iterations):
			m = X.shape[0]

			h = hypothesis(theta, X)

			# for j = 0
			theta[0] = theta[0] - alpha * np.sum((h - y) * X[:, 0]) / m

			# for j ≥ 1
			for j in range(1, theta.shape[0]):
				theta[j] = theta[j] - alpha * (np.sum((h - y) * X[:, j]) / m) + ((Lambda / m) * theta[j])

			cost_history.append(cost_function_reg(theta, X, y, Lambda))

		#plot_cost_history(cost_history)
		cost = cost_function_reg(theta, X, y, Lambda)

		# The predict function will produce “1” or “0” predictions given a dataset
		# and a learned parameter vector θ.
		accuracy = np.mean((hypothesis(theta, X) >= 0.5).astype(float) == y) * 100

		result = 'Iterations = %d, lambda = %.1f, Accuracy = %.2f%%' % (iterations, Lambda, accuracy)

		print(result)

		#plot_classification(positive, negative, theta, result)


import numpy as np

'''
教材第45页
已知正实例点x1=(3，3)T,x2=[4,3]T,负实例点x3=(1,1)T
用感知机学习算法的对偶形式求感知机模型f(x)=sign(w·x+b)。
这里w=(w(1),w(2))T,x=(x(1),x(2))T
'''

def perceptron_antithesis():
    x = np.array([[3, 3], [4, 3], [1, 1]])
    y = np.array([1, 1, -1])
    aa = np.array([0, 0, 0])
    b = 0
    G = np.array([[18, 21, 6], [21, 25, 7], [6, 7, 2]])
    # print(np.matmul(x, x[0].T))
    for a in range(5):
        print('-----------第{}轮------------'.format(a + 1))
        for i in range(3):
            L = y[i] * (np.sum(aa * y * np.matmul(x, x[i].T)) + b)
            if L <= 0:
                print("x{},L={}".format(i + 1, L))
                aa[i] = aa[i] + 1
                print("a={}".format(aa))
                b = b + y[i]
                print("b={}".format(b))

if __name__ == "__main__":
    perceptron_antithesis()


import numpy as np

# Whiteboard: https://wbd.ms/share/v2/aHR0cHM6Ly93aGl0ZWJvYXJkLm1pY3Jvc29mdC5jb20vYXBpL3YxLjAvd2hpdGVib2FyZHMvcmVkZWVtLzk4ZjBjYzM3OTc1MzQ3YjY5ZTQ4OTA3MjYxODIxN2Y0X0JCQTcxNzYyLTEyRTAtNDJFMS1CMzI0LTVCMTMxRjQyNEUzRA==

def print_paths(n, start, end, arr):
    """
    We leverage the bijection between Catalan paths
    and valid parenthesizations. start and end are the
    coordinates of the starting and ending points in the
    Catalan paths.
    Note that end never changes, so passing it to the function
    is redundant. Also, n never changes.
    """
    # one less on the x-coordiate and one more on
    # the y-coordinate, means we're one step away
    # from end point. We could also check for start[1]-end[1]==1
    # but the abs makes it not specific to paths above the grid
    if start[0]==end[0]-1 and abs(start[1]-end[1])==1:
        arr.append(')')
        print(''.join(arr))
    ## This means we're at the peak (n,n).
    # We can never let the sum of the x and y-coordinates
    # exceed 2n. This ensures we stay within the square boundary
    # of the grid. We can never cross the line x=y by design.
    # the condition ensure we also never cross
    # x+y=2n, the other boundary.
    elif sum(start)==2*n:
        # Since we're at the peak, must move down.
        arr.append(')')
        start+=np.array([1,-1])
        print_paths(n,start,end,arr)
    # If we've touched the x-axis, we move up.
    ## this is specific to Catalan paths.
    elif start[1] == 0:
        # Must move up now.
        arr.append('(')
        start+=np.array([1,1])
        print_paths(n,start,end,arr)
    ## If within all boundaries, move up and also move down.
    else:
        arr_up = arr.copy()
        arr_down=arr.copy()
        arr_up.append('(')
        start1=start+np.array([1,1])
        print_paths(n,start1,end,arr_up)
        arr_down.append(')')
        start2=start+np.array([1,-1])
        print_paths(n,start2,end,arr_down)

def valid_parenth(n):
    start=np.array([0,0])
    end=np.array([2*n,0])
    arr=[]
    print_paths(n,start,end,arr)


import numpy as np

class DHs:
    def __init__(self, **kwargs):
        self.alpha = kwargs['alpha']
        self.theta = kwargs['theta']
        self.d = kwargs['d']
        self.a = kwargs['a']

    def DH(self):

        wholeDT = []

        for i in range(len(self.theta)): # you can use others it doesnt matter
            aco = 0 if ((np.cos(np.deg2rad(self.alpha[i] % 360)) < 1e-10) & (np.cos(np.deg2rad(self.alpha[i] % 360)) > -1e-10)) else np.cos(np.deg2rad(self.alpha[i] % 360))
            asi = 0 if ((np.sin(np.deg2rad(self.alpha[i] % 360)) < 1e-10) & (np.sin(np.deg2rad(self.alpha[i] % 360)) > -1e-10)) else np.sin(np.deg2rad(self.alpha[i] % 360))
            tco = 0 if ((np.cos(np.deg2rad(self.theta[i] % 360)) < 1e-10) & (np.cos(np.deg2rad(self.theta[i] % 360)) > -1e-10)) else np.cos(np.deg2rad(self.theta[i] % 360))
            tsi = 0 if ((np.sin(np.deg2rad(self.theta[i] % 360)) < 1e-10) & (np.sin(np.deg2rad(self.theta[i] % 360)) > -1e-10)) else np.sin(np.deg2rad(self.theta[i] % 360))

            DT = [
                [tco, -tsi, 0, self.a[i]],
                [tsi*aco, tco*aco, -asi, -self.d[i]*asi],
                [asi*tsi, asi*tco, aco, self.d[i]*aco],
                [0, 0, 0, 1]
                ]

            wholeDT.append(DT)

        return np.reshape(wholeDT, [len(self.theta), 4, 4]), len(self.theta)

    def multDT(self):

        multipliedDTs = np.matmul(
            self.DH()[0][self.DH()[1] - 2],
            self.DH()[0][self.DH()[1] - 1]
            )

        if self.DH()[1] > 2:
            for i in range(self.DH()[1] - 3, -1, -1):
                multipliedDTs = np.matmul(
                    self.DH()[0][i],
                    multipliedDTs
                    )
        return multipliedDTs

    def pointInPlane(self, nokta, **axis):
        if axis['axis'] == 'global':
            return np.matmul(self.multDT(), np.reshape(np.append(nokta, [1]), [4, 1]))
        else:
            return np.matmul(np.linalg.inv(self.multDT()), np.reshape(np.append(nokta, [1]), [4, 1]))