import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.spatial.distance import pdist, squareform
from scipy.cluster.hierarchy import linkage, dendrogram
from sklearn.cluster import AgglomerativeClustering

# # Organizing clusters as a hierarchical tree

# ## Grouping clusters in bottom-up fashion

np.random.seed(123)

variables = ['X', 'Y', 'Z']
labels = ['ID_0', 'ID_1', 'ID_2', 'ID_3', 'ID_4']

X = np.random.random_sample([5, 3])*10
df = pd.DataFrame(X, columns=variables, index=labels)
print(df)

# ## Performing hierarchical clustering on a distance matrix

row_dist = pd.DataFrame(squareform(pdist(df, metric='euclidean')),
                        columns=labels,
                        index=labels)
print(row_dist)

# We can either pass a condensed distance matrix (upper triangular) from the `pdist` function, or we can pass the "original" data array and define the `metric='euclidean'` argument in `linkage`. However, we should not pass the squareform distance matrix, which would yield different distance values although the overall clustering could be the same.

# 1. incorrect approach: Squareform distance matrix
#row_clusters = linkage(row_dist, method='complete', metric='euclidean')
#pd.DataFrame(row_clusters,
#             columns=['row label 1', 'row label 2',
#                      'distance', 'no. of items in clust.'],
#             index=['cluster %d' % (i + 1)
#                    for i in range(row_clusters.shape[0])])

# 2. correct approach: Condensed distance matrix
row_clusters = linkage(pdist(df, metric='euclidean'), method='complete')
pd.DataFrame(row_clusters,
             columns=['row label 1', 'row label 2',
                      'distance', 'no. of items in clust.'],
             index=['cluster %d' % (i + 1)
                    for i in range(row_clusters.shape[0])])

# 3. correct approach: Input matrix
row_clusters = linkage(df.values, method='complete', metric='euclidean')
pd.DataFrame(row_clusters,
             columns=['row label 1', 'row label 2',
                      'distance', 'no. of items in clust.'],
             index=['cluster %d' % (i + 1)
                    for i in range(row_clusters.shape[0])])

# make dendrogram
row_dendr = dendrogram(row_clusters,
                       labels=labels,
                       color_threshold=np.inf
                       )
plt.tight_layout()
plt.ylabel('Euclidean distance')
plt.show()

# ## Attaching dendrograms to a heat map

# plot row dendrogram
fig = plt.figure(figsize=(8, 8), facecolor='white')
axd = fig.add_axes([0.09, 0.1, 0.2, 0.6])

# note: for matplotlib < v1.5.1, please use orientation='right'
row_dendr = dendrogram(row_clusters, orientation='left')

# reorder data with respect to clustering
df_rowclust = df.iloc[row_dendr['leaves'][::-1]]

axd.set_xticks([])
axd.set_yticks([])

# remove axes spines from dendrogram
for i in axd.spines.values():
    i.set_visible(False)

# plot heatmap
axm = fig.add_axes([0.23, 0.1, 0.6, 0.6])  # x-pos, y-pos, width, height
cax = axm.matshow(df_rowclust, interpolation='nearest', cmap='hot_r')
fig.colorbar(cax)
axm.set_xticklabels([''] + list(df_rowclust.columns))
axm.set_yticklabels([''] + list(df_rowclust.index))
plt.show()

# ## Applying agglomerative clustering via scikit-learn
ac = AgglomerativeClustering(n_clusters=3,
                             affinity='euclidean',
                             linkage='complete')
labels = ac.fit_predict(X)
print('Cluster labels: %s' % labels)

ac = AgglomerativeClustering(n_clusters=2,
                             affinity='euclidean',
                             linkage='complete')
labels = ac.fit_predict(X)
print('Cluster labels: %s' % labels)

Chapter 11/Organizing clusters as a hierarchical tree/program1.py


import numpy as np

def perceptron(weight, bias, x):
    model = np.add(np.dot(x, weight), bias)
    print('model: {}'.format(model))
    logit = 1/(1+np.exp(-model))
    print('Type: {}'.format(logit))
    return np.round(logit)

def compute(logictype, weightdict, dataset):
    weights = np.array([ weightdict[logictype][w] for w in weightdict[logictype].keys()[::-1]])
    output = np.array([ perceptron(weights, weightdict['bias'][logictype], val) for val in dataset])
    print(logictype)
    return logictype, output

logic = {
    '_and' : {
        'w0': -0.1,
        'w1': 0.2,
        'w2': 0.2
    },
    '_or': {
        'w0': -0.1,
        'w1': 0.7,
        'w2': 0.7
    },
    '_nand': {
        'w0': 0.6,
        'w1': -0.8,
        'w2': -0.8
    },
    '_nor': {
        'w0': 0.5,
        'w1': -0.7,
        'w2': -0.7
    },
    '_not': {
        'w0': 0.5,
        'w1': -0.7
    },
    'bias': {
        '_and': -0.2,
        '_or': -0.1,
        '_nand': 0.3,
        '_nor': 0.1,
        '_not': 0.1
    }
}
dataset = np.array([
    [1,0,0],
    [1,0,1],
    [1,1,0],
    [1,1,1]
])

_and = compute('_and', logic, dataset)
_or = compute('_or', logic, dataset)
_nand = compute('_nand', logic, dataset)
_nor = compute('_nor', logic, dataset)
_not = compute('_not', logic, [[1,0],[1,1]])

def template(dataset, name, data):
    print("\nLogic Function: {}".format(name[1:].upper()))
    if name is "_not":
        print("X\tY")
        toPrint = ["{3}\t{0}".format(output, *datas) for datas, output in zip(dataset, data)]
        for i in toPrint:
            print(i)
    else:
        print("X1\tX2\tY")
        toPrint = ["{2}\t{3}\t{0}".format(output, *datas) for datas, output in zip(dataset, data)]
        for i in toPrint:
            print(i)

gates = [_and, _or, _nand, _nor, _not]

for i in gates:
    template(dataset, *i)


import numpy as np
from collections import defaultdict

def solve(A, b, *args, **kwargs):
    safe_kwargs = defaultdict(lambda: None)
    for key, value in kwargs.items():
        safe_kwargs[key] = value

    methods = {
            "lu" : lu,
            "jacobi": jacobi,
            "gauss seidel": gauss_seidel,
            "sor": successive_overrelaxation
            }

    configs = {
            "tolerance": 1e-10,
            "max_iter": 100,
            "method": "gauss seidel"
            }

    for key, value in configs.items():
        print(key, value)# safe_kwargs[key])
        configs[key] = safe_kwargs[key] or value

    return methods[configs["method"]](A, b, *args, **configs)

def lu(A, b):
    m, n = np.shape(A)
    assert n == m, "Input matrix has dimension {}x{} and isn't square.".format(m,n)

    perm = np.eye(n)
    lower = np.zeros(n)
    upper = A.copy()

    for j in range(n):
        index = np.argmax(np.abs(upper[j:n, j]))
        assert upper[index, j] != 0.0, "This matrix is singular!"
        index += j

        if index > j:
            upper[[index, j]] = upper[[j, index]]
            perm[[index, j]] = perm[[j, index]]
            lower[[index, j]] = lower[[j, index]]

        k = slice(j+1, n)
        js = slice(j, n)
        lower[k, j] = upper[k, j] / upper[j, j]
        upper[k, js] -= lower[k,j] * upper[j, js]
    lower += np.eye(n)

    return perm, lower, upper

def _iteration_submethod(A, b, x, i):
    return 1./A[i,i] * (b[i] + A[i,i] * x[i] - A[i,:] @ x)

def _generic_iteration(A, b, subfunc, *args, tolerance=1e-10, max_iter=100):
    x = np.zeros(A.shape[0])
    iterations = 0

    while iterations < max_iter:
        for i in range(x.size):
            x[i] = subfunc(A, b, x, i, *args)
        err = np.linalg.norm(A @ x - b)
        if err < tolerance:
            break
        iterations += 1

    return x, iterations

def jacobi(A, b, *args, tolerance=1e-10, max_iter=100):
    x = np.zeros(A.shape[0])
    iterations = 0

    while iterations < max_iter:
        xprev = x.copy()
        for i in range(x.size):
            x[i] = _iteration_submethod(A, b, xprev, i)
        err = np.linalg.norm(A @ x - b)
        if err < tolerance:
            break
        iterations += 1

    return x, iterations

def gauss_seidel(A, b, *args, tolerance=1e-10, max_iter=100):
    def gauss_seidel_subfunc(A, b, x, i, *args):
        return _iteration_submethod(A, b, x, i)

    return _generic_iteration(A,b, gauss_seidel_subfunc,
            tolerance=tolerance, max_iter=max_iter)

def successive_overrelaxation(A, b, omega = 1.01, *args, tolerance=1e-10, max_iter=100):
    def sor_subfunc(A, b, x, i, omega):
        return omega * _iteration_submethod(A, b, x, i) + (1 - omega) * x[i]

    return _generic_iteration(A, b, sor_subfunc, omega, tolerance=1e-10, max_iter=100)


from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import numpy as np

plt.style.use('dark_background')
plt.tight_layout()

X_VALUES = []
Y_VALUES = []

INITIAL_THETA = 0
STEP_SIZE = (np.pi)/60
RADIUS = 3
INDEX = 0

def function_iteration(i):
    global INITIAL_X, STEP_SIZE, RADIUS, INDEX
    X_VALUES.append(RADIUS*np.sin(INITIAL_THETA + (INDEX * STEP_SIZE)))
    Y_VALUES.append(RADIUS*np.cos(INITIAL_THETA + (INDEX * STEP_SIZE)))
    INDEX += 1

    plt.cla()
    plt.xlim([-RADIUS, RADIUS])
    plt.ylim([-RADIUS, RADIUS])
    plt.plot(X_VALUES, Y_VALUES, "w")
    plt.style.use('dark_background')
    plt.xlabel("$x^2 + y^2 = " + str(RADIUS) + "^2 $")

ANIMATION = FuncAnimation(plt.gcf(), function_iteration, frames = 120,  interval = 0)
ANIMATION.save("DrawingCircleGraphAnimation.mp4", dpi = 300, fps = 60, writer = "ffmpeg")
 #plt.show()


# -*- coding: utf-8 -*-
"""
Created on Mon Dec 13 22:05:32 2021

@author: Oliver
"""
import sympy  as sp
import numpy as np
import matplotlib.pyplot as plt
import math

E = 200000 #MPA
I = 300000000 #mm^4
w0 = 250 #N/mm
dx = 125 #mm
y0 = 0
yL = 0
L = 3000
y = np.linspace(0,3000,24000)
x = sp.Symbol('x')
f = sp.Function('f')(x)
f = w0/(120*E*I*L)*(-5*x**4+6*L**2*x**2-L**4)

df = sp.diff(f)
M_x = E*I*df
dMdxV_x = sp.diff(E*I*df)
dVdxw_x = -sp.diff(dMdxV_x)

"E*I*dthetadx = M(x)"
"dMdx = V(x)"
"dVdx = -w(x)"
deflection = sp.integrate(f)
print(deflection)
# deflection_values = []
# for i in y:
#     v = deflection.evalf(subs = {x:i})
#     deflection_values.append(v)

# plt.plot(y,deflection_values)
# plt.xlabel('Length of bar (mm)')
# plt.ylabel('Deflection (mm)')
# plt.show()

print(f'Moment is given by the following equation: {M_x}')
print(f'Shear is given by the following equation: {dMdxV_x}')
print(f'Load is given by the following equation: {dVdxw_x}')

#%% QUESTION 2

t_init = 0
x_final = 100

def model(y,x):
    g = 9.81
    C = 0.55
    h = 2.75
    r = 1.5
    D = 0.03
    A = 3.14*(D/2)**2
    Q = C*A*math.sqrt(2*g*y)
    dQdt = (-Q)/(2*3.14*y*r - 3.14*y**2)
    return dQdt

# ------------------------------------------------------
x0 = t_init
y0 = 2.75
# ------------------------------------------------------
# Euler method
x_final = 10000
# step size
x = 1
# number of steps
n_step = math.ceil(x_final/x)

# Definition of arrays to store the solution
y_eul = np.zeros(n_step+1)
x_eul = np.zeros(n_step+1)

# Initialize first element of solution arrays
# with initial condition
y_eul[0] = 2.75
x_eul[0] = 0

# Populate the x array
for i in range(n_step):
    x_eul[i+1]  = x_eul[i] + x

# Apply Euler method n_step times
for i in range(n_step):
    # compute the slope using the differential equation
    slope = model(y_eul[i],x_eul[i])
    # use the Euler method
    y_eul[i+1] = y_eul[i] + x * slope
    if y_eul[i+1] <0:
        break

plt.plot(x_eul, y_eul , 'b.-',)
plt.xlabel('time (s)')
plt.ylabel('y(x)')
plt.show()

#%% QUESTION 3
print()
print("________________________________________________")
print()
f = 60
L = 30
E = 1.25*10**8
I = 0.05

y = sp.Function('y')
z = sp.Symbol('z')

y = f/(2*E*I)*(L-z)**2
int_y = sp.integrate(y,z)
d_int_y = sp.integrate(int_y)
print(f'The first integral is : {int_y}')
print(f'The second integral is : {d_int_y}')
d_of_mast = d_int_y.evalf(subs = {z:30})
print(f'The deflection of the mast at the peak is : {d_of_mast}m')


#########################
##                     ##
## Irving Gomez Mendez ##
##    March 03, 2021   ##
##                     ##
#########################

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm, uniform

# m(x) = e_1.T(X_x.T W_x X_x)**(-1) @ (X_x.T W_x Y)

def m(x):
    return (np.sin(2*np.pi*x**3))**3

n = 100
h = 0.024
epsilon = norm.rvs(scale=0.1, size=n)
x_dat = uniform.rvs(size=n)
y = np.array([m(xx) for xx in x_dat])

x_vect = np.linspace(0,1,100)
m_vect =  [m(xx) for xx in x_vect]

y_dat = y+epsilon

plt.figure(figsize=(15,7.5))
plt.scatter(x_dat, y+epsilon)
plt.plot(x_vect, m_vect, 'r--')

def hat_m(x):
    XX = np.vstack([np.ones(n),(x_dat-x)]).T
    W = np.diag(norm.pdf((x_dat-x)/h))
    beta_0 = np.linalg.solve(XX.T @ W @ XX, XX.T @ W @ y_dat)[0]
    return(beta_0)

hat_m_vect = [hat_m(xx) for xx in x_vect]

plt.figure(figsize=(15,7.5))
plt.scatter(x_dat, y+epsilon)
plt.plot(x_vect, m_vect, 'r--')
plt.plot(x_vect, hat_m_vect, 'purple')


from typing import List, Tuple, Optional

import numpy as np

from banditpylib.arms import PseudoArm
from .utils import OrdinaryLearner

class UCBV(OrdinaryLearner):
  r"""UCBV policy :cite:`audibert2009exploration`

  At time :math:`t`, play arm

  .. math::
    \mathrm{argmax}_{i \in [0, N-1]} \left\{ \hat{\mu}_i(t) + \sqrt{ \frac{ 2
    \hat{V}_i(t) \ln(t) }{T_i(t)} }+ \frac{ b \ln(t) }{T_i(t)} \right\}

  .. note::
    Reward has to be bounded within :math:`[0, b]`.
  """
  def __init__(self, arm_num: int, horizon: int,
               name: str = None, b: float = 1.0):
    """
    Args:
      arm_num: number of arms
      horizon: total number of time steps
      name: alias name
      b: upper bound of reward
    """
    super().__init__(arm_num=arm_num, horizon=horizon, name=name)
    if b <= 0:
      raise Exception('%s: b is set to %.2f which is no greater than 0!' %
                      (self.name, b))
    self.__b = b

  def _name(self) -> str:
    """
    Returns:
      default learner name
    """
    return 'ucbv'

  def reset(self):
    """Reset the learner

    .. warning::
      This function should be called before the start of the game.
    """
    self.__pseudo_arms = [PseudoArm() for arm_id in range(self.arm_num())]
    # current time step
    self.__time = 1

  def UCBV(self) -> np.ndarray:
    """
    Returns:
      optimistic estimate of arms' real means using empirical variance
    """
    ucbv = [
        arm.em_mean +
        np.sqrt(2 * arm.em_var * np.log(self.__time) / arm.total_pulls()) +
        self.__b * np.log(self.__time) / arm.total_pulls()
        for arm in self.__pseudo_arms
    ]
    return ucbv

  def actions(self, context=None) -> Optional[List[Tuple[int, int]]]:
    """
    Args:
      context: context of the ordinary bandit which should be `None`

    Returns:
      arms to pull
    """
    del context
    if self.__time > self.horizon():
      self.__last_actions = None
    elif self.__time <= self.arm_num():
      self.__last_actions = [((self.__time - 1) % self.arm_num(), 1)]
    else:
      self.__last_actions = [(np.argmax(self.UCBV()), 1)]
    return self.__last_actions

  def update(self, feedback: List[Tuple[np.ndarray, None]]):
    """Learner update

    Args:
      feedback: feedback returned by the bandit environment by executing
        :func:`actions`
    """
    self.__pseudo_arms[self.__last_actions[0][0]].update(feedback[0][0])
    self.__time += 1


'''
Construct a box with the maximum volume from a solid piece of material.
'''

import math
from sympy import Derivative, Symbol, solve

def box_volume( w, h ):
	s = Symbol( 's' )
	# v = b * * w * h
	V = ( h - 2*s ) * ( w - 2*s ) * s
	dV = Derivative( V, s ).doit()

	canidates = solve( dV )

	# Eliminate impossible Values
	for c in canidates:
		l = 2 * c.evalf()

		if( l > w or l > h ):
			canidates.remove( c )

	max_vol = 0

	if( len( canidates ) != 1 ):
		print( 'Invalid number of solutions.' )
	else:
		s0 = canidates[ 0 ].evalf()
		max_vol = V.subs( { s: s0 } )

	return max_vol

if __name__ == '__main__':

	try:
		w = float( input( 'Enter the width of the material piece: ') )
		h = float( input( 'Enter the height of the material piece: ') )
	except ValueError:
		print( 'Error parsing values' )
	else:
		print( 'material dimentions: {0} x {1}'.format( w, h ) )
		print( 'Maximum box volume: {0}'.format( box_volume( w, h ) ) )


import cv2
import numpy as np

# mean filter
def mean_filter(img, K_size=3):
    H, W, C = img.shape
    # zero padding
    pad = K_size // 2
    out = np.zeros((H + pad * 2, W + pad * 2, C), dtype=np.float)
    out[pad : pad + H, pad : pad + W] = img.copy().astype(np.float)
    tmp = out.copy()
    # filtering
    for y in range(H):
        for x in range(W):
            for c in range(C):
                out[pad + y, pad + x, c] = np.mean(
                    tmp[y : y + K_size, x : x + K_size, c]
                )
    out = out[pad : pad + H, pad : pad + W].astype(np.uint8)
    return out

def customize_mean_filter(img):
    rows, cols, c = img.shape
    new_img = img.copy().astype(np.float)
    for i in range(rows):
        for j in range(cols):
            m = 0
            count = 0
            for x in range(i - 1, i + 2):
                for y in range(j - 1, j + 2):
                    if x == -1 or y == -1 or x == 256 or y == 256:
                        continue
                    count = count + 1
                    m = m + new_img[x][y]
            new_img[i][j] = m / count
            # new_img[i][j] = np.mean(new_img[i - 1 : i + 1, j - 1 : j + 1])
    return new_img.astype(np.uint8)

def customize_std_deviation_filter(img, k_size):
    rows, cols, c = img.shape
    new_img = img.copy().astype(np.float)
    C = 3
    pad = k_size // 2
    new_img = np.zeros((rows + pad * 2, cols + pad * 2, C), dtype=np.float)
    new_img[pad : pad + rows, pad : pad + cols] = img.copy().astype(np.float)
    tmp = new_img.copy()
    M = cv2.blur(img, (3, 3))
    for i in range(rows):
        for j in range(cols):
            # for c in range(C):
            #     new_img[i][j][c] = np.sqrt(
            #         np.mean(np.square(tmp[i : i + k_size, j : j + k_size, c] - M[i][j][c]))
            #     )
            sigma = np.sqrt(
                np.mean(np.square(tmp[i : i + k_size, j : j + k_size] - M[i][j]))
            )
            new_img[pad + i][pad + j] = sigma
    return new_img[pad : pad + rows, pad : pad + cols].astype(np.uint8)

# Read image
img = cv2.imread("./imageData/cameraman.tif")

# Mean Filter
# out = mean_filter(img, K_size=3)
out = customize_std_deviation_filter(img, 3)
print(out)

# Save result

# cv2.imwrite("out.jpg", out)
cv2.imshow("original", img)
cv2.imshow("out", out)

cv2.waitKey(0)

# cv2.destroyAllWindows()


import numpy as np
from numpy import vectorize

@vectorize
def relu(x: float) -> float:
    """
    The ReLu activation function

    Args:
        x: The input to the function

    Returns:
        The output of the function
    """
    if x > 0:
        return x
    return 0.1 * x

@vectorize
def relu_d(x: float) -> float:
    """
    The gradient of the ReLu activation function

    Args:
        x: The point at which to take the gradient

    Returns:
        The gradient of the ReLu activation function
    """
    if x > 0:
        return 1
    return 0.1

tanh = np.tanh  # Assigned to this module for code clarity in other files

@vectorize
def tanh_d(x: float) -> float:
    """
    The gradient of the Hyperbolic Tangent activation function

    Args:
        x: The point at which to take the gradient

    Returns:
        The gradient of the tanh activation function
    """
    return 1 - x ** 2


import numpy as np

def softmax(L):
    return np.exp(L) / sum(np.exp(L))

if __name__ == "__main__":
    data = [5, 6, 7]
    print(np.exp(data))
    print(sum(np.exp(data)))
    print(softmax(data))

### Expect output
[ 148.4131591   403.42879349 1096.63315843]
1648.4751110237703
[0.09003057 0.24472847 0.66524096]
###


"""
Created on Mon Apr 27 11:45:32 2020

@author: Patrick
"""

import numpy as np
from molreps.methods.geo_npy import rigid_transform

# Random rotation and translation
R = np.random.rand(3,3)
t = np.random.rand(3,1)

# make R a proper rotation matrix, force orthonormal
U, S, Vt = np.linalg.svd(R)
R = np.dot(U,Vt)

# remove reflection
if np.linalg.det(R) < 0:
   Vt[2,:] *= -1
   R = np.dot(U,Vt)
print("det:",np.linalg.det(R))

# number of points

n = 10

A = np.random.rand(3, n)
B = np.dot(R,A) + np.tile(t, (1, n))
B= B.T
A = A.T

# Recover R and t
B2,ret_R, ret_t = rigid_transform(A, B)

# Compare the recovered R and t with the original

# Find the root mean squared error
err = B2 - B
err = np.multiply(err, err)
err = np.sum(err)
rmse = np.sqrt(err/n);

print("Points a")
print(A)
print("")

print("Points b")
print(B)
print("")

print("Ground truth rotation")
print(R)

print("Recovered rotation")
print(ret_R)
print("")

print("Ground truth translation")
print(t)

print("Recovered translation")
print(ret_t)
print("")

print("RMSE:", rmse)

if rmse < 1e-5:
    print("Everything looks good!\n");
else:
    print("Hmm something doesn't look right ...\n");


import numpy as np

a = 9
b = 12
c = 4

print(np.gcd(a, b))
print(np.gcd(b, c))
print(np.gcd(a, c))

arr = np.array([20, 56, 8, 10, 90])

print(np.gcd.reduce(arr))

Tutorial/Code/37. NumPy GCD Greatest Common Denominator.py


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

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

# Método de Newton para minimizar funciones

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

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

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

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

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

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

# Derivadas parciales de segundo orden:
fxx_sym=sp.Lambda((x,y), sp.simplify(sp.diff(fx_sym(x,y),x)))
def fxx(w):
	return float(fxx_sym(w[0],w[1]))

fxy_sym=sp.Lambda((x,y), sp.simplify(sp.diff(fx_sym(x,y),y)))
def fxy(w):
	return float(fxy_sym(w[0],w[1]))

fyy_sym=sp.Lambda((x,y), sp.simplify(sp.diff(fy_sym(x,y),y)))
def fyy(w):
	return float(fyy_sym(w[0],w[1]))

# Matriz Hessiana
def hessf(w):
	a=fxy(w) # f es de clase 2, así que fxy = fyx
	return np.array([[fxx(w),a],[a,fyy(w)]])

# Método de Newton para encontrar un 0 en la derivada
def newton(w, grad_fun, hess_fun, fun, max_iters=500):

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

	for _ in range(max_iters):

		H1=np.linalg.inv(hess_fun(w))
		w = w - np.dot(H1,grad_fun(w))
		graf.append(fun(w))

	return w, graf

# Gradiente descendiente (para compararlo)
def gd(w, lr, grad_fun, fun, max_iters = 1000):

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

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

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

	return w, graf

print('Comparación del método de Newton con el gradiente descendente:\n')

# Número de iteraciones
max_iters=20
# Tasa de aprendizaje para el gradiente descendente
lr=0.01
# Puntos de inicio
condiciones_iniciales=np.array([(2.1, -2.1),(3.0, -3.0),(1.5, 1.5),(1.0, -1.0)])

# Experimentos con resultados (no he puesto pausas porque se pausa sólo hasta que se cierre la gráfica que genera, se puede descomentar la pausa)
for w in condiciones_iniciales:
    wn, grafn = newton(w, gradf, hessf, f, max_iters)
    wg, grafg = gd(w, lr, gradf, f, max_iters)

    # Resultados obtenidos
    print('Punto de inicio:', w)
    print('Solución y valor del método de Newton:')
    print ('(x,y) = (', wn[0], ', ', wn[1],')')
    print ('f(x,y) = ',f(wn))
    print('Solución y valor del gradiente estocástico:')
    print ('(x,y) = (', wg[0], ', ', wg[1],')')
    print ('f(x,y) = ',f(wg))
    print()

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

    # Curva de decrecimiento de la función
    plt.plot(range(0,max_iters+1), grafn, 'bo', alpha=0.6, label='Newton')
    plt.plot(range(0,max_iters+1), grafg, 'ro', alpha=0.4, label='Grad. Desc.')
    plt.xlabel('Iteraciones')
    plt.ylabel('f(x,y)')
    plt.title('Punto de inicio: w = '+str(w))
    plt.legend()
    plt.show()

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


__author__ = 'Justin Niosi'

import numpy as np

def sigmoid(t):
    return 1.0 / (1.0 + np.exp(-t))

def sigmoid_derivative(t):
    # return np.exp(t) / np.square(np.exp(t) + 1)
    return sigmoid(t) * (1 - sigmoid(t))

def quadratic_cost(goal, actual):
    return np.sum(np.square(np.linalg.norm(goal - actual))) / (2 * len(goal))

def quadratic_cost_derivative(goal, actual):
    return actual[:len(goal)] - goal

class NeuralNetwork:

    def __init__(self, layers, max_neurons, rate, out_func=sigmoid, out_derivative=sigmoid_derivative,
                 cost_func=quadratic_cost, cost_derivative=quadratic_cost_derivative):
        self.layers = layers
        self.maxneurons = max_neurons
        self.rate = rate
        self.weights = np.zeros((self.layers, self.maxneurons, self.maxneurons))
        self.biases = np.zeros((self.layers, self.maxneurons))
        self.outfunc = out_func
        self.outderivative = out_derivative
        self.costfunc = cost_func
        self.costderivative = cost_derivative

    def feed_forward(self, inputs):
        values = np.zeros((self.layers, self.maxneurons))
        z_values = np.zeros((self.layers, self.maxneurons))
        values[0, :len(inputs)] = inputs
        for i in xrange(1, self.layers):
            z_values[i] = np.dot(values[i-1], self.weights[i])
            values[i] = self.outfunc(z_values[i] + self.biases[i])
        return np.array([values, z_values])

    def cost(self, goal, actual):
        return self.costfunc(goal, actual)

    def output_error(self, goal, actual, z_values):
        return self.costderivative(goal, actual) * self.outderivative(z_values[:len(goal)])

    def backpropagate(self, goal, feed_forward_output):
        output = np.zeros(self.biases.shape)
        cost_derivative = self.costderivative(goal, feed_forward_output[0][-1])
        output_derivative = self.outderivative(feed_forward_output[1][-1])
        output_error = cost_derivative * output_derivative
        output[-1] = output_error
        for i in xrange(self.layers - 1, 0, -1):
            weight_times_error = np.dot(self.weights[i].transpose(), output[i])
            out_derivative_z = self.outderivative(feed_forward_output[1][i - 1])
            output[i - 1] = np.dot(weight_times_error, out_derivative_z)
        return output

    def update_parameters(self, test_output):
        values, error = test_output
        self.biases -= self.rate * error
        values = np.roll(values, 1, axis=0).repeat(self.maxneurons, axis=0).reshape(self.weights.shape).transpose(0, 2, 1)
        error = error.repeat(self.maxneurons, axis=0).reshape(self.weights.shape)
        self.weights -= self.rate * (error + values)

    def run_test(self, input_values, goal):
        results = self.feed_forward(input_values)
        gradient = self.backpropagate(goal, results)
        return np.array([results, gradient])


import numpy as np

from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split

def fit_least_squares(X, y):
    """Fit ordinary least squares model to the data.

    Parameters
    ----------
    X : array, shape [N, D]
        (Augmented) feature matrix.
    y : array, shape [N]
        Regression targets.

    Returns
    -------
    w : array, shape [D]
        Optimal regression coefficients (w[0] is the bias term).

    """
    x_transposed=np.transpose(X)
    return np.matmul(np.matmul(np.linalg.inv(np.matmul(x_transposed,X)),x_transposed),y)

def fit_ridge(X, y, reg_strength):
    """Fit ridge regression model to the data.

    Parameters
    ----------
    X : array, shape [N, D]
        (Augmented) feature matrix.
    y : array, shape [N]
        Regression targets.
    reg_strength : float
        L2 regularization strength (denoted by lambda in the lecture)

    Returns
    -------
    w : array, shape [D]
        Optimal regression coefficients (w[0] is the bias term).

    """
    x_transposed = np.transpose(X)
    lamb=np.zeros((np.shape(X)[1],np.shape(X)[1]))
    np.fill_diagonal(lamb,reg_strength)
    return np.matmul(np.matmul(np.linalg.inv(np.matmul(x_transposed,X)+lamb),x_transposed),y)

def predict_linear_model(X, w):
    """Generate predictions for the given samples.

    Parameters
    ----------
    X : array, shape [N, D]
        (Augmented) feature matrix.
    w : array, shape [D]
        Regression coefficients.

    Returns
    -------
    y_pred : array, shape [N]
        Predicted regression targets for the input data.

    """
    return np.matmul(X,w)

def mean_squared_error(y_true, y_pred):
    """Compute mean squared error between true and predicted regression targets.

    Reference: `https://en.wikipedia.org/wiki/Mean_squared_error`

    Parameters
    ----------
    y_true : array
        True regression targets.
    y_pred : array
        Predicted regression targets.

    Returns
    -------
    mse : float
        Mean squared error.

    """
    n=np.shape(y_true)[0]
    return np.matmul(np.transpose(y_true-y_pred),y_true-y_pred)/n


import matplotlib.pyplot as plt
import numpy as np
from scipy.fftpack import ifft

Ns = 64
hNs = Ns//2

mY = np.zeros(hNs)
pY = np.zeros(hNs)
Y = np.zeros(Ns)
yw = np.zeros(Ns)
Y = np.zeros(Ns, dtype=complex)

k0 = 5
ph0 = 1.5
A0 = .8
mY[k0] = A0 * Ns
pY[k0] = ph0
Y[:hNs] = .5*mY*np.exp(1j*pY)
Y[hNs+1:] = Y[hNs-1:0:-1].conjugate()

plt.figure(1, figsize=(9, 5))
plt.subplot(3,1,1)
plt.plot(np.arange(hNs), mY, color='r', lw=1.5)
plt.axis([0,hNs-1,-1,Ns])
plt.title('mY; k0 = 5, A0 = .8, N = 64')

plt.subplot(3,1,2)
plt.plot(np.arange(hNs), pY, color='c', lw=1.5)
plt.axis([0,hNs-1,-.3, 2])
plt.title('pY; k0 = 5, theta0 = .1.5, N = 64')

y = np.real(ifft(Y))
yw[:hNs-1] = y[hNs+1:]
yw[hNs-1:] = y[:hNs+1]

plt.subplot(3,1,3)
plt.plot(np.arange(Ns), yw, 'b', lw=1.5)
plt.axis([0, Ns-1,-.9,.9])
plt.title('y; N = 64')

plt.tight_layout()
plt.savefig('sine-synthesis-periodic.png')
plt.show()


import numpy

EARTH_RADIUS = 1.0 # 6371000. # in metres
DEG2RAD = numpy.pi/180.

def lonLat2XYZ(p, radius):
    lam = p[0]*DEG2RAD
    the = p[1]*DEG2RAD
    rho = radius*numpy.cos(the)
    return  numpy.array([rho*numpy.cos(lam),
                         rho*numpy.sin(lam),
                         radius*numpy.sin(the)])

def lonLat2XYZArray(p, radius):
    lam = p[...,0]*DEG2RAD
    the = p[...,1]*DEG2RAD
    rho = radius*numpy.cos(the)
    xyz = numpy.zeros(p.shape, numpy.float64)
    xyz[..., 0] = rho*numpy.cos(lam) # x
    xyz[..., 1] = rho*numpy.sin(lam) # y
    xyz[..., 2] = radius*numpy.sin(the) # z
    return xyz

def getArcLengthArray(xyzA, xyzB, radius=EARTH_RADIUS):
    radiusSquare = radius*radius
    angle = numpy.arccos(  numpy.sum(xyzA*xyzB, axis=-1) / radiusSquare )
    return numpy.fabs(radius * angle)

def getArcLength(xyzA, xyzB, radius=EARTH_RADIUS):
    return abs( radius * numpy.arccos( xyzA.dot(xyzB)/radius**2 ) )

class PoleRotator(object):

    def __init__(self, deltaDeg=(0., 0.)):

        # transformation matrix
        alpha = numpy.pi * deltaDeg[1] / 180.
        beta = numpy.pi * deltaDeg[0] / 180.
        cos_alp = numpy.cos(alpha)
        sin_alp = numpy.sin(alpha)
        cos_bet = numpy.cos(beta)
        sin_bet = numpy.sin(beta)

        # http://gis.stackexchange.com/questions/10808/lon-lat-transformation
        rot_alp = numpy.array([[ cos_alp, 0., sin_alp],
                               [ 0.,      1., 0.     ],
                               [-sin_alp, 0., cos_alp]])
        rot_bet = numpy.array([[ cos_bet, sin_bet, 0.],
                               [-sin_bet, cos_bet, 0.],
                               [ 0.     , 0.,      1.]])
        self.transfMatrix = numpy.dot(rot_bet, rot_alp)

    def apply(self, lons, lats):

        lam = lons * DEG2RAD
        the = lats * DEG2RAD

        cos_the = numpy.cos(the)
        sin_the = numpy.sin(the)
        cos_lam = numpy.cos(lam)
        sin_lam = numpy.sin(lam)

        # to Cartesian
        rho = cos_the
        xx = rho * cos_lam
        yy = rho * sin_lam
        zz = sin_the

        # apply rotation
        xyz = numpy.zeros([3] + list(xx.shape), numpy.float64)
        xyz[0, ...] = xx
        xyz[1, ...] = yy
        xyz[2, ...] = zz
        xyzTransformed = numpy.tensordot(self.transfMatrix, xyz, axes=(0, 0))

        # back to lons and lats
        lonsNew = numpy.arctan2(xyzNew[1,...], xyzNew[0,...]) / DEG2RAD
        latsNew = numpy.arcsin(xyzNew[2,...]) / DEG2RAD

        # NOTE may need to apply dateline fix in some cases

        return lonsNew, latsNew


import numpy as np
from scipy import interpolate

import matplotlib.pyplot as plt

#x = np.arange(0, 2*np.pi+np.pi/4, 2*np.pi/8)
#y = np.sin(x)

ctr =np.array( [(3 , 1, 1), (2.5, 4, 2), (0, 1, 3), (-2.5, 4, 2),
                (-3, 0, 1.5), (-2.5, -4, 2), (0, -1, 4), (2.5, -4, 5), (3, -1, 4)])

x=ctr[:,0]
y=ctr[:,1]
z = ctr[:,2]

#x=np.append(x,x[0])
#y=np.append(y,y[0])

tck,u = interpolate.splprep([x,y],k=3,s=0)
u=np.linspace(0,1,num=50,endpoint=True)
out = interpolate.splev(u,tck)

plt.figure()
plt.plot(x, y, 'ro', out[0], out[1], 'b')
plt.legend(['Points', 'Interpolated B-spline', 'True'],loc='best')
plt.axis([min(x)-1, max(x)+1, min(y)-1, max(y)+1])
plt.title('B-Spline interpolation')
plt.show()

from mpl_toolkits import mplot3d

tck,u = interpolate.splprep([x,y,z],k=3,s=0)
u=np.linspace(0,1,num=50,endpoint=True)
out = interpolate.splev(u,tck)

fig = plt.figure()
ax = plt.axes(projection='3d')
# plt.figure()
plt.plot(x, y, z, 'ro')
plt.plot( out[0], out[1], out[2], 'b')
plt.legend(['Points', 'Interpolated B-spline', 'True'],loc='best')
# plt.axis([min(x)-1, max(x)+1, min(y)-1, max(y)+1])
plt.title('B-Spline interpolation')
plt.show()


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

from metropolis.metropolis import MetropolisAlgorithm

# Random generation according to normal distribution
np.random.seed(568)
x = np.random.normal(loc=0.0, scale=2.0, size=500)
print('Sampled mean and std: mean={:2.2f}, std={:2.2f}'.format(np.mean(x), np.std(x)))

lupost = lambda param: np.sum(stats.norm.logpdf(x, loc=param[0], scale=np.exp(param[1])))
metrop = MetropolisAlgorithm(lupost=lupost,
                             initial=np.array([-2, np.log(7)]),
                             scale=np.array([0.04, 0.04]),
                             burn_cont=100)

# Sample the distribution of parameters
result = metrop.run(batches=1000)

# second parameter requires transform
result.batch[:, 1] = np.exp(result.batch[:, 1])

means = [np.mean(result.batch[:, i]) for i in [0, 1]]
modes = [stats.mode(result.batch[:, i]).mode[0] for i in [0, 1]]

# Print results
print('Mean for parameters: mean={:2.2f}, std={:2.2f}'.format(*means))
print('Mode for parameters: mean={:2.2f}, std={:2.2f}'.format(*modes))
print('Accept rate is {:2.2f}'.format(result.accept))

# Plot simulated markov chains, the parameters
plt.figure()
for i in [0, 1]:
    ax = plt.subplot(1, 2, i + 1)
    ax.plot(result.batch[:, i])
plt.show()

# Plot histograms of the parameters
plt.figure()
for i in [0, 1]:
    ax = plt.subplot(1, 2, i + 1)
    ax.hist(result.batch[:, i])
plt.show()


import numpy as np
import matplotlib.pyplot as pyplot
import scipy.spatial.distance as sd
import sklearn.cluster as skc
import sklearn.metrics as skm
import scipy
import scipy
import sys
import os

sys.path.append(os.path.dirname(os.getcwd())+"/code_material_python")
from helper import *
from graph_construction.func import *
path = os.getcwd()

def build_laplacian(W, laplacian_normalization=""):
    D = np.zeros(W.shape)
    D_inv = np.zeros(W.shape)
    D_invsqrt = np.zeros(W.shape)
    for i in range(W.shape[0]):
        D[i,i] = np.sum(W[i,:])
        D_inv[i,i] = 1./np.sum(W[i,:])
        D_invsqrt[i,i] = np.sqrt(D_inv[i,i])
    if laplacian_normalization == "unn":
        return D - W
    elif laplacian_normalization == "sym":
        return np.eye(W.shape[0]) - D_invsqrt.dot(W).dot(D_invsqrt)
    elif laplacian_normalization == "rw":
        return np.eye(W.shape[0]) - D_inv.dot(W)

def spectral_clustering(L, chosen_eig_indices, num_classes=2):
    [E,U] = np.linalg.eig(L)
    idx = np.argsort(np.real(E))
    E = np.diag(E[idx])
    U = np.real(U[:,idx])
    normalization = np.linalg.norm(U[:,chosen_eig_indices], axis=0)
    Y = U[:,chosen_eig_indices] / normalization
    Y = skc.KMeans(num_classes).fit(Y).labels_
    return Y

def two_blobs_clustering():
    # load the data
    in_data =scipy.io.loadmat(path+'/data/data_2blobs')
    X = in_data['X']
    Y = in_data['Y']
    num_classes = len(np.unique(Y))

    k = 10
    var =  0.5

    laplacian_normalization = 'unn'; #either 'unn'normalized, 'sym'metric normalization or 'rw' random-walk normalization
    chosen_eig_indices =  [0,1]

    # build laplacian
    W, similarities = build_similarity_graph(X, var=var, k=k, eps=0)
    L = build_laplacian(W, laplacian_normalization=laplacian_normalization)
    Y_rec = spectral_clustering(L,chosen_eig_indices)
    plot_clustering_result(X, Y, L, Y_rec, skc.KMeans(num_classes).fit_predict(X), normalized_switch=0)

def choose_eig_function(eigenvalues):
    gap = [eigenvalues[i+1]-eigenvalues[i] for i in range(len(eigenvalues)-1)]
    sortedGapIdx = np.argsort(-abs(np.array(gap)))
    idx = -1
    maxGap = 0
    for i in range(len(sortedGapIdx)):
        if abs(gap[i])>= maxGap:
            idx = i
            maxGap = abs(gap[i])
    return range(idx)

def spectral_clustering_adaptative(L, num_classes=2):
    [E,U] = np.linalg.eig(L)
    idx = np.argsort(np.real(E))
    chosen_eig_indices = choose_eig_function(np.real(E[idx])[:15])
    E = np.diag(np.real(E[idx]))
    U = np.real(U[:,idx])
    Y = U[:,chosen_eig_indices] / np.linalg.norm(U[:,chosen_eig_indices], axis=0)
    Y = skc.KMeans(num_classes).fit(Y).labels_
    return Y

def find_the_bend():
    num_samples = 600

    [X, Y] = blobs(num_samples,4,0.03)

    num_classes = len(np.unique(Y))

    k = 10
    var =  0.5

    laplacian_normalization = 'unn'; #either 'unn'normalized, 'sym'metric normalization or 'rw' random-walk normalization

    # build the laplacian
    W, similarities = build_similarity_graph(X, var, k=k, eps=0)
    L = build_laplacian(W, laplacian_normalization=laplacian_normalization)

    [E,U] = np.linalg.eig(L)
    idx = np.argsort(np.real(E))
    E = E[idx]
    U = np.real(U[:,idx])
    eigenvalues = E[:15]
    chosen_eig_indices = choose_eig_function(eigenvalues) # indices of the ordered eigenvalues to pick
    normalization = np.linalg.norm(U[:,chosen_eig_indices], axis=0)
    Y_rec = U[:,chosen_eig_indices] / normalization
    Y_rec = skc.KMeans(num_classes).fit_predict(Y_rec)

    plot_the_bend(X, Y, L, Y_rec, eigenvalues)

def two_moons_clustering():
    in_data =scipy.io.loadmat(path+'/data/data_2moons')
    X = in_data['X']
    Y = in_data['Y']
    num_classes = len(np.unique(Y))

    k = 5
    eps = 0.5
    var = 0.5

    laplacian_normalization = 'sym'; #either 'unn'normalized, 'sym'metric normalization or 'rw' random-walk normalization
    chosen_eig_indices = [0, 1] # indices of the ordered eigenvalues to pick

    W, similarities = build_similarity_graph(X, var, k=k, eps=eps)
    L = build_laplacian(W, laplacian_normalization=laplacian_normalization)
    Y_rec = spectral_clustering(L, chosen_eig_indices)

    plot_clustering_result(X, Y, L, Y_rec,skc.KMeans(num_classes).fit_predict(X))

def point_and_circle_clustering():
    in_data =scipy.io.loadmat(path+'/data/data_pointandcircle')
    X = in_data['X']
    Y = in_data['Y']
    num_classes = len(np.unique(Y))

    k = 15
    eps = 0.
    var = 0.5; # exponential_euclidean's sigma^2

    laplacian_normalization = 'rw'; #either 'unn'normalized, 'sym'metric normalization or 'rw' random-walk normalization
    chosen_eig_indices = [0, 1] # indices of the ordered eigenvalues to pick

    #  build the laplacian
    W, similarities = build_similarity_graph(X, var, k=k, eps=eps)
    L_unn = build_laplacian(W, laplacian_normalization='unn')
    L_norm = build_laplacian(W, laplacian_normalization='rw')

    # Distribution of nodes' degrees/connections
    plt.hist(np.sum((L_unn!=0).astype(int),axis=0))
    plt.xlabel("Number of edges (connectivity)", fontsize=16)
    plt.ylabel("Number of nodes", fontsize=16)
    plt.show()

    Y_unn = spectral_clustering(L_unn, chosen_eig_indices)
    Y_norm = spectral_clustering(L_norm, chosen_eig_indices)
    plot_clustering_result(X, Y, L_unn, Y_unn, Y_norm, 1);

def parameter_sensitivity(param='k'):
    num_samples = 500;

    var = 0.5

    laplacian_normalization = 'unn'; #either 'unn'normalized, 'sym'metric normalization or 'rw' random-walk normalization
    chosen_eig_indices =  [0, 1]
    if (param == 'k'):
        parameter_candidate = range(1,50,3)   # the number of neighbours for the graph or the epsilon threshold
    else:
        parameter_candidate = np.linspace(0.05,1,20)
    parameter_performance=[]

    for p in parameter_candidate:
        print(param+ " = " + str(p))
        [X, Y] = two_moons(num_samples,1,0.02)
        num_classes = len(np.unique(Y))
        if (param=='k'):
            W, similarities = build_similarity_graph(X, k=p)
        else:
            W, similarities = build_similarity_graph(X, eps=p)
        L =  build_laplacian(W, laplacian_normalization=laplacian_normalization)

        Y_rec = spectral_clustering(L, chosen_eig_indices, num_classes)
        parameter_performance+= [skm.adjusted_rand_score(Y,Y_rec)]

    plt.figure()
    plt.plot(parameter_candidate, parameter_performance)
    plt.title('parameter sensitivity')
    if param=='k':
        plt.xlabel("k", fontsize=16)
    else:
        plt.xlabel("epsilon", fontsize=16)
    plt.ylabel("Performance", fontsize=16)
    plt.show()

two_blobs_clustering()
find_the_bend()
two_moons_clustering()
point_and_circle_clustering()
parameter_sensitivity('k')
parameter_sensitivity('eps')


from numpy import array, random, dot, exp, linalg, zeros
from typing import List

def sigmoid(x):
    return 1.0 / (1.0 + exp(-x))

# Derivative of the sigomid function.
# x is the output of the sigmoid function. You can see it as x = sigmoid(y).
def _dvsigmoid(x: array) -> array:
    return x * (1 - x)

# Derivative of the sigmoid function
def dvsigmoid(x: array) -> array:
    return _dvsigmoid(sigmoid(x))

# Error or cost
def cost(x: array, y: array) -> array:
    return (linalg.norm(y - x) ** 2) / 2

def dvcost(x: array, y: array) -> array:
    return (x - y)

class Network:
    def __init__(self, dims: List[int]):
        random.seed(5)

        self.n_layers = len(dims)
        self.dims = dims
        # randomly initialize biases
        self.B = [2 * random.random((j, 1)) - 1 for j in dims[1:]]
        # randomly initialize weights
        self.W = [
            2 * random.random((j, i)) - 1
            for j, i in zip(dims[1:], dims[:-1])
        ]
        self.lr = 1

    # Return the ouput of the network given x input
    def feedforward(self, x: array) -> List[array]:
        L = [0] * self.n_layers
        L[0] = x
        for i in range(self.n_layers - 1):
            w, b, a = self.W[i], self.B[i], L[i]
            L[i + 1] = sigmoid(dot(w, a) + b)
        return L

    def backprop(self, tx: array, ty: array) -> tuple:
        # Initialize empty lists of n_layers - 1 size
        db = [0] * (self.n_layers - 1)
        dw = [0] * (self.n_layers - 1)

        # Output of each layer
        L = self.feedforward(tx)

        # Direction to move to reduce the cost times
        # the rate of change of the sigmoid function at a certain layer
        l_delta = dvcost(L[-1], ty) * _dvsigmoid(L[-1])

        db[-1] = l_delta
        dw[-1] = dot(l_delta, L[-2].T)

        # Same as - for i in reversed(range(1, self.num_layers)):
        for i in range(self.n_layers - 2, 0, -1):
            # How sensitive the function is to previous weights
            l_delta = dot(self.W[i].T, l_delta) * _dvsigmoid(L[i])

            db[i - 1] = l_delta
            dw[i - 1] = dot(l_delta, L[i - 1].T)

        return dw, db

    """
    Update weights and biases given a batch
    """
    def update_batch(self, batch, batch_size) -> None:
        sdW = [zeros(w.shape) for w in self.W]
        sdB = [zeros(b.shape) for b in self.B]

        """
        sdWB = array([self.backprop(x, y) for x, y in batch])
        """
        # Sum of all the delta weights and biases calculated from the batch
        for tx, ty in batch:
            dW, dB = self.backprop(tx, ty)

            for i in range(self.n_layers - 1):
                sdW[i] += dW[i]
                sdB[i] += dB[i]

        temp_calc = float(self.lr) / float(batch_size)
        # basically -learning rate * mean(delta weight) or
        # W[i] = W[i] - (learning_rate * sum_delta_weights) / n
        for i in range(self.n_layers - 1):
            self.W[i] += -temp_calc * sdW[i]
            self.B[i] += -temp_calc * sdB[i]

    """
    Train the neural network using mini-batch stochastic gradient descent.
    training_data -> List of tuples (x, y)
        x being the training inputs and
        y being the expect outputs
    """
    def SGD(self,
            tdata,
            epochs: int,
            batch_size: int,
            batch_n: int,
            learning_rate: float):
        self.lr = learning_rate

        for j in range(epochs):
            random.shuffle(tdata)

            # array of batch_n x batch_size shape
            batches = (
                tdata[k:k+batch_size]
                for k in range(0, batch_n * batch_size, batch_size)
             )

            for batch in batches:
                self.update_batch(batch, batch_size)

    def accuracy(self, test_data):
        n = len(test_data)
        correct = 0
        for i in range(n):
            tx, ty = test_data[i]

            a = self.feedforward(tx)[-1]
            correct += (a.argmax() == ty.argmax()).all()

        return correct / n

if __name__ == '__main__':
    net_dims = [3, 4, 1]
    net = Network(net_dims)

    tX = [array([[0], [0], [1]]),
          array([[0], [1], [1]]),
          array([[1], [0], [1]]),
          array([[0], [1], [0]]),
          array([[1], [1], [1]])]
    tY = [
        array([[0]]),
        array([[1]]),
        array([[1]]),
        array([[1]]),
        array([[0]])
    ]

    net.SGD(list(zip(tX, tY)), 1000, 5, 1, 6)

    x = array([[1], [0], [1]])
    y = net.feedforward(x)[-1]
    print(y)


import numpy as np
import sys, os
sys.path.append(os.pardir)
from common.activation_functions import sigmoid, identity_function

'''
신경망의 내적
간단한 레이어간의 내적 구현해보기
'''
# X=np.array([1,2])
# print(X.shape)
# W=np.array([[1,3,5],[2,4,6]])
# print(W)
# print(W.shape)
# Y=np.dot(X,W)
# print(Y)

'''
3층 신경망 구현하기
'''
# X=np.array([1.0, 0.5])
#
# W1=np.array([[0.1,0.3,0.5],[0.2,0.4,0.6]])
# B1=np.array([0.1,0.2,0.3])
# print(W1.shape)
# print(X.shape)
# print(B1.shape)
# A1=np.dot(X,W1)+B1
# Z1=sigmoid(A1)
# print(A1)
# print(Z1)
#
# W2=np.array([[.1, .4],[.2,.5],[.3,.6]])
# B2=np.array([.1, .2])
# print(Z1.shape)
# print(W2.shape)
# print(B2.shape)
# A2=np.dot(Z1,W2)+B2
# Z2=sigmoid(A2)
# print(A2)
# print(Z2)
#
# W3=np.array([[.1,.3],[.2,.4]])
# B3=np.array([.1,.2])
# print(Z2.shape)
# print(W3.shape)
# print(B3.shape)
# A3=np.dot(Z2,W3)+B3
# Y=identity_function(A3)
# print(A3)
# print(Y)

'''
구현 정리
'''
def init_network():
    network = {}
    network['W1'] = np.array([[.1,.3,.5],[.2,.4,.6]])
    network['b1'] = np.array([.1, .2, .3])
    network['W2'] = np.array([[.1, .4],[.2,.5],[.3,.6]])
    network['b2'] = np.array([.1,.2])
    network['W3'] = np.array([[.1,.3],[.2,.4]])
    network['b3'] = np.array([.1,.2])

    return network

def forward(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']

    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = identity_function(a3)

    return y

network = init_network()
x = np.array([1.0, .5])
y = forward(network, x)
print(y)


"""
Linear algebra functions (matrix multiplication, vector length etc.)
"""

import numpy as np

def gramian(matrix):
    """
    Parameters
    ----------
    matrix : numpy.ndarray
        A matrix

    Returns
    -------
    numpy.ndarray
        The Gramian of `matrix`.
    """

    return np.transpose(matrix).dot(matrix)

def dot_product(vector1, vector2):
    """
    Calculates a dot product of two vectors.

    Parameters
    ----------
    vector1, vector2 : numpy.ndarray
        Two n by 1 matrices.

    Returns
    -------
    float
        The dot product of two matrices
    """

    return np.dot(np.transpose(vector1), vector2)[0, 0]

def matrix_size(matrix):
    """
    Parameters
    ----------
    matrix : numpy.ndarray
        A matrix.

    Returns
    -------
    tuple of two integers
        Size of a matrix. First integer is the number of rows.
    """

    rows = len(matrix)

    if rows > 0:
        columns = len(matrix[0])
    else:
        columns = 0

    return (rows, columns)


import matplotlib
matplotlib.rcParams = matplotlib.rc_params_from_file('../../matplotlibrc')

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn import decomposition
from scipy import linalg as la

import solutions

iris = load_iris()

def iris_base():
    fig = plt.figure(figsize=(10, 10))
    ax = fig.add_subplot(111, aspect='equal')

    plt.plot(iris.data[50:150,0], iris.data[50:150,2], 'k.')
    plt.xlim([2, 8])
    plt.ylim([2, 8])
    plt.xlabel(r"Sepal Length (cm)")
    plt.ylabel(r"Petal Length (cm)")

    return fig

def ibase():
    iris_base()
    plt.savefig('iris0.pdf')
    plt.clf()

def iris1():
    fig = iris_base()

    pca = decomposition.PCA(n_components=2)
    pca.fit(iris.data[50:150, np.array([0, 2])])
    mean = np.mean(iris.data[50:150, np.array([0, 2])], 0)
    stds = np.std(iris.data[50:150, np.array([0, 2])], 0)
    components = pca.components_

    plt.quiver(mean[0], mean[1], 1.5 * stds[0], 0, scale_units='xy', angles='xy', scale=1)
    plt.quiver(mean[0], mean[1], 0, 1.5 * stds[1], scale_units='xy', angles='xy', scale=1)
    plt.savefig('iris1.pdf')
    plt.clf()

def iris2():
    fig = iris_base()

    pca = decomposition.PCA(n_components=2)
    pca.fit(iris.data[50:150, np.array([0, 2])])
    mean = np.mean(iris.data[50:150, np.array([0, 2])], 0)
    stds = np.std(iris.data[50:150, np.array([0, 2])], 0)
    components = pca.components_
    variance_ratio = pca.explained_variance_ratio_

    plt.quiver(mean[0], mean[1],
               -2 * variance_ratio[0] * components[0,0],
               -2 * variance_ratio[0]*components[0,1],
               scale_units='xy', angles='xy', scale=1)
    plt.quiver(mean[0], mean[1],
               5 * variance_ratio[1] * components[1,0],
               5 * variance_ratio[1] * components[1,1],
               scale_units='xy', angles='xy', scale=1)
    plt.savefig('iris2.pdf')
    plt.clf()

def iris_pca_scree():
    #First make PCA plot of iris dataset
    U, S, Vh = la.svd(iris.data, full_matrices=False)
    X = U.dot(np.diag(S))

    setosa = iris.target==0
    versicolor = iris.target==1
    virginica = iris.target==2
    p1, p2 = X[:,0], X[:,1]
    plt.scatter(p1[setosa], p2[setosa], marker='.', color='blue', label='Setosa')
    plt.scatter(p1[versicolor], p2[versicolor], marker='.', color='red', label='Versicolor')
    plt.scatter(p1[virginica], p2[virginica], marker='.', color='green', label='Virginica')
    plt.xlabel("First Principal Component")
    plt.ylabel("Second Principal Component")
    plt.legend(loc=2)
    plt.savefig('iris_pca.pdf')
    plt.clf()

    L = S**2
    scree = solutions.scree(L/L.sum(dtype=float))
    scree.savefig('iris_scree.pdf')
    plt.clf()

if __name__ == "__main__":
    ibase()
    iris1()
    iris2()
    iris_pca_scree()


from scipy.stats import norm
from scipy.stats import zipf
import sys
sys.path.append ("../tableformula")
from tableformula import *
from tableformulagraph import *

def generate_n_obs_zipf (tail_index, n) :
    return list(zipf.rvs(tail_index, size=n))

def diff_std_deviation (px, py) :
    s = px*(1-px) + py*(1-py)
    return px, py, s**0.5

def pvalue (diff, std, N) :
    theta = abs(diff)
    bn = (2*N)**0.5 * theta / std
    pvalue = (1 - norm.cdf(bn))*2
    return pvalue

def draw_heavy_tail (sample, imagename) :
    table   = TableFormula (["obs"], [ [_] for _ in sample ] )
    avg,std = table.avg_std (lambda v : v["obs"])
    print ("avg,std", avg,std)
    std = 1

    normal  = norm.rvs (size = len(sample))
    normal  = [ x*std  for x in normal ]
    nortbl  = TableFormula (["obs"], [ [_] for _ in normal ] )
    nortbl.addc ("iobs", lambda v : int(v ["obs"] * 10))
    histon  = nortbl.groupby ( lambda v :v["iobs"],
                            [ lambda v : v["iobs"] ],
                            ["value", "nb"],
                            [ len ] )
    histon.sort (lambda v : v["nb"], reverse = True)

    histo   = table.groupby ( lambda v :v["obs"],
                            [ lambda v : v["obs"] ],
                            ["value", "nb"],
                            [ len ] )

    histo.sort (lambda v : v["nb"], reverse = True)
    histo.add_column_index("index", 1)

    vec  = list (histon.select (lambda v : v ["nb"]))
    vec += [0,] * len(histo)
    histo.add_column_vector("nb_normal", vec [:len(histo) ] )

    histo.addc ("log(index)", lambda v : math.log(v ["index"]) / math.log(10) )
    histo.addc ("log(nb)", lambda v : math.log(v ["nb"]) / math.log(10) )
    histo.addc ("log(nb_normal)", lambda v : math.log(v ["nb_normal"]) / math.log(10) if v["nb_normal"] > 0 else 0)
    histo = TableFormulaGraph (histo)
    histo.graph_XY ( [
            [ lambda v: v["log(index)"], lambda v: v["log(nb)"], "Zipf"],
            [ lambda v: v["log(index)"], lambda v: v["log(nb_normal)"], "Gauss"],
                        ],
                     outImage = imagename,
                     marker=False, linkPoint=True)

def draw_variancen (sample, imagename) :
    avg = 0.
    std = 0.
    n   = 0.
    w   = 1.
    add = []
    for i,x in enumerate(sample) :
        x    = float (x)
        avg += x * w
        std += x*x * w
        n   += w
        val  = (std/n - (avg/n)**2)**0.5
        add.append ( [ i, avg/n, val] )

    print add[-1]
    table = TableFormulaGraph ( ["index", "avg(n)", "std(n)"], add)
    table.graph_XY ( [
            [ lambda v: v["index"], lambda v: v["avg(n)"], "avg(n)"],
            [ lambda v: v["index"], lambda v: v["std(n)"], "std(n)"],
                        ],
                     outImage = imagename,
                     marker=False, linkPoint=True)

def hill_estimator (sample) :
    sample = list(sample)
    sample.sort(reverse=True)
    end = len(sample)/10
    end = min(end,100)
    s = 0.
    res = []
    for k in range (0,end) :
        s += math.log(sample[k])
        h = (s - (k+1)*math.log(sample[k+1]))/(k+1)
        h = 1./h
        res.append( [k, h] )
    return res

def draw_hill_estimator (sample, imagename) :
    res = hill_estimator(sample)
    table = TableFormulaGraph (["d", "hill"], res )
    table.graph_XY ( [
            [ lambda v: v["d"], lambda v: v["hill"], "Hill"],
                        ],
                     outImage = imagename,
                     marker=False, linkPoint=True)

def generate_series ( Ndays, tail_index, N) :
    res = [ ]
    total = [ ]
    for i in range(0,Ndays) :
        sample = generate_n_obs_zipf(tail_index, N)
        total.extend(sample)
        dis = { }
        for t in total : dis[t] = 0
        res.append( len(dis) )
    return res

def std (l) :
    m = sum(l)
    v = sum ( [_*_ for _ in l ] )
    m = m*1. / len(l)
    v = v*1. / len(l)
    return (v - m*m)**0.5

if __name__ == "__main__" :
    sys.path.append("../tableformula")
    from tableformula import *
    TableFormula = TableFormulaCore

    # mix
    tail_index  = 3
    N           = 100
    Ndays       = 200

    values = [ ]
    label  = None
    for k in range (0,50) :
        print k
        series      = generate_series( Ndays, tail_index, N)
        if label == None :
            label = [ "d%d" % (k+1) for k in range(0,len(series)) ]
        values.append (series)

    table = TableFormula (label, values)
    table = table.transpose (labelAsRow = False)
    table.addc ("ave", lambda v : sum( v.values() )*1.0 / len(v) )
    table.addc ("dev", lambda v : std( v.values() ) )

    print table

    if False :
        draw_heavy_tail(sample, "distribution_zipf_%d.png" % N)
        draw_variancen(sample, "std deviation after n obs.png")
        draw_hill_estimator(sample, "hill.png")

        TableFormulaGraph.ShowLastGraph()


# -*- coding: utf-8 -*-
"""
Created on Tue Nov 27 15:45:40 2018

@author: Emanuele

Activation functions: provides both the activations functions and the dictionary
 to easy call them.
"""

import numpy as np

def linear(z):

    return z;

def exp(z):

    return np.exp(z)

def tanh(z):

    return (np.exp(z)-np.exp(-z))/(np.exp(z)+np.exp(-z))

def relu(z):

    return np.where(z > 0, z, 0.)

def leaky_relu(z):

    return np.where(z > 0, z, z * 0.01)

dict_activations = { 'linear': linear,
                     'exp': exp,
                     'tanh': tanh,
                     'relu': relu,
                     'leaky_relu': leaky_relu
        }


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

# In[41]:

# Quantile regression
# Step-1. Load libraries
from __future__ import print_function
#get_ipython().run_line_magic('matplotlib', 'inline')
import patsy
import numpy as np
import pandas as pd
import statsmodels.api as sm
import statsmodels.formula.api as smf
import matplotlib.pyplot as plt
from statsmodels.regression.quantile_regression import QuantReg
import seaborn as sns
import os
sns.set_style('whitegrid')

# Step-2. Import data
os.chdir('/Users/pauline/Documents/Python')
data = pd.read_csv("Tab-Morph.csv")

# Step-3. Least Absolute Deviation
mod = smf.quantreg('profile ~ sedim_thick', data)
res = mod.fit(q=.5)
print(res.summary())

# Step-4. Placing the quantile regression results in a Pandas DataFrame, and the OLS results in a dictionary
quantiles = np.arange(.05, .96, .1)
def fit_model(q):
    res = mod.fit(q=q)
    return [q, res.params['Intercept'], res.params['sedim_thick']] +             res.conf_int().loc['sedim_thick'].tolist()

models = [fit_model(x) for x in quantiles]
models = pd.DataFrame(models, columns=['q', 'a', 'b','lb','ub'])

ols = smf.ols('profile ~ sedim_thick', data).fit()
ols_ci = ols.conf_int().loc['sedim_thick'].tolist()
ols = dict(a = ols.params['Intercept'],
           b = ols.params['sedim_thick'],
           lb = ols_ci[0],
           ub = ols_ci[1])

print(models)
print(ols)

# Step-5.
x = np.arange(data.sedim_thick.min(), data.sedim_thick.max(), 5)
get_y = lambda a, b: a + b * x

fig, ax = plt.subplots(figsize=(8, 6))

for i in range(models.shape[0]):
    y = get_y(models.a[i], models.b[i])
    ax.plot(x, y, linestyle='dotted', color='grey')

y = get_y(ols['a'], ols['b'])

ax.plot(x, y, color='red', label='OLS')
ax.scatter(data.sedim_thick, data.profile, alpha=.5, c='#00a381', s=70)
ax.set_xlim((40, 145))
ax.set_ylim((0, 25))
legend = ax.legend()
ax.set_xlabel('Sediment thickness, m', fontsize=14)
ax.set_ylabel('Profile, nr.', fontsize=14);

plt.title("Mariana Trench: Quantile regression for all the data set \nof sediment thickness by 25 bathymetric profiles", fontsize=14)
plt.annotate('E', xy=(-0.01, 1.06), xycoords="axes fraction", fontsize=18,
           bbox=dict(boxstyle='round, pad=0.3', fc='w', edgecolor='grey', linewidth=1, alpha=0.9))
plt.show()

# In[ ]:

import numpy,import statsmodels,from statsmodels


import mobula.layers as L
import numpy as np

def test_sigmoid():
    X = ((np.arange(10000) - 5000) / 1000.0).reshape((-1, 1, 1, 1))
    data = L.Data(X, "data")
    data.reshape()
    l = L.Sigmoid(data)
    l.reshape()
    assert l.Y.shape == X.shape
    l.forward()
    l.dY = np.random.random(l.Y.shape) * 10
    l.backward()

    enx = np.exp(-X)
    assert np.allclose(l.Y.ravel(), (1.0 / (1.0 + enx)).ravel())
    assert np.allclose(l.dX.ravel(), (enx / np.square(1 + enx) * l.dY).ravel())

def test_relu():
    X = ((np.arange(10000) - 5000) / 1000.0).reshape((-1, 1, 1, 1))
    data = L.Data(X, "data")
    data.reshape()
    l = L.ReLU(data)
    l.reshape()
    assert l.Y.shape == X.shape
    l.forward()
    l.dY = np.random.random(l.Y.shape) * 10
    l.backward()
    Y = np.zeros(X.shape)
    b = (X > 0)
    Y[b] = X[b]
    dX = np.zeros(X.shape)
    dX[b] = l.dY[b]
    '''
    d = (l.dX != dX)
    print (l.dX[d], dX[d])
    '''
    assert np.allclose(l.Y.ravel(), Y.ravel())
    assert np.allclose(l.dX.ravel(), dX.ravel())

def test_selu():
    X = ((np.arange(10000) - 5000) / 1000.0).reshape((-1, 1, 1, 1))
    data = L.Data(X, "data")
    data.reshape()
    l = L.SELU(data)
    y = l.eval()
    ty = np.zeros(X.shape)
    ty[X > 0] = l.scale * X[X>0]
    ty[X<=0] = l.scale * (l.alpha * np.exp(X[X<=0]) - l.alpha)
    assert np.allclose(y, ty)
    l.dY = np.random.random(l.Y.shape)
    l.backward()
    dX = np.zeros(X.shape)
    dX[X > 0] = l.scale
    dX[X <= 0] = l.scale * l.alpha * np.exp(X[X<=0])
    dX *= l.dY
    assert np.allclose(dX, l.dX)

def test_PReLU():
    X = ((np.arange(10000) - 5000) / 1000.0).reshape((-1, 1, 1, 1))
    data = L.Data(X, "data")
    data.reshape()
    l = L.PReLU(data)
    y = l.eval()
    ty = np.zeros(X.shape)
    ty[X>0] = X[X>0]
    ty[X<=0] = l.alpha * X[X<=0]
    assert np.allclose(y, ty)
    l.dY = np.random.random(l.Y.shape)
    l.backward()
    dX = np.zeros(X.shape)
    dX[X>0] = 1
    dX[X<=0] = l.alpha
    dX *= l.dY
    print (dX, l.dX)
    assert np.allclose(dX, l.dX)

def test_tanh():
    X = ((np.arange(10000) - 5000) / 1000.0).reshape((-1, 1, 1, 1))
    data = L.Data(X, "data")
    data.reshape()
    l = L.Tanh(data)
    y = l.eval()
    p = np.exp(X)
    n = np.exp(-X)
    ty = (p - n) / (p + n)
    assert np.allclose(y, ty)
    l.dY = np.random.random(l.Y.shape)
    l.backward()
    dX = 1.0 - np.square(p - n) / np.square(p + n)
    dX *= l.dY
    assert np.allclose(dX, l.dX)


''' Heat equation '''

import numpy as np
import networkx as nx
import pdb
import random

import gds

def heat_grid(n = 10, steady_state=False) -> gds.node_gds:
	G = gds.square_lattice(n, n)
	temp = gds.node_gds(G)
	if steady_state:
		''' Steady-state version (for comparison) '''
		temp.set_evolution(cost=lambda t, y: temp.laplacian(y))
	else:
		temp.set_evolution(dydt=lambda t, y: temp.laplacian(y))
	return temp

def grid_const_boundary(steady_state=False) -> gds.node_gds:
	n = 7
	temp = heat_grid(n=n, steady_state=steady_state)
	temp.set_constraints(dirichlet = lambda x: 1.0 if (0 in x or (n-1) in x) else None)
	return temp

def grid_mixed_boundary(steady_state=False) -> gds.node_gds:
	n = 10
	temp = heat_grid(n=n, steady_state=steady_state)
	def dirichlet(t, x):
		if x[0] == 0 or x[0] == n-1:
			return 0.5
		elif x[1] == 0:
			return 1.0
		return None
	def neumann(t, x):
		if x[1] == n-1 and x[0] not in (0, n-1):
			return -0.1
		return None
	temp.set_constraints(dirichlet=dirichlet, neumann=neumann)
	return temp

def grid_sinus_boundary(steady_state=False, phi=0) -> gds.node_gds:
	n = 10
	temp = heat_grid(n=n, steady_state=steady_state)
	def dirichlet(t, x):
		if x[0] == 0:
			return np.sin(t+x[1]/4+phi)**2
		elif x[0] == n-1:
			return 0.
		return None
	temp.set_constraints(dirichlet=dirichlet)
	return temp

def grid_tv_boundary():
	G = gds.square_lattice(10, 10)
	temperature = gds.node_gds(G)
	temperature.set_evolution(dydt=lambda t, y: temperature.laplacian())
	temperature.set_constraints(dirichlet=gds.combine_bcs(
		lambda x: 0 if x[0] == 9 else None,
		lambda t, x: np.sin(t+x[1]/4)**2 if x[0] == 0 else None
	))
	gds.render(temperature, title='Heat equation with time-varying boundary')

def grid_linear(steady_state=False) -> gds.node_gds:
	n = 10
	temp = heat_grid(n=n, steady_state=steady_state)
	def dirichlet(x):
		if x[0] == 0:
			return 1.0
		elif x[0] == n-1:
			return 0.
		return None
	temp.set_constraints(dirichlet=dirichlet)
	return temp

def heat_test():
	G = gds.grid_graph(10, 10)
	temp1 = gds.node_gds(G)
	x = (5,5)
	i = temp1.X[x]
	B = temp1.incidence.copy().todense()
	B[i][B[i] < 0] = 0
	temp1.set_evolution(dydt=lambda t, y: -B@B.T@y)
	temp1.set_initial(y0=lambda n: 1.0 if n == x else 0.0)
	temp2 = gds.node_gds(G)
	temp2.set_evolution(dydt=lambda t, y: temp2.laplacian(y))
	temp2.set_constraints(dirichlet={x: 1.0})
	return temp1, temp2

def heat_free_lr():
	temp = heat_grid(10)
	temp.set_constraints(dirichlet=gds.combine_bcs(
		lambda x: 0. if x[1] == 9 else None,
		lambda x: 1. if x[1] == 0 else None,
	))
	gds.render(temp)

if __name__ == '__main__':
	# Use coupling to visualize multiple PDEs simultaneously
	# p1 = grid_linear(steady_state=True)
	# p3 = grid_sinus_boundary(steady_state=True)
	# p4 = grid_sinus_boundary(steady_state=True, phi=np.pi/4)

	# t1, t2 = heat_test()

	# sys = gds.couple({
		# 'heat0': p1,
		# 'heat1': t1,
		# 'heat2': t2
	# })

	# G = nx.random_geometric_graph(200, 0.125)
	# p5 = gds.node_gds(G)
	# p5.set_evolution(dydt=lambda t, y: 10*p5.laplacian())
	# p5.set_constraints({random.randint(0, 200): 1.0 for _ in range(10)})

	# gds.render(p5, title='Diffusion on a random geometric graph')
	# gds.render(sys, dynamic_ranges=True)

	heat_free_lr()


import numpy as np
import matplotlib.pyplot as plt

class PayOff:
    def __init__(self, TheOptionsType_, Strike_):
        '''
        Inputs:
        =========
        TheOptionsType_: string (European call, European put, Binary call, Binary put)
        Strike_: float strike price
        '''

        self.__TheOptionsType = TheOptionsType_
        self.__Strike = Strike_

    def __call__(self,spot):
        # Overloading the ( ) operator
        '''
        inputs:
        =========
        spot: numpy array of spot prices

        returns:
        =========
        payoff value for each option
        '''

        if self.__TheOptionsType == 'European call':
            return np.maximum(spot - self.__Strike,0)
        elif self.__TheOptionsType == 'European put':
            return np.maximum(self.__Strike - spot,0)
        elif self.__TheOptionsType == 'Binary call':
            return np.piecewise(spot, [spot < self.__Strike, spot >= self.__Strike], [0, 1])
        elif self.__TheOptionsType == 'Binary put':
            return np.piecewise(spot, [spot <= self.__Strike, spot > self.__Strike], [1, 0])
        else:
            raise Exception('Unknown option type found.')

def GBM_fd(S0, r, d, sigma, T, num_steps = 50, num_paths = 1, plot = False, seed = None):
    '''
    Simulate Geometric Brownian Motion Stochastic Differential Equation using Euler'Maruyama method (finite difference)
    to calculate terminal stock price

    inputs:
    ===========

    S0: initial stock price
    r: risk-free interest rate
    d: dividend
    sigma: volatility
    T: time to maturity
    num_steps: numer of discretization steps
    num_paths: number of paths (integer)
    plot: plot of all paths generated
    seed: controls the random number generator np.random.RandomState().standard_normal()

    returns:
    =========
    numpy array of terminal stock prices of all paths
    '''

    dt = T / num_steps

    if num_paths == 1:
        S_path = [0] * (num_steps + 1)
    else:
        S_path = np.zeros((num_steps + 1, num_paths))

    S_path[0] = S0
    standard_normal_array = np.random.RandomState(seed).standard_normal((num_steps, num_paths))

    for i in range(1, num_steps + 1):
        S_path[i] = S_path[i-1] + r * S_path[i-1] * dt + S_path[i-1] * sigma * np.sqrt(dt) * standard_normal_array[i-1]

    if plot:
        plt.figure(figsize= (10,6))
        plt.plot(S_path)
        plt.xlabel('number of discretization steps')
        plt.ylabel('Stock price');

    return S_path[-1]

def GBM_formula(S0, mu, d, sigma, T, num_paths = 1, seed = None):
    '''
    Simulate Geometric Brownian Motion using analytical formula

    inputs:
    ===========

    S0: initial stock price
    mu: drift
    d: dividend
    sigma: volatility
    T: time to maturity
    num_paths: number of paths (integer)
    seed: Control normal distribution generation

    returns
    ===========

    numpy array containing stock price(s) at time T
    '''

    return S0 * np.exp((mu - d - 0.5 * sigma ** 2) * T + sigma * np.sqrt(T) * np.random.RandomState(seed).standard_normal(num_paths))

def monte_carlo(payoff):
    '''
    Monte Carlo method:
    1. Average all payoffs at time T
    2. Discount the average using continuously compounded risk-free interest rate

    inputs:
    ===========

    payoff: 1D numpy array of payoffs

    returns
    ===========
    integer approximate price of an option
    '''

    return np.mean(payoff)

def black_scholes_monte_carlo_pricer(option_type, S0, K, r, d, sigma, T, num_steps = 100, num_paths = 20, full_list = False, seed = None):
    '''
    Apply Monte Carlo method to price Black Schole option

    inputs:
    ==========

    option_type: string (European call, European put, Binary call, Binary put)
    S0: initial stock price
    K: strike price
    r: risk-free interest rate
    d: dividend
    sigma: volatility
    T: time to maturity
    num_steps: numer of discretization steps
    num_paths: int number of paths
    full_list: boolean return full list of monte carlo values if True, otherwise return the last value
    seed: None or int

    returns:
    ==========

    Black-Scholes price of the option using monte carlo method
    '''

    if not full_list:
        ST = GBM_fd(S0, r, d, sigma, T, num_steps, 2**num_paths, False, seed)
        payoff = np.exp(- r * T) * PayOff(option_type, K)(ST)
        return monte_carlo(payoff)

    mc = [0] * num_paths

    for num_path in range(1, num_paths + 1):
        ST = GBM_fd(S0, r, d, sigma, T, num_steps, 2**num_path, False, seed)
        payoff = np.exp(- r * T) * PayOff(option_type, K)(ST)
        mc[num_path - 1] = monte_carlo(payoff)

    return mc


#! /usr/bin/env python

##########################################################################################
# calc_doublePendulumFreq.py
#
# script to calculate the linearized frequencies for a double-pendulum
#
# NOTE: Any plotting is set up for output, not viewing on screen.
#       So, it will likely be ugly on screen. The saved PDFs should look
#       better.
#
# Created: 04/22/15
#   - Joshua Vaughan
#   - joshua.vaughan@louisiana.edu
#   - http://www.ucs.louisiana.edu/~jev9637
#
# Modified:
#   *
#
##########################################################################################

import numpy as np
import matplotlib.pyplot as plt

def calc_doublePendulumFreq(mh, mp, l1, l2, g = 9.81):
    """
    Function to calculate the linearized frequencies of a double-pendulum

    Arguments:
      mh : mass of the hook (kg)
      mp : mass of the payload (kg)
      l1 : supension cable length (m)
      l2 : rigging length (m)
      g : gravitation acceleration (9.81 m/s^2 is default, we're on Earth)

    Returns:
      The two natural frequencies (rad/s)

    """
    R = mp / mh

    beta = np.sqrt((1 + R)**2 * (1.0/l1 + 1.0/l2)**2 - 4 * ((1.0 + R) / (l1 * l2)))

    w1 = np.sqrt(g / 2) * np.sqrt((1+R) * (1.0/l1 + 1.0/l2) - beta)
    w2 = np.sqrt(g / 2) * np.sqrt((1+R) * (1.0/l1 + 1.0/l2) + beta)

    return w1, w2

if __name__ == '__main__':
    # Define system parameters
    mh = 50.0           # mass of the hook (kg)
    mp = 22.7/2           # mass of the payload (kg)
    l1 = 3.5            # suspension cable length (m)
    l2 = 1.8            # rigging length (m)

    w1, w2 = calc_doublePendulumFreq(mh, mp, l1, l2)

    print 'The natrual frequencies are {:0.4f} rad/s and {:0.4f} rad/s.'.format(w1, w2)
    print 'The natrual frequencies are {:0.4f} Hz and {:0.4f} Hz.'.format(w1/(2*np.pi), w2/(2*np.pi))

    # We can also look at a range of payload masses
    mp = np.arange(10, 50, 1)

    w1, w2 = calc_doublePendulumFreq(mh, mp, l1, l2)

    # Set the plot size - 3x2 aspect ratio is best
    fig = plt.figure(figsize=(6,4))
    ax = plt.gca()
    plt.subplots_adjust(bottom=0.17, left=0.17, top=0.96, right=0.96)

    # Change the axis units to CMUSerif-Roman
    plt.setp(ax.get_ymajorticklabels(),fontsize=18)
    plt.setp(ax.get_xmajorticklabels(),fontsize=18)

    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')

    ax.xaxis.set_ticks_position('bottom')
    ax.yaxis.set_ticks_position('left')

    # Turn on the plot grid and set appropriate linestyle and color
    ax.grid(True,linestyle=':', color='0.75')
    ax.set_axisbelow(True)

    # Define the X and Y axis labels
    plt.xlabel('Payload Mass (kg)', fontsize=22, weight='bold', labelpad=5)
    plt.ylabel('Frequency (Hz)', fontsize=22, weight='bold', labelpad=10)

    plt.plot(mp, w1 / (2*np.pi), linewidth=2, linestyle="-", label=r'$\omega_1$')
    plt.plot(mp, w2 / (2*np.pi), linewidth=2, linestyle="--", label=r'$\omega_2$')

    # uncomment below and set limits if needed
    # plt.xlim(0,5)
    plt.ylim(0,0.75)

    # Create the legend, then fix the fontsize
    leg = plt.legend(loc='upper right', ncol = 2, fancybox=True)
    ltext  = leg.get_texts()
    plt.setp(ltext,fontsize=18)

    # Adjust the page layout filling the page using the new tight_layout command
    plt.tight_layout(pad=0.5)

    # save the figure as a high-res pdf in the current folder
    # plt.savefig('plot_filename.pdf')

    # show the figure
    plt.show()

Misc Python Tools and Helpers/calc_doublePendulumFreq.py


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

import pandas as pd
import numpy as np
#from sklearn.preprocessing import StandardScaler

def PCA(dataset, col_mean):

    cov_mat = np.dot((dataset - col_mean),(dataset - col_mean).T) / (dataset.shape[1])
    eigenvalues, eigenvectors = np.linalg.eig(cov_mat)

    # Make a list of (eigenvalue, eigenvector) tuples
    eigen_pairs = [(np.abs(eigenvalues[i]), eigenvectors[:,i]) for i in range(len(eigenvalues))]

    # Sort the (eigenvalue, eigenvector) tuples from high to low
    eigen_pairs.sort()
    eigen_pairs = eigen_pairs[::-1]

    components = []
    for i in range(4):
        components.append(eigen_pairs[i][1].reshape(4,1))

    eigen_vec = np.hstack((components))

    return eigen_vec

def MSE(dataset, component_mat):

    mse = np.sum(np.square(component_mat-dataset))/dataset.shape[1]
    return mse

def reconstruct(u, mean, data, n_components):

    ri = np.dot(u.T, (data - mean)) #ri = UT mi = UT(xi − mean ({x})).

    #generate pi
    pi = np.zeros(ri.shape)
    pi[:n_components, :] = ri[:n_components, :]
    #xi = Upi + mean ({x})
    #unrotate and untranslate adding mean: xˆi = Upi + mean ({x})
    xi = np.dot(u, pi)
    #reshape xi to have the shape of the original data

    xi += mean
    return xi

N = np.array(pd.read_csv('iris.csv', na_values=" ?")).T
data1 = np.array(pd.read_csv('dataI.csv', na_values=" ?")).T
data2 = np.array(pd.read_csv('dataII.csv', na_values=" ?")).T
data3 = np.array(pd.read_csv('dataIII.csv', na_values=" ?")).T
data4 = np.array(pd.read_csv('dataIV.csv', na_values=" ?")).T
data5 = np.array(pd.read_csv('dataV.csv', na_values=" ?")).T
noisy_data = [data1, data2, data3, data4, data5]

N0 = np.mean(N, axis=1, keepdims=True)
u_noiseless = PCA(N, N0 )

data1_2pc_representation = []
mse_matrix = []

# For each of the noisy datasets
# Estimate the MSE between
# A) noiseless data and the PC representation of the noisy dataset
# computed from mean and cov_mat of the noiseless data
# B) noisy data and the PC representation of the same data
# computed from mean and cov_mat of the data itself
for i in range(len(noisy_data)):
    mse = []
    #noiseless
    for j in range(5):
        #do not dot if it is 0 PC
        if j != 0:
            #reconstructed version on noisy dataset i using PC of noiseless data j
            xi = reconstruct(u_noiseless, N0, noisy_data[i], j)
        else:
            xi = N0

        #MSE between the noiseless version N and the pca representation
        mse.append(MSE(N, xi))

    mean_noisy = np.mean(noisy_data[i], axis=1, keepdims=True)
    u_noisy = PCA(noisy_data[i], mean_noisy)

    for k in range(5):

        if k != 0:
            #reconstructed version on noisy dataset i using k PC computed from
            # mean and covmat of the same set
            xi = reconstruct(u_noisy,mean_noisy, noisy_data[i], k)
            if i == 0 and k==2:
                data1_2pc_representation = xi.T
        else:
            xi = mean_noisy

        #MSE between the noisy version i and the k-th pca representation of
        mse.append(MSE(N, xi))

    mse_matrix.append(mse)

mse_matrix = np.around(mse_matrix, decimals=2)
data1_2pc_representation = np.around(data1_2pc_representation, decimals=2)

print(mse_matrix)

np.savetxt("shterev2-numbers.csv", mse_matrix, delimiter=",", fmt='%5.4f')
np.savetxt("shterev2-recon.csv", data1_2pc_representation, delimiter=",", fmt='%5.4f')


import pandas as pd
import numpy as np

np.random.seed(42)

def generate_linear_data(n, betas, sigma):
    """Generate pandas df with x and y variables related by a linear equation.
    Export data as csv.
    :param n: Number of observations.
    :param betas: beta parameters.
    :param sigma: standard deviation
    :return: None
    """
    x = np.linspace(start=0.0, stop=1.0, num=n)
    y = betas[0] + betas[1]*x + np.random.normal(loc=1, scale=sigma, size=n)
    df = pd.DataFrame({'x': x, 'y': y})
    df.to_csv('data/train_data.csv', index=False)
    return None

if __name__ == "__main__":
    generate_linear_data(n=100, betas=(1.0, 3.0), sigma=0.2)


#%%
"""
Created on July 05  2021
Impact of conditional expectation pricing (Black-Scholes with Jump volatility)

This code is purely educational and comes from "Financial Engineering" course by L.A. Grzelak
The course is based on the book “Mathematical Modeling and Computation
in Finance: With Exercises and Python and MATLAB Computer Codes”,
by C.W. Oosterlee and L.A. Grzelak, World Scientific Publishing Europe Ltd, 2019.
@author: Lech A. Grzelak
"""
import numpy as np
import matplotlib.pyplot as plt
import enum
import scipy.stats as st

# This class defines puts and calls
class OptionType(enum.Enum):
    CALL = 1.0
    PUT = -1.0

def GeneratePaths(NoOfPaths,NoOfSteps,S0,T,muJ,sigmaJ,r):
    # Create empty matrices for Poisson process and for compensated Poisson process
    X = np.zeros([NoOfPaths, NoOfSteps+1])
    S = np.zeros([NoOfPaths, NoOfSteps+1])
    time = np.zeros([NoOfSteps+1])

    dt = T / float(NoOfSteps)
    X[:,0] = np.log(S0)
    S[:,0] = S0

    Z = np.random.normal(0.0,1.0,[NoOfPaths,NoOfSteps])
    J = np.random.normal(muJ,sigmaJ,[NoOfPaths,NoOfSteps])
    for i in range(0,NoOfSteps):
        # making sure that samples from normal have mean 0 and variance 1
        if NoOfPaths > 1:
            Z[:,i] = (Z[:,i] - np.mean(Z[:,i])) / np.std(Z[:,i])

        X[:,i+1]  = X[:,i] + (r - 0.5*J[:,i]**2.0)*dt +J[:,i]*np.sqrt(dt)* Z[:,i]
        time[i+1] = time[i] +dt

    S = np.exp(X)
    paths = {"time":time,"X":X,"S":S,"J":J}
    return paths

def EUOptionPriceFromMCPaths(CP,S,K,T,r):
    # S is a vector of Monte Carlo samples at T
    if CP == OptionType.CALL:
        return np.exp(-r*T)*np.mean(np.maximum(S-K,0.0))
    elif CP == OptionType.PUT:
        return np.exp(-r*T)*np.mean(np.maximum(K-S,0.0))

def BS_Call_Put_Option_Price(CP,S_0,K,sigma,t,T,r):
    K = np.array(K).reshape([len(K),1])
    d1 = (np.log(S_0 / K) + (r + 0.5 * np.power(sigma,2.0))
    * (T-t)) / (sigma * np.sqrt(T-t))
    d2 = d1 - sigma * np.sqrt(T-t)
    if CP == OptionType.CALL:
        value = st.norm.cdf(d1) * S_0 - st.norm.cdf(d2) * K * np.exp(-r * (T-t))
    elif CP == OptionType.PUT:
        value = st.norm.cdf(-d2) * K * np.exp(-r * (T-t)) - st.norm.cdf(-d1)*S_0
    return value

def CallOption_CondExpectation(NoOfPaths,T,S0,K,J,r):

    # Jumps at time T
    J_i = J[:,-1]

    result = np.zeros([NoOfPaths])

    for j in range(0,NoOfPaths):
        sigma = J_i[j]
        result[j] = BS_Call_Put_Option_Price(OptionType.CALL,S0,[K],sigma,0.0,T,r)

    return np.mean(result)

def mainCalculation():
    NoOfPaths = 25
    NoOfSteps = 500
    T = 5
    muJ = 0.3
    sigmaJ = 0.005

    S0 =100
    r  =0.00
    Paths = GeneratePaths(NoOfPaths,NoOfSteps,S0, T,muJ,sigmaJ,r)
    timeGrid = Paths["time"]
    X = Paths["X"]
    S = Paths["S"]

    plt.figure(1)
    plt.plot(timeGrid, np.transpose(X))
    plt.grid()
    plt.xlabel("time")
    plt.ylabel("X(t)")

    plt.figure(2)
    plt.plot(timeGrid, np.transpose(S))
    plt.grid()
    plt.xlabel("time")
    plt.ylabel("S(t)")

    # Check the convergence for a given strike
    K = 80
    CP =OptionType.CALL

    NGrid = range(100,10000,1000)
    NoOfRuns = len(NGrid)

    resultMC = np.zeros([NoOfRuns])
    resultCondExp = np.zeros([NoOfRuns])

    for (i,N) in enumerate(NGrid):
            print(N)
            Paths = GeneratePaths(N,NoOfSteps,S0, T,muJ,sigmaJ,r)
            timeGrid = Paths["time"]
            S = Paths["S"]
            resultMC[i] = EUOptionPriceFromMCPaths(CP,S[:,-1],K,T,r)

            J = Paths["J"]

            resultCondExp[i]=CallOption_CondExpectation(NoOfPaths,T,S0,K,J,r)

    plt.figure(3)
    plt.plot(NGrid,resultMC)
    plt.plot(NGrid,resultCondExp)
    plt.legend(['MC','Conditional Expectation'])
    plt.title('Call Option Price- Convergence')
    plt.xlabel('Number of Paths')
    plt.ylabel('Option price for a given strike, K')
    plt.grid()

mainCalculation()

Lecture 02-Understanding of Filtrations and Measures/Materials/Black_Scholes_Jumps.py


import numpy as np
from sklearn.cluster import DBSCAN
import matplotlib.pyplot as plt

# Creating data
c1 = np.random.randn(100, 2) + 5
c2 = np.random.randn(50, 2)

# Creating a uniformly distributed background
u1 = np.random.uniform(low=-10, high=10, size=100)
u2 = np.random.uniform(low=-10, high=10, size=100)
c3 = np.column_stack([u1, u2])

# Pooling all the data into one 150 x 2 array
data = np.vstack([c1, c2, c3])

# Calculating the cluster with DBSCAN function.
# db.labels_ is an array with identifiers to the
# different clusters in the data.
db = DBSCAN().fit(data, eps=0.95, min_sapltes=10)
labels = db.labels_

# Retrieving coordinates for points in each
# identified core. There are two clusters
# denoted as 0 and 1 and the noise is denoted
# as -1. Here we split the data based on which
# component they belong to.
dbc1 = data[labels == 0]
dbc2 = data[labels == 1]
noise = data[labels == -1]

# Setting up plot details
x1, x2 = -12, 12
y1, y2 = -12, 12

fig = plt.figure()
fig.subplots_adjust(hspace=0.1, wspace=0.1)

ax1 = fig.add_subplot(121, aspect='equal')
ax1.scatter(c1[:, 0], c1[:, 1], lw=0.5, color='#00CC00')
ax1.scatter(c2[:, 0], c2[:, 1], lw=0.5, color='#028E9B')
ax1.scatter(c3[:, 0], c3[:, 1], lw=0.5, color='#FF7800')
ax1.xaxis.set_visible(False)
ax1.yaxis.set_visible(False)
ax1.set_xlim(x1, x2)
ax1.set_ylim(y1, y2)
ax1.text(-11, 10, 'Original')

ax2 = fig.add_subplot(122, aspect='equal')
ax2.scatter(dbc1[:, 0], dbc1[:, 1], lw=0.5, color='#00CC00')
ax2.scatter(dbc2[:, 0], dbc2[:, 1], lw=0.5, color='#028E9B')
ax2.scatter(noise[:, 0], noise[:, 1], lw=0.5, color='#FF7800')
ax2.xaxis.set_visible(False)
ax2.yaxis.set_visible(False)
ax2.set_xlim(x1, x2)
ax2.set_ylim(y1, y2)
ax2.text(-11, 10, 'DBSCAN identified')

fig.savefig('scikits_422_ex1.pdf', bbox_inches='tight')


""" Tools:
Numpy
numpy.array(tuple)
array.shape --> rows, columns
array.dtype
numpy.zeros(shape, dtype=float, order='C')
numpy.ones(shape, dtype=None, order='C')[source]
numpy.empty(shape, dtype=float, order='C')
numpy.eye(N, M=None, k=0, dtype=<type 'float'>)
numpy.arange([start, ]stop, [step, ]dtype=None)
"""

import numpy as np

# You can parse a list as an object

myList = [1,2,3,4]

myArray1 = np.array(myList)

#print myArray1

# you can then quickly make a multi-dimensional array from tuples or lists of lists

myList2 = [11,22,33,44]

myList3 = [111,222,333,444]

myLists = [myList, myList2, myList3]

myArray2 = np.array(myLists)

#print myArray2
#print myArray2.shape

# We can check the TYPE of the array using dtype
#print myArray2.dtype

# Make a list of zeros, default floating type

zeros1 = np.zeros([5,5])
#print zeros1

# Make an array of 1s, default floating type

ones1 = np.ones([5,5])
#print ones1

# Make an empty matrix

empty1 = np.empty(5)
#print empty1

# Make an identity matrix

identityMatrix = np.eye(5)
#print identityMatrix

# Make an evenly spaced list, starting at 3, ending at 50 and going up by 4's

myArray3 = np.arange(3,50,4)
#print myArray3

Python for Data Analysis and Visualisation/Lecture7-Creating Arrays.py


import matplotlib
matplotlib.use('MacOSX')
import matplotlib.pyplot as plt
plt.style.use('./my.mplstyle')
import numpy as np

def plot_filename(ax, filename, color, linestyle):
    t, f = np.loadtxt(filename, skiprows=0, usecols=(0,1), unpack=True)
    ax.plot(t, f, lw=2.5, color=color, linestyle=linestyle)

def gaussian(x, mu, sigma):
    return np.exp(-0.5 * np.power((x - mu) / sigma, 2.0))

def plot_analytical_solutions_gaussian(ax):
    x = np.linspace(0, 1, 2000)
    y = gaussian(x, 0.1, 0.01)
    v = 1.
    ax.plot(x + v * 0.6, y, '--', lw=1, color='k')

def wave(x):
    return np.sin(8.0 * x * np.pi);

def plot_analytical_solutions(ax):
    x = np.linspace(0, 1, 2000)
    y = wave(x)
    ax.plot(x, y, '--', lw=1, color='k')

def plot_numerical_solutions(ax, filename, linestyle, color):
#    plot_filename(ax, filename + '_0.txt', 'k', ':')
#    plot_filename(ax, filename + '_2.txt', 'tab:orange', linestyle)
#    plot_filename(ax, filename + '_4.txt', 'tab:olive', linestyle)
#    plot_filename(ax, filename + '_6.txt', 'tab:green', linestyle)
#    plot_filename(ax, filename + '_8.txt', 'tab:blue', linestyle)
    plot_filename(ax, filename + '_1.txt', color, linestyle)

def make_plot():
    fig = plt.figure(figsize=(10.5,8))
    ax = fig.add_subplot(111)
    ax.set_xlabel('x')
    ax.set_ylabel('f(x)')
    ax.set_xlim([0., 1.0])
    ax.set_ylim([-1.1, 1.1])
    return fig, ax

def plot_Upwind():
    fig, ax = make_plot()
    plot_numerical_solutions(ax, 'output/upwind_1_7', '-', 'tab:red')
    plot_numerical_solutions(ax, 'output/upwind_1_8', '--', 'tab:green')
    plot_numerical_solutions(ax, 'output/upwind_1_9', ':', 'tab:blue')
    plot_analytical_solutions(ax)
    ax.set_title('Upwind')
    plt.savefig('AdvectionUpwind.pdf')

def plot_Laxf():
    fig, ax = make_plot()
    plot_numerical_solutions(ax, 'output/laxf_1_7', '-', 'tab:red')
    plot_numerical_solutions(ax, 'output/laxf_1_8', '--', 'tab:green')
    plot_numerical_solutions(ax, 'output/laxf_1_9', ':', 'tab:blue')
    plot_analytical_solutions(ax)
    ax.set_title('Laxf')
    plt.savefig('AdvectionLF.pdf')

def plot_Laxw():
    fig, ax = make_plot()
    plot_numerical_solutions(ax, 'output/laxw_1_7', '-', 'tab:red')
    plot_numerical_solutions(ax, 'output/laxw_1_8', '--', 'tab:green')
    plot_numerical_solutions(ax, 'output/laxw_1_9', ':', 'tab:blue')
    plot_analytical_solutions(ax)
    ax.set_title('Laxw')
    plt.savefig('AdvectionLW.pdf')

def plot_CN():
    fig, ax = make_plot()
    ax.set_xlim([0.5,0.8])
    ax.set_ylim([0, 1.1])
    plot_numerical_solutions(ax, 'output/CN_0.6_8', '-', 'tab:red')
    plot_numerical_solutions(ax, 'output/CN_0.6_9', '-', 'tab:orange')
    plot_numerical_solutions(ax, 'output/CN_0.6_10', '-', 'tab:green')
    plot_numerical_solutions(ax, 'output/CN_0.6_11', '-', 'tab:blue')
    plot_analytical_solutions_gaussian(ax)
    ax.set_title('Crank-Nicolson')
    ax.text(0.75, 0.90, r'$2^8$', color='tab:red')
    ax.text(0.75, 0.80, r'$2^9$', color='tab:orange')
    ax.text(0.75, 0.70, r'$2^{10}$', color='tab:green')
    ax.text(0.75, 0.60, r'$2^{11}$', color='tab:blue')
    plt.savefig('AdvectionCN.pdf')

if __name__== "__main__":
    plot_Upwind()
    plot_Laxw()
    plot_Laxf()
    plot_CN()


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

def hw1p3a(train_data, train_target, test_data, test_target, plot_gate):
    # from sklearn.datasets import load_boston
    # import numpy as np
    # from numpy import linalg as linalg

    # boston = load_boston()
    # b_data = boston.data
    # b_target = boston.target
    #
    # t0 = np.median(b_target)
    # divider = 406
    #
    # bDataTrainS = b_data[:divider,:]
    # bDataTestS = b_data[divider:,:]
    #
    # bTargetTrainS = b_target[:divider]
    # bTargetTestS = b_target[divider:]

    bDataTrainS = train_data
    bTargetTrainS = train_target

    bDataTestS = test_data
    bTargetTestS = test_target

    # class1 -> 0, > t0 ; class2 -> 1, <= t0;  result > 0-> 1-> class2
    class1 = bTargetTrainS == 0
    class2 = bTargetTrainS == 1

    N1 = sum(class1)
    N2 = sum(class2)

    m1 = np.mean(bDataTrainS[class1],0)[None,:] # 1*D
    m2 = np.mean(bDataTrainS[class2,:],0)[None,:]
    m = np.mean(bDataTrainS,0)[None,:]

    x1 = bDataTrainS[class1] # N * D=13
    x2 = bDataTrainS[class2]

    Sw = (x1-m1).transpose().dot((x1-m1)) + (x2-m2).transpose().dot(x2-m2)

    # w = linalg.inv(Sw).dot((m2-m1).transpose())
    w = linalg.pinv(Sw).dot((m2-m1).transpose())
    w = w/linalg.norm(w) # D*1
    # print(w)

    m = m.transpose() # D*1

    def classifier(x,win,mid):
        # x is N*D data matrix
        # x = x.reshape((D,1))

        x = x.transpose()
        D = len(win)
        win = win.reshape((D,1))
        mid = mid.reshape((D,1))
        # return np.inner(w,x)>0
        return (win.transpose().dot(x-mid))[0]>0 # D contracted, inner product on D, feature space.

    # test classifier:
    # a = np.array([np.ones([1,13]),np.ones([1,13])*2])[:,0,:]
    # print(a.shape)
    # print(classifier(a,w))

    # Histogram the projected points:
    # %matplotlib inline # jupyter notebook magical command
    # import matplotlib.pyplot as plt

    # x = [x1,x2,x1[:50]+x2[:50],x1[:50]*x2[:50]]
    x = [x1,x2]
    y = []

    if plot_gate:
        plt.figure()

        plt.subplot(2,1,1)
        for num,labName in zip([0,1],"01"):
            y_i = w.transpose().dot(x[num].transpose()-m)  # 1*N
            # print(y.shape)
            plt.scatter(y_i, np.ones(y_i.shape)*.5, label = ("class"+labName), cmap = plt.get_cmap('gist_rainbow'))
            y.append(y_i[0])
        plt.vlines(0,0,1)
        plt.legend()
        plt.title('Projected points of Training set in the last run of validation')

        plt.subplot(2,1,2)
        n_bins = 20
        plt.hist(y, n_bins, histtype= 'bar')
        # plt.title('Hist of projected points')
        # plt.legend()

    x11 = bDataTestS[np.where(bTargetTestS == 0)] # N * D=13
    x22 = bDataTestS[np.where(bTargetTestS == 1)]
    xx = [x11, x22]
    if plot_gate:
        plt.figure()

        plt.subplot(2,1,1)
        for num,labName in zip([0,1],"01"):
            y_i = w.transpose().dot(xx[num].transpose()-m)  # 1*N
            # print(y.shape)
            plt.scatter(y_i, np.ones(y_i.shape)*.5, label = ("class"+labName), cmap = plt.get_cmap('gist_rainbow'))
            # y.append(y_i[0])
        plt.vlines(0,0,1)
        plt.legend()
        plt.title('Projected points of Testing set in the last run of validation')

        plt.subplot(2,1,2)
        n_bins = 20
        plt.hist(y, n_bins, histtype= 'bar')
        # plt.title('Hist of projected points')
        # plt.legend()

    # Error rate:
    x_test = bDataTestS
    y_test = bTargetTestS
    result_test = classifier(x_test,w,m)

    err = np.mean(y_test != result_test)

    x_train = bDataTrainS
    y_train = bTargetTrainS
    result_train = classifier(x_train,w,m)

    err_train = np.mean(y_train != result_train)

    return err, err_train, y_test, result_test, y_train, result_train


import numpy as np
from manimlib.utils.bezier import bezier
from manimlib.utils.simple_functions import sigmoid

def linear(t):
    return t

def smooth(t, inflection=10.0):
    error = sigmoid(-inflection / 2)
    return np.clip(
        (sigmoid(inflection * (t - 0.5)) - error) / (1 - 2 * error),
        0, 1,
    )

def rush_into(t, inflection=10.0):
    return 2 * smooth(t / 2.0, inflection)

def rush_from(t, inflection=10.0):
    return 2 * smooth(t / 2.0 + 0.5, inflection) - 1

def slow_into(t):
    return np.sqrt(1 - (1 - t) * (1 - t))

def double_smooth(t):
    if t < 0.5:
        return 0.5 * smooth(2 * t)
    else:
        return 0.5 * (1 + smooth(2 * t - 1))

def there_and_back(t, inflection=10.0):
    new_t = 2 * t if t < 0.5 else 2 * (1 - t)
    return smooth(new_t, inflection)

def there_and_back_with_pause(t, pause_ratio=1. / 3):
    a = 1. / pause_ratio
    if t < 0.5 - pause_ratio / 2:
        return smooth(a * t)
    elif t < 0.5 + pause_ratio / 2:
        return 1
    else:
        return smooth(a - a * t)

def running_start(t, pull_factor=-0.5):
    return bezier([0, 0, pull_factor, pull_factor, 1, 1, 1])(t)

def not_quite_there(func=smooth, proportion=0.7):
    def result(t):
        return proportion * func(t)
    return result

def wiggle(t, wiggles=2):
    return there_and_back(t) * np.sin(wiggles * np.pi * t)

def squish_rate_func(func, a=0.4, b=0.6):
    def result(t):
        if a == b:
            return a

        if t < a:
            return func(0)
        elif t > b:
            return func(1)
        else:
            return func((t - a) / (b - a))

    return result

# Stylistically, should this take parameters (with default values)?
# Ultimately, the functionality is entirely subsumed by squish_rate_func,
# but it may be useful to have a nice name for with nice default params for
# "lingering", different from squish_rate_func's default params

def lingering(t):
    return squish_rate_func(lambda t: t, 0, 0.8)(t)

def exponential_decay(t, half_life=0.1):
    # The half-life should be rather small to minimize
    # the cut-off error at the end
    return 1 - np.exp(-t / half_life)


import numpy as np
import random

def softmax(x):
    """
    Compute the softmax function for each row of the input x.
    """

    if x.ndim == 1 \
        or (x.ndim == 2 and x.shape[0] == 1 ) \
        or (x.ndim == 2 and x.shape[1] == 1):
        x -= np.max(x)
        return np.exp(x) / np.sum(np.exp(x))
    elif x.ndim == 2:
        x-= np.max(x, axis = 1).reshape(-1,1)
        return np.exp(x) / np.sum(np.exp(x), axis=1).reshape(-1,1)
    else:
        raise ValueError("can only accept 1 or 2-d inputs to softmax")

    return x

def sigmoid(x):
    """
    Computes the sigmoid function for the input.
    """

    return 1. / (1 + np.exp(-x))

def sigmoid_grad(f):
    """
    Computes the gradient for the sigmoid function
    """
    return f * (1.0 - f)

def normalizeRows(x):
    """ Row normalization function """
    norm = np.sqrt(np.sum(x**2 , axis = 1))
    return (x.T / norm).T