import numpy as np

### Create Random Number

# 1. Return Random Number Between 0 And !
random_number = np.random.rand()
print(random_number)

# 2. Return Random Number Between low number and hight number
random_number = np.random.randint(10, 100)
print(random_number)

# 3. Return Random Number from List
random_number = np.random.choice([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
print(random_number)

### Create Random Array

# 1. rand()
random_array = np.random.rand(10)
print(random_array)

random_array = np.random.rand(2,5)
print(random_array)

random_array = np.random.rand(2,3,5)
print(random_array)

# 2. randint()
random_array = np.random.randint(100, size=10)
print(random_array)

random_array = np.random.randint(100, size=(10))
print(random_array)

random_array = np.random.randint(100, size=(2, 5))
print(random_array)

# 3. choice()
random_array = np.random.choice([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], size=5)
print(random_array)

random_array = np.random.choice([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], size=(2,4))
print(random_array)

random_array = np.random.choice(np.random.randint(1000, size=100), size=(5,10))
print(random_array)

Tutorial/Code/15. Random Numbers in NumPy.py


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

from __future__ import absolute_import

from packtml.decision_tree.metrics import (entropy, gini_impurity,
                                           InformationGain)

import numpy as np
from numpy.testing import assert_almost_equal

def test_entropy():
    events = np.asarray(9 * [0] + 5 * [1])  # 9/14, 5/14
    ent = entropy(events)
    assert round(ent, 2) == 0.94, round(ent, 2)

def test_gini_impurity():
    x = np.asarray([0] * 10 + [1] * 10)
    assert gini_impurity(x) == 0.5
    assert gini_impurity(x[:10]) == 0.

    # show that no mixing of gini yields 0.0
    assert gini_impurity(np.array([0, 0])) == 0.

    # with SOME mixing we get 0.5
    assert gini_impurity(np.array([0, 1])) == 0.5

    # with a lot of mixing we get a number close to 0.8
    gi = gini_impurity([0, 1, 2, 3, 4])
    assert_almost_equal(gi, 0.8)

def test_information_gain():
    X = np.array([
        [0, 3],
        [1, 3],
        [2, 1],
        [2, 1],
        [1, 3]
    ])

    y = np.array([0, 0, 1, 1, 2])

    uncertainty = gini_impurity(y)
    assert_almost_equal(uncertainty, 0.63999999)
    mask = X[:, 0] == 0

    # compute the info gain for this mask
    infog = InformationGain("gini")
    ig = infog(y, mask, uncertainty)
    assert_almost_equal(ig, 0.1399999)


import numpy as np
import pandas as pd

'''
     Gini impurity is a measure of how often a randomly
     chosen element from the set would be incorrectly labeled
     if it was randomly labeled according to the distribution
     of labels in the subset.
'''

# Read example from csv
#example = "ImpurityMeasures/example.csv"
example = "ImpurityMeasures/example2.csv"
data = pd.read_csv(example)

# The fastest way to find occurences within an array
# Check it out in this stackoverflow thread:
# https://stackoverflow.com/questions/10741346/numpy-most-efficient-frequency-counts-for-unique-values-in-an-array
def unique_count(A):
    unique, inverse = np.unique(A, return_inverse=True)
    count = np.zeros(len(unique), dtype=int)
    np.add.at(count, inverse, 1)
    return np.vstack((unique, count)).T

# Get the gini impurity of one node
def gini(N):
    uniques = unique_count(N)
    total = len(N)
    # Probability of every node leaf Pi
    Pi = np.zeros(uniques.shape[0])
    for i in range(uniques.shape[0]):
        pi = uniques[i,1]/total
        Pi[i] = pi

    # Appliying the Gini formula: 1 - Sum[Pi(t)^2]
    gini = 1 - np.sum(Pi**2)

    print(uniques)
    print("Probabilities of Pi: ", Pi)
    print("Gini impurity: {}\n".format(gini))
    return gini

# Finding the purest node within data
def findPurest():
    purest = {
        "column": "",
        "gini": 1
    }

    for node in data:
        print("------------ {} ------------".format(node))
        gini_ = gini(data[node].values)

        if gini_ < purest['gini']:
            purest['column'] = node
            purest['gini'] = gini_

    print("The purest node is: {} \nWith an gini index: {}"
    .format(purest['column'], purest['gini']))

    return purest['gini']

# You can select the Father node
#father = findPurest() # is the purest node
father = "Clase"
child = "Talla_Camisa"

def giniWeighted():
    #
    crosstab = pd.crosstab(data[child], data[father], margins=True, margins_name="Total")
    print(crosstab,'\n')
    index = crosstab.index
    crosstab = crosstab.values
    # Sum the ginis
    giniW = 0

    for i in range(len(index)-1):
        print("--------------- {} ---------------".format(index[i]))
        pi = crosstab[i,:-1]/crosstab[i,-1]
        gini_ = 1 - np.sum(pi**2)

        # Calculate the weighted gini and sum
        giniW += (crosstab[i,-1]/crosstab[-1,-1])*gini_

        print("Probabilities of Pi: {}\nGini impurity: {}\n"
        .format(pi, gini_))

    print("The weighted gini is: ", giniW)
    return giniW

giniW = giniWeighted()


import math

# import numpy as np
# from sympy import Symbol, integrate, lambdify, solve, re
print("Квадратурные формулы наивысшей алгебраической степени точности (формулы типа Гаусса)\nВариант 5\n")

# Весовая функция p(x)
def p(y):
    return 1 / y ** (1 / 3)

# Функция f(x)
def f(y):
    return math.cos(y)

# Функция phi(x) = p(x)f(x)
def phi(y):
    return f(y) * p(y)

# Моменты
def m(i_, a_, b_):
    if i_ == 0:
        return 3 / 2 * (b_ ** (2 / 3) - a_ ** (2 / 3))  # m_0(x)
    if i_ == 1:
        return 3 / 5 * (b_ ** (5 / 3) - a_ ** (5 / 3))  # m_1(x)

# Накопленные произведения для Лагранжа
def mult(k, z):
    t = 1
    for p in range(m + 1):
        if p != k:
            t = t * (z - values[p])
    return t

# Метод Лагранжа
def lagrange(q):
    ans = 0
    for t in range(m + 1):
        ans = ans + (f(values[t]) * mult(t, q) / mult(t, values[t]))
    return ans

# КФ средних прямоугольников
def mid():
    s = 0
    for j in range(m):
        s = s + phi(values[j + 1] - h / 2)

    return h * s

# Формула Гаусса
def gauss():
    global values
    values = [-(0.6 ** 0.5), 0, 0.6 ** 0.5]
    p_ = [-0.4, -0.5, 0.4]
    a_ = []
    for j in range(m + 1):
        # print(j, values[j], p_[j])
        a_.append((2 * (1 - values[j] ** 2)) / (((m + 1) ** 2) * p_[j] ** 2))

    sum_ = 0
    for j in range(m + 1):
        # print(a_[j], phi((b - a) * values[j] / 2 + (b + a) / 2))
        sum_ += a_[j] * phi((b - a) * values[j] / 2 + (b + a) / 2)
    return ((b - a) / 2) * sum_

r = 1
while r:
    print("Функция phi(x) = cos(x)/x^(1/3):\np(x) = 1/x^(1/3), f(x) = cos(x)\n")
    print("Нижний предел интегрирования, A = 0")
    a = 0
    print("Верхний предел интегрирования, B = 1")
    b = 1
    print("Число промежутков деления, m:")
    m = int(input())

    values = []
    h = (b - a) / m  # длина частичного разбиения

    # Массив узлов
    for i in range(m + 1):
        xi = (a + i * h)
        values.append(xi)

    print('h =', h)

    # точный интеграл phi от 0 до 1
    j_ = 1.3212230741459003099469074212370546202293316300043820048748526319098001457707427010561826248610759312

    print('Точное значение интеграла J =', j_)
    int_ = mid()

    print('\nМетод средних прямоугольников, J(h):', int_)
    print('Фактическая погрешность, |J - J(h)|:', abs(j_ - int_))

    # print(lagrange(0))
    values = [1 / 4, 3 / 4]
    a_0 = (3 / 5 - 3 / 2 * values[1]) / (values[0] - values[1])
    a_1 = (3 / 5 - 3 / 2 * values[0]) / (values[1] - values[0])
    int_ = a_0 * f(values[0]) + a_1 * f(values[1])

    # print('\nУзлы: 1/4, 3/4')
    print('\nИнтерполяционный метод, J(h):', int_)
    print('Фактическая погрешность, |J - J(h)|:', abs(j_ - int_))

    int_ = gauss()
    print('\nФормула Гаусса, J(h):', int_)
    print('Фактическая погрешность, |J - J(h)|:', abs(j_ - int_))


import numpy as np

# Define the gaussian coefficients for collocation points

class gauss:

    # Input: n - stages of the gaussian coefficients
    def __init__(self, n):
        self.n = n

        if n == 2:
            x1 = 0.577350269189626
            w1 = 1.000000000000000
            t = [(-x1+1)*0.5, (x1+1)*0.5]
            w = [w1*0.5, w1*0.5]
            self.t = np.array(t, dtype=np.float64)
            self.w = np.array(w, dtype=np.float64)
        elif n == 3:
            x0 = 0.000000000000000
            x1 = 0.774596669241483
            w0 = 0.888888888888889
            w1 = 0.555555555555556
            t = [(-x1+1)*0.5, 0.5, (x1+1)*0.5]
            w = [w1*0.5, w0*0.5, w1*0.5]
            self.t = np.array(t, dtype=np.float64)
            self.w = np.array(w, dtype=np.float64)
        elif n == 4:
            x1 = 0.339981043584856
            x2 = 0.861136311594053
            w1 = 0.652145154862546
            w2 = 0.347854845137454
            t = [(-x2+1)*0.5, (-x1+1)*0.5, (x1+1)*0.5, (x2+1)*0.5]
            w = [w2*0.5, w1*0.5,  w1*0.5, w2*0.5]
            self.t = np.array(t, dtype=np.float64)
            self.w = np.array(w, dtype=np.float64)
        elif n == 5:
            x0 = 0.000000000000000
            x1 = 0.538469310105683
            x2 = 0.906179845938664
            w0 = 0.568888888888889
            w1 = 0.478628670499366
            w2 = 0.236926885056189
            t = [(-x2+1)*0.5, (-x1+1)*0.5, 0.5, (x1+1)*0.5, (x2+1)*0.5]
            w = [w2*0.5, w1*0.5, w0*0.5, w1*0.5, w2*0.5]
            self.t = np.array(t, dtype=np.float64)
            self.w = np.array(w, dtype=np.float64)
        elif n == 6:
            x1 = 0.238619186083197
            x2 = 0.661209386466265
            x3 = 0.932469514203152
            w1 = 0.467913934572691
            w2 = 0.360761573048139
            w3 = 0.171324492379170
            t = [(-x3+1)*0.5, (-x2+1)*0.5, (-x1+1)*0.5, (x1+1)*0.5, (x2+1)*0.5, (x3+1)*0.5]
            w = [w3*0.5, w2*0.5, w1*0.5,  w1*0.5, w2*0.5, w3*0.5]
            self.t = np.array(t, dtype=np.float64)
            self.w = np.array(w, dtype=np.float64)
        elif n == 7:
            x0 = 0.000000000000000
            x1 = 0.405845151377397
            x2 = 0.741531185599394
            x3 = 0.949107912342759
            w0 = 0.417959183673469
            w1 = 0.381830050505119
            w2 = 0.279705391489277
            w3 = 0.129484966168870
            t = [(-x3+1)*0.5, (-x2+1)*0.5, (-x1+1)*0.5, 0.5, (x1+1)*0.5, (x2+1)*0.5, (x3+1)*0.5]
            w = [w3*0.5, w2*0.5, w1*0.5,  w0*0.5, w1*0.5, w2*0.5, w3*0.5]
            self.t = np.array(t, dtype=np.float64)
            self.w = np.array(w, dtype=np.float64)
        elif n == 8:
            x1 = 0.183434642495650
            x2 = 0.525532409916329
            x3 = 0.796666477413627
            x4 = 0.960289856497536
            w1 = 0.362683783378362
            w2 = 0.313706645877887
            w3 = 0.222381034453374
            w4 = 0.101228536290376
            t = [(-x4+1)*0.5, (-x3+1)*0.5, (-x2+1)*0.5, (-x1+1)*0.5, (x1+1)*0.5, (x2+1)*0.5, (x3+1)*0.5, (x4+1)*0.5]
            w = [w4*0.5, w3*0.5, w2*0.5, w1*0.5,  w1*0.5, w2*0.5, w3*0.5, w4*0.5]
            self.t = np.array(t, dtype=np.float64)
            self.w = np.array(w, dtype=np.float64)
        elif n == 9:
            x0 = 0.000000000000000
            x1 = 0.324253423403809
            x2 = 0.613371432700590
            x3 = 0.836031107326636
            x4 = 0.968160239507626
            w0 = 0.330239355001260
            w1 = 0.312347077040003
            w2 = 0.260610696402935
            w3 = 0.180648160694857
            w4 = 0.081274388361574
            t = [(-x4+1)*0.5, (-x3+1)*0.5, (-x2+1)*0.5, (-x1+1)*0.5, 0.5, (x1+1)*0.5, (x2+1)*0.5, (x3+1)*0.5, (x4+1)*0.5]
            w = [w4*0.5, w3*0.5, w2*0.5, w1*0.5,  w0*0.5, w1*0.5, w2*0.5, w3*0.5, w4*0.5]
            self.t = np.array(t, dtype=np.float64)
            self.w = np.array(w, dtype=np.float64)
        elif n == 10:
            x1 = 0.148874338981631
            x2 = 0.433395394129247
            x3 = 0.679409568299024
            x4 = 0.865063366688985
            x5 = 0.973906528517172
            w1 = 0.295524224714753
            w2 = 0.269266719309996
            w3 = 0.219086362515982
            w4 = 0.149451349150581
            w5 = 0.066671344308688
            t = [(-x5+1)*0.5, (-x4+1)*0.5, (-x3+1)*0.5, (-x2+1)*0.5, (-x1+1)*0.5, (x1+1)*0.5, (x2+1)*0.5, (x3+1)*0.5, (x4+1)*0.5, (x5+1)*0.5]
            w = [w5*0.5, w4*0.5, w3*0.5, w2*0.5, w1*0.5,  w1*0.5, w2*0.5, w3*0.5, w4*0.5, w5*0.5]
            self.t = np.array(t, dtype=np.float64)
            self.w = np.array(w, dtype=np.float64)
        elif n == 11:
            x0 = 0.000000000000000
            x1 = 0.269543155952345
            x2 = 0.519096129110681
            x3 = 0.730152005574049
            x4 = 0.887062599768095
            x5 = 0.978228658146057
            w0 = 0.272925086777901
            w1 = 0.262804544510247
            w2 = 0.233193764591990
            w3 = 0.186290210927734
            w4 = 0.125580369464905
            w5 = 0.055668567116174
            t = [(-x5+1)*0.5, (-x4+1)*0.5, (-x3+1)*0.5, (-x2+1)*0.5, (-x1+1)*0.5, 0.5, (x1+1)*0.5, (x2+1)*0.5, (x3+1)*0.5, (x4+1)*0.5, (x5+1)*0.5]
            w = [w5*0.5, w4*0.5, w3*0.5, w2*0.5, w1*0.5,  w0*0.5, w1*0.5, w2*0.5, w3*0.5, w4*0.5, w5*0.5]
            self.t = np.array(t, dtype=np.float64)
            self.w = np.array(w, dtype=np.float64)


# Neural Networks and the Simplist XOR Problem
- This was adopted from the PyTorch Tutorials.
- Simple supervised machine learning.
- http://pytorch.org/tutorials/beginner/pytorch_with_examples.html

## Neural Networks
- Neural networks are the foundation of deep learning, which has revolutionized the

```In the mathematical theory of artificial neural networks, the universal approximation theorem states[1] that a feed-forward network with a single hidden layer containing a finite number of neurons (i.e., a multilayer perceptron), can approximate continuous functions on compact subsets of Rn, under mild assumptions on the activation function.```

- A simple task that Neural Networks can do but simple linear models cannot is called the [XOR problem](https://medium.com/@jayeshbahire/the-xor-problem-in-neural-networks-50006411840b).

- The XOR problem involves an output being 1 if either of two inputs is 1, but not both.

### Generate Fake Data
- `D_in` is the number of dimensions of an input varaible.
- `D_out` is the number of dimentions of an output variable.
- Here we are learning some special "fake" data that represents the xor problem.
- Here, the dv is 1 if either the first or second variable is

# -*- coding: utf-8 -*-
import numpy as np

#This is our independent and dependent variables.
x = np.array([ [0,0,0],[1,0,0],[0,1,0],[0,0,0] ])
y = np.array([[0,1,1,0]]).T
print("Input data:\n",x,"\n Output data:\n",y)

### A Simple Neural Network
- Here we are going to build a neural network.
- First layer (`D_in`)has to be the length of the input.
- `H` is the length of the output.
-  `D_out` is 1 as it will be the probability it is a 1.

np.random.seed(seed=83832)
#D_in is the number of input variables.
#H is the hidden dimension.
#D_out is the number of dimensions for the output.
D_in, H, D_out = 3, 2, 1

# Randomly initialize weights og out 2 hidden layer network.
w1 = np.random.randn(D_in, H)
w2 = np.random.randn(H, D_out)
bias = np.random.randn(H, 1)

### But "Hidden Layers" Aren't Hidden
- Let's take a look
- These are just random numbers.

print(w1, w2)

### Update the Weights using Gradient Decent
- Calculate the predited value
- Calculate the loss function
- Compute the gradients of w1 and w2 with respect to the loss function
- Update the weights using the learning rate

learning_rate = .01
for t in range(500):
    # Forward pass: compute predicted y
    h = x.dot(w1)

    #A relu is just the activation.
    h_relu = np.maximum(h, 0)
    y_pred = h_relu.dot(w2)

    # Compute and print loss
    loss = np.square(y_pred - y).sum()
    print(t, loss)

    # Backprop to compute gradients of w1 and w2 with respect to loss
    grad_y_pred = 2.0 * (y_pred - y)
    grad_w2 = h_relu.T.dot(grad_y_pred)
    grad_h_relu = grad_y_pred.dot(w2.T)
    grad_h = grad_h_relu.copy()
    grad_h[h < 0] = 0
    grad_w1 = x.T.dot(grad_h)

    # Update weights
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2

Fully connected

### Verify the Predictions
- Obtained a predicted value from our model and compare to origional.

pred = np.maximum(x.dot(w1),0).dot(w2)

print (pred, "\n", y)

y

#We can see that the weights have been updated.
w1

w2

# Relu just removes the negative numbers.
h_relu


import numpy as np

class Softmax:
    def __call__(self, X):
        return np.exp(X) / np.expand_dims(np.sum(np.exp(X), axis=1), axis=1)

class Sigmoid:
    def __call__(self, x):
        return 1 / (1 + np.exp(-x))

    def gradient(self, x):
        return self.__call__(x) * (1 - self.__call__(x))

class Softplus:
    def __call__(self, X):
        return np.log(1 - np.exp(X))


import numpy as np

from typing import List, Tuple
from app.model import DenavitHartenberg

def linalg_multi_dot(dh: List[np.ndarray]) -> np.ndarray:
    if len(dh) > 1:
        return np.linalg.multi_dot(dh)

    return dh[0]

def get_coord(dh: np.ndarray) -> Tuple:
    vector = np.array([[0], [0], [0], [1]])
    x, y, z, _ = dh.dot(vector).tolist()
    return x[0], y[0], z[0]

def generate_dh(dh: DenavitHartenberg) -> np.ndarray:
    return np.array([
        [
            np.cos(dh.theta), -np.cos(dh.alpha) * np.sin(dh.theta),
            np.sin(dh.alpha) * np.sin(dh.theta), dh.a * np.cos(dh.theta)
        ],
        [
            np.sin(dh.theta), np.cos(dh.theta) * np.cos(dh.alpha),
            -np.sin(dh.alpha) * np.cos(dh.theta), dh.a * np.sin(dh.theta)
        ],
        [0, np.sin(dh.alpha), np.cos(dh.alpha), dh.d],
        [0, 0, 0, 1],
    ])

def multiply_matrix(matrices: List) -> Tuple:
    try:
        dh_matrices = [generate_dh(dh=m) for m in matrices]
        dh_array = linalg_multi_dot(dh=dh_matrices)
        x, y, z = get_coord(dh=dh_array)
    except ValueError as e:
        return [], 0, 0, 0, str(e)

    return dh_array.tolist(), x, y, z, None


import numpy as np

def Gram_Schmidt(A):
    """
    A: Matriz donde cada columna es un vector de la base
    del espacio vectorial.

    Devuelve una matriz donde cada columna es un vector
    de una base ortonormal del espacio vectorial.
    """
    filas, columnas = A.shape

    # Crear matriz de ceros del tamaño de A
    base_ortonormal = np.zeros((filas,columnas), np.float64)

    base_ortonormal[:,0] = np.copy(A[:,0]) / np.linalg.norm(A[:,0])

    # wi = vi - (Σ[(<vi,wj> / <wj,wj>)]wj), j = 1, 2, 3, ..., i-1
    for i in range(1, columnas):
        vi = np.copy(A[:,i] )
        wi = vi
        for j in reversed(range(i)):
            wj = np.copy(base_ortonormal[:,j])
            cociente = np.dot(vi, wj) / np.dot(wj,wj)  # <vi,wj> / <wj,wj>
            wi -= cociente * wj
            # ui = wi / ‖wi‖, i = 1, 2, 3, ..., n
            ui = wi / np.linalg.norm(wi)

        base_ortonormal[:,i] = ui

    base_ortonormal = np.round(base_ortonormal,10)
    return base_ortonormal


import numpy as np

vector = np.array([5, 10, 15, 20])

print(vector.sum())

print(vector.mean())

print(vector.max())

matrix = np.array([[5, 10, 15, 20], [20, 25, 30, 35], [20, 45, 50, 55]])

print(matrix.sum(axis=1))

print(matrix.sum(axis=0))

#Utiliser la méthode sum() pour calculer la somme des valeurs de alcohol_consumption. Assigner le résultat à la variable total_alcohol

world_alcohol = np.genfromtxt('world_alcohol.csv', delimiter = ',', skip_header = 1)

alcohol_comsumption = world_alcohol[:, 4]

alcohol_comsumption = alcohol_comsumption.astype(float)

def new_func(alcohol_comsumption):
    total_alcohol = alcohol_comsumption.sum()
    return total_alcohol

total_alcohol = new_func(alcohol_comsumption)

print(total_alcohol)

#tiliser la méthode mean() pour calculer la moyenne des valeurs de alcohol_consumption. Assigner le résultat à la variable average_alcohol

average_alcohol = alcohol_comsumption.mean()

print(average_alcohol)


import numpy as np
from scipy.stats import norm

class Option:
    def __init__(self, S, K, r, d, sigma, T):
        '''
        Parameters:
        ===========
        S: stock price
        K: strike price
        r: risk-free interest rate
        d: dividend
        sigma: volatility (implied)
        T: time to maturity

        Returns:
        ===========
        Forward price, vanilla European call and put option' prices, cash-or-nothing call and put options' prices,
        zero coupon bond and forward contract.
        '''

        self.S = S
        self.K = K
        self.r = r
        self.d = d
        self.sigma = sigma
        self.T = T

        self.d1 = (np.log(self.S/self.K) + (self.r - self.d + self.sigma**2 / 2) * self.T) / (self.sigma * np.sqrt(self.T))
        self.d2 = self.d1 - self.sigma * np.sqrt(self.T)

    def forward_price(self):
        '''
        output forward price
        '''
        return self.S * np.exp(self.r * self.T)

    def european_call(self):
        '''
        output vanilla European call option's price using Black-Scholes formula
        '''
        return self.S * np.exp(-self.d * self.T) * norm.cdf(self.d1) - self.K * np.exp(-self.r * self.T)*norm.cdf(self.d2)

    def european_put(self):
        '''
        output vanilla European put option's price using Black-Scholes formula
        '''
        return self.K * np.exp(-self.r * self.T)*norm.cdf(-self.d2) - self.S * np.exp(-self.d * self.T)*norm.cdf(-self.d1)

    def binary_call(self, face_value):
        '''
        output cash-or-nothing call option's price
        '''
        return face_value * np.exp(-self.r * self.T) * norm.cdf(self.d2)

    def binary_put(self, face_value):
        '''
        ouput cash-or-nothing put option's price
        '''
        return face_value * np.exp(-self.r * self.T) * norm.cdf(-self.d2)

    def zero_coupon_bond(self, face_value):
        '''
        output zero coupon bond's price based on the face value
        '''
        return face_value * np.exp(-self.r * self.T)

    def forward_contract(self):
        '''
        output forward contract's value
        '''
        return self.S * np.exp(-self.d * self.T) - self.K * np.exp(-self.r * self.T)

    def print_all_values(self, face_value):
        '''
        print prices of all options and zero coupon bond
        '''
        print('Forward price: {}'.format(self.forward_price()))
        print('European call: {}'.format(self.european_call()))
        print('European put: {}'.format(self.european_put()))
        print('Binary call: {}'.format(self.binary_call(face_value = 1)))
        print('Binary put: {}'.format(self.binary_put(face_value = 1)))
        print('Forward contract: {}'.format(self.forward_contract()))


# Author: Daniel Williams
import numpy as np
import matplotlib.pyplot as plt

'''
The code in this file follows the exercises explained in the paper by
Hogg et al. (2010), as a means of familiarising myself with statistical
approaches to data analysis. Exercises 1-3 consider the technique of linear
regression: first to a linear then quadratic fit.
'''

data = np.genfromtxt('hoggtutorial.txt', names=True)

#%% EXERCISE 1

ex1 = data[4:20]
Y = np.array(ex1['y']).reshape((len(ex1), 1))
A = np.c_[ np.ones(len(ex1)), ex1['x']]
C = np.diag(ex1['sigy'])

# Matrix notation of below: (A.T * C^-1 * A)^-1 (A.T * C^-1 * Y)
Xa = np.linalg.inv(np.dot(A.T,(np.dot(np.linalg.inv(C),A))))
Xb = np.dot(A.T,(np.dot(np.linalg.inv(C),Y)))
X = np.dot(Xa,Xb)

c = X[0]
m = X[1]
xfit = np.arange(min(ex1['x']), max(ex1['x']))
yfit = xfit*m + c

plt.figure(1, figsize=(5,5))
plt.errorbar(ex1['x'], ex1['y'],  yerr=ex1['sigy'], fmt='o')
plt.plot(xfit, yfit)
plt.xlim(0,300)
plt.ylim(0,700)

print(X)
#%% EXERCISE 2

ex2 = data
Y = np.array(ex2['y']).reshape((len(ex2), 1))
A = np.c_[ np.ones(len(ex2)), ex2['x']]
C = np.diag(ex2['sigy'])

# Matrix notation of below: (A.T * C^-1 * A)^-1 (A.T * C^-1 * Y)
Xa = np.linalg.inv(np.dot(A.T,(np.dot(np.linalg.inv(C),A))))
Xb = np.dot(A.T,(np.dot(np.linalg.inv(C),Y)))
X = np.dot(Xa,Xb)

c = X[0]
m = X[1]
xfit = np.arange(min(ex2['x']), max(ex2['x']))
yfit = xfit*m + c

plt.figure(2, figsize=(5,5))
plt.errorbar(ex2['x'], ex2['y'],  yerr=ex2['sigy'], fmt='o')
plt.plot(xfit, yfit)
plt.xlim(0,300)
plt.ylim(0,700)

print('m = ' + str(m))
print('c = ' + c)

#%% EXERCISE 3
ex3 = data[4:20]
Y = np.array(ex3['y']).reshape((len(ex3), 1))
A = np.c_[ np.ones(len(ex3)), ex3['x'], (ex3['x'])**2]
C = np.diag(ex3['sigy'])

# Matrix notation of below: (A.T * C^-1 * A)^-1 (A.T * C^-1 * Y)
Xa = np.linalg.inv(np.dot(A.T,(np.dot(np.linalg.inv(C),A))))
Xb = np.dot(A.T,(np.dot(np.linalg.inv(C),Y)))
X = np.dot(Xa,Xb)

c = X[0]
m = X[1]
q = X[2]

xfit = np.arange(min(ex3['x']), max(ex3['x']))
yfit = q*xfit**2 + xfit*m + c

plt.figure(3, figsize=(5,5))
plt.errorbar(ex3['x'], ex3['y'],  yerr=ex3['sigy'], fmt='o')
plt.plot(xfit, yfit)
plt.xlim(0,300)
plt.ylim(0,700)

print(X)


import numpy as np
# set the matplotlib backend so figures can be saved in the background
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

def feature_normalize(X):
    X_norm = X
    mu = np.zeros((1, X.shape[1]))
    sigma = np.zeros((1, X.shape[1]))
    mu = np.mean(X, axis=0)
    sigma = np.std(X, axis=0)
    X_norm = np.subtract(X, mu) / sigma
    return X_norm, mu, sigma

def gradient_descent_multi(X, y, theta, alpha, num_iters):
    m = y.size
    J_history = np.zeros((num_iters, 1))

    for i in range(0, num_iters):
        h = X.dot(theta)
        thetaNew = theta - (alpha * 1 / m * ((h - y).T.dot(X)).T)
        theta = thetaNew

        # Save the cost J in every iteration
        J_history[i] = compute_cost_multi(X, y, theta)
    return theta, J_history

def compute_cost_multi(X, y, theta):
    m = y.size
    J = 0
    h = X.dot(theta)
    J = 1 / (2 * m) * (h - y).T.dot(h - y)
    return J

def normal_equation(X, y):
    theta = np.zeros((X.shape[1], 1))
    theta = np.linalg.pinv(X.T.dot(X)).dot(X.T).dot(y)
    return theta

data = np.loadtxt("../ex1data2.txt", delimiter=',')
X = data[:, :-1]
y = data[:, -1:]
m = y.size

# % Print out some data points
print('First 10 examples from the dataset: \n')
print(f'x = {X[:10, :]}, \n y = {y[:10]}')

# % Scale features and set them to zero mean
print('Normalizing Features ...\n')

X, mu, sigma = feature_normalize(X)

# % Add intercept term to X
X = np.append(X, np.ones((m, 1)), axis=1)

# % % == == == == == == == == Part 2: Gradient Descent == == == == == == == ==
print('Running gradient descent ...\n')

# % Choose some alpha value
alpha = 0.001
num_iters = 40000

# % Init Theta and Run Gradient Descent
theta = np.zeros((X.shape[1], 1))

theta, J_history = gradient_descent_multi(X, y, theta, alpha, num_iters)

# plot the training loss and accuracy
print("[INFO] about to plot...")
plt.style.use("ggplot")
plt.figure()
plt.plot(np.arange(0, num_iters), J_history, label="error")
plt.title("Training Loss on Gradient Descent")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend(loc="lower left")
plt.savefig('plot.png')

# % Display gradient descent's result
print('Theta computed from gradient descent: \n')
print(f' {theta} \n')
print('\n')

# % Estimate the price of a 1650 sq - ft, 3 br house
sample_house_X = np.array([1650, 3])
s = (sample_house_X - mu) / sigma
s = np.append(s, np.ones((1, 1)))
price = s.dot(theta)[0]

print(
    f'Predicted price of a 1650 sq-ft, 3 br house (using gradient descent):\n ${price}\n')

# % % == == == == == == == == Part 3: Normal Equations == == == == == == == ==

print('Solving with normal equations...\n')

data = np.loadtxt("../ex1data2.txt", delimiter=',')
X = data[:, :-1]
y = data[:, -1:]
m = y.size

# % Add intercept term to X
X = np.append(X, np.ones((m, 1)), axis=1)

theta = normal_equation(X, y)

# % Display normal equation's result
print('Theta computed from the normal equations: \n')
print(f' {theta} \n')
print('\n')

# % Estimate the price of a 1650 sq - ft, 3 br house
s = np.array([1650, 3, 1])
price = s.dot(theta)[0]

print(
    f'Predicted price of a 1650 sq-ft, 3 br house (using normal equation):\n ${price}\n')


# Solutions to problem 1
import scipy as sp
import numpy as sp
from matplotlib import pyplot as plt
from scipy.signal import fftconvolve

def getFrame(m):
    coeffs = []
    k_max = int(sp.pi*2**(m+1))
    for k in xrange(k_max):
        coeffs.append(-2**m*(sp.cos((k+1)*2**(-m)) - sp.cos(k*2**(-m))))
    coeffs.append(-2**m*(1-sp.cos(k_max*2**(-m))))
    return sp.array(coeffs)

# frame_4 = getFrame(4)
# frame_6 = getFrame(6)
# frame_8 = getFrame(8)

# Here's how to plot each one:
# plt.plot([x*2*sp.pi/len(frame_6) for x in range(len(frame_6))],frame_6,drawstyle='steps')

# Solutions to problem 2

def getDetail(m):
    coeffs = []
    k_max = int(sp.pi*2**(m+1))
    for k in xrange(k_max):
        coeffs.append(-2**m*(2*sp.cos((2*k+1)*2**(-m-1)) - sp.cos((k+1)*2**(-m)) - sp.cos(k*2**(-m))))
    if (2*sp.pi < (2*k_max+1)*2**(-m-1)):
        coeffs.append(-2**m*(1-sp.cos(k_max*2**(-m))))
    else:
        coeffs.append(-2**m*(2*sp.cos((2*k_max+1)*2**(-m-1)) - 1 - sp.cos(k*2**(-m))))
    return sp.array(coeffs)

# detail = getDetail(4)

# Here's how to plot the details
#b = []
#for i in detail:
#    b.extend([i,-i])
#plt.plot([x*2*sp.pi/len(b) for x in range(len(b))],b,drawstyle='steps')

# Here's how to calculate the frame for m=5
#details = getDetail(4)
#frame = getFrame(4)
#frame_5 = sp.zeros(2*len(details))
#for i in range(2*len(details)):
#    frame_5[i] = frame[i/2] + (-1)**i*details[i/2]

''' Notes: these methods use the fftconvolve function from sp.signal.
	I have found that the default, mode='full', is the best setting.
	However, the convolution outputs a vector that is one entry too
	long, and so either the first or last element should be omitted.
'''

def dwt(f, lo, hi):
    '''
    Compute the discrete wavelet transform of f with respect to
    the wavelet filters lo and hi.
    Inputs:
        f -- numpy array corresponding to the signal
        lo -- numpy array giving the lo-pass filter
        hi -- numpy array giving the hi-pass filter
    Returns:
        list of the form [A, D1, D2, ..., Dn] where each entry
        is a numpy array. These are the approximation frame (A)
        and the detail coefficients.
    '''
    ans = []
    frame = f
    while len(frame) >= len(lo):
        detail = fftconvolve(frame, hi, mode='full')[1:][::2]
        frame = fftconvolve(frame, lo, mode='full')[1:][::2]
        ans.append(detail)
    ans.append(frame)
    ans.reverse()
    return ans

def idwt(t, lo, hi):
    '''
    Compute the inverse discrete wavelet transform of a list of
    transform coefficients with respect to the wavelet filters
    lo and hi.
    Inputs:
        t -- a list containing the frame and detail coefficients of
             a signal, corresponding to the output of dwt.
        lo -- numpy array giving the lo-pass filter
        hi -- numpy array giving the hi-pass filter
    Outputs:
        f -- a numpy array giving the recovered signal.
    '''
    f = t[0]
    for i in xrange(len(t)-1):
        det = t[i+1]
        frame = np.zeros(len(f)*2)
        frame[::2] = f
        frame = fftconvolve(frame, lo, mode='full')[:-1]
        detail = np.zeros(len(det)*2)
        detail[::2] = det
        detail = fftconvolve(detail, hi, mode='full')[:-1]
        f = detail + frame
    return f


import numpy as np
from numpy.random import *
import matplotlib.pyplot as plt
from numpy.fft import *

""" Ce script genere des interferogrammes tels qu'obtenus avec un interferometre
de Michelson dans le but d'etudier la transformée de Fourier et de comprendre
comment la resolution spectrale est déterminée.
"""

def readVectorsFromFile(filename):
	x = np.loadtxt(filename, usecols=(0))
	y = np.loadtxt(filename, usecols=(1))
	return (x,y)

def generateHeNeInterferogram(xMin, xMax, N):
	""" Genere un tableau de N valeurs equidistantes enntre xMin et xMax.
	Ensuite, genere un tableau de N valeurs qui representent un interferogramme
	d'un laser He-Ne a 0.6328 microns. On ajoute du bruit pour rendre le tout
	plus realiste.
	"""
	dx = (xMax - xMin)/N
	x = np.linspace(xMin, xMax, N)
	noise = random(len(x))*0.05
	y = 1+np.cos(2 * np.pi / 0.6328 * x)+noise
	return (x,y)

def generateWhiteLightInterferogram(xMin, xMax, N):
	""" Genere un tableau de N valeurs equidistantes enntre xMin et xMax.
	Ensuite, genere un tableau de N valeurs qui representent un interferogramme
	d'une source blanche visible. On ajoute du bruit pour rendre le tout
	plus realiste.
	"""
	dx = (xMax - xMin)/N
	x = np.linspace(xMin, xMax, N)
	noise = random(len(x))*0.05
	k1 = 1/0.4
	k2 = 1/0.8
	y = (1+(np.sin(2 * np.pi * (k1+k2)*x/2)/x))**2
	return (x,y)

def fourierTransformInterferogram(x,y):
	""" A partir du tableau de valeurs Y correspondant a l'abscisse X,
	la transformée de Fourier est calculée et l'axes des fréquences (f en
	µm^-1) et des wavelengths (1/f en microns) est retournée.

	Le spectre est un ensemble de valeurs complexes pour lesquelles l'amplitude
	et la phase sont pertinentes: l'ordre des valeurs commence par la valeur DC (0)
	et monte jusqu'a f_max=1/2/∆x par resolution de ∆f = 1/N/∆x. A partir de la
	(N/2) ieme valeur, la frequence est negative jusqu'a -∆f dans la N-1 case.
	Voir
	https://github.com/dccote/Enseignement/blob/master/HOWTO/HOWTO-Transformes%20de%20Fourier%20discretes.pdf
	"""
	spectrum = fft(y)
	dx = x[1]-x[0] # on obtient dx, on suppose equidistant
	N = len(x)     # on obtient N directement des données
	frequencies = fftfreq(N, dx) # Cette fonction est fournie par numpy
	wavelengths = 1/frequencies  # Les fréquences en µm^-1 sont moins utiles que lambda en µm
	return (wavelengths, frequencies, spectrum)

def plotCombinedFigures(x, y, w, s, title="", left=400, right=800):
	""""
	On met l'interferogramme et le spectre sur la meme page.
	"""
	fig, (axes, axesFFT) = plt.subplots(2,1,figsize=(10, 7))
	axes.plot(x, y, '-')
	axes.set_title("Interferogramme")
	axesFFT.plot(w*1000, abs(s), 'o-')
	axesFFT.set_xlim(left=left, right=right)
	axesFFT.set_xlabel("Longueur d'onde [nm]")
	axesFFT.set_title(title)
	plt.show()

# # Basse resolution
# (x,y) = generateHeNeInterferogram(xMin=-10, xMax=10, N=200) # en microns
# (w, f, s)  = fourierTransformInterferogram(x,y)
# df = f[1]-f[0]
# dl = 0.6328*0.6328*df*1000 # x 1000 pour nm
# plotCombinedFigures(x,y,w,s,left=632.8-5*dl, right=632.8+5*dl, title="Spectre He-Ne basse resolution {0:0.2f} nm".format(dl))

# # Haute resolution
# # Resolution ∆f = 1/(200 µm * 2000)
# # Resolution @ 632.8 nm : ∆lambda = 632.8^2 * ∆f car ∆lambda/lambda = ∆f/f.
# (x,y) = generateHeNeInterferogram(xMin=-100, xMax=100, N=2000) # en microns
# (w, f, s) = fourierTransformInterferogram(x,y)
# df = f[1]-f[0]
# dl = 0.6328*0.6328*df*1000
# plotCombinedFigures(x,y,w,s,left=632.8-5*dl, right=632.8+5*dl, title="Spectre He-Ne haute resolution {0:0.2f} nm".format(dl))

# # Tres haute resolution
# # Resolution ∆f = 1/(2000 µm * 2000)
# # Resolution @ 632.8 nm : ∆lambda = 632.8^2 * ∆f
# (x,y) = generateHeNeInterferogram(xMin=-1000, xMax=1000, N=20000) # en microns
# (w, f, s) = fourierTransformInterferogram(x,y)
# df = f[1]-f[0]
# dl = 0.6328*0.6328*df*1000
# plotCombinedFigures(x,y,w,s,left=632.8-5*dl, right=632.8+5*dl, title="Spectre He-Ne tres haute resolution {0:0.2f} nm".format(dl))

# # Hyper haute resolution
# # Resolution ∆f = 1/(20000 µm * 20000)
# # Resolution @ 632.8 nm : ∆lambda = 632.8^2 * ∆f
# (x,y) = generateHeNeInterferogram(xMin=-10000, xMax=10000, N=200000) # en microns
# (w, f, s) = fourierTransformInterferogram(x,y)
# df = f[1]-f[0]
# dl = 0.6328*0.6328*df*1000
# plotCombinedFigures(x,y,w,s,left=632.8-5*dl, right=632.8+5*dl, title="Spectre He-Ne hyper haute resolution {0:0.2f} nm".format(dl))

# Spectre de lumiere blanche
# Resolution ∆f = 1/(20000 µm * 20000)
# Resolution @ 500 nm : ∆lambda = 500^2 * ∆f
(x,y) = generateWhiteLightInterferogram(xMin=-100, xMax=100, N=20000) # en microns
(w, f, s)  = fourierTransformInterferogram(x,y)
df = f[1]-f[0]
dl = 0.500*0.500*df*1000 # resolution autour de 0.500 µm en nm
plotCombinedFigures(x,y,w,s,left=0, right=2000, title="Spectre lumiere blanche, resolution {0:0.2f} nm".format(dl))


# integrate the equations of motion of a pendulum, w/o the small angle
# approximation

import numpy
import pylab
import math

# global parameters
g = 9.81     # gravitational acceleration [m/s]
L = 9.81     # length of pendulum [m]

class pendulumHistory:
    """ simple container to store the pendulum history """

    def __init__(self):
        self.t = None
        self.theta = None
        self.omega = None

    def energy(self):
        """ return the energy (per unit mass) """
        return 0.5*L**2*self.omega**2 - g*L*numpy.cos(self.theta)

def rhs(theta, omega):
    """ equations of motion for a pendulum
        dtheta/dt = omega
        domega/dt = - (g/L) sin theta """

    return omega, -(g/L)*numpy.sin(theta)

def intVVerlet(theta0, dt, tmax, rhs):
    """ integrate the equations of motion using Euler-Cromer """

    # initial conditions
    t = 0.0
    theta = theta0
    omega = 0.0    # at the maximum angle, the angular velocity is 0

    # store the history for plotting
    tPoints = [t]
    thetaPoints = [theta]
    omegaPoints = [omega]

    while (t < tmax):

        # get the RHS at time-level n
        thetadot, omegadot = rhs(theta, omega)

        thetanew = theta + dt*thetadot + 0.5*dt**2*omegadot

        # get the RHS with the updated theta -- omega doesn't matter
        # here, since we only need thetadot and omega doesn't affect
        # that.
        thetadot_np1, omegadot_np1 = rhs(thetanew, omega)

        omeganew = omega + 0.5*dt*(omegadot + omegadot_np1)

        t += dt

        # store
        tPoints.append(t)
        thetaPoints.append(thetanew)
        omegaPoints.append(omeganew)

        # set for the next step
        theta = thetanew; omega = omeganew

    # return a pendulumHistory object with the trajectory
    H = pendulumHistory()
    H.t = numpy.array(tPoints)
    H.theta = numpy.array(thetaPoints)
    H.omega = numpy.array(omegaPoints)

    return H

# 10 degree pendulum
theta0 = numpy.radians(10.0)

# period estimate
T = 2.0*math.pi*math.sqrt(L/g)*(1.0 + theta0**2/16.0)
print "period = ", T

tmax = 10.0*T
#dts = [0.5, 0.25, 0.125, 0.06125, 0.030625]
dts = [1, 0.1, 0.01, 0.001, 0.0001]

err = []
for dt in dts:
    HVVerlet = intVVerlet(theta0, dt, tmax, rhs)

    E = HVVerlet.energy()
    err.append(abs(E[-1]-E[0])/abs(E[0]))

    print dt, abs(E[-1]-E[0])/abs(E[-1])
    pylab.plot(HVVerlet.t, HVVerlet.theta, label="dt = %f" % (dt))

leg = pylab.legend(frameon=False)
ltext = leg.get_texts()
pylab.setp(ltext, fontsize='small')

pylab.savefig("Verlet-theta-dt.png")

pylab.clf()

pylab.scatter(dts, err)

pylab.plot(numpy.array(dts), err[0]*(dts[0]/numpy.array(dts))**-2, label="2nd order scaling")
pylab.plot(numpy.array(dts), err[0]*(dts[0]/numpy.array(dts))**-4, ls=":", label="4th order scaling")
pylab.plot(numpy.array(dts), err[0]*(dts[0]/numpy.array(dts))**-6, ls="--", label="6th order scaling")

leg = pylab.legend(loc=2, frameon=False)
ltext = leg.get_texts()
pylab.setp(ltext, fontsize='small')

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

pylab.xlim(0.00001, 1.0)
pylab.ylim(1.e-12, 1.e-1)

pylab.savefig("Verlet-E-converge.png")


import numpy as np
from scipy import linalg

from numfun import chebyshev

def test_coefficients_to_values() -> None:
    tol = 100 * np.spacing(1)

    # Test that a single value is converted correctly
    c = np.array([np.sqrt(2)])
    v = chebyshev.chebyshev_coefficients_to_values(c)
    assert c == v

    # Some simple data
    c = np.r_[1:6]
    # Exact coefficients
    v_true = np.array([3.0, -4.0+np.sqrt(2.0), 3.0, -4.0-np.sqrt(2.0), 15.0])

    # Test real branch
    v = chebyshev.chebyshev_coefficients_to_values(c)
    assert np.linalg.norm(v - v_true, np.inf) < tol
    assert not np.any(v.imag)

    # Test imaginary branch
    v = chebyshev.chebyshev_coefficients_to_values(1j * c)
    assert np.linalg.norm(v - 1j * v_true, np.inf) < tol
    assert not np.any(v.real)

    # Test general branch
    v = chebyshev.chebyshev_coefficients_to_values((1+1j) * c)
    assert np.linalg.norm(v - (1 + 1j) * v_true, np.inf) < tol

    # Test for symmetry preservation
    c = np.array([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0])
    v = chebyshev.chebyshev_coefficients_to_values(c)
    assert np.linalg.norm(v - np.flipud(v), np.inf) == 0.0

    c = np.array([0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0])
    v = chebyshev.chebyshev_coefficients_to_values(c)
    assert np.linalg.norm(v + np.flipud(v), np.inf) == 0.0

def test_values_to_coefficients() -> None:
    tol = 100 * np.spacing(1)

    # Test that a single value is converted correctly
    v = np.array([np.sqrt(2)])
    c = chebyshev.chebyshev_values_to_coefficients(v)
    assert v == c

    # Some simple data
    v = np.r_[1:6]
    # Exact coefficients
    c_true = np.array([3, 1 + 1/np.sqrt(2), 0, 1 - 1/np.sqrt(2), 0])

    # Test real branch
    c = chebyshev.chebyshev_values_to_coefficients(v)
    assert np.linalg.norm(c - c_true, np.inf) < tol
    assert not np.any(c.imag)

    # Test imaginary branch
    c = chebyshev.chebyshev_values_to_coefficients(1j * v)
    assert np.linalg.norm(c - 1j * c_true, np.inf) < tol
    assert not np.any(c.real)

    # Test general branch
    c = chebyshev.chebyshev_values_to_coefficients((1 + 1j) * v)
    assert np.linalg.norm(c - (1 + 1j) * c_true, np.inf) < tol

    # Test for symmetry preservation
    v = np.array([1.1, -2.2, 3.3, -2.2, 1.1])
    c = chebyshev.chebyshev_values_to_coefficients(v)
    assert np.linalg.norm(c[1::2], np.inf) == 0.0
    v = np.array([1.1, -2.2, 0.0, 2.2, -1.1])
    c = chebyshev.chebyshev_values_to_coefficients(v)
    assert linalg.norm(c[::2], np.inf) == 0.0

def test_chebyshev_points() -> None:
    # Test that n = 0 returns empty results:
    x = chebyshev.chebyshev_points(0)
    assert x.size == 0
    assert len(x) == 0

    # Test n = 1:
    x = chebyshev.chebyshev_points(1)
    assert x.size == 1
    assert len(x) == 1
    assert x[0] == 0.0

    # Test that n = 2 returns [-1 , 1]:
    x = chebyshev.chebyshev_points(2)
    assert len(x) == 2
    assert np.all(x == np.array([-1.0, 1.0]))

    # Test that n = 3 returns [-1, 0, 1]:
    x = chebyshev.chebyshev_points(3)
    assert len(x) == 3
    assert np.all(x == np.array([-1.0, 0.0, 1.0]))

    # % Test that n = 129 returns vectors of the correct size:
    n = 129
    x = chebyshev.chebyshev_points(n)
    assert len(x) == n
    assert np.linalg.norm(x[0:int((n-1)/2)] + np.flipud(x[int((n+1)/2):]), np.inf) == 0.0
    assert x[int((n-1)/2)] == 0.0

def test_alias() -> None:
    tol = 100 * np.spacing(1)

    # Testing a vector of coefficients.
    c0 = np.r_[10:0:-1]

    # Padding:
    c1 = chebyshev.alias_chebyshev_coefficients(c0, 11)
    assert linalg.norm(np.r_[c0, 0.0] - c1, np.inf) == 0.0

    # Aliasing:
    c2 = chebyshev.alias_chebyshev_coefficients(c0, 9)
    assert linalg.norm(np.r_[10:3:-1, 4.0, 2.0] - c2, np.inf) == 0.0
    c3 = chebyshev.alias_chebyshev_coefficients(c0, 3)
    assert linalg.norm(np.array([18.0, 25.0, 12.0]) - c3, np.inf) == 0.0

    # Compare against result of evaluating on a smaller grid:
    v = chebyshev.chebyshev_clenshaw_evaluation(chebyshev.chebyshev_points(9), c0)
    assert linalg.norm(chebyshev.chebyshev_values_to_coefficients(v) - c2, np.inf) < tol

    v = chebyshev.chebyshev_clenshaw_evaluation(chebyshev.chebyshev_points(3), c0)
    assert linalg.norm(chebyshev.chebyshev_values_to_coefficients(v) - c3, np.inf) < tol

    #
    # Test aliasing a large tail.
    c0 = 1.0 / np.arange(1.0, 1001.0)**5
    n = 17
    c1 = chebyshev.alias_chebyshev_coefficients(c0, n)
    assert len(c1) == n
    # This should give the same result as evaluating via clenshaw
    v2 = chebyshev.chebyshev_clenshaw_evaluation(chebyshev.chebyshev_points(n), c0)
    c2 = chebyshev.chebyshev_values_to_coefficients(v2)
    assert linalg.norm(c1 - c2, np.inf) < n*tol

def test_derivative() -> None:
    tol = 100 * np.spacing(1)

    # Testing a vector of coefficients.
    d = chebyshev.chebyshev_coefficients_of_derivative([])
    assert len(d) == 0

    c = np.array([0.0])
    d = chebyshev.chebyshev_coefficients_of_derivative(c)
    assert np.array_equal(c, d)

    c = np.array([10.0])
    d = chebyshev.chebyshev_coefficients_of_derivative(c)
    assert np.array_equal(0.0 * c, d)

    c = np.array([0.0, 4.0])
    d = chebyshev.chebyshev_coefficients_of_derivative(c)
    assert np.array_equal(np.array([4.0]), d)

    # x**2
    c = np.array([1.0/2.0, 0, 1.0/2.0])
    # 2*x
    c_exact = np.array([0.0, 2.0])
    d = chebyshev.chebyshev_coefficients_of_derivative(c)
    assert np.linalg.norm(d - c_exact, np.inf) < tol

    # This function takes about 41 points to resolve:
    xx = np.linspace(-1.0, 1.0, 2001)

    def f(x):
        return x + np.sin(2.0 * np.pi * x) + np.cos(2.0 * np.pi * x**2)

    def fp(x):
        return 1.0 + 2.0 * np.pi * np.cos(2.0 * np.pi * x) - 4.0 * np.pi * x * np.sin(2.0 * np.pi * x**2)

    x_ = chebyshev.chebyshev_points(60)
    c = chebyshev.chebyshev_values_to_coefficients(f(x_))
    d = chebyshev.chebyshev_coefficients_of_derivative(c)

    error = chebyshev.chebyshev_clenshaw_evaluation(xx, c) - f(xx)
    assert np.linalg.norm(error, np.inf) < 10 * tol
    error = chebyshev.chebyshev_clenshaw_evaluation(xx, d) - fp(xx)
    assert np.linalg.norm(error, np.inf) < 10 * tol

def test_cumsum() -> None:
    tol = 100 * np.spacing(1)

    # Testing a vector of coefficients.
    d = chebyshev.chebyshev_coefficients_of_integral([])
    assert len(d) == 0

    c = np.array([0.0])
    d = chebyshev.chebyshev_coefficients_of_integral(c)
    assert np.array_equal(np.array([0.0, 0.0]), d)

    c = np.array([10.0])
    d = chebyshev.chebyshev_coefficients_of_integral(c)
    # 10 * x + 10
    assert np.array_equal(np.array([10.0, 10.0]), d)

    # x
    c = np.array([0.0, 1.0])
    d = chebyshev.chebyshev_coefficients_of_integral(c)
    # integral is x^2/2 - 1/2
    assert np.array_equal(np.array([-1.0/4.0, 0.0, 1.0/4.0]), d)

    # This function takes about 41 points to resolve:
    xx = np.linspace(-1.0, 1.0, 2001)

    def f(x):
        return 1.0 + 2.0 * np.pi*np.cos(2.0 * np.pi * x) - 4.0 * np.pi * x * np.sin(2.0 * np.pi * x**2)

    def F(x):  # noqa
        return x + np.sin(2.0 * np.pi*x) + np.cos(2.0 * np.pi*x**2)

    def integral(x):
        return F(x) - F(-1)

    x_ = chebyshev.chebyshev_points(60)
    c = chebyshev.chebyshev_values_to_coefficients(f(x_))
    d = chebyshev.chebyshev_coefficients_of_integral(c)

    error = chebyshev.chebyshev_clenshaw_evaluation(xx, c) - f(xx)
    assert np.linalg.norm(error, np.inf) < 10 * tol
    error = chebyshev.chebyshev_clenshaw_evaluation(xx, d) - integral(xx)
    assert np.linalg.norm(error, np.inf) < 10 * tol

def test_clenshaw_evaluation():
    # Set a tolerance (pref.chebfunnp.spacing(1) doesn't matter)
    tol = 10*np.spacing(1)

    # Test that a single coefficient is evaluated correctly:
    # For an evaluation with one point only
    c = np.array([np.sqrt(2.0)])
    v = chebyshev.chebyshev_clenshaw_evaluation([0], c)
    assert c == v

    # For a vector evaluation:
    x = np.array([-.5, 1.0])
    v = chebyshev.chebyshev_clenshaw_evaluation(x, c)
    assert len(v) == 2
    assert np.array_equal([c[0], c[0]], v)

    # Test that a vector coefficient is evaluated correctly:
    # Some simple data :
    c = np.arange(5, 0, -1)
    x = np.array([-.5, -.1, 1.0])

    # Scalar coefficient
    v = chebyshev.chebyshev_clenshaw_evaluation(x, c)
    # Exact values:
    v_true = np.array([3.0, 3.1728, 15.0])
    assert np.linalg.norm(v - v_true, np.inf) < tol

    # another set of coefficients
    v_true2 = np.array([0, 3.6480, 15.0])
    v = chebyshev.chebyshev_clenshaw_evaluation(x, np.flipud(c))
    assert np.linalg.norm(v - v_true2, np.inf) < tol

# TODO: the following can be appended to a test:
# from chebyshev import chebyshev_coefficients_to_values
#
# p_n = lambda n: np.concatenate([np.zeros(n), [1.0]])
#
# print(chebyshev_coefficients_to_values(p_n(0)))
# print(chebyshev_coefficients_to_values(p_n(1)))
# print(chebyshev_coefficients_to_values(p_n(2)))
# print(chebyshev_coefficients_to_values(p_n(3)))
# print(chebyshev_coefficients_to_values(p_n(4)))
# print(chebyshev_coefficients_to_values(p_n(5)))
# # Coefficients of x**2 in the Chebyshev T basis
# print(chebyshev_coefficients_to_values(np.array([1/2, 0, 1/2])))

# if __name__ == '__main__':
#     # f = chebyshev('x + np.cos(x) - 1')
#     # f = chebyshev('1 + x + x**2 + x**3 + x**4')
#     # f.poly()
#
#     suite = unittest.TestLoader().loadTestsFromTestCase(TestChebyshevMethods)
#     unittest.TextTestRunner(verbosity=2).run(suite)
#     #suite = unittest.TestSuite()
#     #suite.addTest(TestchebyshevMethods('test_mul'))
#     #runner = unittest.TextTestRunner(verbosity=2)
#     #runner.run(suite)
#
#     #coeffs = np.array([\
#     #    -2.348023134420334e-01, \
#     #     1.000000000000000e+00, \
#     #    -2.298069698638009e-01, \
#     #                         0, \
#     #     4.953277928219901e-03, \
#     #     6.902385958693666e-18, \
#     #    -4.187667600481507e-05, \
#     #    -2.043108576058326e-17, \
#     #     1.884468834568858e-07, \
#     #    -1.268726182963996e-17, \
#     #    -5.261229800551637e-10, \
#     #     1.157775533567783e-17, \
#     #     9.999481711403524e-13, \
#     #     2.134620574478668e-17, \
#     #    -1.373900992973631e-15, \
#     #     4.163336342344337e-17, \
#     #    -1.387778780781446e-17, \
#     #                         0, \
#     #    -4.163336342344337e-17, \
#     #                         0, \
#     #    -1.799775606325937e-17, \
#     #    -3.576819105040345e-17, \
#     #    -1.927846987950788e-17, \
#     #    -2.545554314349229e-17, \
#     #     2.095665390625546e-18, \
#     #    -2.656504963745442e-17, \
#     #     4.582787057824667e-17, \
#     #     3.430887356839772e-17, \
#     #     1.431146867680866e-17, \
#     #    -6.981586047542980e-20, \
#     #     1.387778780781446e-17, \
#     #                         0, \
#     #                         0])
#     #print(chebyshev.standard_chop(coeffs, np.spacing(1)))


# 数学函数
# ```
# 本次学习内容为数学函数，顾名思义，就是常见的数学上的操作，最基础的有：加减乘除等
# 运算符为 元素级，只用于位置相同的元素之间，所得到的运算结果组成一个
# 新的数组
# ```
## 基础的数学操作
# - 加法
#   ```
#   numpy.add(x1, x2, *args, **kwargs)
#   ```
# - 减法
#   ```
#   numpy.subtract(x1, x2, *args, **kwargs)
#   ```
# - 乘法
#   ```
#   numpy.multiply(x1, x2, *args, **kwargs)
#   ```
# - 除法
#   ```
#   numpy.divide(x1, x2, *args, **kwargs)
#   ```
# - 除法，只保留整数
#   ```
#   numpy.floor_divide(x1, x2, *args, **kwargs)
#   ```
# - N次方
#   ```
#   numpy.power(x1, x2, *args, **kwargs)
#   ```
import numpy as np

x = np.arange(25,37).reshape([3,4])
print(x)

# y = x + 1
print(np.add(x,1))
print(np.subtract(x, 1))
print(np.multiply(x, 2))
print(np.divide(x, 2))
print(np.floor_divide(x, 3))
print(np.power(x, 2))

y = np.arange(1,13).reshape([3,4])

print(np.add(x, y))
print(np.subtract(x, y))
print(np.multiply(x, y))

# - 平方根
#   ```
#   numpy.sqrt(x1, x2, *args, **kwargs)
#   ```
print(np.sqrt(x))
# - 平方
#   ```
#   numpy.square(x1, x2, *args, **kwargs)
#   ```

print(np.square(x)) # == print(np.power(x,2))

print(np.power(y, 3))

# 三角函数
#   ```
#   几何图形三角函数，常用的：求正弦值，余弦值
#   ```

## 三角函数操作
# - 正弦值
#   ```
#   numpy.sin(x1, x2, *args, **kwargs)
#   ```
#   ```
#   numpy.cos(x1, x2, *args, **kwargs)
#   ```
#   ```
#   numpy.tan(x1, x2, *args, **kwargs)
#   ```
#   ```
#   numpy.arcsin(x1, x2, *args, **kwargs)
#   ```
#   ```
#   numpy.arccos(x1, x2, *args, **kwargs)
#   ```
#   ```
#   numpy.arctan(x1, x2, *args, **kwargs)
#   ```
# 要点 2
# 通用函数（universal function）通常叫作ufunc，它对数组中的各个元素逐一进行操作。这表明，通用函数分别处理输入数组的每个元素，生成
# 的结果组成一个新的输出数组。输出数组的大小跟输入数组相同
# 很多数学运算符合通用函数的定义，例如，计算平方根的sqrt() 函数、用来取对数的log() 函数和求正弦值的sin() 函数

l  = np.linspace(start=0, stop=np.pi / 2, num=10)

print(l)

# 要点3
# 通过不同的 axis ，numpy 会沿着不同的方向进行操作：如果不设置，那么对所有的元素操作；如果axis=0 ，则沿着纵轴进行操
# 作； axis=1 ，则沿着横轴进行操作。但这只是简单的二位数组，如果是多维的呢？可以总结为一句话：设axis=i ，则 numpy 沿着第i 个
# 下标变化的方向进行操作。

# 要点 4
# 聚合函数 是指对一组值（比如一个数组）进行操作，返回一个单一值作为结果的函数。因而，求数组所有元素之和的函数就是聚合函
# 数。ndarray 类实现了多个这样的函数。

# 要点 5
# 上限 基本上是 +1
# 下限 是只取整数

# numpy.clip
# 裁剪 等于把数组里小于裁剪下限的值换成下限值，大于上限的值换成上限值


import numpy as np
import matplotlib.pyplot as plt

def simular_gp(mu, sigma, m, ax=None):
  X = np.random.multivariate_normal(mu, cov=sigma, size=m)
  d = mu.shape[0]

  if ax is None:
    fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(15,5))

  for i in range(m):
    ax.plot(X[i,:])
  ax.set_xlabel("T")
  ax.set_ylabel("$X_i$")
  ax.set_xticks([i for i in range(d)])

def m_zeros(X, parametros):
  return np.zeros(X.shape)

def m_constante(X, parametros):
  c = parametros[0]
  return np.repeat(c, X.shape[0]).reshape(X.shape)

def m_linear(X, parametros):
  a, b = parametros
  return np.linspace(a,b, X.shape[0]).reshape(X.shape)

def Cov(x1, x2, kernel, parametros):
  n1 = x1.shape[0]
  n2 = x2.shape[0]
  cov = np.zeros((n1,n2))
  for i in range(n1):
    cov[i] = kernel(x1[i], x2, parametros)
  return cov

def plotar_cov(cov, m):
  fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(15,5))
  d = cov.shape[0]
  map = ax[0].matshow(cov)
  ax[0].set_xlabel("$X_1$")
  ax[0].set_ylabel("$X_2$")
  ax[0].set_title("$\Sigma$")
  fig.colorbar(map, ax=ax[0])
  simular_gp(m_zeros(x1, []).flatten(), cov, m, ax=ax[1])
  ax[1].set_title("Amostras do $\mathcal{GP}$")
  plt.tight_layout()

def plotar_kernel(x1, x2, kernel, parametros, mu=m_zeros, mu_parametros=[], m=5):
  cov = Cov(x1, x2, kernel, parametros)
  plotar_cov(cov, m)

def k_linear(x1, x2, parametros):
  return x1.dot(x2.T)

def k_polinomial(x1, x2, parametros):
  return x1.dot(x2.T) ** parametros[0]

def k_rbf(x1, x2, parametros):
  sigma = parametros[0]
  return np.exp(-.5*sigma**2 * np.sqrt(np.sum((x1 - x2)**2, axis=1))).flat

def k_laplaciano(x1, x2, parametros):
  alpha = np.array(parametros[0])
  return np.exp(-alpha * np.abs(x1 - x2)).flat

def sin2(x):
  return (1 - np.cos(2*x))/2

def k_periodico(x1, x2, parametros):
  p = np.array(parametros[0])
  sigma = np.array(parametros[1])
  l = np.array(parametros[2])
  return sigma*np.exp(-(2 * sin2((np.pi * np.abs(x1 - x2))/p)/l)).flat

from numpy import linalg

def GP(Tc, Xc, Td, mu, kernel, mu_parametros=[], kernel_parametros=[], ruido=0):
  Scc = Cov(Tc, Tc, kernel, kernel_parametros) + np.eye(Xc.shape[0])*ruido
  Sdd = Cov(Td, Td, kernel, kernel_parametros)
  Scd = Cov(Tc, Td, kernel, kernel_parametros)
  Sdc = Scd.T
  Xd = mu(Td, mu_parametros) + Sdc.dot( linalg.inv(Scc)).dot(Xc - mu(Tc, mu_parametros))
  Sd = Sdd - Sdc.dot(linalg.inv(Scc)).dot(Scd)
  return Xd, Sd


import numpy as np
import scipy.stats as stats

class MultiArmedBandit:
    """Define a simple implementation of Multi-Armed Bandit with a Beta distribution.

    Based on https://peterroelants.github.io/posts/multi-armed-bandit-implementation/
    """

    def __init__(self, n_bandits, reshape_factor=1, minimize=False, boltzmann=False):
        self.n_bandits      = n_bandits
        self.alpha_priors   = np.ones(n_bandits)
        self.beta_priors    = np.ones(n_bandits)
        self.reshape_factor = reshape_factor # Higher reshape factor favors exploitation
        self.minimize       = minimize
        self.boltzmann      = boltzmann

    def choose_bandit(self):

        if self.boltzmann:
            probs = self.get_empirical_probs()
            self.chosen_bandit_idx = np.random.choice(self.n_bandits, p=np.exp(probs) / np.sum(np.exp(probs)))

        else:

            # Define prior distribution for each bandit
            self.bandit_priors = [stats.beta(alpha, beta)
                                  for alpha, beta in zip(self.alpha_priors, self.beta_priors)]

            # Sample a probability theta for each bandit
            theta_samples = [d.rvs(1) for d in self.bandit_priors]

            # Choose a bandit
            if self.minimize:
                self.chosen_bandit_idx = np.argmin(theta_samples)
            else:
                self.chosen_bandit_idx = np.argmax(theta_samples)

        return self.chosen_bandit_idx

    def update_posterior(self, observation):
        """Update the posterior of the current chosen bandit based on the observation (0 or 1)
        """

        assert 0 <= observation <= 1

        # Update posterior

        self.alpha_priors[self.chosen_bandit_idx] += observation * self.reshape_factor
        self.beta_priors[self.chosen_bandit_idx] += (1 - observation) * self.reshape_factor

    def get_empirical_probs(self):
        return np.array([(a / (a + b - 1)) for a, b in zip(self.alpha_priors, self.beta_priors)])

if __name__ == '__main__':

    import matplotlib.pyplot as plt
    import seaborn as sns

    sns.set_style('darkgrid')

    nb_bandits = 4

    # True probability of winning for each bandit
    p_bandits = np.random.rand(nb_bandits)

    def pull(i):
        if np.random.rand() < p_bandits[i]:
            return 1
        else:
            return 0

    def plot(priors, step, ax):
        """Plot the priors for the current step."""
        plot_x = np.linspace(0.001, .999, 100)
        for prior in priors:
            y = prior.pdf(plot_x)
            p = ax.plot(plot_x, y)
            ax.fill_between(plot_x, y, 0, alpha=0.2)
        ax.set_xlim([0, 1])
        ax.set_ylim(bottom=0)
        ax.set_title('Priors at step {}'.format(step))

    mab = MultiArmedBandit(nb_bandits, 1)

    plots = [1, 2, 5, 10, 25, 50, 100, 200, 500, 1000]
    # plots = np.logspace(0.2, 2, 10).astype(int)

    # Setup plot
    fig, axs = plt.subplots(5, 2, figsize=(8, 10))
    axs = axs.flat

    trials = [0] * nb_bandits

    n = 1000
    # Run the trail for `n` steps
    for step in range(1, n + 1):
        idx = mab.choose_bandit()

        trials[idx] += 1

        if step in plots:
            plot(mab.bandit_priors, step, next(axs))

        x = pull(idx)

        mab.update_posterior(x)

    emperical_p_bandits = [(a / (a + b - 1)) for a, b in zip(mab.alpha_priors, mab.beta_priors)]
    for i in range(nb_bandits):
        print(('True prob={:.2f};  '
               'Emperical prob={:.2f};  '
               'Trials={:d}'.format(p_bandits[i], emperical_p_bandits[i], trials[i])
               ))

    plt.tight_layout()
    plt.show()


import numpy as np
from numpy import zeros
from sklearn.cluster import KMeans

def cluster_points(X, mu):
    clusters = {}
    for x in X:
        bestmukey = min([(i[0], np.linalg.norm(x - mu[i[0]])) \
                         for i in enumerate(mu)], key=lambda t: t[1])[0]
        try:
            clusters[bestmukey].append(x)
        except KeyError:
            clusters[bestmukey] = [x]
    return clusters

def Wk(mu, clusters):
    K = len(mu)
    return sum([np.linalg.norm(mu[i] - c) ** 2 / (2 * len(c)) \
                for i in range(K) for c in clusters[i]])

def find_centers(X, K):
    kmeans = KMeans(n_clusters=K);
    mu = kmeans.fit(X).cluster_centers_;
    clusters = cluster_points(X, mu);
    return (mu, clusters)

def gap_statistic(X, k_max):
    '''
    Algorithm described in paper: http://web.stanford.edu/~hastie/Papers/gap.pdf
    :param X: data matrix
    :param k_max: the maximum number of clusters
    :return: the optimal number of clusters
    '''
    oldGap = 0;
    num_cluster = 0;
    for k in xrange(1, k_max + 1):
        mu, clusters = find_centers(X, k)
        Wks = np.log(Wk(mu, clusters))
        # Create B reference datasets
        B = 10
        BWkbs = zeros(B)
        for i in range(B):
            Xb = []
            for n in range(X.shape[0]):
                Xb.append(np.random.uniform(0, 1, size=X.shape[1]));
            Xb = np.array(Xb);
            mu, clusters = find_centers(Xb, k);
            BWkbs[i] = np.log(Wk(mu, clusters))
        Wkbs = sum(BWkbs) / B
        sk = np.sqrt(sum((BWkbs - Wkbs) ** 2) / B)
        Gap = Wkbs - Wks;
        if Gap - oldGap <= sk:
            num_cluster = k;
            break;
        oldGap = Gap;
    return num_cluster;

def elbow_method(X, k_max):
    '''
    Algorithm: Elbow Method ("http://blog.geomblog.org/2010/03/this-is-part-of-occasional-series-of.html")
    :param X: data matrix
    :param k_max: the maximum number of clusters
    :return: the optimal number of clusters
    '''
    threshold = 0.01;
    mu, clusters = find_centers(X, 1)
    WksOld = np.log(Wk(mu, clusters));
    for k in xrange(2, k_max + 1):
        mu, clusters = find_centers(X, k)
        Wks = np.log(Wk(mu, clusters));
        if WksOld - Wks < threshold:  # We take the log of the SSE because we want to compare the relative change
            num_cluster = k;
            break;
        WksOld = Wks;
    return num_cluster;


#Ref: Sreenivas Sarwar Anik

"""

Hough Transform to detect straight lines and measure angles between them.

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

The origin is the top left corner of the original image. X and Y axis are
horizontal and vertical edges respectively. The distance is the minimal
algebraic distance from the origin to the detected line. The angle accuracy
can be improved by decreasing the step size in the theta array.

https://scikit-image.org/docs/dev/auto_examples/edges/plot_line_hough_transform.html#sphx-glr-auto-examples-edges-plot-line-hough-transform-py

Image downloaded from: https://geometryhelp.net/wp-content/uploads/2019/04/intersecting-lines.jpg
Then inverted to dark background.
"""

from skimage.transform import (hough_line, hough_line_peaks)
import numpy as np
import cv2
from matplotlib import pyplot as plt

image = cv2.imread('images/lines1.jpg', 0) #Fails if uses as-is due to bright background.
#Also try lines2 to see how it only picks up straight lines
#Invert images to show black background
image = ~image  #Invert the image (only if it had bright background that can confuse hough)
plt.imshow(image, cmap='gray')

# Set a precision of 1 degree. (Divide into 180 data points)
# You can increase the number of points if needed.
tested_angles = np.linspace(-np.pi / 2, np.pi / 2, 180)

# Perform Hough Transformation to change x, y, to h, theta, dist space.
hspace, theta, dist = hough_line(image, tested_angles)

plt.figure(figsize=(10,10))
plt.imshow(hspace)

#Now, to find the location of peaks in the hough space we can use hough_line_peaks
h, q, d = hough_line_peaks(hspace, theta, dist)

#################################################################
#Example code from skimage documentation to plot the detected lines
angle_list=[]  #Create an empty list to capture all angles

# Generating figure 1
fig, axes = plt.subplots(1, 3, figsize=(15, 6))
ax = axes.ravel()

ax[0].imshow(image, cmap='gray')
ax[0].set_title('Input image')
ax[0].set_axis_off()

ax[1].imshow(np.log(1 + hspace),
             extent=[np.rad2deg(theta[-1]), np.rad2deg(theta[0]), dist[-1], dist[0]],
             cmap='gray', aspect=1/1.5)
ax[1].set_title('Hough transform')
ax[1].set_xlabel('Angles (degrees)')
ax[1].set_ylabel('Distance (pixels)')
ax[1].axis('image')

ax[2].imshow(image, cmap='gray')

origin = np.array((0, image.shape[1]))

for _, angle, dist in zip(*hough_line_peaks(hspace, theta, dist)):
    angle_list.append(angle) #Not for plotting but later calculation of angles
    y0, y1 = (dist - origin * np.cos(angle)) / np.sin(angle)
    ax[2].plot(origin, (y0, y1), '-r')
ax[2].set_xlim(origin)
ax[2].set_ylim((image.shape[0], 0))
ax[2].set_axis_off()
ax[2].set_title('Detected lines')

plt.tight_layout()
plt.show()

###############################################################
# Convert angles from radians to degrees (1 rad = 180/pi degrees)
angles = [a*180/np.pi for a in angle_list]

# Compute difference between the two lines
angle_difference = np.max(angles) - np.min(angles)
print(180 - angle_difference)   #Subtracting from 180 to show it as the small angle between two lines


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

# This function computes the average sentence length for a given corpora
def average_len(file):
    with open(file) as fn:
        sentences = fn.readlines()

    len_sentences = [len(sentence.split()) for sentence in sentences]
    len_avg, len_std, len_max = stat.mean(len_sentences), stat.stdev(len_sentences), max(len_sentences)
    print('Average sentence length\tStandard deviation\tMaximum sentence length\n')
    print('{}\t{}\t{}'.format(len_avg, len_std, len_max))
    return len_avg, len_std, len_max

# Compute the histogram for the sentence lenght in a given corpora
def sentence_len_histogram(file, plot=False):
    with open(file) as fn:
        sentences = fn.readlines()

    len_sentences = [len(sentence.split()) for sentence in sentences]
    hist, bins = np.histogram(len_sentences, bins=range(0, 90, 10))
    print('\t'.join(['bin {}'.format(bins[n]) for n in range(len(bins))]))
    print('\t'.join([str(hist[n]) for n in range(len(bins)-1)]))

    if plot:
        _ = plt.hist(hist, bins=bins)
        plt.title("Sentence length histogram")
        plt.show()
    return hist, bins


import numpy as np
import timeit
import time
from scipy import integrate

def golub_welsch(n):
    i = np.arange(n)
    b = (i+1) / np.sqrt(4*(i+1)**2 - 1)
    J = np.diag(b, -1) + np.diag(b, 1)
    x, ev = np.linalg.eigh(J)   #x are eigenvalues
    w = 2 * ev[0,:]**2
    return x, w

def gauss(f, a, b, N):
    x,w = golub_welsch(N)
    x_transformed = 0.5*(a+b+(b-a)*x)
    values = w*f(x_transformed)
    return (b-a)/2.0 * np.sum(values)

def composite_gauss(f, a, b, n, N):     #n number of subintervals, N degree
    h = (b-a)/n
    intervals = np.linspace(a, b, n)
    x,w = golub_welsch(N)
    x_transformed = 0.5*(2*a+h+h*x)
    result = 0

    for i in range(n):
        result += h/2.0*np.sum(w*f(x_transformed))
        x_transformed += h

    return result

def mpr(f, a, b, N):
    h = float(b-a)/N
    x = np.linspace(a+h/2, b-h/2, N)
    ft = h*f(x)
    return np.sum(ft)

def tpr(f, a, b, N):
    h = float(b-a)/N
    x = np.linspace(a, b, N+1)
    return h*np.sum(f(x[1:-1]))+h/2*(f(x[0])+f(x[N]))

def simpson(f, a, b, N):
    N*=2
    h = float(b-a)/N
    x = np.linspace(a, b, N+1)
    fx = f(x)
    a = 2*(h/3)*np.sum(fx[2:-1:2])
    b = 2*(h/6)*(fx[0]+fx[-1])
    c = 8*(h/6)*np.sum(fx[1::2])
    return a+b+c

def adaptive_h(f, a, b, tol=0.00000001):                                 #Usually not efficient because of recursion. TODO: Implement in Cython
    return _adaptive_h(f,a,b,f(a),f(b), f((a+b)/2), (b-a)/6*(f(a)+4*f((a+b)/2) +f(b)),tol)

def _adaptive_h(f, a, b, fa, fb, fm, sab, tol):
    h = (b-a)/2
    fm_new1 = f(a+h/2)
    fm_new2 = f(b-h/2)
    sam = h/6*(fa+4*fm_new1+fm)
    smb = h/6*(fm+4*fm_new2+fb)

    err = np.abs(sam+smb-sab)

    if(err>15*tol):
        return _adaptive_h(f,a,a+h,fa,fm,fm_new1,sam,tol/2)+_adaptive_h(f,a+h,b,fm,fb,fm_new2,smb,tol/2)

    return sam+smb

def sliced(f, y):
    def g(*args):
        return f(*args, y)

    return g

def sliced_list(lf, y):
    return [sliced(f, y) for f in lf]

def quad_ruleNd(rule, n):
    """
    Generates a high dimensional quad rule from 1-dimensional blue-print

    Arguments:

    rule: A quadrature rule which expects:

        - g: a function expecting 1 argument, returning a float
        - a: float, lower bounds
        - b: float, upper bounds
        - N: resolution

    n:    Dimensions, a positive integer

    Returns a quadrature rule which expects:

        - f: A function with n float arguments, returns a float

        - bounds: A list of n functions, which return a 2-tuple of floats. The first function should expect n-1 arguments, the second n-2 etc.

        - nodes: A list of positive integers, representing the resolution along each axis

    Equivalent to:

    nquad(f, [lambda a1, a2, ... an: bounds[0](an, ... a1), ....])
    """

    if(n==1):
        return lambda f, bounds, nodes: rule(f, bounds[0]()[0], bounds[0]()[1], nodes[0])

    lower_rule = quad_ruleNd(rule, n-1)

    def f(f, bounds, nodes):
        integral = lambda y:  lower_rule(sliced(f, y), sliced_list(bounds[:-1], y), nodes[:-1])
        return rule(np.vectorize(integral), bounds[-1]()[0], bounds[-1]()[1], nodes[-1])

    return f

def cube_quad_ruleNd(rule, n):
    qnd = quad_ruleNd(rule, n)
    return lambda f, bounds, nodes: qnd(f, [lambda *args: bound for bound in bounds], nodes)

def test(f, exact_val, name):
    result = f()
    t = timeit.timeit(f, number = 30)
    print(name, ":", result, ", ERROR: ", np.abs(exact_val-result), ", TOOK:", t, "seconds")

def test_batch(f, exact):
    test(lambda: simpson(f, 0, 4, 12000),exact,"Simpson")
    test(lambda: adaptive_h(f, 0, 4),exact,"Adaptive")
    test(lambda: gauss(f, 0, 4, 80),exact,"Gauss")
    test(lambda: tpr(f, 0, 4, 120000),exact,"TPR")
    test(lambda: mpr(f, 0, 4, 120000),exact,"MPR")
    print()

def expensive(x):
    if(x<2.3234):
        return 0.0
    return x-2.3234

if __name__ == "__main__":
    f = lambda x: 1/(1+25*x**2)
    exact = integrate.quad(f, 0, 4)[0]

    test_batch(f, exact)

    f = lambda x: x**0.5
    exact = integrate.quad(f, 0, 4)[0]

    test_batch(f, exact)

    f = lambda x: np.sin(x)
    exact = integrate.quad(f, 0, 4)[0]

    test_batch(f, exact)

    exact = integrate.quad(np.vectorize(expensive), 0, 4)[0]

    test_batch(np.vectorize(expensive), exact)


import pandas as pd

from scipy import misc
from mpl_toolkits.mplot3d import Axes3D
import matplotlib
import matplotlib.pyplot as plt
import os
from sklearn import manifold

def Plot2D(T, title, x, y, num_to_plot=80):
  # This method picks a bunch of random samples (images in your case)
  # to plot onto the chart:
  fig = plt.figure()
  ax = fig.add_subplot(111)
  ax.set_title(title)
  ax.set_xlabel('Component: {0}'.format(x))
  ax.set_ylabel('Component: {0}'.format(y))

  # It also plots the full scatter:
  ax.scatter(T[:,x],T[:,y], c=colors, marker='.',alpha=0.7)

def Plot3D(T, title, x, y, z, num_to_plot=80):
  # This method picks a bunch of random samples (images in your case)
  # to plot onto the chart:
  fig = plt.figure()
  ax = fig.add_subplot(111, projection = '3d')
  ax.set_title(title)
  ax.set_xlabel('Component: {0}'.format(x))
  ax.set_ylabel('Component: {0}'.format(y))
  ax.set_zlabel('Component: {0}'.format(z))
  # It also plots the full scatter:
  ax.scatter(T[:,x],T[:,y],T[:,z], c=colors, marker='.',alpha=0.7)

def doIsomap(df, n_neighbors, n_components):
  iso = manifold.Isomap(n_neighbors=n_neighbors, n_components=n_components)
  iso.fit(df)
  result = iso.transform(df)
#
# TODO: Create a 2D Scatter plot to graph your manifold. You
# can use either 'o' or '.' as your marker. Graph the first two
# isomap components
#
  Plot2D(result, '2d scatter - manifold', 0, 1)
#
# TODO: Create a 3D Scatter plot to graph your manifold. You
# can use either 'o' or '.' as your marker:
#
  Plot3D(result, '3d scatter - manifold', 0, 1, 2)

# Look pretty...
# matplotlib.style.use('ggplot')
plt.style.use('ggplot')

#
# TODO: Start by creating a regular old, plain, "vanilla"
# python list. You can call it 'samples'.
#
samples = []
colors = []

#
# TODO: Write a for-loop that iterates over the images in the
# Module4/Datasets/ALOI/32/ folder, appending each of them to
# your list. Each .PNG image should first be loaded into a
# temporary NDArray, just as shown in the Feature
# Representation reading.
#
# Optional: Resample the image down by a factor of two if you
# have a slower computer. You can also convert the image from
# 0-255  to  0.0-1.0  if you'd like, but that will have no
# effect on the algorithm's results.
#
for fname in os.listdir('Datasets/ALOI/32'):
  path = os.path.join('Datasets/ALOI/32', fname)
  img = misc.imread(path)
  samples.append((img[::2,::2] / 255.0).reshape(-1))
  colors.append('b')

#
# TODO: Once you're done answering the first three questions,
# right before you converted your list to a dataframe, add in
# additional code which also appends to your list the images
# in the Module4/Datasets/ALOI/32_i directory. Re-run your
# assignment and answer the final question below.
#
for fname in os.listdir('Datasets/ALOI/32i'):
  path = os.path.join('Datasets/ALOI/32i', fname)
  img = misc.imread(path)
  samples.append((img[::2,::2] / 255.0).reshape(-1))
  colors.append('r')

#
# TODO: Convert the list to a dataframe
#
df = pd.DataFrame(samples)

#
# TODO: Implement Isomap here. Reduce the dataframe df down
# to three components, using K=6 for your neighborhood size
#

doIsomap(df, 6, 3)
#doIsomap(df, 5, 3)
#doIsomap(df, 4, 3)
#doIsomap(df, 3, 3)
#doIsomap(df, 2, 3)
#doIsomap(df, 1, 3)

plt.show()


#!/usr/bin/env python3

"""

Image Processing -- SCC0251/5830— Prof. Moacir A. Ponti

Assignment 1 : image generation

assignment1: fundamentals of image processing -- generation, sampling, and quantization

                2021, April -- 1º Semester

"""

__author__      = "Erikson Aguiar -- NUSP: 11023222"

import numpy as np
import random
'''
    normalize values of pixels

    parameters: z is an image (numpy array), c is min value (int) and d is max value
    return: image normalized from min to max values of pixels
'''
def normalize(z, c, d):
    a = z.min()
    b = z.max()

    tz = (z-a)*((d-c)/(b-a)) + c

    return tz

'''
    generate synthetic image using function one

    parameters: C is the image size (int)
    return: synthetic image
'''
def gen_func_one(c):
    new_image = np.zeros((c,c), dtype=float)
    for x in range(c):
        for y in range(c):
            new_image[x,y] = ((x*y) + (2*y))

    n_img = normalize(new_image, 0, ((2**16)-1))

    return n_img

'''
    generate synthetic image using function two

    parameters: C is the image size (int), Q is parameter for image generation (int)
    return: synthetic image
'''
def gen_func_two(c,q):
    new_image = np.zeros((c,c), dtype=float)
    for x in range(c):
        for y in range(c):
            new_image[x,y] = np.abs(np.cos(x/q) + (2*np.sin(y/q)))

    n_img = normalize(new_image, 0, ((2**16)-1))

    return n_img

'''
    generate synthetic image using function three

    parameters: C is the image size (int), Q is parameter for image generation (int)
    return: synthetic image
'''
def gen_func_three(c,q):
    new_image = np.zeros((c,c), dtype=float)
    for x in range(c):
        for y in range(c):
            new_image[x,y] = float(np.abs((3*(x/q)) - (np.cbrt(y/q))))

    n_img = normalize(new_image, 0, ((2**16)-1))

    return n_img

'''
    generate synthetic image using function four

    parameters: C is the image size (int), S is a seed value for random number generation (int)
    return: synthetic image
'''
def gen_func_four(c,s):
    random.seed(s)
    new_image = np.zeros((c,c), dtype=float)
    for x in range(c):
        for y in range(c):
            new_image[x,y] = random.random()

    n_img = normalize(new_image, 0, ((2**16)-1))

    return n_img

'''
    function to walking on image coordinates

    parameters: C is the image size (int), x coordinate with axis x (int), y is coordinate with axis y (int)
    return: coordinate x (int) and coordinate y (int)
'''
def random_walk(c,x, y):
    dx = random.randint(-1,1)
    dy = random.randint(-1,1)
    new_x = np.mod((x+dx),c)
    new_y = np.mod((y+dy),c)

    return new_x,new_y

'''
    generate synthetic image using function four that represent a random walk

    parameters: C is the image size (int), S is a seed value for random number generation (int)
    return: synthetic image
'''
def gen_func_five(c,s):
    random.seed(s)
    new_image = np.zeros((c,c), dtype=float)
    x, y = 0,0
    new_image[x,y] = 1
    for _ in range(1, (1+c**2)):
        x, y = random_walk(c,x,y)
        new_image[x,y] = 1

    return new_image

'''
    downsampling image CxC following regions r, which select first value of the region
    parameters: image (numpy array), c is image size c*c (int), N is size sampled image (int)
    return: image reduced
'''
def downsampling(image, c,n):
    r = int((c/n)**2)
    tam = int(c/(r/2))
    new_image = np.zeros((tam,tam), dtype=float)
    px, py = 0,0
    for x in range(0, c, int(c/n)):
        for y in range(0, c, int(c/n)):
            px, py = int(x/(c/n)), int(y/(c/n))
            new_image[px,py] = image[x,y]

    return new_image

'''
    Quantize images with B bits
    parameters: image (numpy array), B is number of bitwise(B)
    return image quantized
'''
def quantization(image, B):
    #normalize image
    new_image = normalize(image, 0, 255).astype(np.uint8)
    #new_image = new_image & 0b11100000
    #calculate bitwise
    zeros = 8 - B
    b = '0b'
    b += '1' * B
    b += '0' * zeros
    #apply AND between pixel value and mask of bits
    new_image = new_image & int(b, base=2)

    return new_image

'''
    calculate difference between two images using root square error
    parameters: reference image (numpy array), generation image (numpy array)
    return: root square error (float)
'''
def difference_img(ref_img, gen_img):
    rse = np.sqrt(np.sum((gen_img - ref_img)**2))

    return rse

'''
    function to select method for generate images
    paramters: func is a method (int), C image size C*C (int), Q generation (int)
               S seed for random number generation (int)
    return: return a synthetic image from a method selected
'''
def generate_image(func, C, Q, S):
    synthetic_img = None
    #swich function
    if func == 1:
        synthetic_img = gen_func_one(C)
    elif func == 2:
        synthetic_img = gen_func_two(C,Q)
    elif func == 3:
        synthetic_img = gen_func_three(C,Q)
    elif func == 4:
        synthetic_img = gen_func_four(C,S)
    elif func == 5:
        synthetic_img = gen_func_five(C,S)

    return synthetic_img

if __name__ == '__main__':
    #input image name
    filename = input().rstrip()
    R = np.load(filename)
    #image size C
    C = int(input())
    #function choose (1,2,3,4,5)
    func = int(input())
    # generation parameter
    Q = int(input())
    # lateral size N
    N = int(input())
    #number of bits per pixel B
    B = int(input())
    #random function seed S
    S = int(input())

    #generate image
    img = generate_image(func, C, Q, S)
    #downscalling image
    down_img = downsampling(img, C,N)
    #apply quantization with B bits
    quant_img = quantization(down_img, B)
    #calculate difference between two images
    diff = difference_img(R, quant_img)
    print(format(diff, '.4f'))


import numpy as np

def merge_sort(vetor):
  if len(vetor) > 1:
    divisao = len(vetor) // 2
    esquerda = vetor[:divisao].copy()
    direita = vetor[divisao:].copy()

    merge_sort(esquerda)
    merge_sort(direita)

    i = j = k = 0

    # ordena esquerda e direita
    while i < len(esquerda) and j < len(direita):
      if esquerda[i] < direita[j]:
        vetor[k] = esquerda[i]
        i += 1
      else:
        vetor[k] = direita[j]
        j += 1
      k += 1

    # ordenação final
    while i < len(esquerda):
      vetor[k] = esquerda[i]
      i += 1
      k += 1
    while j < len(direita):
      vetor[k] = direita[j]
      j += 1
      k += 1

  return vetor

ordenado = merge_sort(np.array([15,34,8,3]))
ordenaado_pior_caso = merge_sort(np.array([10,9,8,7,6,5,4,3,2,1]))
print(ordenado)
print(ordenaado_pior_caso)


import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import math
from scipy import stats

# data source: https://ourworldindata.org/coronavirus-source-data

def setup(csv_filename, country):
    df = pd.read_csv(csv_filename)
    df = df.loc[: , ["location", "date", "new_cases" ]]
    df = df[df["location"] == country]
    # Data prep
    df = df[df["new_cases"].notna()] # remove not a number-rows
    df = df[df["new_cases"] > 0]
    df.drop_duplicates()
    print(df.head())
    return df

def statistics(df):
    print("Dataset size", len(df["new_cases"].tolist()))

def calculate_first_digit(df):
    new_cases = df["new_cases"]
    first_digit = []
    for row in df["new_cases"]: # get first digit
        try:
            first_digit.append(int(str(row)[:1]))
        except:
            first_digit.append(0)
            print(row)
    df["first_digit"] = first_digit
    df = df.drop(df[df.first_digit <= 0].index) # drop rows with 0 values
    n = len(df["first_digit"].tolist())
    count_first_digit = df["first_digit"].value_counts(sort=False)#count number of 1's, 2's, 3's and so on
    count_first_digit.to_frame().to_numpy()
    total_count = count_first_digit.sum() # number of numbers in list. Equal to len(df["first_digit"].tolist())
    percentage = []
    for elem in count_first_digit:
        p = float("{:.4f}".format( elem / total_count))
        percentage.append(p)
    x = np.linspace(1,9,9)
    percentage = dict(zip(x, percentage))
    return df, percentage

def calculate_first_two_digits(df):
    first_two = []
    for row in df["new_cases"]:
        temp_int = int(row*10)
        first_two.append(int(str(temp_int)[:2]))
    df["first_two"] = first_two

    count_first_two = df["first_two"].value_counts(sort=False)[1:]
    print(count_first_two)
    count_first_two.to_numpy()
    total_count = count_first_two.sum()
    percentage = []
    for elem in count_first_two:
        percentage.append(float("{:.4f}".format( elem / total_count)))
    return df, percentage

def plot_figure(percentage, perfect_benford):
    _x = np.linspace(1, 9, 9)
    plt.plot(_x,percentage, label="first digit benford") # calculated perfentage
    plt.plot(_x, list(perfect_benford.values()), label="perfect benford")
    plt.xlabel("Digits")
    plt.ylabel("Percentage")
    plt.legend()
    plt.show()

def get_perfect_benford():
    x = np.linspace(1,9,9)
    y = [0.31, 0.176, 0.125, 0.097,0.079, 0.067, 0.058, 0.051, 0.046]
    return dict(zip(x,y))

def pearson_coefficient(list_a, list_b):
    assert (len(list_a) != 0)
    assert (len(list_b) != 0) # list b is perfect benford
    sum_a = sum(list_a)
    sum_b = sum(list_b)
    mean_a = float(sum_a / len(list_a))
    mean_b = float(sum_b / len(list_b))
    list_mean_a = [(x - mean_a) for x in list_a]
    list_mean_b = [(y - mean_b) for y in list_b]
    numerator = sum(x * y for x,y in zip(list_mean_a, list_mean_b))
    denominator = math.sqrt(sum(x*x for x in list_mean_a) * sum(y * y for y in list_mean_b))
    if (denominator != 0):
        p_value = numerator / denominator
    else:
        p_value = 0
    print("------ Pearson coefficient --------")
    print(p_value)
    return p_value

def mantissa_arc_test(list_a):
    """
        The mantissa arc test.
        :parm list_a: df["new_cases"]
        :return: p-value and a plot
    """
    x_coordinates = [(math.cos(2*math.pi * (math.log10(x) % 1))) for x in list_a] # abscissa - x-coordinate for the mantissa
    y_coordinates = [(math.sin(2*math.pi * (math.log10(x) % 1))) for x in list_a] # ordinate

    x_nominator = sum(math.cos(2*math.pi * (math.log10(x) % 1)) for x in list_a)
    y_nominator = sum(math.sin(2*math.pi * (math.log10(x) % 1)) for x in list_a)
    x_coordinate = x_nominator / len(list_a) # Center of mass
    y_coordinate = y_nominator / len(list_a) # Center of mass

    L_squared = (x_coordinate)**2 + (y_coordinate)**2
    p_value = 1 - math.exp(-L_squared * len(list_a))
    print("--------- p-value ---------")
    print(p_value)

    ''' Plotting '''
    plt.scatter(x_coordinates, y_coordinates)
    plt.plot(x_coordinate, y_coordinate, 'o', color="red") # center of mass
    plt.axhline(y=0, color='k')
    plt.axvline(x=0, color='k')
    plt.show()

### TODO: implement chi-squared
def chi_squared(df, perfect_benford):
    '''
    #observed, expected ....
    H0: status_que_hypothesis
    '''
    sample_size = len(df["new_cases"].tolist())
    benford_distribution = [sample_size*x for x in perfect_benford] # expected distribution
    count_first_digit = df["first_digit"].value_counts(sort=False)
    residual_squared = [math.pow(x-y, 2) / y for x,y in zip(count_first_digit, benford_distribution)]
    degrees_of_freedom = (9-1)*(2-1)
    p_value= stats.chi2.pdf(sum(residual_squared), degrees_of_freedom)
    print("chi squared p-value: ",p_value)
    #print("residual", residual)
    #print(benford_distribution)
    #print("Not implemented yet")

def main():
    df = setup("owid-covid-data.csv","Belgium") #csv_filename, country
    statistics(df) # Get info about the dataset
    df, percentage = calculate_first_digit(df)
    print(df.head())
    chi_squared(df, list(get_perfect_benford().values()))
    pearson = pearson_coefficient(list(percentage.values()), get_perfect_benford())
    mantissa_arc_test(df["new_cases"].tolist())
    plot_figure(list(percentage.values()), get_perfect_benford())

if __name__ == "__main__":
    main()


'''
Ankit Khandelwal
15863
Home Work 7
Exercise 4
'''

from math import sin, sqrt

import numpy as np

def f(x):
    return sin(1 / (x * (2 - x))) ** 2

a = 2227057010910366687
M = 2 ** 64 - 59
c = 0

N = 10000
area = 2

x1 = np.zeros(N + 1)
y1 = np.zeros(N + 1)
z1 = np.zeros(N)
x2 = np.zeros(N + 1)
y2 = np.zeros(N + 1)
z2 = np.zeros(N)
x3 = np.zeros(N + 1)
y3 = np.zeros(N + 1)
z3 = np.zeros(N)

X0 = 0
X1 = 2
Y0 = 0
Y1 = 1

x1[0] = 154968415  # seed
x2[0] = 25163788741  # seed
x3[0] = 3135897647  # seed

for i in range(1, N + 1, 1):
    x1[i] = int(a * x1[i - 1] + c) % M
    y1[i] = x1[i] / (M - 1)
    z1[i - 1] = X0 + (X1 - X0) * y1[i]
    x2[i] = int(a * x2[i - 1] + c) % M
    y2[i] = x2[i] / (M - 1)
    z2[i - 1] = Y0 + (Y1 - Y0) * y2[i]
    x3[i] = int(a * x3[i - 1] + c) % M
    y3[i] = x3[i] / (M - 1)
    z3[i - 1] = X0 + (X1 - X0) * y3[i]

k = 0
summ = 0
summ_2 = 0
for i in range(N):
    summ = summ + f(z3[i])
    summ_2 = summ_2 + f(z3[i]) ** 2
    if z2[i] <= f(z1[i]):
        k = k + 1
I1 = k * area / N
I2 = 2 / N * summ
var1 = N * (I1 / area) * (1 - I1 / area)
e1 = sqrt(var1) * area / N
var2 = summ_2 / N - (summ / N) ** 2
e2 = (2) * sqrt(var2) / sqrt(N)
print('From hit and miss, I = {}, error = {}'.format(I1, e1))
print('From mean value, I = {}, error = {}'.format(I2, e2))

Ankit Khandelwal_HW7/Exercise 4/exercise 4.py


"""
Module that contains commonly used loss-functions in machine learning. The following
functions are defined:

- :func:`se`
- :func:`ae`
- :func:`zero_one_loss`
- :func:`cross_entropy`
"""

import numpy as np

def se(y, p):
    """Squared error.

    Sqaured error can be defined as follows:

    .. math::

        \sum_i^n (y_i - p_i)^2

    where :math:`n` is the number of provided records.

    Parameters
    ----------
    y : :class:`ndarray`
        One dimensional array with ground truth values.

    p : :class:`ndarray`
        One dimensional array with predicted values.

    Returns
    -------
    float
        Squared error as desribed above.

    Notes
    -----
    Usually used for regression problems.
    """
    return np.sum((y - p)**2)

def ae(y, p):

    """Absolute error.

    Absolute error can be defined as follows:

    .. math::

        \sum_i^n abs(y_i - p_i)

    where :math:`n` is the number of provided records.

    Parameters
    ----------
    y : :class:`ndarray`
        One dimensional array with ground truth values.

    p : :class:`ndarray`
        One dimensional array with predicted values.

    Returns
    -------
    float
        Absolute error as desribed above.
    """
    return np.abs(y-p).sum()

def zero_one_loss(y, p):
    """Number of incorrectly classified records.

    Parameters
    ----------
    y : :class:`ndarray`
        One dimensional array with ground truth values.

    p : :class:`ndarray`
        One dimensional array with predicted values.

    Returns
    -------
    int
        Number of misclassified records.
    """
    return np.sum(y != p)

def cross_entropy(y, p):

    """
    Cross-entropy is a measure of the difference between two probability distributions for a given random variable or set of events.
    (`source <https://machinelearningmastery.com/cross-entropy-for-machine-learning/>`_)

    Parameters
    ----------
    y : :class:`ndarray`
        One dimensional array with ground truth values.

    p : :class:`ndarray`
        One dimensional array with predicted values.

    Returns
    -------
    float
        Cross entropy score.
    """

    return -np.sum(np.log(p) * y)


from numpy import random

"""
What is Data Distribution?
Data Distribution is a list of all possible values, and how often each value occurs.

Such lists are important when working with statistics and data science.

The random module offer methods that returns randomly generated data distributions.

Example
Generate a 1-D array containing 100 values, where each value has to be 3, 5, 7 or 9.

The probability for the value to be 3 is set to be 0.1

The probability for the value to be 5 is set to be 0.3

The probability for the value to be 7 is set to be 0.6

The probability for the value to be 9 is set to be 0
"""

x = random.choice([3, 5, 7, 9], size=(100), p=[0.1, 0.3, 0.6, 0.0])
print(x)


'''
Overfitting in Linear Regression
Author: Rowel Atienza
Project: https://github.com/roatienza/Deep-Learning-Experiments
'''
# On command line: python3 overfit_regression.py
# Prerequisite: tensorflow 1.0 (see tensorflow.org)
#             : matplotlib (http://matplotlib.org/)

from __future__ import print_function

import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import numpy as np
import math

# Tunable parameters (Try changing the values and see what happens)
samples = 100
learning_rate = 0.0001

# xcoeff should be predicted by the model, yp
xcoeff = tf.transpose(tf.constant([[1., 1., 1.]]))

# a = tf.random_uniform([1, samples],-2.5,2.5)
a = tf.linspace(-2.5,2.5,samples)
# Correct the shape
a = tf.reshape(a,[samples,1])

# In theory, polynomial degree greater than 2 will overfit but the training is still able to guess the weights
# correctly for 3rd and 4th degree polynomials
# Inputs to form yp = a*a*a*a*xp[0] + a*a*a*xp[1] + a*a*xp[2] + a*xp[3] + xp[4], xp[] are the weights
# Overfit since our data generating model is quadratic
Ap = tf.concat([tf.concat([tf.concat([tf.concat([a*a*a*a*a*a,a*a*a*a],1),a*a],1),a],1),tf.ones_like(a)],1)

# Inputs to form yp = a*a*a*xp[0] + a*a*xp[1] + a*xp[2] + xp[3], xp[] are the weights
# Overfit since our data generating model is quadratic
# Ap = tf.concat(1,[tf.concat(1,[tf.concat(1,[a*a*a,a*a]),a]),tf.ones_like(a)])

# Inputs to form y = a*a*xcoeff[0] + a*xcoeff[1] + xcoeff[2]
A = tf.concat([tf.concat([a*a,a],1),tf.ones_like(a)],1)

# Initial guess on coefficients of predicted linear model
xp = tf.Variable(tf.random_uniform([5,1], -1.0, 1.0))

# xp = tf.Variable(tf.random_uniform([4,1], -1.0, 1.0))

# Predicted Model
yp = tf.matmul(Ap,xp)

# Observed outputs
y = tf.matmul(A,xcoeff)
# noise = tf.random_normal(y.get_shape(),stddev=0.8)
noise = tf.sin(math.pi*a)
y = tf.add(y,noise)

# The smaller the loss, the closer our prediction to the observed outputs
# The loss model used is square of error (yp - y)
# Miinimization of loss is done by Gradient Descent
loss = tf.reduce_mean(tf.square(yp - y))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
train_step = optimizer.minimize(loss)

init = tf.global_variables_initializer()
with tf.Session() as session:
    session.run(init)
    for i in range(10000):
        session.run(train_step)
        if ((i+1) % 100) == 0:
            print("%d : Loss=%0.1lf,  Predicted Parameters = %s" % (i+1, loss.eval(), session.run(xp)))
    # Let's plot
    a = np.array(a.eval())
    plt.plot(a, y.eval(), 'ro', a, yp.eval(), 'b')
    red = mpatches.Patch(color='red', label='Data')
    blue = mpatches.Patch(color='blue', label='Model')
    plt.legend(handles=[red,blue])
    plt.show()


# -*- coding: utf-8 -*-
"""
Created on Wed Apr  8 15:05:29 2020

@author: Wallace

Examples based on https://realpython.com/linear-regression-in-python/
"""
#
# Step 1: Import packages and classes
#
import numpy as np
import statsmodels.api as sm
import matplotlib.pyplot as plt

#
# Step 2: Provide data
#

# Multiple - Multivariate linear regression y = b0 + b11*x1 + b12*x2  +... + b1n*xn
# Vector of independent variable
x = [[0, 1], [5, 1], [15, 2], [25, 5], [35, 11], [45, 15], [55, 34], [60, 35]]
y = [4, 5, 20, 14, 32, 22, 38, 43]
x, y = np.array(x), np.array(y)

x = sm.add_constant(x) #intercept is not added by default

#
# Step 3: Create a model and fit it
#

model = sm.OLS(y, x)

#
# Step 4: Get results
#

results = model.fit()
print(results.summary())

r_sq = results.rsquared
print('Coefficient of determination - R^2:', r_sq)

b0 = results.params[0]
b11 = results.params[1]
b12 = results.params[2]

print('Intercept - b0:', b0) # coefficient b0
print('Slopes - b11 and b12:', b11,b12) # coefficients b11 and b12

#
# Step 5: Predict response
#

y_pred = results.fittedvalues # saeme of results.predict(x)
print('Predicted response:', y_pred, sep='\n')

# Predicting for new data
x_new = sm.add_constant(np.arange(10).reshape((-1, 2)))
print('New data points:')
print(x_new)

y_new = results.predict(x_new)
print('Predicted response for new data:')
print(y_new)

#
# Step 6: Plot data
#

fig, ax = plt.subplots()
ax.plot(y, y_pred, linewidth=0, marker='s', label = "Predicted")
ax.plot(y, y, label=' Exact, y_pred = y')
ax.set_xlabel('Actual Response, y')
ax.set_ylabel('Predicted Response, y_pred')
ax.legend(facecolor='white')
plt.show()