from sympy import *

ax, bx, cx, dx, ay, by, cy, dy, t = symbols('ax bx cx dx ay by cy dy t')
speed_t = diff((3*ax*t**2 + 2*bx*t + cx)**2 + (3*ay*t**2 + 2*by*t + cy)**2, t )
print('speed by t expression: ')
print(speed_t)
print('\n')

constant_speed_eq = integrate(speed_t**2, (t, 0, 1))
print('constant speed equation: ')
print(constant_speed_eq)
print('\n')

# p0 => t = 0; p1 => t = 1
p0x, p0y, p1x, p1y, p0dx, p0dy, p1dy_to_dx = symbols('p0x p0y p1x p1y p0dx p0dy p1dy_to_dx')

point0_x_eq = dx - p0x
point0_y_eq = dy - p0y
point1_x_eq = ax + bx + cx + dx - p1x
point1_y_eq = ay + by + cy + dy - p1y

point0_dx_eq = cx - p0dx
point0_dy_eq = cy - p0dy

point1_dy_to_dx_eq = 3*ay + 2*by + cy - p1dy_to_dx*(3*ax + 2*bx + cx)

solution = solve([constant_speed_eq, point0_x_eq, point0_y_eq, point1_x_eq, point1_y_eq, point0_dx_eq, point0_dy_eq, point1_dy_to_dx_eq], (ax, bx, cx, dx, ay, by, cy, dy))

print('solution: ')
print(solution)
print('\n')


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

def cos_sim(a, b):
	"""Takes 2 vectors a, b and returns the cosine similarity according
	to the definition of the dot product
	"""
	dot_product = np.dot(a, b)
	norm_a = np.linalg.norm(a)
	norm_b = np.linalg.norm(b)
	return dot_product / (norm_a * norm_b)

# the counts we computed above
sentence_m = np.array([1, 1, 1, 1, 0, 0, 0, 0, 0])
sentence_h = np.array([0, 0, 1, 1, 1, 1, 0, 0, 0])
sentence_w = np.array([0, 0, 0, 1, 0, 0, 1, 1, 1])

# We should expect sentence_m and sentence_h to be more similar
print(cos_sim(sentence_m, sentence_m)) # 1.0
print(cos_sim(sentence_m, sentence_h)) # 0.5
print(cos_sim(sentence_m, sentence_w)) # 0.25


from numpy import any, array, array_str, concatenate, dot, intersect1d
from numpy import nonzero, ravel, setdiff1d, zeros
from numpy.linalg import lstsq, norm

def active_constraints(A, b, x):
    """Return a set of active constraints
    """
    dx = b - dot(A, x)
    if any(dx > 0):
        raise ValueError('x is infeasible')
    return nonzero(dx == 0)[0]

def get_starting_point(A, b):
    raise NotImplementedError('You need to provide x_0')

def get_dual_vars(G, f, A, x, W):
    """Compute lagrange multiplies for W"""
    mu, res, rank, s = lstsq(A[W, :].T, dot(G, x) + f)
    return mu

def quadprog(G, f, A, b, x_0=None, max_iter=1e6, tol=1e-4, verbose=True):
    """Solve convex QP via active set method

    min 0.5 * x^T * G * x + f^T * x
    s.t. A * x >= b

    """
    # Compute a feasible starting point
    if x_0 is None:
        x = get_starting_point(A, b)
    else:
        x = x_0.copy()
    m, n, k = x.size, A.shape[0], 0
    # Set initial active-set of contraints
    W = active_constraints(A, b, x)
    while k < max_iter:
       f_obj = dot(x.T, dot(G, x)) + dot(f.T, x)
       if verbose:
           print 'Iter: {0}\tObj: {1}\tW: {2:5}\tx: {3}'.format(k,
               array_str(ravel(f_obj), precision=3), array_str(W),
               array_str(ravel(x), precision=3))
       p = solve_qp_eq(G, f, A[W, :], b[W], x)
       if norm(p) <= tol * m**2:
           lmbda = get_dual_vars(G, f, A, x, W)
           if all(lmbda >= 0):
               # Global minimizer was found
               if verbose:
                   print 'Optimization finished\n'
               break
           else:
               # Remove most-violated constraint
               j = lmbda.argmin()
               W = setdiff1d(W, [W[j]])
       else:
           alpha, j = step_size(A, b, x, p, W)
           x = x + alpha*p
           if j is not None:
               # Add a blocking constraint
               W = concatenate((W, [j]), axis=0)
       k += 1
    if k == max_iter and verbose:
        print 'Max number of iterations reached'
    return x

def solve_qp_eq(G, f, C, d, x):
    """Solve QP with equality constraint"""
    m, n = x.size, C.shape[0]
    A = concatenate((concatenate((G, C.T), axis=1),
                     concatenate((C, zeros((n, n))), axis=1)), axis=0)
    b = concatenate((f + dot(G, x), dot(C, x) - d), axis=0)
    lmbda, res, rank, s = lstsq(A, b)
    return -lmbda[:m, :]

def step_size(A, b, x, p, W):
    """Compute minimum step size such that x + p is still in the polyhedron"""
    num, den, alpha_min, block = b - dot(A, x), dot(A, p), 1, None
    alpha = num / den
    J = intersect1d(setdiff1d(range(A.shape[0]), W, assume_unique=True),
                    nonzero(den < 0)[0])
    if J.size != 0:
        alpha_min = alpha[J].min()
    alpha_hat = min(1, alpha_min)
    # Check blocking constraints
    if alpha_hat < 0:
        raise ValueError('Got a negative alpha (step length)')
    elif alpha_hat < 1:
        block = nonzero(alpha_hat == alpha)[0][0]
    return alpha_hat, block

def hw5_1b():
    """
    Solve the following qp with active set method
    min x_1^2 + 2*x_2^2 - 2*x_1 - 6*x_2 - 2*x_1*x_2
    s.t. 0.5*x_1 + 0.5*x_2 <= 1; -1*x_1 + 2*x_2 <= 2; x_1>=0; x_2>= 0

    Choose x_0 inside, in the boundary and as extrem point.
    """
    G = array([[2, -2],[-2, 4]])
    F = array([[-2],[-6]])
    A = -1 * array([[0.5, 0.5], [-1, 2], [-1, 0], [0, -1]])
    b = -1 * array([[1],[2],[0],[0]])
    x_seed = [array([[1], [0.5]]), array([[0], [0]]), array([[0], [0.5]])]
    for x_0 in x_seed:
        x = quadprog(G, F, A, b, x_0)

if __name__ == '__main__':
    hw5_1b()


import numpy as np
import matplotlib.pyplot as plt
from welib.tools.signal import *
from numpy.random import seed; seed(0)

# --- Parameters
dt    = 1
n     = 10000
coeff = 0.95 # 1:full corr, 0: no-corr
nMax  = 180
# --- Create a correlated time series
tvec = np.arange(0,n)*dt
ts   = correlated_signal(coeff, n)
# --- Compute correlation coefficient
R, tau = correlation(ts, nMax=nMax, dt=dt)

# --- Plot
fig,axes = plt.subplots(2, 1, sharey=False, figsize=(6.4,4.8)) # (6.4,4.8)
fig.subplots_adjust(left=0.12, right=0.95, top=0.95, bottom=0.11, hspace=0.20, wspace=0.20)
ax=axes[0]
# Plot time series
ax.plot(tvec,ts)
ax.set_xlabel('t [s]')
ax.set_ylabel('u [m/s]')
ax.tick_params(direction='in')
# Plot correlation
ax=axes[1]
ax.plot(tau,  R              ,'-o', label='Computed')
ax.plot(tau, coeff**(tau/dt) ,'--' ,label=r'Theoretical -  c$^{\tau/dt}$') # analytical coeff^n trend
ax.set_xlabel(r'$\tau$ [s]')
ax.set_ylabel(r'$R(\tau)$ [-]')
ax.set_title('Signal - Correlation coefficient')
ax.legend()

if __name__=='__main__':
    plt.show()
if __name__ == '__test__':
    pass
if __name__=="__export__":
    from welib.tools.repo import export_figs_callback
    export_figs_callback(__file__)


import numpy as np
import matplotlib.pyplot as plt

# Plot 2D points
def displaypoints2d(points):
  plt.figure(0)
  plt.plot(points[0,:],points[1,:], '.b')
  plt.xlabel('Screen X')
  plt.ylabel('Screen Y')

# Plot 3D points
def displaypoints3d(points):
  fig = plt.figure(1)
  ax = fig.add_subplot(111, projection='3d')
  ax.scatter(points[0,:], points[1,:], points[2,:], 'b')
  ax.set_xlabel("World X")
  ax.set_ylabel("World Y")
  ax.set_zlabel("World Z")

def cart2hom(points):
  """ Transforms from cartesian to homogeneous coordinates.

  Args:
    points: a np array of points in cartesian coordinates

  Returns:
    points_hom: a np array of points in homogeneous coordinates
  """

  #
  # You code here
  #

  # add an additional component and fill it with ones
  return np.concatenate((points, np.ones((1, points.shape[1]))))

def hom2cart(points):
  """ Transforms from homogeneous to cartesian coordinates.

  Args:
    points: a np array of points in homogenous coordinates

  Returns:
    points_hom: a np array of points in cartesian coordinates
  """

  #
  # You code here
  #

  # Perform perspective division
  res = points[:-1,:]/points[-1,:]
  return res

def gettranslation(v):
  """ Returns translation matrix T in homogeneous coordinates for translation by v.

  Args:
    v: 3d translation vector

  Returns:
    T: translation matrix in homogeneous coordinates
  """

  #
  # You code here
  #

  T = np.eye(4)
  T[0:3,3] = v
  return T

def getxrotation(d):
  """ Returns rotation matrix Rx in homogeneous coordinates for a rotation of d degrees around the x axis.

  Args:
    d: degrees of the rotation

  Returns:
    Rx: rotation matrix
  """

  #
  # You code here
  #

  r = np.radians(d)
  Rx = np.eye(4)
  Rx[1:3,1:3] = np.array([[np.cos(r), -np.sin(r)],[np.sin(r),np.cos(r)]])
  return Rx

def getyrotation(d):
  """ Returns rotation matrix Ry in homogeneous coordinates for a rotation of d degrees around the y axis.

  Args:
    d: degrees of the rotation

  Returns:
    Ry: rotation matrix
  """

  #
  # You code here
  #

  r = np.radians(d)
  Ry = np.eye(4)
  Ry[0:3:2, 0:3:2] = np.array([[np.cos(r),np.sin(r)],[-np.sin(r),np.cos(r)]])
  return Ry

def getzrotation(d):
  """ Returns rotation matrix Rz in homogeneous coordinates for a rotation of d degrees around the z axis.

  Args:
    d: degrees of the rotation

  Returns:
    Rz: rotation matrix
  """

  #
  # You code here
  #

  r = np.radians(d)
  Rz = np.eye(4)
  Rz[0:2,0:2] = np.array([[np.cos(r),-np.sin(r)],[np.sin(r),np.cos(r)]])
  return Rz

def getcentralprojection(principal, focal):
  """ Returns the (3 x 4) matrix L that projects homogeneous camera coordinates on homogeneous
  image coordinates depending on the principal point and focal length.

  Args:
    principal: the principal point, 2d vector
    focal: focal length

  Returns:
    L: central projection matrix
  """

  #
  # You code here
  #

  # l1-image_formation-v1 Seite 35

  # [[f,0,px,0],
  #  [0,f,py,0],
  #  [0,0,1,0]]

  return np.array([[focal, 0.0, principal[0], 0.0],
                    [0.0, focal, principal[1], 0.0],
                    [0.0, 0.0, 1.0, 0.0]])

def getfullprojection(T, Rx, Ry, Rz, L):
  """ Returns full projection matrix P and full extrinsic transformation matrix M.

  Args:
    T: translation matrix
    Rx: rotation matrix for rotation around the x-axis
    Ry: rotation matrix for rotation around the y-axis
    Rz: rotation matrix for rotation around the z-axis
    L: central projection matrix

  Returns:
    P: projection matrix
    M: matrix that summarizes extrinsic transformations
  """

  #
  # You code here
  #

  # l1-image_formation-v1 Seite 39

  # Model transformations
  M = Rz.dot(Rx.dot(Ry.dot(T)))
  # Full projection matrix
  P = L.dot(M)
  return P,M

def projectpoints(P, X):
  """ Apply full projection matrix P to 3D points X in cartesian coordinates.

  Args:
    P: projection matrix
    X: 3d points in cartesian coordinates

  Returns:
    x: 2d points in cartesian coordinates
  """

  #
  # You code here
  #

  return hom2cart(P.dot(cart2hom(X)))

def loadpoints():
  """ Load 2D points from obj2d.npy.

  Returns:
    x: np array of points loaded from obj2d.npy
  """

  #
  # You code here
  #

  # Load arrays from ``.npy``
  x = np.load('data/obj2d.npy')
  return x

def loadz():
  """ Load z-coordinates from zs.npy.

  Returns:
    z: np array containing the z-coordinates
  """

  #
  # You code here
  #
  z = np.load('data/zs.npy')
  return z

def invertprojection(L, P2d, z):
  """
  Invert just the projection L of cartesian image coordinates P2d with z-coordinates z.

  Args:
    L: central projection matrix
    P2d: 2d image coordinates of the projected points
    z: z-components of the homogeneous image coordinates

  Returns:
    P3d: 3d cartesian camera coordinates of the points
  """

  #
  # You code here
  #

  # Extract camera intrinsics
  # l1-image_formation-v Seite 37
  K = L[:,0:3]
  # Account for unknown scale
  # l1-image_formation-v1 Seite 24
  P3d = z*(np.linalg.solve(K,cart2hom(P2d)))
  return P3d

def inverttransformation(M, P3d):
  """ Invert just the model transformation in homogeneous coordinates
  for the 3D points P3d in cartesian coordinates.

  Args:
    M: matrix summarizing the extrinsic transformations
    P3d: 3d points in cartesian coordinates

  Returns:
    X: 3d points after the extrinsic transformations have been reverted
  """

  #
  # You code here
  #

  # extrinsic transformations
  # l1-image_formation-v1 Seite 29

  X = np.linalg.solve(M,cart2hom(P3d))
  return X

def p3multiplecoice():
  '''
  Change the order of the transformations (translation and rotation).
  Check if they are commutative. Make a comment in your code.
  Return 0, 1 or 2:
  0: The transformations do not commute.
  1: Only rotations commute with each other.
  2: All transformations commute.
  '''

  return -1


#------------------------------------------------------------------------------------------------------------#
#Chapter 2 - Visualization with hierarchical clustering and t-SNE

#------------------------------------------------------------------------------------------------------------#
#Hierarchical clustering of the grain data

# Perform the necessary imports
from scipy.cluster.hierarchy import linkage, dendrogram
import matplotlib.pyplot as plt

# Calculate the linkage: mergings
mergings = linkage(samples, method='complete')

# Plot the dendrogram, using varieties as labels
dendrogram(mergings,
           labels=varieties,
           leaf_rotation=90,
           leaf_font_size=6,
)
plt.show()

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

#Hierarchies of stocks
# Import normalize
from sklearn.preprocessing import normalize

# Normalize the movements: normalized_movements
normalized_movements = normalize(movements)

# Calculate the linkage: mergings
mergings = linkage(normalized_movements, method='complete')

# Plot the dendrogram
dendrogram(mergings,
           labels=companies,
           leaf_rotation=90,
           leaf_font_size=6,
)

plt.show()

#------------------------------------------------------------------------------------------------------------#
#Different linkage, different hierarchical clustering!
# Perform the necessary imports
import matplotlib.pyplot as plt
from scipy.cluster.hierarchy import dendrogram, linkage

# Calculate the linkage: mergings
mergings = linkage(samples,method='single')

# Plot the dendrogram
dendrogram(mergings,
           labels=country_names,
           leaf_rotation=90,
           leaf_font_size=6,
)
plt.xlabel('European Nations')
plt.ylabel('Number of votes')
plt.title('EuroVision 2017 Denogram ')
plt.legend(loc='upper right')
plt.show()

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

#Extracting the cluster labels
# Perform the necessary imports
import pandas as pd
from scipy.cluster.hierarchy import fcluster

# Use fcluster to extract labels: labels
labels = fcluster(mergings,6,criterion='distance')

# Create a DataFrame with labels and varieties as columns: df
df = pd.DataFrame({'labels': labels, 'varieties': varieties})

# Create crosstab: ct
ct = pd.crosstab(df['labels'],df['varieties'])

# Display ct
print(ct)

#------------------------------------------------------------------------------------------------------------#
#t-SNE visualization of grain dataset
# Import TSNE
from sklearn.manifold import TSNE

# Create a TSNE instance: model
model = TSNE(learning_rate=200)

# Apply fit_transform to samples: tsne_features
tsne_features = model.fit_transform(samples)

# Select the 0th feature: xs
xs = tsne_features[:,0]

# Select the 1st feature: ys
ys = tsne_features[:,1]

# Scatter plot, coloring by variety_numbers
plt.scatter(xs,ys,c=variety_numbers)
plt.show()

#------------------------------------------------------------------------------------------------------------#
#A t-SNE map of the stock market

# Import TSNE
from sklearn.manifold import TSNE

# Create a TSNE instance: model
model = TSNE(learning_rate=50)

# Apply fit_transform to normalized_movements: tsne_features
tsne_features = model.fit_transform(normalized_movements)

# Select the 0th feature: xs
xs = tsne_features[:,0]

# Select the 1th feature: ys
ys = tsne_features[:,1]

# Scatter plot
plt.scatter(xs,ys,alpha=0.5)

# Annotate the points
for x, y, company in zip(xs, ys, companies):
    plt.annotate(company, (x, y), fontsize=5, alpha=0.75)
plt.show()

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

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

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

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

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

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

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

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

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

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

Unsupervised Learning in Python/Chapter 2 - Visualization with hierarchical clustering and t-SNE.py


# -*- coding: utf-8 -*-
"""problem 2 class 4 offline

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/10n45tcpjVcRcO65S-6hJK2_trgI091yp
"""

# libraries
import random
import math
import numpy as np
import matplotlib.pyplot as plt
random.seed(10)

def integral(N):
  A= 0
  B = 8
  # lists for storing the values
  y1_values = []
  y1_square_values =[]

  y2_values =[]
  y2_square_values =[]

  count_1 = 0
  count_2 = 0

  for i in range(1,N+1):
    # x random value generation
    x = random.uniform(A,B)
    # calculating first area value
    if x <=4 :
      y1 = math.sqrt(4 * x)
      y1_values.append(y1)
      y1_square_values.append(y1*y1)
      count_1 += 1
    else:
      y2 = 8 - x
      y2_values.append(y2)
      y2_square_values.append(y2*y2)
      count_2 += 1

  # calculate 0 to 4 area first part
  y1_average = sum(y1_values) / len(y1_values)
  y1_square_average = sum(y1_square_values) / len(y1_square_values)
  area_1 = y1_average * ( 4-0 )
  error_1 = ( (4-0) / math.sqrt(count_1) ) * math.sqrt(y1_square_average - y1_average**2)

  # calculate 4 to 8 area second part
  y2_average = sum(y2_values) / len(y2_values)
  y2_square_average = sum(y2_square_values) / len(y2_square_values)
  area_2 = y2_average * ( 8-4 )
  error_2 = ( (8-4) / math.sqrt(count_2) ) * math.sqrt(y2_square_average - y2_average**2)

  #total area and error
  integral_value = area_1 + area_2
  error_estimate = error_1 + error_2

  print("For number of sample points: ", N)
  print("Integral Value: ", integral_value)
  print("Estimated Error: ", error_estimate)
  print("")

N = [100,1000,5000,10000]
for i in N:
  integral(i)

Assignment 03 - Monte Carlo Intregral/problem2.py


"""
You have a list of points in the plane. Return the area of the largest triangle that can be formed by any 3 of the points.

Example:

    Input: points = [[0,0],[0,1],[1,0],[0,2],[2,0]]
    Output: 2
    Explanation: The five points are show in the figure below. The red triangle is the largest.

    https://s3-lc-upload.s3.amazonaws.com/uploads/2018/04/04/1027.png

Notes:
    1. 3 <= points.length <= 50.
    2. No points will be duplicated.
    3. -50 <= points[i][j] <= 50.
    4. Answers within 10^(-6) of the true value will be accepted as correct.
"""

import itertools
import numpy as np

class Solution:
    def largestTriangleArea1(self, points):
        def area(A, B, C):
            x_1, y_1 = A
            x_2, y_2 = B
            x_3, y_3 = C
            return 0.5 * abs(x_2 * y_3 - x_3 * y_2 - x_1 * y_3 + x_3 * y_1 + x_1 * y_2 - x_2 * y_1)

        return max(area(*selected) for selected in itertools.combinations(points, 3))

    def largestTriangleArea2(self, points):
        return max(
            abs(np.linalg.det(np.hstack((np.array(selected), np.ones((3, 1)))))) * 0.5 for selected in itertools.combinations(points, 3)
        )


#regla de simpson compuesta

import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return (1/4)*x*(10-x)+ np.sin(np.pi*x)
a=0
b=5
N=5
h=(b-a)/N

def simpson(f,a,b,N, h):
    h = h / 2
    Xi=np.array([a+h*i for i in range(2*N+1)])
    Yi=f(Xi)
    suma1=sum(np.array([Yi[2*i] for i in range(1,N)]))
    suma2=sum(np.array([Yi[2*i+1] for i in range(N)]))
    simpson= (h/3)*(f(a)+2*suma1+4*suma2+f(b))
    print(simpson)

    return simpson

print("La aprox. de la integral por la regla de simpson compuesta es: ", simpson(f,a,b,N))

Xi= np.array([a+h*i for i in range(N)]) #para calcular la funcion
Yi= f(Xi)

xi=np.linspace(a,b,100) #Para graficar muchos puntos para f(x) y sea suave
yi=f(xi)

plt.title("Funcion y funcion escalon usada para integrar")
plt.xlabel("x")
plt.ylabel("y")
plt.step(Xi,Yi,'r') #funcion escalon
plt.plot(xi,yi,'b') #funcion f(x)

for j in range(len(Xi)):
    plt.plot(Xi[j], Yi[j],'go') #puntos (xi,yi)

plt.savefig("EjReglaDeSimpson.png")
plt.show()

N = 10
x = [1 * i for i in range(2*N+1)]
n1 = len(x)
n2 = len([x[2*i] for i in range(1,N)])
n3 = len([x[2*i+1] for i in range(N)])


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

# 3. Calculate the logistic map function for l = 0.5, 2.5, 3.5, 4
#    Xn+1 = l * Xn (1 - Xn)
# 4. Compare the same statistical features of your RW (2) and the four
#    different logistic map time series (3)

LENGTH = 100
l = np.asarray([0.5, 2.5, 3.5, 4])
l_len = len(l)

means = np.zeros((l_len, 1))
variances = np.zeros((l_len, 1))
strd_deviations = np.zeros((l_len, 1))

ensemble = np.zeros(LENGTH)
ensemble_mean = 0
ensemble_strd_dev = 0

# Temporary storage for calculations
tmp_arr = np.zeros((l_len, LENGTH))

X = np.zeros((l_len, LENGTH))

for i in range(l_len):
    # Initial value
    X[i][0] = 0.3
    for n in range(LENGTH - 1):
        X[i][n+1] = l[i] * X[i][n] * (1 - X[i][n])

    means[i] = np.mean(X[i])

    # Standard deviation
    tmp_arr[i] = np.subtract(X[i], means[i])
    tmp_arr[i] = tmp_arr[i] * tmp_arr[i]
    variances[i] = np.sum(tmp_arr[i]) / LENGTH

    strd_deviations[i] = np.sqrt(np.sum(tmp_arr[i]) / (LENGTH - 1))

print ("Means")
print (means)
print ("Variances")
print (variances)
print ("Standard deviations")
print (strd_deviations)

# Calculate ensemble
ensemble = np.sum(X, axis=0)
ensemble = ensemble / l_len

# Ensemble time-average mean
ensemble_mean = np.mean(ensemble)

# Ensemble standard deviation
ensemble_tmp = np.subtract(ensemble, ensemble_mean)
ensemble_tmp = ensemble_tmp * ensemble_tmp
ensemble_strd_dev = np.sqrt(np.sum(ensemble_tmp) / (LENGTH - 1))

print ("Ensemble mean: {}".format(ensemble_mean))
print ("Ensemble standard deviation: {}".format(ensemble_strd_dev))

# Logistic map functions
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
ax1.plot(X[0])
ax1.axhline(means[0], label='time-average', color='r', linestyle='-')
ax1.set_title("l = {}".format(l[0]))
ax2.plot(X[1])
ax2.set_title("l = {}".format(l[1]))
ax2.axhline(means[1], label='time-average', color='r', linestyle='-')
ax3.plot(X[2])
ax3.set_title("l = {}".format(l[2]))
ax3.axhline(means[2], label='time-average', color='r', linestyle='-')
ax4.plot(X[3])
ax4.set_title("l = {}".format(l[3]))
ax4.axhline(means[3], label='time-average', color='r', linestyle='-')
plt.show()

# Ensemble
# Time-average mean
plt.axhline(ensemble_mean, label='time-average', color='r', linestyle='-')
# Ensemble average
plt.plot(ensemble, color='b', label='Ensemble')
plt.legend()
plt.show()

flatX = X.flatten()
n, bins, patches = plt.hist(flatX, 25, facecolor='b')
plt.grid(True)
plt.show()


# Databricks notebook source
# MAGIC %md
# MAGIC
# MAGIC # [SDS-2.2, Scalable Data Science](https://lamastex.github.io/scalable-data-science/sds/2/2/)
# MAGIC
# MAGIC This is used in a non-profit educational setting with kind permission of [Adam Breindel](https://www.linkedin.com/in/adbreind).
# MAGIC This is not licensed by Adam for use in a for-profit setting. Please contact Adam directly at `adbreind@gmail.com` to request or report such use cases or abuses.
# MAGIC A few minor modifications and additional mathematical statistical pointers have been added by Raazesh Sainudiin when teaching PhD students in Uppsala University.

# COMMAND ----------

# MAGIC %md
# MAGIC Archived YouTube video of this live unedited lab-lecture:
# MAGIC
# MAGIC [![Archived YouTube video of this live unedited lab-lecture](http://img.youtube.com/vi/eJBR6sm4p2g/0.jpg)](https://www.youtube.com/embed/eJBR6sm4p2g?start=0&end=2654&autoplay=1) [![Archived YouTube video of this live unedited lab-lecture](http://img.youtube.com/vi/TDisCsfbmYs/0.jpg)](https://www.youtube.com/embed/TDisCsfbmYs?start=0&end=2907&autoplay=1) [![Archived YouTube video of this live unedited lab-lecture](http://img.youtube.com/vi/-LLL3MUl9ps/0.jpg)](https://www.youtube.com/embed/-LLL3MUl9ps?start=0&end=2467&autoplay=1)

# COMMAND ----------

# MAGIC %md
# MAGIC # Artificial Neural Network - Perceptron
# MAGIC
# MAGIC The field of artificial neural networks started out with an electromechanical binary unit called a perceptron.
# MAGIC
# MAGIC The perceptron took a weighted set of input signals and chose an ouput state (on/off or high/low) based on a threshold.
# MAGIC
# MAGIC

# COMMAND ----------

# MAGIC %md
# MAGIC (raaz) Thus, the perceptron is defined by:
# MAGIC
# MAGIC $$
# MAGIC f(1, x\_1,x\_2,\ldots , x\_n \, ; \, w\_0,w\_1,w\_2,\ldots , w\_n) =
# MAGIC \begin{cases}
# MAGIC 1 & \text{if} \quad \sum\_{i=0}^n w\_i x\_i > 0 \\\\
# MAGIC 0 & \text{otherwise}
# MAGIC \end{cases}
# MAGIC $$
# MAGIC and implementable with the following arithmetical and logical unit (ALU) operations in a machine:
# MAGIC
# MAGIC  * n inputs from one \\(n\\)-dimensional data point: \\( x_1,x_2,\ldots x_n \, \in \, \mathbb{R}^n\\)
# MAGIC  * arithmetic operations
# MAGIC    * n+1 multiplications
# MAGIC    * n additions
# MAGIC * boolean operations
# MAGIC   * one if-then on an inequality
# MAGIC * one output \\(o \in \\{0,1\\}\\), i.e., \\(o\\) belongs to the set containing \\(0\\) and \\(1\\)
# MAGIC * n+1 parameters of interest
# MAGIC
# MAGIC This is just a hyperplane given by a dot product of \\(n+1\\) known inputs and \\(n+1\\) unknown parameters that can be estimated. This hyperplane can be used to define a hyperplane that partitions \\(\mathbb{R}^{n+1}\\), the real Euclidean space, into two parts labelled by the outputs \\(0\\) and \\(1\\).
# MAGIC
# MAGIC The problem of finding estimates of the parameters, \\( (\hat{w}\_0,\hat{w}\_1,\hat{w}\_2,\ldots \hat{w}\_n) \in \mathbb{R}^{(n+1)} \\), in some statistically meaningful manner for a predicting task by using the training data given by, say \\(k\\) *labelled points*, where you know both the input and output:
# MAGIC $$
# MAGIC  \left( ( \, 1, x\_1^{(1)},x\_2^{(1)}, \ldots x\_n^{(1)}), (o^{(1)}) \, ), \, ( \, 1, x\_1^{(2)},x\_2^{(2)}, \ldots x\_n^{(2)}), (o^{(2)}) \, ), \, \ldots \, , ( \, 1, x\_1^{(k)},x\_2^{(k)}, \ldots x\_n^{(k)}), (o^{(k)}) \, ) \right) \, \in \, (\mathbb{R}^{n+1} \times \\{ 0,1 \\} )^k
# MAGIC $$
# MAGIC is the machine learning problem here.
# MAGIC
# MAGIC Succinctly, we are after a random mapping, denoted below by \\( \mapsto\_{\rightsquigarrow} \\), called the *estimator*:
# MAGIC $$
# MAGIC (\mathbb{R}^{n+1} \times \\{0,1\\})^k \mapsto_{\rightsquigarrow} \, \left( \, \mathtt{model}( (1,x\_1,x\_2,\ldots,x\_n) \,;\, (\hat{w}\_0,\hat{w}\_1,\hat{w}\_2,\ldots \hat{w}\_n)) : \mathbb{R}^{n+1} \to \\{0,1\\} \,  \right)
# MAGIC $$
# MAGIC which takes *random* labelled dataset (to understand random here think of two scientists doing independent experiments to get their own training datasets) of size \\(k\\) and returns a *model*. These mathematical notions correspond exactly to the `estimator` and `model` (which is a `transformer`) in the language of Apache Spark's Machine Learning Pipleines we have seen before.
# MAGIC
# MAGIC We can use this `transformer` for *prediction* of *unlabelled data* where we only observe the input and what to know the output under some reasonable assumptions.
# MAGIC
# MAGIC Of course we want to be able to generalize so we don't overfit to the training data using some *empirical risk minisation rule* such as cross-validation. Again, we have seen these in Apache Spark for other ML methods like linear regression and decision trees.

# COMMAND ----------

# MAGIC %md
# MAGIC If the output isn't right, we can adjust the weights, threshold, or bias (\\(x_0\\) above)
# MAGIC
# MAGIC The model was inspired by discoveries about the neurons of animals, so hopes were quite high that it could lead to a sophisticated machine. This model can be extended by adding multiple neurons in parallel. And we can use linear output instead of a threshold if we like for the output.
# MAGIC
# MAGIC If we were to do so, the output would look like \\({x \cdot w} + w_0\\) (this is where the vector multiplication and, eventually, matrix multiplication, comes in)
# MAGIC
# MAGIC When we look at the math this way, we see that despite this being an interesting model, it's really just a fancy linear calculation.
# MAGIC
# MAGIC And, in fact, the proof that this model -- being linear -- could not solve any problems whose solution was nonlinear ... led to the first of several "AI / neural net winters" when the excitement was quickly replaced by disappointment, and most research was abandoned.

# COMMAND ----------

# MAGIC %md
# MAGIC ### Linear Perceptron
# MAGIC
# MAGIC We'll get to the non-linear part, but the linear perceptron model is a great way to warm up and bridge the gap from traditional linear regression to the neural-net flavor.
# MAGIC
# MAGIC Let's look at a problem -- the diamonds dataset from R -- and analyze it using two traditional methods in Scikit-Learn, and then we'll start attacking it with neural networks!

# COMMAND ----------

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import mean_squared_error

input_file = "/dbfs/databricks-datasets/Rdatasets/data-001/csv/ggplot2/diamonds.csv"

df = pd.read_csv(input_file, header = 0)

# COMMAND ----------

import IPython.display as disp
pd.set_option('display.width', 200)
disp.display(df[:10])

# COMMAND ----------

df2 = df.drop(df.columns[0], axis=1)

disp.display(df2[:3])

# COMMAND ----------

df3 = pd.get_dummies(df2) # this gives a one-hot encoding of categorial variables

disp.display(df3[range(7,18)][:3])

# COMMAND ----------

# pre-process to get y
y = df3.iloc[:,3:4].as_matrix().flatten()
y.flatten()

# preprocess and reshape X as a matrix
X = df3.drop(df3.columns[3], axis=1).as_matrix()
np.shape(X)

# break the dataset into training and test set with a 75% and 25% split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)

# Define a decisoin tree model with max depth 10
dt = DecisionTreeRegressor(random_state=0, max_depth=10)

# fit the decision tree to the training data to get a fitted model
model = dt.fit(X_train, y_train)

# predict the features or X values of the test data using the fitted model
y_pred = model.predict(X_test)

# print the MSE performance measure of the fit by comparing the predicted versus the observed values of y
print("RMSE %f" % np.sqrt(mean_squared_error(y_test, y_pred)) )

# COMMAND ----------

from sklearn import linear_model

# Do the same with linear regression and not a worse MSE
lr = linear_model.LinearRegression()
linear_model = lr.fit(X_train, y_train)

y_pred = linear_model.predict(X_test)
print("RMSE %f" % np.sqrt(mean_squared_error(y_test, y_pred)) )

# COMMAND ----------

# MAGIC %md
# MAGIC Now that we have a baseline, let's build a neural network -- linear at first -- and go further.

# COMMAND ----------

# MAGIC %md
# MAGIC ## Neural Network with Keras
# MAGIC
# MAGIC ### Keras is a High-Level API for Neural Networks and Deep Learning
# MAGIC
# MAGIC #### "*Being able to go from idea to result with the least possible delay is key to doing good research.*"
# MAGIC Maintained by Francois Chollet at Google, it provides
# MAGIC
# MAGIC * High level APIs
# MAGIC * Pluggable backends for Theano, TensorFlow, CNTK, MXNet
# MAGIC * CPU/GPU support
# MAGIC * The now-officially-endorsed high-level wrapper for TensorFlow; a version ships in TF
# MAGIC * Model persistence and other niceties
# MAGIC * JavaScript, iOS, etc. deployment
# MAGIC * Interop with further frameworks, like DeepLearning4J, Spark DL Pipelines ...
# MAGIC
# MAGIC Well, with all this, why would you ever *not* use Keras?
# MAGIC
# MAGIC As an API/Facade, Keras doesn't directly expose all of the internals you might need for something custom and low-level ... so you might need to implement at a lower level first, and then perhaps wrap it to make it easily usable in Keras.
# MAGIC
# MAGIC Mr. Chollet compiles stats (roughly quarterly) on "[t]he state of the deep learning landscape: GitHub activity of major libraries over the past quarter (tickets, forks, and contributors)."
# MAGIC
# MAGIC (October 2017: https://twitter.com/fchollet/status/915366704401719296; https://twitter.com/fchollet/status/915626952408436736)
# MAGIC

__GitHub__

# MAGIC
# MAGIC   	__Research__

# MAGIC

# COMMAND ----------

# MAGIC %md
# MAGIC ### We'll build a "Dense Feed-Forward Shallow" Network:
# MAGIC (the number of units in the following diagram does not exactly match ours)
# MAGIC
# MAGIC
# MAGIC Grab a Keras API cheat sheet from https://s3.amazonaws.com/assets.datacamp.com/blog_assets/Keras_Cheat_Sheet_Python.pdf

# COMMAND ----------

from keras.models import Sequential
from keras.layers import Dense

# we are going to add layers sequentially one after the other (feed-forward) to our neural network model
model = Sequential()

# the first layer has 30 nodes (or neurons) with input dimension 26 for our diamonds data
# we will use Nomal or Guassian kernel to initialise the weights we want to estimate
# our activation function is linear (to mimic linear regression)
model.add(Dense(30, input_dim=26, kernel_initializer='normal', activation='linear'))
# the next layer is for the response y and has only one node
model.add(Dense(1, kernel_initializer='normal', activation='linear'))
# compile the model with other specifications for loss and type of gradient descent optimisation routine
model.compile(loss='mean_squared_error', optimizer='adam', metrics=['mean_squared_error'])
# fit the model to the training data using stochastic gradient descent with a batch-size of 200 and 10% of data held out for validation
history = model.fit(X_train, y_train, epochs=10, batch_size=200, validation_split=0.1)

scores = model.evaluate(X_test, y_test)
print()
print("test set RMSE: %f" % np.sqrt(scores[1]))

# COMMAND ----------

model.summary() # do you understand why the number of parameters in layer 1 is 810? 26*30+30=810

# COMMAND ----------

# MAGIC %md
# MAGIC Notes:
# MAGIC
# MAGIC * We didn't have to explicitly write the "input" layer, courtesy of the Keras API. We just said `input_dim=26` on the first (and only) hidden layer.
# MAGIC * `kernel_initializer='normal'` is a simple (though not always optimal) *weight initialization*
# MAGIC * Epoch: 1 pass over all of the training data
# MAGIC * Batch: Records processes together in a single training pass
# MAGIC
# MAGIC How is our RMSE vs. the std dev of the response?

# COMMAND ----------

y.std()

# COMMAND ----------

# MAGIC %md
# MAGIC Let's look at the error ...

# COMMAND ----------

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'val'], loc='upper left')

display(fig)

# COMMAND ----------

# MAGIC %md
# MAGIC Let's set up a "long-running" training. This will take a few minutes to converge to the same performance we got more or less instantly with our sklearn linear regression :)
# MAGIC
# MAGIC While it's running, we can talk about the training.

# COMMAND ----------

from keras.models import Sequential
from keras.layers import Dense
import numpy as np
import pandas as pd

input_file = "/dbfs/databricks-datasets/Rdatasets/data-001/csv/ggplot2/diamonds.csv"

df = pd.read_csv(input_file, header = 0)
df.drop(df.columns[0], axis=1, inplace=True)
df = pd.get_dummies(df, prefix=['cut_', 'color_', 'clarity_'])

y = df.iloc[:,3:4].as_matrix().flatten()
y.flatten()

X = df.drop(df.columns[3], axis=1).as_matrix()
np.shape(X)

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)

model = Sequential()
model.add(Dense(30, input_dim=26, kernel_initializer='normal', activation='linear'))
model.add(Dense(1, kernel_initializer='normal', activation='linear'))

model.compile(loss='mean_squared_error', optimizer='adam', metrics=['mean_squared_error'])
history = model.fit(X_train, y_train, epochs=250, batch_size=100, validation_split=0.1, verbose=2)

scores = model.evaluate(X_test, y_test)
print("\nroot %s: %f" % (model.metrics_names[1], np.sqrt(scores[1])))

# COMMAND ----------

# MAGIC %md
# MAGIC After all this hard work we are closer to the MSE we got from linear regression, but purely using a shallow feed-forward neural network.

# COMMAND ----------

# MAGIC %md
# MAGIC ### Training: Gradient Descent
# MAGIC
# MAGIC A family of numeric optimization techniques, where we solve a problem with the following pattern:
# MAGIC
# MAGIC 1. Describe the error in the model output: this is usually some difference between the the true values and the model's predicted values, as a function of the model parameters (weights)
# MAGIC
# MAGIC 2. Compute the gradient, or directional derivative, of the error -- the "slope toward lower error"
# MAGIC
# MAGIC 4. Adjust the parameters of the model variables in the indicated direction
# MAGIC
# MAGIC 5. Repeat
# MAGIC
# MAGIC
# MAGIC
# MAGIC #### Some ideas to help build your intuition
# MAGIC
# MAGIC * What happens if the variables (imagine just 2, to keep the mental picture simple) are on wildly different scales ... like one ranges from -1 to 1 while another from -1e6 to +1e6?
# MAGIC
# MAGIC * What if some of the variables are correlated? I.e., a change in one corresponds to, say, a linear change in another?
# MAGIC
# MAGIC * Other things being equal, an approximate solution with fewer variables is easier to work with than one with more -- how could we get rid of some less valuable parameters? (e.g., L1 penalty)
# MAGIC
# MAGIC * How do we know how far to "adjust" our parameters with each step?
# MAGIC
# MAGIC
# MAGIC
# MAGIC What if we have billions of data points? Does it makes sense to use all of them for each update? Is there a shortcut?
# MAGIC
# MAGIC Yes: *Stochastic Gradient Descent*
# MAGIC
# MAGIC But SGD has some shortcomings, so we typically use a "smarter" version of SGD, which has rules for adjusting the learning rate and even direction in order to avoid common problems.
# MAGIC
# MAGIC What about that "Adam" optimizer? Adam is short for "adaptive moment" and is a variant of SGD that includes momentum calculations that change over time. For more detail on optimizers, see the chapter "Training Deep Neural Nets" in Aurélien Géron's book: *Hands-On Machine Learning with Scikit-Learn and TensorFlow* (http://shop.oreilly.com/product/0636920052289.do)

# COMMAND ----------

# MAGIC %md
# MAGIC ### Training: Backpropagation
# MAGIC
# MAGIC With a simple, flat model, we could use SGD or a related algorithm to derive the weights, since the error depends directly on those weights.
# MAGIC
# MAGIC With a deeper network, we have a couple of challenges:
# MAGIC
# MAGIC * The error is computed from the final layer, so the gradient of the error doesn't tell us immediately about problems in other-layer weights
# MAGIC * Our tiny diamonds model has almost a thousand weights. Bigger models can easily have millions of weights. Each of those weights may need to move a little at a time, and we have to watch out for underflow or undersignificance situations.
# MAGIC
# MAGIC __The insight is to iteratively calculate errors, one layer at a time, starting at the output. This is called backpropagation. It is neither magical nor surprising. The challenge is just doing it fast and not losing information.__
# MAGIC
# MAGIC

# COMMAND ----------

# MAGIC %md
# MAGIC ## Ok so we've come up with a very slow way to perform a linear regression.
# MAGIC
# MAGIC ### *Welcome to Neural Networks in the 1960s!*
# MAGIC
# MAGIC ---
# MAGIC
# MAGIC ### Watch closely now because this is where the magic happens...
# MAGIC
# MAGIC

# COMMAND ----------

# MAGIC %md
# MAGIC # Non-Linearity + Perceptron = Universal Approximation

# COMMAND ----------

# MAGIC %md
# MAGIC ### Where does the non-linearity fit in?
# MAGIC
# MAGIC * We start with the inputs to a perceptron -- these could be from source data, for example.
# MAGIC * We multiply each input by its respective weight, which gets us the \\(x \cdot w\\)
# MAGIC * Then add the "bias" -- an extra learnable parameter, to get \\({x \cdot w} + b\\)
# MAGIC     * This value (so far) is sometimes called the "pre-activation"
# MAGIC * Now, apply a non-linear "activation function" to this value, such as the logistic sigmoid
# MAGIC
# MAGIC
# MAGIC
# MAGIC ### Now the network can "learn" non-linear functions
# MAGIC
# MAGIC To gain some intuition, consider that where the sigmoid is close to 1, we can think of that neuron as being "on" or activated, giving a specific output. When close to zero, it is "off."
# MAGIC
# MAGIC So each neuron is a bit like a switch. If we have enough of them, we can theoretically express arbitrarily many different signals.
# MAGIC
# MAGIC In some ways this is like the original artificial neuron, with the thresholding output -- the main difference is that the sigmoid gives us a smooth (arbitrarily differentiable) output that we can optimize over using gradient descent to learn the weights.
# MAGIC
# MAGIC ### Where does the signal "go" from these neurons?
# MAGIC
# MAGIC * In a regression problem, like the diamonds dataset, the activations from the hidden layer can feed into a single output neuron, with a simple linear activation representing the final output of the calculation.
# MAGIC
# MAGIC * Frequently we want a classification output instead -- e.g., with MNIST digits, where we need to choose from 10 classes. In that case, we can feed the outputs from these hidden neurons forward into a final layer of 10 neurons, and compare those final neurons' activation levels.
# MAGIC
# MAGIC Ok, before we talk any more theory, let's run it and see if we can do better on our diamonds dataset adding this "sigmoid activation."
# MAGIC
# MAGIC While that's running, let's look at the code:

# COMMAND ----------

from keras.models import Sequential
from keras.layers import Dense
import numpy as np
import pandas as pd

input_file = "/dbfs/databricks-datasets/Rdatasets/data-001/csv/ggplot2/diamonds.csv"

df = pd.read_csv(input_file, header = 0)
df.drop(df.columns[0], axis=1, inplace=True)
df = pd.get_dummies(df, prefix=['cut_', 'color_', 'clarity_'])

y = df.iloc[:,3:4].as_matrix().flatten()
y.flatten()

X = df.drop(df.columns[3], axis=1).as_matrix()
np.shape(X)

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)

model = Sequential()
model.add(Dense(30, input_dim=26, kernel_initializer='normal', activation='sigmoid')) # <- change to nonlinear activation
model.add(Dense(1, kernel_initializer='normal', activation='linear')) # <- activation is linear in output layer for this regression

model.compile(loss='mean_squared_error', optimizer='adam', metrics=['mean_squared_error'])
history = model.fit(X_train, y_train, epochs=2000, batch_size=100, validation_split=0.1, verbose=2)

scores = model.evaluate(X_test, y_test)
print("\nroot %s: %f" % (model.metrics_names[1], np.sqrt(scores[1])))

# COMMAND ----------

# MAGIC %md
# MAGIC ##### What is different here?
# MAGIC
# MAGIC * We've changed the activation in the hidden layer to "sigmoid" per our discussion.
# MAGIC * Next, notice that we're running 2000 training epochs!
# MAGIC
# MAGIC Even so, it takes a looooong time to converge. If you experiment a lot, you'll find that ... it still takes a long time to converge. Around the early part of the most recent deep learning renaissance, researchers started experimenting with other non-linearities.
# MAGIC
# MAGIC (Remember, we're talking about non-linear activations in the hidden layer. The output here is still using "linear" rather than "softmax" because we're performing regression, not classification.)
# MAGIC
# MAGIC In theory, any non-linearity should allow learning, and maybe we can use one that "works better"
# MAGIC
# MAGIC By "works better" we mean
# MAGIC
# MAGIC * Simpler gradient - faster to compute
# MAGIC * Less prone to "saturation" -- where the neuron ends up way off in the 0 or 1 territory of the sigmoid and can't easily learn anything
# MAGIC * Keeps gradients "big" -- avoiding the large, flat, near-zero gradient areas of the sigmoid
# MAGIC
# MAGIC Turns out that a big breakthrough and popular solution is a very simple hack:
# MAGIC
# MAGIC ### Rectified Linear Unit (ReLU)
# MAGIC
# MAGIC

# COMMAND ----------

# MAGIC %md
# MAGIC ### Go change your hidden-layer activation from 'sigmoid' to 'relu'
# MAGIC
# MAGIC Start your script and watch the error for a bit!

# COMMAND ----------

from keras.models import Sequential
from keras.layers import Dense
import numpy as np
import pandas as pd

input_file = "/dbfs/databricks-datasets/Rdatasets/data-001/csv/ggplot2/diamonds.csv"

df = pd.read_csv(input_file, header = 0)
df.drop(df.columns[0], axis=1, inplace=True)
df = pd.get_dummies(df, prefix=['cut_', 'color_', 'clarity_'])

y = df.iloc[:,3:4].as_matrix().flatten()
y.flatten()

X = df.drop(df.columns[3], axis=1).as_matrix()
np.shape(X)

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)

model = Sequential()
model.add(Dense(30, input_dim=26, kernel_initializer='normal', activation='relu')) # <--- CHANGE IS HERE
model.add(Dense(1, kernel_initializer='normal', activation='linear'))

model.compile(loss='mean_squared_error', optimizer='adam', metrics=['mean_squared_error'])
history = model.fit(X_train, y_train, epochs=2000, batch_size=100, validation_split=0.1, verbose=2)

scores = model.evaluate(X_test, y_test)
print("\nroot %s: %f" % (model.metrics_names[1], np.sqrt(scores[1])))

# COMMAND ----------

# MAGIC %md
# MAGIC Would you look at that?!
# MAGIC
# MAGIC * We break $1000 RMSE around epoch 112
# MAGIC * $900 around epoch 220
# MAGIC * $800 around epoch 450
# MAGIC * By around epoch 2000, my RMSE is < $600
# MAGIC
# MAGIC ...
# MAGIC
# MAGIC
# MAGIC __Same theory; different activation function. Huge difference__

# COMMAND ----------

# MAGIC %md
# MAGIC # Multilayer Networks
# MAGIC
# MAGIC If a single-layer perceptron network learns the importance of different combinations of features in the data...
# MAGIC
# MAGIC What would another network learn if it had a second (hidden) layer of neurons?
# MAGIC
# MAGIC It depends on how we train the network. We'll talk in the next section about how this training works, but the general idea is that we still work backward from the error gradient.
# MAGIC
# MAGIC That is, the last layer learns from error in the output; the second-to-last layer learns from error transmitted through that last layer, etc. It's a touch hand-wavy for now, but we'll make it more concrete later.
# MAGIC
# MAGIC Given this approach, we can say that:
# MAGIC
# MAGIC 1. The second (hidden) layer is learning features composed of activations in the first (hidden) layer
# MAGIC 2. The first (hidden) layer is learning feature weights that enable the second layer to perform best
# MAGIC     * Why? Earlier, the first hidden layer just learned feature weights because that's how it was judged
# MAGIC     * Now, the first hidden layer is judged on the error in the second layer, so it learns to contribute to that second layer
# MAGIC 3. The second layer is learning new features that aren't explicit in the data, and is teaching the first layer to supply it with the necessary information to compose these new features
# MAGIC
# MAGIC ### So instead of just feature weighting and combining, we have new feature learning!
# MAGIC
# MAGIC This concept is the foundation of the "Deep Feed-Forward Network"
# MAGIC
# MAGIC
# MAGIC
# MAGIC ---
# MAGIC
# MAGIC ### Let's try it!
# MAGIC
# MAGIC __Add a layer to your Keras network, perhaps another 20 neurons, and see how the training goes.__
# MAGIC
# MAGIC if you get stuck, there is a solution in the Keras-DFFN notebook
# MAGIC
# MAGIC ---
# MAGIC
# MAGIC I'm getting RMSE < $1000 by epoch 35 or so
# MAGIC
# MAGIC < $800 by epoch 90
# MAGIC
# MAGIC In this configuration, mine makes progress to around 700 epochs or so and then stalls with RMSE around $560

# COMMAND ----------

# MAGIC %md
# MAGIC ### Our network has "gone meta"
# MAGIC
# MAGIC It's now able to exceed where a simple decision tree can go, because it can create new features and then split on those
# MAGIC
# MAGIC ## Congrats! You have built your first deep-learning model!
# MAGIC
# MAGIC So does that mean we can just keep adding more layers and solve anything?
# MAGIC
# MAGIC Well, theoretically maybe ... try reconfiguring your network, watch the training, and see what happens.
# MAGIC
# MAGIC


import numpy as np
a = np.array([10,20,30,40])
b = np.arange(4)

print(a,b)
c = a+b
print(c)

#b的平方
d = b ** 2
print(d)

e = 10 * np.sin(a)
print(e)

print(b)
print(b<3)

aa = np.array([[1,1],
               [0,1]])
bb = np.arange(4).reshape(2,2)
c = aa * bb
c_dot = np.dot(aa,bb)
# another write method
c_dot_2 = aa.dot(bb)
print(aa)
print(bb)
print(c)
print(c_dot)
print(c_dot_2)

f = np.random.random((2,4))
print(f)
print(np.sum(f,axis=1))
print(np.min(f,axis=0))
print(np.max(f,axis=1))


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

#######################################
#setting up
print ("Lets getstarted with non linear regression")
import math
import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVR
from sklearn.linear_model import LinearRegression

#train data/model input
x = np.array([[64], [128], [256],[512]])
y = np.array([[38440.0], [158760.0],  [645160.0], [2601000.0]])
yflat = np.array([38440.0, 158760.0,  645160.0, 2601000.0])

x_log = np.array([[math.log(d,2)] for d in x])

#here, we are giving an estimated model
x_new = np.hstack([ x_log, x, x**2, x**3]) # if you take x**4 it might overfit

# # Building Models
# Lets build some sample models.

#################################### building models
#model 1 -- scikit linear regression
model = LinearRegression()
model.fit(x_new,y)

#to hecking model
#x.shape
#x_new.shape
#model.coef_
#model.intercept_

#test data
xt = np.array([[256], [512], [1024], [2048],[4096],
               [8*1024],[16*1024], [1024*32]
              ])
xt_log = np.array([[math.log(d,2)] for d in xt])
x_target = np.hstack([xt_log, xt, xt**2, xt**3])
y_pred = model.predict(x_target) #LinearRegression()--sklearn.linear_model

#Model 2 SVR/POLY -- http://scikit-learn.org/stable/auto_examples/svm/plot_svm_regression.html
svr_poly = SVR(kernel='poly', C=1e3, degree=2, gamma='scale')
model_poly = svr_poly.fit(x, yflat)
xtest_large = np.array([[4096], [8192], [16384] ])
y_poly = model_poly.predict(xtest_large)

#Model 3 -- SVR LINEAR
#svr_lin = SVR(kernel='linear', C=1e3)

#Model 4, SVR RBF kernel
#svr_rbf = SVR(kernel='rbf', C=1e3, gamma=0.1)
#model_rbf  = svr_rbf.fit(x, yflat)
#xtest2 = np.array([[512], [1024], [2048], [4096], [8192] ])
#y_rbf = model_rbf.predict(xtest2)
#plt.plot(xtest2, y_rbf, color='navy', lw=lw, label='RBF model')

# ## Lets Plot our results and the source data
# We can write the results to a file or plot using matplotlib

############################ plotting

#markers: ['o', '.', ',', 'x', '+', 'v', '^', '<', '>', 's', 'd']:#default o
#linestyle: '-', '--', '-.', ':', '', (offset, on-off-seq), ...}

lw, msize = 2, 10
plt.xlabel('Problem Size')
plt.ylabel('Kernel Iterations')
plt.title('Iteration Estimation SVR vs. Linear')

#our plots
plt.scatter(x,y,marker="o", label="Data",
          edgecolor='black', facecolor='none', s=50.0)
plt.plot(xt,y_pred,'blue', label="LinearRegression", marker="+", linestyle="-.", ms=msize)
plt.plot(xtest_large, y_poly, color='black', lw=lw, linestyle="--",label='Polynomial/Scaling SVR', marker="x", ms=msize)

plt.legend() #oldest last
plt.show()


from statistics import mean
import numpy as np
import matplotlib.pyplot as plt

from matplotlib import style
import random

style.use("fivethirtyeight")

# xs = np.array([1, 2, 3, 4, 5, 6], dtype=np.float64)
# ys = np.array([5, 4, 6, 5, 6, 7], dtype=np.float64)

# hm = how many datapoints
# variance = how variable do we want the dataset to be
# step how far on average should we step up per point
def create_dataset(hm, variance, step=2, correlation=False):
	val = 1
	ys = []
	for i in range(hm):
		y = val + random.randrange(-variance, variance)
		ys.append(y)
		if correlation and correlation == "pos":
			val += step
		elif correlation and correlation == "neg":
			val -= step

	xs = [i for i in range(len(ys))]

	return np.array(xs, dtype=np.float64), np.array(ys, dtype=np.float64)

def best_fit_slope_and_intercept(xs, ys):
	m = ( ( ( mean(xs) * mean(ys) ) - mean(xs*ys) ) /
		( (mean(xs) ** 2) - mean(xs**2) )
		)
	b = mean(ys) - m * mean(xs)

	return m, b

# Distance between the line in question and the points
def squared_error(ys_orig, ys_line):

	return sum( (ys_line - ys_orig)**2 )

def coefficient_of_determination(ys_orig, ys_line):
	y_mean_line = [ mean(ys_orig) for y in ys_orig ]
	squared_error_regr = squared_error(ys_orig, ys_line)
	squared_error_y_mean = squared_error(ys_orig, y_mean_line)

	return 1 - (squared_error_regr / squared_error_y_mean)

# Lower the variance the better the accuracy
xs, ys = create_dataset(40, 10, 2, correlation="pos")

m, b = best_fit_slope_and_intercept(xs, ys)

regression_line = [(m*x) + b for x in xs]

# Predict x = 8
predict_x = 8
predict_y = (m*predict_x) + b

# plt.scatter(xs, ys)
# plt.plot(xs, regression_line)
# plt.show()

r_squared = coefficient_of_determination(ys, regression_line)

# Anything above 0 means the regression is more accurate.
# squared error and cofficient of determination is a way to calculate
# how good of a fit the best fit line is
print r_squared


import matplotlib.pyplot as plt
from ipywidgets import interact, fixed
import numpy as np
plt.style.use('seaborn-whitegrid')
from mpl_toolkits.mplot3d import *
from matplotlib import cm
from scipy.optimize import minimize

plt.style.use('bmh')
plt.rcParams["figure.figsize"] = [7,7]
plt.rcParams["axes.spines.right"] = False
plt.rcParams["axes.spines.top"] = False
plt.rcParams["font.size"] = 18

ALPHA = 1/2

# Consumer choice

def budgetc(c0,p,I):
    '''c1 as a function of c0 along budget line'''
    return I - p*c0

def u(c, a=ALPHA):
    '''Utility at c=(c[0], c[1])'''
    return (c[0]**a)*(c[1]**(1-a))

def MU0(c, a=ALPHA):
    '''MU of Cobb-Douglas'''
    return  a*u(c,a)/c[0]

def MU1(c, a=ALPHA):
    return  (1-a)*u(c,a)/c[1]

def indif(c0, ubar, a=ALPHA):
    '''c1 as function of c0, implicitly defined by U(c0, c1) = ubar'''
    return (ubar/(c0**a))**(1/(1-a))

def cd_demands(p,I,a =ALPHA):
    '''Analytic solution for interior optimum'''
    c0 = a * I/p
    c1 = (1-a)*I
    c = [c0,c1]
    uopt = u(c,a)
    return c, uopt

def consume_plot(p, I, a=ALPHA):
    cmax = max(I, I/p)*1.1
    c0 = np.linspace(0.1,cmax,num=100)
    ce, uebar = cd_demands(p, I, a)
    fig, ax = plt.subplots(figsize=(9,9))
    ax.plot(c0, budgetc(c0, p, I), lw=2.5)
    ax.fill_between(c0, budgetc(c0, p, I), alpha = 0.2)
    ax.plot(c0, indif(c0, uebar, a), lw=2.5)
    ax.vlines(ce[0],0,ce[1], linestyles="dashed")
    ax.hlines(ce[1],0,ce[0], linestyles="dashed")
    ax.plot(ce[0],ce[1],'ob')

    ax.set_xlim(0, cmax)
    ax.set_ylim(0, cmax)
    ax.set_xlabel(r'$c_0$', fontsize=16)
    ax.set_ylabel('$c_1$', fontsize=16)
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)

def arb_plot(c0g, I, p):
    cg = [c0g, I - c0g]
    cmax = max(I, I/p)*1.1
    c0 = np.linspace(0.1,cmax,num=100)

    '''Display characteristics of a guess along the constraint'''
    fig, ax = plt.subplots(figsize=(9,9))
    ax.plot(c0, budgetc(c0, p, I), lw=1)
    ax.fill_between(c0, budgetc(c0, p, I), alpha = 0.2)
    ax.plot(c0, indif(c0, u(cg)), lw=2.5)
    ax.vlines(cg[0],0,cg[1], linestyles="dashed")
    ax.hlines(cg[1],0,cg[0], linestyles="dashed")
    ax.plot(cg[0],cg[1],'ob')
    mu0pd, mu1pd = MU0(cg), MU1(cg)/p
    if mu0pd > mu1pd:
        inq = r'$>$'
    elif mu0pd < mu1pd:
        inq = r'$<$'
    else:
        inq =r'$=$'
    ax.text(60, 120, r'$\frac{MU_0}{p_0}$'+inq+r'$\frac{MU_1}{p_1}$',fontsize=20)
    utext = r'$({:5.1f}, {:5.1f}) \ \ U={:5.3f}$'.format(cg[0], cg[1], u(cg))
    ax.text(60, 100, utext, fontsize=12)
    ax.set_xlim(0, cmax)
    ax.set_ylim(0, cmax)
    ax.set_xlabel(r'$c_0$', fontsize=16)
    ax.set_ylabel('$c_1$', fontsize=16)
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)
    ax.set_title('The No-Arbitrage argument')
    plt.show()

#

## Ricardian model

def rppf(mplx, mply, lbar, show = True, title='Home'):
    '''Plot a linear PPF diagram
       show == False delays plt.show() to allow other elements to be plotted first'''
    qy = mply*lbar - (mply/mplx) * QX
    plt.plot(QX, qy, linewidth=2, label='PPF')
    plt.axis([0,XMAX,0,YMAX])
    plt.xlabel(NAMEX), plt.ylabel(NAMEY), plt.title(title)
    plt.text(0.3*XMAX, 0.9*YMAX,
             r'   $\frac{MPL_Y}{MPL_X}=$'+'{:3.2f}'.format(mply/mplx))
    if show: #use False for subplots
        plt.show();

## Linear Demand and Supply

def PD(Q, A, b):
    return np.array(A - b * Q)

def PS(Q, F, c):
    return np.array(F + c * Q)

def market(Q, A, b, F, c):
    plt.figure(figsize=(7,7))
    plt.plot(Q,PD(Q, A, b))
    plt.plot(Q, PS(Q, F, c))
    plt.show()

if __name__ == '__main__':
    print('Running program tests')


import numpy as np

def get_pagerank(adj_matrix, DAMPING_FACTOR=0.15, EPSILON=0.001):
    """[summary]
        pagerank values calculation

    Arguments:
        adj_matrix {[float[][]]} -- [[input Adjacent matrix lists like [[1, 0], [0, 1]]]

    Keyword Arguments:
        DAMPING_FACTOR {float} -- [factor of residual probability] (default: {0.15})
        EPSILON {float} -- [factor of change comparision] (default: {0.01})

    Returns:
        [float[]] -- [pagerank values]
    """

    # initialize
    page_length = adj_matrix.shape[0]
    pagerank = np.ones(page_length)
    new_pagerank = np.ones(page_length)
    escape = DAMPING_FACTOR / page_length

    # normalize
    normalize_adj_matrix = adj_matrix / np.linalg.norm(adj_matrix, ord=1, axis=1, keepdims=True)
    normalize_adj_matrix = np.nan_to_num(normalize_adj_matrix)
    is_coverage = False
    while not is_coverage:
        for node in range(page_length):
            single_rank = escape + (1-DAMPING_FACTOR) * np.dot(normalize_adj_matrix.T, new_pagerank)[node]
            new_pagerank[node] = single_rank

        # normalize pagerank
        normalize_pagerank = lambda x: x / sum(new_pagerank)
        new_pagerank = normalize_pagerank(new_pagerank)

        # check is coverage
        diff = abs(sum(new_pagerank - pagerank))

        if diff < EPSILON:
            is_coverage = True
        else:
            pagerank = new_pagerank.copy()

    return new_pagerank


"""
Burak Himmetoglu, 2019

Loss functions
"""

import numpy as np

EPS = 1e-5 # Clipping factor for probabilities

def mse(Y, yHat):
    return np.mean( (Y-yHat)**2)

def binary_log_loss(Y, P):
    """
    Compute negative log loss
    """
    N = len(Y)
    # Clip values very close to 1 or 0
    P = np.clip(P, EPS, 1 - EPS)

    # Negative log likelihood function
    mask0 = (Y == 0) # label = 0 observations
    mask1 = (Y == 1) # label = 1 observations

    nll = -(np.log(P[mask1]).sum() + np.log(1-P[mask0]).sum())

    return nll/N


import numpy as np

def polar_to_cartesion(r, phi):
    '''
    Two 1D vectors of polar r (radial) and phi (angular) coordinates
    Function returns the Cartesian vectors
    '''
    x = r * np.cos(phi)
    y = r * np.sin(phi)
    return x, y

def cartesian_to_polar(x, y):
    '''
    Two 1d vectors of cartesian x and y coordinates
    Function converts them to polar coordinates r and phi
    '''
    r = np.sqrt(np.square(x) + np.square(y))
    phi = np.arctan2(y, x)
    return r, phi

def cartesian_to_spherical_coords(vectors):
    '''
    N by 3 vectors of (x, y, z) are converted to spherical coordinates
    '''
    r = np.sqrt(np.sum(np.square(vectors), axis=-1))
    theta = np.arctan(np.sqrt(np.square(vectors[:, 0]) + np.square(vectors[:, 1]))/vectors[:, 2])
    phi = np.zeros(np.size(vectors[:, 0]))
    phi[vectors[:, 0] != 0] = np.arctan(vectors[:, 1][vectors[:, 0] != 0]/vectors[:, 0][vectors[:, 0] !=0])
#    theta = np.arctan(vectors[:, 1]/vectors[:, 2])
#    phi = np.arccos(vectors[:, 0]/r)
    phi[(vectors[:, 1] > 0) * (vectors[:, 0] < 0)] += np.pi # +y, -z
    phi[(vectors[:, 1] < 0) * (vectors[:, 0] >= 0)] += 2*np.pi # -y, +z
    phi[(vectors[:, 1] < 0) * (vectors[:, 0] < 0)] += np.pi # -y, -z
    phi[(vectors[:, 1] > 0) * (vectors[:, 0] == 0)] = np.pi/2
    phi[(vectors[:, 1] < 0) * (vectors[:, 0] == 0)] = 3*np.pi/2
    phi[(vectors[:, 1] == 0) * (vectors[:, 0] <= 0)] = np.pi
    theta[theta<0] += np.pi
    return r, theta, phi

def spherical_to_cartesian_coords(vectors):
    '''
    N by 3 vectors of (r, theta, phi)
    '''
    x = vectors[:, 0] * np.sin(vectors[:, 1]) * np.cos(vectors[:, 2])
    y = vectors[:, 0] * np.sin(vectors[:, 1]) * np.sin(vectors[:, 2])
    z = vectors[:, 0] * np.cos(vectors[:, 1])
    return x, y, z

def cartesian_to_spherical_vector_field(theta, phi, fx, fy, fz):
    f_r = (np.sin(theta) * np.cos(phi) * fx +
       np.sin(theta) * np.sin(phi) * fy +
       np.cos(theta) * fz)
    f_th = (np.cos(theta) * np.cos(phi) * fx +
        np.cos(theta) * np.sin(phi) * fy -
        np.sin(theta) * fz)
    f_ph = (-np.sin(phi) * fx +
        np.cos(phi) * fy)
    return f_r, f_th, f_ph

def spherical_to_cartesian_vector_field(theta, phi, f_r, f_th, f_ph):
    f_x = (np.sin(theta) * np.cos(phi) * f_r +
           np.cos(theta) * np.cos(phi) * f_th -
           np.sin(phi) * f_ph)
    f_y = (np.sin(theta) * np.sin(phi) * f_r +
           np.cos(theta) * np.sin(phi) * f_th +
           np.cos(phi) * f_ph)
    f_z = (np.cos(theta) * f_r -
           np.sin(theta) * f_th)
    return f_x, f_y, f_z

def field_magnitude(f, axis=-1):
    f_mag = np.sqrt(np.sum(f * np.conj(f), axis=axis))
    f_mag = np.real(f_mag)
    return f_mag

def rotate_vector(xyz, angle, rotation_axis):
    '''
    xyz: a vectors to be rotated, length 3
    angle: the angle by which to rotate xyz, in radians
    rotation_axis: the axis around which to rotate xyz of length 3
    '''
    if np.count_nonzero(xyz) == 0:
        raise ValueError('Input vector is the null vector')
    term1_rot = xyz*np.cos(angle)
    term2_rot = np.cross(rotation_axis, xyz, axis=0) * np.sin(angle)
    term3_rot = rotation_axis * np.transpose(np.tensordot(rotation_axis, xyz, axes=(0,0)))*(1-np.cos(angle))
    xyz_rot = term1_rot + term2_rot + term3_rot
    return xyz_rot

def rotate_vector_Nd(xyz, angle, rotation_axis):
    '''
    xyz: an array of vectors to be rotated, with N dimensions, of which the last has 3 elements
    angle: the angle by which to rotate xyz, in radians
    rotation_axis: the axis around which to rotate xyz, of length 3
    '''
    # Normalize rotation axis
    rotation_axis = rotation_axis/np.sqrt(np.sum(np.square(rotation_axis)))
    # Expand dimensions of rotation axis for broadcasting
    rotation_axis = np.reshape(rotation_axis, (xyz.ndim-1)*[1]+[3])
    # Calculate rotation vector (Rodrigues formula)
    term1_rot = xyz*np.cos(angle)
    term2_rot = np.cross(rotation_axis, xyz, axis=-1) * np.sin(angle)
    term3_rot = rotation_axis * np.expand_dims(np.dot(xyz, np.squeeze(rotation_axis)), axis=-1)*(1-np.cos(angle))
    xyz_rot = term1_rot + term2_rot + term3_rot
    return xyz_rot

def expand_quadrant_symmetry(mag, quadrant_num):
    '''
    Uses symmetry to turn an array representing values in one quadrant of an
    image into values for a whole image/array
    quadrant_num = 1, 2, 3 ,4
    quadrants: 1  2
               3  4
    assumes image should be reflected around two axes, removing double rows/columns of pixels caused by reflection
    '''
    if quadrant_num == 1:
        Q1 = mag
        Q2 = np.flip(Q1, axis = 1)[:, 1:]
        Q3 = np.flip(Q1, axis = 0)[1:, :]
        Q4 = np.flip(np.flip(Q1, axis = 1), axis=0)[1:, 1:]
    elif quadrant_num == 2:
        Q2 = mag
        Q1 = np.flip(Q2, axis = 1)[:, :-1]
        Q4 = np.flip(Q2, axis = 0)[1:, :]
        Q3 = np.flip(np.flip(Q2, axis=1), axis=0)[1:, :-1]
    elif quadrant_num == 3:
        Q3 = mag
        Q4 = np.flip(Q3, axis=1)[:, 1:]
        Q1 = np.flip(Q3, axis=0)[:-1, :]
        Q2 = np.flip(np.flip(Q3, axis=1), axis=0)[:-1, 1:]
    elif quadrant_num == 4:
        Q4 = mag
        Q3 = np.flip(Q4, axis=1)[:, :-1]
        Q2 = np.flip(Q4, axis = 0)[:-1, :]
        Q1 = np.flip(np.flip(Q4, axis=1), axis=0)[:-1, :-1]

    Q12 = np.append(Q1, Q2, axis=1)
    Q34 = np.append(Q3, Q4, axis=1)
    total = np.append(Q12, Q34, axis=0)
    return total


import numpy as np
import math

# this is the estimated population variance where the denominator is n-1
def variance(x):
    return np.var(x, ddof=1)

def covariance(x1,x2):
    mean_x1 = np.mean(x1)
    mean_x2 = np.mean(x2)
    num_measurements = x1.size # should be same as x2.size
    return np.dot(x1 - mean_x1 , x2 - mean_x2) / (num_measurements - 1)

# ---- correlation is always between -1,1
def correlation(x1,x2):
    variance_x1 = variance(x1)
    variance_x2 = variance(x2)
    return covariance/(math.sqrt(variance_x1) * math.sqrt(variance_x2) )


import sys
import numpy as np

def floyd_warshall(graph):
    dist = graph.copy()

    v = graph.shape[0]

    for k in range(v):
        for i in range(v):
            for j in range(v):
                if dist[i,k] + dist[k,j] < dist[i,j]:
                    dist[i,j] = dist[i,k] + dist[k,j]

    return dist

def minDistance(dist, V, sptSet):
    minimum = sys.maxint
    for v in range(V):
        if dist[v] < minimum and sptSet[v] == False:
            minimum = dist[v]
            min_index = v
    return min_index

def dijkstra(g,V,src = 0):
    graph = g.copy()
    dist = [sys.maxint] * V
    dist[src] = 0
    sptSet = [False] * V
    for cout in range(V):
        u = minDistance(dist, V, sptSet)
        sptSet[u] = True

        for v in range(V):
            if(graph[u][v] > 0 and sptSet[v] == False
                and dist[v] > dist[u] + graph[u][v]):
                    dist[v] = dist[u] + graph[u][v]

    return np.asarray(dist)


"""
Objetivo: Resolver questão 3 do segundo laboratorio.
"""
from math import pow, pi, cos
import numpy as np

def cosseno(a):  # calcula o cosseno do angulo
    soma = 0
    for i in range(0, 30):
        soma = soma + (pow(-1, i) * (pow(a, 2 * i) / fatorial(2 * i)))
        # o primeiro elemento escolhe o sinal, o segundo o numero da expressão
    return soma

def fatorial(n):  # calcula o fatorial de um numero qualquer
    if n == 0:
        return 1
    else:
        x = 1
        for i in range(1, n + 1):
            x = x * i
        return x

# usaremos numpy para gerar um lista onde o passo possa ser float, coisa que no for não se pode
c = np.arange(0, pi + 0.00001, (pi / 100))  # +0.00001 para que o valor de pi tambem entre no array

cossenos_aprox = [cosseno(i) for i in c]
# gera uma lista onde cada item é valor de uma iteração do for aplicando a função
print(f'Valores aproximados = {cossenos_aprox}')

cossenos_exatos = [cos(i) for i in c]  # lista com valores exatos dos cossenos
print(f'Valores exatos = {cossenos_exatos}')

erro = abs(cossenos_exatos[-1] - cossenos_aprox[-1])
# como o erro aumenta a cada iteração da nossa função, escolhendo o ultimo valor de cada lista, teremos o maior erro
# possivel
print(f'Erro absoluto = {erro}')


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
BE523 Biosystems Analysis & Design
HW5 - Problem 1. Calculation of exponential K
https://mathinsight.org/doubling_time_half_life_discrete

Created on Tue Jan 26 22:37:49 2021
@author: eduardo
"""
import statsmodels.api as sm  # allows linear regression without intercept
import matplotlib.pyplot as plt
import numpy as np

# Bacteria density data
B = np.array([22.1, 23.4, 26.1, 27.5, 30.5, 34.4, 36.6])  # Exercise 4C

steps = len(B)  # Adjust the lengths of the vectors with the number of steps
dB = np.zeros(steps)
Bexp = np.zeros(steps)
dt = 5
t = np.linspace(0, (steps-1)*dt, steps)  # time vector

for i in range(1, steps):
    dB[i] = B[i] - B[i-1]  # compute the increment between time steps

print(B)

# Perform a linear regression with B and dB, then plot (dB vs B)
model = sm.OLS(dB, B)  # No intercept by default, force through the origin??
results = model.fit()
slope = results.params[0]  # growth rate
print("slope=", slope)

# Figure 1, plotting dB vs B
plt.figure(1)
plt.plot(B, dB, 'bx', B, slope*B, 'r-')  # plot and linear eq.
plt.legend(['data', 'linear regression $R^2$=%.2f' % results.rsquared], loc='best')
plt.xlabel('B')
plt.ylabel('dB')
# plt.savefig('p1_growth_%dsteps_linear2.png' % steps, dpi=300, bbox_inches='tight')

# Create the parameters for an exponential equation
tdouble = np.log(2)/np.log(1+slope)*dt  # time to double population
mu = np.log(2)/tdouble  # constant for exponential eq. with base on natural log
print('tdouble =', tdouble, 'mu=', mu)

# Generate an exponential equation (exact solution)
Bexp = B[0] * np.exp(mu*t)

# Generate predictions with the model: B(t+1) = B[0]*(r+1)^t (numerical solution)
Bmodel = B[0] * (1 + slope)**(t/dt)

# Figure 2, plotting B vs t
plt.figure(2)
plt.plot(t, B, 'bx', t, Bmodel, 'r-', t, Bexp, 'k+')  # Plot data vs exponential growth eq.
plt.legend(['data',
            'equation B=%.2f*%.3f^t' % (B[0], slope+1),
            'exponential B=%.2f * exp(%.3f*t)' % (B[0], mu)],
           loc='best')
plt.xlabel('time (min)')
plt.ylabel('B')
plt.savefig('p1_growth_%dsteps2.png' % steps, dpi=300, bbox_inches='tight')


import numpy as np

# numpy.amin() 用于计算数组中的元素沿指定轴的最小值。
# numpy.amax() 用于计算数组中的元素沿指定轴的最大值。
a = np.array([[3, 7, 5], [8, 4, 3], [2, 4, 9]])
print('我们的数组是：')
print(a)
print('\n')
print('调用 amin() 函数：')
print(np.amin(a, 1))
print('\n')
print('再次调用 amin() 函数：')
print(np.amin(a, 0))
print('\n')
print('调用 amax() 函数：')
print(np.amax(a))
print('\n')
print('再次调用 amax() 函数：')
print(np.amax(a, axis=0))

# numpy.ptp()函数计算数组中元素最大值与最小值的差（最大值 - 最小值）。
a = np.array([[3, 7, 5], [8, 4, 3], [2, 4, 9]])
print('我们的数组是：')
print(a)
print('\n')
print('调用 ptp() 函数：')
print(np.ptp(a))
print('\n')
print('沿轴 1 调用 ptp() 函数：')
print(np.ptp(a, axis=1))
print('\n')
print('沿轴 0 调用 ptp() 函数：')
print(np.ptp(a, axis=0))

# numpy.percentile()
# 百分位数是统计中使用的度量，表示小于这个值的观察值的百分比。 函数numpy.percentile()接受以下参数。
#
# numpy.percentile(a, q, axis)
# 参数说明：
#
# a: 输入数组
# q: 要计算的百分位数，在 0 ~ 100 之间
# axis: 沿着它计算百分位数的轴
a = np.array([[10, 7, 4], [3, 2, 1]])
print('我们的数组是：')
print(a)

print('调用 percentile() 函数：')
# 50% 的分位数，就是 a 里排序之后的中位数
print(np.percentile(a, 50))

# axis 为 0，在纵列上求
print(np.percentile(a, 50, axis=0))

# axis 为 1，在横行上求
print(np.percentile(a, 50, axis=1))

# 保持维度不变
print(np.percentile(a, 50, axis=1, keepdims=True))

# numpy.median()
# numpy.median() 函数用于计算数组 a 中元素的中位数（中值）
a = np.array([[1, 2, 3], [3, 4, 5], [4, 5, 6]])
print('我们的数组是：')
print(a)
print('\n')
print('调用 mean() 函数：')
print(np.mean(a))
print('\n')
print('沿轴 0 调用 mean() 函数：')
print(np.mean(a, axis=0))
print('\n')
print('沿轴 1 调用 mean() 函数：')
print(np.mean(a, axis=1))

# numpy.average()
# numpy.average() 函数根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值。
#
# 该函数可以接受一个轴参数。 如果没有指定轴，则数组会被展开。
#
# 加权平均值即将各数值乘以相应的权数，然后加总求和得到总体值，再除以总的单位数。
#
# 考虑数组[1,2,3,4]和相应的权重[4,3,2,1]，通过将相应元素的乘积相加，并将和除以权重的和，来计算加权平均值。
a = np.array([1, 2, 3, 4])
print('我们的数组是：')
print(a)
print('\n')
print('调用 average() 函数：')
print(np.average(a))
print('\n')
# 不指定权重时相当于 mean 函数
wts = np.array([4, 3, 2, 1])
print('再次调用 average() 函数：')
print(np.average(a, weights=wts))
print('\n')
# 如果 returned 参数设为 true，则返回权重的和
print('权重的和：')
print(np.average([1, 2, 3, 4], weights=[4, 3, 2, 1], returned=True))

a = np.arange(6).reshape(3, 2)
print('我们的数组是：')
print(a)
print('\n')
print('修改后的数组：')
wt = np.array([3, 5])
print(np.average(a, axis=1, weights=wt))
print('\n')
print('修改后的数组：')
print(np.average(a, axis=1, weights=wt, returned=True))

# 标准差
# 标准差是一组数据平均值分散程度的一种度量。
#
# 标准差是方差的算术平方根。
#
# 标准差公式如下：
#
# std = sqrt(mean((x - x.mean())**2))
# 如果数组是 [1，2，3，4]，则其平均值为 2.5。 因此，差的平方是 [2.25,0.25,0.25,2.25]，并且再求其平均值的平方根除以 4，即 sqrt(5/4) ，结果为 1.1180339887498949。
print(np.std([1, 2, 3, 4]))
# 方差
# 统计中的方差（样本方差）是每个样本值与全体样本值的平均数之差的平方值的平均数，即 mean((x - x.mean())** 2)。
#
# 换句话说，标准差是方差的平方根。

print(np.var([1, 2, 3, 4]))


"""
The Commodity Channel Index (CMCI), developed by Donald Lambert,
measures the variation of a security's price from its statistical mean.

The CMCI can be used to identify possible divergences that may indicate
a forthcoming trend for a selected security. A CMCI indicator falling
below a value of -100 indicates an oversold condition. A buy signal is
triggered when the indicator crosses -100 from below. Similarly, a CCI
value greater than 100 indicates an overbought condition. A sell signal
is triggered when the indicator crosses 100 from above.

CMCI Calculations
CMCI=(HLC3 - N Period Simple MA of HLC3) /
     (0.015 * N Period Mean Deviation of HLC3)

where:
HLC3 = (High + Low + Close) / 3
N Period= Number of data points to use;

"""
import numpy as np

def cmci(ohlcv, period=13):
    """
    VALIDATION

    Results are similar to Bloomberg data to the 4th digit after the decimal point.
    But very different from TradingView data.
    In some formulas, high and low are the highs and lows of the past N days.
    """
    _ohlcv = ohlcv[['high', 'low', 'close']].copy(deep=True)
    _ohlcv['hlc3'] = _ohlcv[['high', 'low', 'close']].mean(axis=1)
    _ohlcv['hlc3_ma'] = _ohlcv['hlc3'].rolling(window=period, min_periods=period).mean()
    _ohlcv['hlc3_mad'] = _ohlcv['hlc3'].rolling(window=period, min_periods=period).apply(
        lambda x: np.fabs(x - x.mean()).mean())

    indicator_values = (_ohlcv['hlc3'] - _ohlcv['hlc3_ma']) / (0.015 * _ohlcv['hlc3_mad'])
    return indicator_values


# PA=LU factorization algorithm test

import numpy as np
from palu_factor import palu_factor
from triangular import triangular

np.set_printoptions(suppress=True, precision=5)
# TEST: PA=LU factorization

# Coefficient matrix
A = np.matrix(' 0 41 53 12 62 26;'
              '43 49 61 60 22 27;'
              '65 25 56 38 43 43;'
              '37  0 24 42 26 56;'
              '26 28 41 15 42 24;'
              '13 50 48 36 46 28 ', float)
print('A = \n', A)
# LU factorization (deep-copy of A because we need it or the "check")
B, p = palu_factor(np.matrix(A))
print('B = \n', B)
# Extract lower part
L = np.matrix(np.tril(B,-1) + np.identity(6))
print('L = \n', L)
# Extract upper part
U = np.matrix(np.triu(B))
print('U = \n', U)
# Check
if np.allclose(A[p], L*U) == False:
    raise Exception('LU factorization test failure')

# TEST: System Resolution
# Ax = b => PAx = Pb => LUx = Pb
# LUx = Pb
b = np.matrix('33; 35; 2; 49; 53; 21')
# Lk = Pb (note the permutation of b using the index vector p)
k = triangular(L, b[p], 1)
# Ux = k
x = triangular(U, k, 0)
# Check
if np.allclose(b, A*x) == False:
    raise Exception('System Resolution test failure')


from scipy.integrate import *
import math
import numpy as np
from pylab import *
import matplotlib.pyplot as plt

# Function to integrate
function_map = lambda x: math.exp(-x**2)

def function(x):
    return math.exp(-x**2)

def integrate(function, time, dt):
    for t in np.nditer(time):
        accum = dt * function
    return accum

# Integration bounds
lower_bound = -5
upper_bound = 5
number_of_points = 500

# Differential time element
t = np.linspace(lower_bound, upper_bound, num = number_of_points)
dt = t[1] - t[0]
# print("dt:", dt)

# Scipy integration method
scipy_result = quad(function_map, lower_bound, upper_bound)
print("Scipy Result\n Value, Error:", scipy_result)

# My integration method
f1 = np.vectorize(function)
my_result = integrate(f1(t), t, dt)
integrated_value = 0
for element in my_result:
    integrated_value += element

# print(my_result)
print("\nMy result:", integrated_value)

error = abs(scipy_result[0] - integrated_value)
print("\nScipy result - my result:", error)

# print((pi)**0.5)      # Exact value

# Plotting function
plt.plot(t, f1(t), 'r--')
plt.fill_between(t, f1(t), facecolor = 'blue', alpha = 1)
xlabel('$x$')
ylabel('$f(x)$')
plt.grid()
title('$e^{-x^2}$')
plt.show()

error_ydata = []
index = []
convergence_n = 52
# Convergence plot error data generation
for n in range(2,convergence_n):
    index += [n]
    integrated_value2 = 0
    integral_value = 0
    number_of_points = n
    t2 = np.linspace(lower_bound, upper_bound, num=number_of_points)
    dt2 = t2[1] - t2[0]
    f2 = np.vectorize(function)
    my_result2 = integrate(f2(t2), t2, dt2)
    for elements in my_result2:
        integrated_value2 += elements
        integral_value += elements
    error_ydata += [integrated_value2]

# Compute best value error:
best_error = abs(error_ydata[-1] - (pi**0.5))
print("\nBest error from my method:", best_error, 'N,', convergence_n)
print("Best value:", integrated_value, 'N:', convergence_n )

# Convergence plot
plt.plot(index, error_ydata, 'b--')
plt.axhline(y=pi**0.5, color='r', linestyle='-')
plt.title("Convergence plot of methods")
xlabel('$N$ (Number of time partitions)')
ylabel('$\int f(x) dx$')
legend(('My method convergence values', 'Exact solution, $\pi^{1/2}$'), loc='best')
plt.show()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Nov 25 20:48:39 2017

@author: ratnadeepb
@License: MIT
"""

# System Import
import numpy as np
import sys

# Local Import
from InnerProductSpaces.norm import unit_vec
from InnerProductSpaces.projection import proj

'''
Gram Schmidt process of creating orthonormal basis from an arbitrary basis
'''

def gram_schmidt(B):
    try:
        B = np.array(B, dtype=np.float16)
    except:
        sys.exit("Not a vector")

    W = np.zeros_like(B)

    # Create and orthogonal basis
    W[0] = B[0]
    i = 1
    while i < len(B):
        p = 0
        j = 1
        while j < i:
            p += proj(B[j], W[i - 1])
            j += 1
        W[i] = B[i] - p
        i += 1

    # Normalise
    U = np.zeros_like(W)
    for ind, w in enumerate(W):
        temp = unit_vec(w)
        for s, u in enumerate(temp):
            U[ind][s] = u

    return U

if __name__ == "__main__":
    B = [[0, 1, 1],
         [2, 1, 0],
         [-1, 0, -1]]
    U = gram_schmidt(B)
    print(U)
    '''
    U = [[0, 1/np.sqrt(2), 1/np.sqrt(2)],
          [2/np.sqrt(6), 1/np.sqrt(6), -1/np.sqrt(6)],
          [-1/np.sqrt(3), 1/np.sqrt(3), -1/np.sqrt(3)]]
    '''


import math
import numpy

# perform 5-point Gauss-Legendre quadrature on a degree 9 (2 N - 1)
# polynomial, and compare to the compound Simpson's rule.

degree = 9

# integrand
def f(x):
    p = 0.0

    n = 0
    while (n <= degree):
        p += x**n
        n += 1

    return p

# analytic (true) integral
def true(a, b):
    t = 0.0

    n = 0
    while (n <= degree):
        t += (b**(n+1) - a**(n+1))/(n+1)
        n += 1

    return t

# do a Simpson's integration by breaking up the domain [a,b] into N
# slabs.  Note: N must be even, because we do a pair at a time
def simp(a,b,f,N):

    xedge = numpy.linspace(a,b,N+1)

    integral = 0.0

    if not N%2 == 0:
        sys.exit("ERROR: N must be even")

    delta = (xedge[1] - xedge[0])

    n = 0
    while n < N:
        integral += (1.0/3.0)*delta*(f(xedge[n]) +
                                     4.0*f(xedge[n+1]) +
                                     f(xedge[n+2]))
        n += 2

    return integral

def x(z, a, b):
    """ convert from [-1, 1] (the integration range of Gauss-Legendre)
        to [a, b] (our general range) through a change of variables z
        -> x """

    return 0.5*(b + a) + 0.5*(b - a)*z

# integration limits
a = 0.0
b = 1.0

# we are doing 5-point quadrature for all methods.  delta is the width
# of the slab (5 points = 4 slabs)
delta = (b - a)/4

# Simpson's
I_S = simp(a, b, f, 4)

# Gauss-Legendre

# we need to convert from [-1, 1] (the range in which the roots are
# found) to [a, b] (the range in which our integrand is defined), so
# convert the roots z1, z2, ...

z1 = -math.sqrt(5.0 + 2.0*math.sqrt(10.0/7.0))/3.0
x1 = x(z1, a, b)
w1 = (322.0-13.0*math.sqrt(70.0))/900.0

z2 = -math.sqrt(5.0 - 2.0*math.sqrt(10.0/7.0))/3.0
x2 = x(z2, a, b)
w2 = (322.0+13.0*math.sqrt(70.0))/900.0

z3 = 0.0
x3 = x(z3, a, b)
w3 = 128.0/225.0

z4 = math.sqrt(5.0 - 2.0*math.sqrt(10.0/7.0))/3.0
x4 = x(z4, a, b)
w4 = (322.0+13.0*math.sqrt(70.0))/900.0

z5 = math.sqrt(5.0 + 2.0*math.sqrt(10.0/7.0))/3.0
x5 = x(z5, a, b)
w5 = (322.0-13.0*math.sqrt(70.0))/900.0

# 5-point Gauss-Legendre quadrature -- note the factor in the front
# is a result of the change of variables from x -> z
integral = 0.5*(b-a)*( w1*f(x1) + w2*f(x2) + w3*f(x3) + w4*f(x4) + w5*f(x5) )

print "exact:                  ", true(a,b)
print "5-point Simpson's:      ", I_S, I_S-true(a,b)
print "5-point Gauss-Legendre: ", integral, integral-true(a,b)


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

def gradient_descent(X, Y, alpha=0.01, converge_criteria=0.0001, max_epoch=10000):
    converged = False
    epoch = 0

    # Number of datasets
    m = X.shape[0]

    # Initial thetas to 0
    theta0 = 0
    theta1 = 0

    # Total error, J(theta)
    J = (1.0 / (2.0 * m)) * sum([ (theta0 + theta1 * X[i] - Y[i]) ** 2 for i in range(m)])

    while not converged:
        # For each training sample, compute the gradient
        gradient0 = (1.0 / m) * sum([(theta0 + theta1 * X[i] - Y[i]) for i in range(m)])
        gradient1 = (1.0 / m) * sum([(theta0 + theta1 * X[i] - Y[i]) * X[i] for i in range(m)])

        # Update the temporary thetas
        tmp0 = theta0 - alpha * gradient0
        tmp1 = theta1 - alpha * gradient1

        # Update thetas
        theta0 = tmp0
        theta1 = tmp1

        # Mean squared error
        error = (1.0 / (2.0 * m)) * sum([(theta0 + theta1 * X[i] - Y[i]) ** 2 for i in range(m)])

        print("Epoch = {0}, Cost = {1}".format(epoch, error.item(0)))

        if abs(J - error) <= converge_criteria:
            print('Converged, epochs: ', epoch, '!!!')
            converged = True

        J = error  # Update error
        epoch += 1  # Update epoch

        if epoch == max_epoch:
            print('Maximum number of epochs exceeded!')
            converged = True

    return theta0.item(0), theta1.item(0)

'''
Step 1: Read in data from the .xls file
'''
DATA_FILE = 'data/fire_theft.xls'

book = xlrd.open_workbook(DATA_FILE, encoding_override='utf-8')
sheet = book.sheet_by_index(0)

number_of_rows = len(list(sheet.get_rows()))
data = np.asarray([sheet.row_values(i) for i in range(1, number_of_rows)])
number_of_samples = number_of_rows - 1

'''
Step 2: Compute the gradients
'''
X, Y = np.matrix(data.T[0]).T, np.matrix(data.T[1]).T

theta0, theta1 = gradient_descent(X, Y, alpha=0.001,
                                  converge_criteria=0.0000001, max_epoch=300000)

print("theta0 = {0}, theta1 = {1}".format(theta0, theta1))

'''
Step 3: Plot the results
'''

# Graphic display
plt.plot(data.T[0], data.T[1], 'ro', label='Original data')
plt.plot(data.T[0], theta0 + theta1 * data.T[0], 'b', label='Fitted line')
plt.xlabel('fire per 1000 housing units')
plt.ylabel('theft per 1000 population')
plt.legend()
plt.show()


""" Orbital Mechanics for Engineering Students Example 1.13
Question:
Given:
    - Position, velocity, and acceleration of the origin O (RO,VO,AO)
    - Angular velocity and acceleration of moving frame (Omega, OmegaDot)
    - Unit vectors of the moving frame (iHat, jHat, kHat)
    - Absolute position, velocity, and acceleration of P (R,V,A)
Find:
    (a) The velocity Vrel of P relative to the moving frame
    (b) The acceleration Arel of P relative to the moving frame
Written by: J.X.J. Bannwarth
"""
from numpy import array, cross, dot, vstack
from numpy.linalg import inv

def PrintVec(v, name, unit = '', inertial=True):
    if inertial:
        print(f"{name} = {v[0]:.4f} I + {v[1]:.4f} J + {v[2]:.4f} K {unit}")
    else:
        print(f"{name} = {v[0]:.4f} i + {v[1]:.4f} j + {v[2]:.4f} k {unit}")

# Title
print("Orbital Mechanics for Engineering Students Example 1.13")

# Origin
RO = array([100.,200.,300.]) # m
VO = array([-50.,30.,-10.]) # m/s
AO = array([-15.,40.,25.]) # m/s^2

# Moving frame
Omega    = array([1.0,-0.4,0.6]) # rad/s
OmegaDot = array([-1.0,0.3,-0.4]) # rad/s^2

# Unit vectors
# <>Hat = x*IHat + y*JHat + z*KHat
iHat = array([0.5571,0.7428,0.3714])
jHat = array([-0.06331,0.4839,-0.8728])
kHat = array([-0.8280,0.4627,0.3166])

# Construct DCM from unit vectors
DCM = vstack((iHat,jHat,kHat))

# Absolute values
R = array([300.,-100.,150.]) # m
V = array([70.,25.,-20]) # m/s
A = array([7.5,-8.5,6.0]) # m/s^2

# (a)
print("Inertial frame: (I,J,K), moving frame: (i,j,k)")
print("(a)")
Rrel = R - RO
PrintVec(Rrel, "R_rel", "m")

Vrel = V - VO - cross(Omega,Rrel)
PrintVec(Vrel, "V_rel", "m/s")
PrintVec(dot(DCM,Vrel), "V_rel", "m/s", False)

# (b)
print("b")
Arel = A - AO - cross(OmegaDot,Rrel) - cross(Omega,cross(Omega,Rrel)) - 2*cross(Omega,Vrel)
PrintVec(Arel, "A_rel", "m/s^2")
PrintVec(dot(DCM,Arel), "A_rel", "m/s^2", False)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Visualizing the Mandelbrot Set Using Python by Blake Sanie, Nov 29, 2020.
https://medium.com/swlh/visualizing-the-mandelbrot-set-using-python-50-lines-f6aa5a05cf0f

Use Python Numba for C-like performance, Jan 11, 2022.
Part 2 of 4 Apply Anti-Aliasing.
"""

from numba import njit, int16
from timeit import default_timer as timer
import numpy as np
import os, sys

jit_start = timer()

sys.path.insert(0, os.path.dirname(__file__))
from ex1 import width, height, precision, minX, maxY, xRange, yRange
from ex1 import hsv_to_rgb, powerColor, save_image

@njit('b1(u1[:], u1[:])', nogil=True)
def check_colors(c1, c2):
    # return false if the colors are within tolerance
    if abs(int16(c2[0]) - c1[0]) > 8: return True
    if abs(int16(c2[1]) - c1[1]) > 8: return True
    if abs(int16(c2[2]) - c1[2]) > 8: return True
    return False

@njit('i4(f8, f8)', nogil=True)
def mandel(x, y):
    oldX = x
    oldY = y
    for i in range(precision + 1):
        a = x*x - y*y # real component of z^2
        b = 2 * x * y # imaginary component of z^2
        x = a + oldX  # real component of new z
        y = b + oldY  # imaginary component of new z
        if x*x + y*y > 4:
            break
    return i

@njit('void(u1[:,:,:])', nogil=True)
def mandelbrot1(pixels):
    for row in range(height):
        for col in range(width):
            x = minX + col * xRange / width
            y = maxY - row * yRange / height
            i = mandel(x, y)
            if i < precision:
                distance = (i + 1) / (precision + 1)
                pixels[row, col] = powerColor(distance, 0.2, 0.27, 1.0)

@njit('void(u1[:,:,:], u1[:,:,:])', nogil=True)
def mandelbrot2(pixels1, pixels2):
    aafactor = 7 # 7x7
    aareach1 = int(aafactor / 2.0)
    aareach2 = aareach1 + 1 if (aafactor % 2) else aareach1
    aaarea = int(aafactor * aafactor)
    aafactorinv = float(1.0 / aafactor)

    for row in range(height):
        c = np.empty((3,), dtype=np.int32)

        for col in range(width):
            c1 = pixels1[row, col]
            count = False

            # skip AA for colors within tolerance
            if not count and col > 0:
                count = check_colors(c1, pixels1[row, col - 1])
            if not count and col + 1 < width:
                count = check_colors(c1, pixels1[row, col + 1])
            if not count and col > 1:
                count = check_colors(c1, pixels1[row, col - 2])
            if not count and col + 2 < width:
                count = check_colors(c1, pixels1[row, col + 2])

            if not count and row > 0:
                count = check_colors(c1, pixels1[row - 1, col])
            if not count and row + 1 < height:
                count = check_colors(c1, pixels1[row + 1, col])
            if not count and row > 1:
                count = check_colors(c1, pixels1[row - 2, col])
            if not count and row + 2 < height:
                count = check_colors(c1, pixels1[row + 2, col])

            if not count:
                pixels2[row, col] = c1
                continue

            # compute AA
            c[:] = c1

            for yi in range(-aareach1, aareach2, 1):
                y = maxY - (row + yi*aafactorinv) * yRange / height

                for xi in range(-aareach1, aareach2, 1):
                    if (xi | yi) == 0: continue
                    x = minX + (col + xi*aafactorinv) * xRange / width

                    i = mandel(x, y)
                    if i < precision:
                        distance = (i + 1) / (precision + 1)
                        r, g, b = powerColor(distance, 0.2, 0.27, 1.0)
                        c[0] += r; c[1] += g; c[2] += b

            c2 = int(c[0]/aaarea), int(c[1]/aaarea), int(c[2]/aaarea)
            pixels2[row, col] = c2

if __name__ == '__main__':
    print("     jit time {:.3f} seconds".format(timer() - jit_start))
    pixels1 = np.empty((height, width, 3), dtype=np.uint8)
    pixels2 = np.empty((height, width, 3), dtype=np.uint8)

    s = timer()
    mandelbrot1(pixels1)
    print("   mandelbrot {:.3f} seconds".format(timer() - s))

    s = timer()
    mandelbrot2(pixels1, pixels2)
    print("anti-aliasing {:.3f} seconds".format(timer() - s))

    save_image(pixels2, "img2.png", show_image=False)


# Computational Linear Algebra Ep#10 Least-Squares w/ built in numpy.linalg.lsq
# By: Nick Space Cowboy

import numpy as np
from time import perf_counter

if __name__ == "__main__":
	# generate A matrix
	A = np.array(np.random.randint(1,100,(3,2)), dtype=np.float64)
	print("A: ")
	print(A)
	b = np.array(np.random.randint(-100, 100, (3, 1)), dtype=np.float64)
	print("b:")
	print(b)
	start = perf_counter()
	lsq = np.linalg.lstsq(A, b, rcond=None)
	x = lsq[0]
	norm = lsq[1][0]**(0.5)
	end = perf_counter()
	print("x:")
	print(x)
	print(f"Norm: {norm}")
	print("Check:")
	print(b - np.dot(A, x))
	print(f"Runtime: {end - start} s")


import numpy as np

from numpy import linalg

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

v, B = linalg.eig(A)

i = 0  # first eigenvalue/eigenvector pair
lambda0 = v[i]
print(lambda0)
# 6.823156164525971
x0 = B[:, i]  # ith column of B
print(x0)
# array([ 0.73271846, -0.20260301, 0.649672352])

linalg.norm(x0)  # 1.0  - eigenvalues are normalised.

lhs = A @ x0
rhs = lambda0*x0
linalg.norm(lhs - rhs)  # 2.8445583831733384e-15 - very small.


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Apr  2 22:01:04 2020

@author: guanfang
"""

import pandas as pds
import numpy as np
import matplotlib.pyplot as plt

class LeastSquaresEstimation():
    def __init__(self, method='OLS'):
        self.method = method

    def fit_line(self, x, y):
        x = np.array(x).reshape(-1, 1)
        # add a column which is all 1s to calculate bias of linear function
        x = np.c_[np.ones(x.size).reshape(-1, 1), x]
        y = np.array(y).reshape(-1, 1)
        if self.method == 'OLS':
            w = np.linalg.inv(x.transpose().dot(x)).dot(x.transpose()).dot(y)
            b = w[0][0]
            w = w[1][0]
            return w, b

    def fit_polynomial(self, x, y, d):
        x_org = np.array(x).reshape(-1, 1)
        # add a column which is all 1s to calculate bias of linear function
        x = np.c_[np.ones(x.size).reshape(-1, 1), x_org]
        x_org_d = x_org
        for i in range(1, d):
            x_org_d = x_org_d * x_org
            x = np.c_[x, x_org_d]
        y = np.array(y).reshape(-1, 1)
        w = np.linalg.inv(x.transpose().dot(x)).dot(x.transpose()).dot(y)
        return w

def polynomial(w, x, d):
    w = np.array(w).reshape(-1, 1)
    x = np.array(x).reshape(-1, 1)
    x_org_d = x
    X = np.ones(x.size).reshape(-1, 1)
    X = np.c_[X, x_org_d]
    for i in range(1, d):
        x_org_d = x_org_d * x
        X = np.c_[X, x_org_d]
    return X.dot(w)

if __name__ == '__main__':
    data_file = pds.read_csv('/home/guanfang/Desktop/ML-master/Linear Regression/data/baby.csv')
    lse = LeastSquaresEstimation()
    x = data_file['male']
    y = data_file['female']
    #w, b = lse.fit_line(x, y)   # linear regression parameter x and y
    weights_polynomial = lse.fit_polynomial(x, y, d=2)
    # day_0 = x[0]
    # day_end = list(x)[-1]
    # days = np.array([day_0,day_end])

    plt.scatter(x, y, c='r', s=30, label='y', marker='o', alpha=0.3)

    plt.scatter(x, polynomial(weights_polynomial, x, d=2), c='b', marker='x', alpha=0.5)
    plt.plot(x, polynomial(weights_polynomial, x, d=2), c="b", label='polynomial', alpha=0.7)
    plt.plot()
    plt.xlabel('x')
    plt.ylabel('y')
    plt.legend()
    plt.show()


from sympy import *
from math import pi

function = sympify(input("Enter a function: "))
lower_bound, upper_bound = tuple(eval(input("Enter an interval: ")))
evaluation_point = float(input("Enter the point that you want to evaluate the function in: "))
order = int(input("Enter the order of series: "))
assert lower_bound == - upper_bound
period = (abs(lower_bound) + abs(upper_bound)) / 2
x = symbols("x")
a_0 = (1 / period) * integrate(function, (x, lower_bound, upper_bound)).doit(simplify=True)

def power_series(i):

    def a_n(n):
        n = n * pi / period
        return (1 / period) * integrate(Mul(function, sympify("cos({} * x)".format(n))), (x, lower_bound, upper_bound))

    def b_n(n):
        n = n * pi / period
        return (1 / period) * integrate(Mul(function, sympify("sin({} * x)".format(n))), (x, lower_bound, upper_bound))

    freq = i * pi / period
    return Add(Mul(a_n(i), sympify("cos({}*x)".format(freq))), Mul(b_n(i),  sympify("sin({}*x)".format(freq))))

fourier_series = (1 / 2) * a_0 + sum([power_series(i) for i in range(1, order + 1)])
print("\nfourier series of f(x) = {}:\n".format(function), fourier_series,
      "\nevaluated value at x = {} is: ".format(evaluation_point), fourier_series.subs(x, evaluation_point).evalf())


import math
import numpy as np

gauss = [
        [-7,2,-3,4,-12],
        [5,-1,14,-1,13],
        [1,9,-7,13,31],
        [-12,13,-8,-4,-32]
        ]

n = len(gauss)

def changeRows(majorRow,k):
    for i in range(0,len(gauss)+1):
        aux = gauss[k][i]
        gauss[k][i] = gauss[majorRow][i]
        gauss[majorRow][i]= aux

def pivoting(k):
    major = math.fabs(gauss[k][k])
    majorRow = k
    for s in range(k+1,n):
        if (math.fabs(gauss[s][k]) > major):
            major = math.fabs(gauss[s][k])
            majorRow = s

    if(major == 0):
        print("division 0")
        return;
    elif(majorRow != k):
        changeRows(majorRow,k)

def elimination():
    for k  in range(0,n-1):
        pivoting(k)
        for i  in range (k + 1, n):
            multiplicator = gauss[i][k]/gauss[k][k]
            for j in range (k,n + 1):
                gauss[i][j] = gauss[i][j]-(multiplicator*gauss[k][j])

    sustitution()

def sustitution():
    n = len(gauss) -1
    x = [i for i in range(n+1)]
    x[len(x)-1] = gauss[n][n+1]/gauss[n][n]
    print(x[len(x)-1])

    for i in range(0,n+1):
        summation = 0
        auxi = n - i
        summation = 0
        for p in range(auxi+1,n+1):
            summation = summation + gauss[auxi][p]*x[p]
        x[auxi]=(gauss[auxi][n+1]-summation)/gauss[auxi][auxi]
    print(x)

elimination()
for i in gauss:
    print(i)


import numpy as np

def zakharov_func(x, d):
    """
    Compute Zakharov function at a given point with given arguments.

    Parameters
    ----------
    point : 1-D array with shape (d, )
            A point used to evaluate the function.
    d : integer
        Dimension

    Returns
    -------
    function value : float
    """
    s_1 = np.sum(x ** 2)
    s_2 = (0.5 * np.arange(1, d + 1)).T @  x
    return s_1 + s_2 ** 2 + s_2 ** 4

def zakharov_grad(x, d):
    """
    Compute Zakharov gradient at a given point with given arguments.

    Parameters
    ----------
    point : 1-D array with shape (d, )
            A point used to evaluate the function.
    d : integer
        Dimension

    Returns
    -------
    grad : 1-D array with shape (d,)
    """
    s_2 = (0.5 * np.arange(1, d + 1)).T @  x
    grad = (2 * x + np.arange(1, d + 1) *
            s_2 + 2 * np.arange(1, d + 1) * (s_2 ** 3))
    return grad