import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plot
import numpy, scipy, cvxpy, pprint, itertools
from scipy.spatial import ConvexHull
from patch import *

def random_2d_convex_hull():
  ps = numpy.random.rand(30, 2)
  hull = ConvexHull(ps)

  print("ps= {}".format(ps) )

  plot.plot(ps[:,0], ps[:,1], 'o')
  for simplex in hull.simplices:
    plot.plot(ps[simplex, 0], ps[simplex, 1], 'k-')
  plot.plot(ps[hull.vertices,0], ps[hull.vertices,1], 'r--', lw=2)
  plot.plot(ps[hull.vertices[0],0], ps[hull.vertices[0],1], 'ro')
  # plot.show()
  plot.savefig("random_2d_convex_hull.png")
  plot.gcf().clear()

def stability_region_mds_4_2():
  ps = numpy.array([ [0, 0],
    [2.5, 0], [0, 2.5], [2, 0], [0, 2], [2, 1], [1, 2] ] )
  hull = ConvexHull(ps)

  for simplex in hull.simplices:
    plot.plot(ps[simplex, 0], ps[simplex, 1], 'k-')
  plot.plot(ps[hull.vertices,0], ps[hull.vertices,1], 'r--', lw=2)
  plot.plot(ps[hull.vertices[0],0], ps[hull.vertices[0],1], 'ro')
  # plot.show()
  plot.savefig("stability_region_mds_4_2.png")
  plot.gcf().clear()

def opt():
  # Problem data.
  m = 30
  n = 20
  numpy.random.seed(1)
  A = numpy.random.randn(m, n)
  b = numpy.random.randn(m)

  # Construct the problem.
  x = Variable(n)
  obj = Minimize(sum_squares(A*x - b))
  constraints = [0 <= x, x <= 1]
  prob = Problem(obj, constraints)

  # The optimal obj is returned by prob.solve().
  result = prob.solve()
  # The optimal value for x is stored in x.value.
  print("x= {}".format(x.value) )
  # The optimal Lagrange multiplier for a constraint is stored in constraint.dual_value.
  print("constraints[0].dual_value= {}".format(constraints[0].dual_value) )

def plot_hull_of_ps(p_l, fname, title):
  ps = numpy.empty((len(p_l), 2))
  for i,p in enumerate(p_l):
    # ps[i,:] = [[p[0], p[1]]]
    ps[i,0] = p[0]
    ps[i,1] = p[1]
  print("ps= {}".format(ps) )
  plot.plot(ps[:,0], ps[:,1], 'o')
  """
  hull = ConvexHull(ps)
  for simplex in hull.simplices:
    plot.plot(ps[simplex, 0], ps[simplex, 1], 'k-')
  plot.plot(ps[hull.vertices,0], ps[hull.vertices,1], 'r--', lw=2)
  plot.plot(ps[hull.vertices[0],0], ps[hull.vertices[0],1], 'ro')
  """

  # plot.show()
  # axes = plot.gca()
  # axes.set_xlim([0, 2] )
  plot.title(title)
  plot.savefig(fname)
  plot.gcf().clear()

"""
# Matrix factorization
alpha = 0.002 # 0.0002
D = numpy.zeros((n,2))
step = 0
while step < 100000:
  step += 1
  for i in range(n):
    for j in range(2):
      if M[i,j] == 1:
        e_ij = M[i,j] - numpy.dot(D[i,:], C[:,j])
        for k in range(2):
          D[i][k] = D[i][k] + alpha*(2*e_ij * C[k][j] )
  # print("step= {}, D=\n{}".format(step, D) )
  e = 0
  for i in range(n):
    for j in range(2):
      e = e + pow(M[i][j] - numpy.dot(D[i,:], C[:,j]), 2)
  if e < 0.1:
    break
print("step= {}, D=\n{}".format(step, D) )

M_ = numpy.dot(D, C)
print("M=\n{}".format(M_) )
"""

def generator_matrix_to_M_C(G):
  n = G.shape[1]
  s_rg_l = [[], []]

  for s in range(0, 2):
    for c in range(n):
      m = numpy.column_stack((G[:,s], G[:,c]))
      if numpy.linalg.det(m) == 0: # c is a systematic node for s
        s_rg_l[s].append((c,))

    for subset in itertools.combinations(range(n), 2):
      if s in subset:
        continue
      m = numpy.column_stack((G[:,subset[0]], G[:,subset[1]]))
      # print("m= {}".format(m) )
      if numpy.linalg.det(m):
        # print("columns {}, {} are LI".format(os, c) )
        s_rg_l[s].append((subset[0], subset[1]))
  print("s_rg_l= {}".format(pprint.pformat(s_rg_l) ) )

  r_0 = len(s_rg_l[0] )
  r_1 = len(s_rg_l[1] )
  r = r_0 + r_1
  # if r != len(s_rg_l[1] ):
  #   log(ERROR, "Code was supposed to be symmetric, but it is not.")
  #   return 1
  x = s_rg_l[0] + s_rg_l[1]
  M = numpy.zeros((n,r))
  for i in range(n):
    for j in range(r):
      if i in x[j]:
        M[i,j] = 1
  print("M= {}".format(M) )

  C = numpy.zeros((2 ,r))
  C[0,0:r_0] = 1
  C[1,r_0:r] = 1
  print("C= {}".format(C) )

  return r, M, C

def generator_matrix(code, n, k=2):
  if k != 2:
    log(ERROR, "Only for k=2")
    return 1
  if code == 'MDS':
    G = numpy.zeros((2, n))
    for j in range(n):
      if j == 0:
        G[0,j] = 1
        G[1,j] = 0
      elif j == 1:
        G[0,j] = 0
        G[1,j] = 1
      else:
        G[0,j] = j-1
        G[1,j] = 1
    return G
  else:
    log(ERROR, "unexpected code= {}".format(code) )
    return 1

def plot_xy_stability_region(n):
  # Rep(2)
  # G = numpy.matrix([[1,0], [0,1]])
  # G = numpy.matrix([[1,0], [0,1], [1,0], [0,1] ])
  # MDS(3,2)
  # G = numpy.matrix([[1,0], [0,1], [1,1]])
  # MDS(4,2)
  # G = numpy.matrix([[1,0], [0,1], [1,1], [2,1]])
  # MDS(5,2)
  # G = numpy.matrix([[1,0], [0,1], [1,1], [2,1], [3,1]])
  # MDS(6,2)
  # G = numpy.matrix([[1,0], [0,1], [1,1], [2,1], [3,1], [4,1]])
  # MDS(7,2)
  # G = numpy.matrix([[1,0], [0,1], [1,1], [2,1], [3,1], [4,1], [5,1]])
  # Mixed
  # G = numpy.matrix([[1,0], [0,1], [1,1], [2,1], [3,1], [1,0] ])
  # G = numpy.matrix([[1,0], [0,1], [1,1], [2,1], [3,1], [1,1] ])
  # G = numpy.matrix([[1,0], [0,1], [1,1], [1,0], [0,1], [1,1] ])
  # G = G.transpose()

  code = 'MDS' # 'Rep' # 'MDS' # 'Mixed'
  G = generator_matrix(code, n)

  print("G= {}".format(G) )
  n = G.shape[1]
  r, M, C = generator_matrix_to_M_C(G)
  p_l = []
  #
  x = cvxpy.Variable(r, 1, name='x')
  for b in numpy.linspace(0, 1, 20):
    # print("b= {}".format(b) )

    length = math.sqrt((1-b)**2 + b**2)
    w = numpy.matrix([[(1-b)/length, b/length]] )
    # print("w.shape= {}, w= {}".format(w.shape, w) )
    w_ = w*C
    # print("w_= {}".format(w_) )
    # obj = cvxpy.Maximize(w*(C*x) )
    obj = cvxpy.Maximize(w_*x)
    # print("obj= {}".format(obj) )
    constraints = [M*x == 1, x >= 0] # [M*x <= 1, x >= 0]
    prob = cvxpy.Problem(obj, constraints)
    # print("prob= {}".format(prob) )
    prob.solve()
    print("status= {}".format(prob.status) )
    # print("optimal value= {}".format(prob.value) )
    y = C*(x.value)
    # print("optimal y= {}".format(y) )
    p_l.append((y[0], y[1]) )
  plot_hull_of_ps(p_l, "plot_xy_stability_region_{}_n_{}.png".format(code, n),
                  title='{}, n= {}, k= 2'.format(code, n) )
  log(WARNING, "done, code= {}, n= {}".format(code, n) )

if __name__ == "__main__":
  # random_2d_convex_hull()
  # stability_region_mds_4_2()
  # opt()

  plot_xy_stability_region(n=4)
  # for n in range(3, 10):
  #   plot_xy_stability_region(n)
  # plot_xy_stability_region(n=100)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Created by techno at 27/05/19

#Feature:  #Enter feature name here
# Enter feature description here

#Scenario:  # Enter scenario name here
# Enter steps here
import numpy as np

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

# Add `x` and `y`
print (np.add(x,y) )

# Subtract `x` and `y`
np.subtract(x,y)

# Multiply `x` and `y`
np.multiply(x,y)

# Divide `x` and `y`
np.divide(x,y)

# Calculate the remainder of `x` and `y`
np.remainder(x,y)

"""
Remember how broadcasting works? Check out the dimensions and the shapes of
both x and y in your IPython shell. Are the rules of broadcasting respected?

But there is more.

Check out this small list of aggregate functions:
a.sum() 	Array-wise sum
a.min() 	Array-wise minimum value
b.max(axis=0) 	Maximum value of an array row
b.cumsum(axis=1) 	Cumulative sum of the elements
a.mean() 	Mean
b.median() 	Median
a.corrcoef() 	Correlation coefficient
np.std(b) 	Standard deviation

Besides all of these functions, you might also find it useful to know that there are
mechanisms that allow you to compare array elements. For example, if you want to
check whether the elements of two arrays are the same, you might use the == operator.
To check whether the array elements are smaller or bigger, you use the < or > operators.
"""


# This code is for fully educational purposes and it implements the simulated annealing AI algorithm
# for more information please visit: https://en.wikipedia.org/wiki/Simulated_annealing

import numpy
import time
import random

NEIGHBORHOOD_MAX = 40
NEIGHBORHOOD_MIN = 0
T_MAX = 100
T_MIN = 0.01

def f(x):
	assert NEIGHBORHOOD_MIN <= x <= NEIGHBORHOOD_MAX
	return numpy.sin(0.15 * x) + numpy.cos(x)

def acceptance(s, new_s, temperature):
	return numpy.exp(-1 * float(new_s - s) / float(temperature))

def next_neighbor(sol, alpha, T, T_max):
	move = alpha * NEIGHBORHOOD_MAX

	if sol - move <= NEIGHBORHOOD_MIN:
		return sol + move
	elif sol + move >= NEIGHBORHOOD_MAX:
		return sol - move
	else:
		return sol + move * random.uniform(-1, 1)

def SA(sol):
	s = sol
	T = T_MAX

	alpha = 0.4
	beta = 0.9

	while T > T_MIN:
		print 'S: %s | T: %s' % (str(s), str(T))
		for _ in range(200):
			new_s = next_neighbor(s, alpha, T, T_MAX)

			if f(new_s) > f(s) or acceptance(s, new_s, T) > random.uniform(0, 1):
				s = new_s

		alpha *= beta
		T *= beta

	return s, f(s), f(12.6025895306)

if __name__ == '__main__':
	print 'SOL: %s | RESULT: %s | TARGET: %s' % SA(15.0)


"""
https://projecteuler.net/problem=6
"""

import numpy

def summary_square(start, end):
    return sum(i ** 2 for i in range(start, end))

def square_sum(start, end):
    return numpy.sum(numpy.arange(start, end)) ** 2

def generate_diff(start, end):
    """
    total result
    >>> generate_diff(1, 101)
    25164150
    >>> generate_diff(1, 100)
    24174150
    """
    a = summary_square(start, end)
    b = square_sum(start, end)

    return numpy.abs(a - b)

if __name__ == "__main__":
    import doctest

    doctest.testmod()


import numpy as np
from numpy import linalg as la
from scipy.linalg import solve_discrete_lyapunov,solve_discrete_are
from functools import reduce

###############################################################################
# General matrix math functions
###############################################################################

# Check for positive definiteness
def is_pos_def(A):
    try:
        la.cholesky(A)
        return True
    except np.linalg.LinAlgError:
        return False

# Vectorize a matrix by stacking its columns
def vec(A):
    return A.reshape(-1, order="F")

# Return the symmetric part of a matrix
def sympart(A):
    return 0.5*(A+A.T)

# Return the positive semidefinite part of a symmetric matrix
def psdpart(X):
    X = sympart(X)
    Y = np.zeros_like(X)
    eigvals, eigvecs = la.eig(X)
    for i in range(X.shape[0]):
        if eigvals[i] > 0:
            Y += eigvals[i]*np.outer(eigvecs[:,i],eigvecs[:,i])
    Y = sympart(Y)
    return Y

# Overload and extend the numpy kron function to take a single argument
def kron(*args):
    if len(args)==1:
        return np.kron(args[0],args[0])
    else:
        return np.kron(*args)

## Multi-dot
def mdot(*args):
    return reduce(np.dot, args)

# Spectral radius of a matrix
def specrad(A):
    try:
        return np.max(np.abs(la.eig(A)[0]))
    except np.linalg.LinAlgError:
        return np.nan

# Minimum singular value
def minsv(A):
    return la.svd(A)[1].min()

# Similar to MATLAB / operator for square invertible matrices
# Solves a = bx
def solveb(a,b):
    return la.solve(b.T,a.T).T

# Overload the numpy randn function so it always uses the same RandomState
# similarly to how MATLAB works (random number generator is 'global')
seed = 3187
rng = np.random.RandomState(seed)

def rand(*args):
    return rng.rand(*args)

def randn(*args):
    return rng.randn(*args)

def randint(*args):
    return rng.randint(*args)

def rngg():
    return rng

# Symmetric log transform
def symlog(X,scale=1):
    return np.multiply(np.sign(X),np.log(1+np.abs(X)/(10**scale)))

def printeigs(A):
    print(la.eig(A)[0])
    return

def succ(A,B):
    return is_pos_def(A-B)

def mip(A,B):
    # Matrix inner product
    return np.trace(mdot(A.T,B))

# Ammend the dlyap and dare functions to correct issue where
# input A, Q matrices are modified (unwanted behavior);
# simply pass a copy of the matrices to protect them from modification
def dlyap(A,Q):
    try:
        return solve_discrete_lyapunov(np.copy(A),np.copy(Q))
    except ValueError:
        return np.full_like(Q,np.inf)

def dare(A,B,Q,R):
    return solve_discrete_are(np.copy(A),np.copy(B),np.copy(Q),np.copy(R))


import numpy as np

def relu(Z):
    """Compute the Rectified Linear Unit (ReLU) activation function.

    Parameters
    ----------
    Z : ndarray
        Pre-activation parameters for the current layer.

    Returns
    -------
    A : ndarray
        Post-activation parameters for the current layer. Same shape as `Z`.
    ndarray
        Store `Z` for computing the backward pass efficiently.
    """

    A = np.maximum(0, Z)

    return A, Z

def relu_backward(dA, cache):
    """Compute backward propagation through the RELU activation function.

    Parameters
    ----------
    dA : ndarray
        Post-activation gradients for the current layer.
    cache : ndarray
        Stored `Z` from `relu()`.

    Returns
    -------
    dZ : ndarray
        Gradients of the cost with respect to `Z`.
    """

    Z = cache

    dZ = np.array(dA, copy=True)
    dZ[Z <= 0] = 0

    return dZ

def sigmoid(Z):
    """Compute the sigmoid activation function.

    Parameters
    ----------
    Z : ndarray
        Pre-activation parameters for the current layer.

    Returns
    -------
    A : ndarray
        Post-activation parameters for the current layer. Same shape as `Z`.
    ndarray
        Store `Z` for computing the backward pass efficiently.
    """

    A = 1 / (1 + np.exp(-Z))

    return A, Z

def sigmoid_backward(dA, cache):
    """Compute backward propagation through the sigmoid activation function.

    Parameters
    ----------
    dA : ndarray
        Post-activation gradients for the current layer.
    cache : ndarray
        Stored `Z` fron `sigmoid()`.

    Returns
    -------
    dZ : ndarray
        Gradients of the cost with respect to `Z`.
    """

    Z = cache

    A, _ = sigmoid(Z)
    dZ = dA * A * (1 - A)

    return dZ


#%%
"""
Created on July 11 2021
Monte Carlo Paths for the CIR Process

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

def GeneratePathsCIREuler(NoOfPaths,NoOfSteps,T,lambd,r0,theta,gamma):
    Z = np.random.normal(0.0,1.0,[NoOfPaths,NoOfSteps])
    W = np.zeros([NoOfPaths, NoOfSteps+1])
    R = np.zeros([NoOfPaths, NoOfSteps+1])
    R[:,0]=r0
    time = np.zeros([NoOfSteps+1])

    dt = T / float(NoOfSteps)
    for i in range(0,NoOfSteps):
        # making sure that samples from normal have mean 0 and variance 1
        if NoOfPaths > 1:
            Z[:,i] = (Z[:,i] - np.mean(Z[:,i])) / np.std(Z[:,i])
        W[:,i+1] = W[:,i] + np.power(dt, 0.5)*Z[:,i]
        R[:,i+1] = R[:,i] + lambd*(theta - R[:,i]) * dt + gamma* np.sqrt(R[:,i]) * (W[:,i+1]-W[:,i])

        # Truncated boundary condition
        R[:,i+1] = np.maximum(R[:,i+1],0.0)
        time[i+1] = time[i] +dt

    # Outputs
    paths = {"time":time,"R":R}
    return paths
def mainCalculation():
    NoOfPaths = 1
    NoOfSteps = 500
    T         = 50.0
    lambd     = 0.1
    gamma     = 0.05
    r0        = 0.05
    theta     = 0.05

    # Effect of mean reversion lambda
    plt.figure(1)
    legend = []
    lambdVec = [0.01, 0.2, 5.0]
    for lambdTemp in lambdVec:
        np.random.seed(2)
        Paths = GeneratePathsCIREuler(NoOfPaths,NoOfSteps,T,lambdTemp,r0,theta,gamma)
        legend.append('lambda={0}'.format(lambdTemp))
        timeGrid = Paths["time"]
        R = Paths["R"]
        plt.plot(timeGrid, np.transpose(R))
    plt.grid()
    plt.xlabel("time")
    plt.ylabel("R(t)")
    plt.legend(legend)

    # Effect of the volatility
    plt.figure(2)
    legend = []
    gammaVec = [0.1, 0.2, 0.3]
    for gammaTemp in gammaVec:
        np.random.seed(2)
        Paths = GeneratePathsCIREuler(NoOfPaths,NoOfSteps,T,lambd,r0,theta,gammaTemp)
        legend.append('gamma={0}'.format(gammaTemp))
        timeGrid = Paths["time"]
        R = Paths["R"]
        plt.plot(timeGrid, np.transpose(R))
    plt.grid()
    plt.xlabel("time")
    plt.ylabel("R(t)")
    plt.legend(legend)

mainCalculation()

Lecture 03-The HJM Framework/Materials/CIR_IR_paths.py


import numpy as np
import matplotlib.pyplot as plt

def main():
    """
    This is basic feed forward implementation demo
    It will implement a single forward calculation of nn with 1 hidden layer
    using random weights
    """

    nPerK = 500

    # create random data for 3 different classes (normally distributed numbers around some avg)
    XK1 = np.random.randn(nPerK, 2) + [0, -2]
    XK2 = np.random.randn(nPerK, 2) + [2, 2]
    XK3 = np.random.randn(nPerK, 2) + [-2, 2]

    # set the "actual" classes (0, 1, 2)
    Y = np.array([0] * nPerK + [1] * nPerK + [2] * nPerK)

    # join all classes to one dataset
    X = np.vstack([XK1, XK2, XK3])

    D = X.shape[1]  # number of "features"
    K = 3  # number of classes
    M = 3  # number of activation units in the first hidden layer

    # weights and bias for the first hidden layer
    W1 = np.random.randn(D, M)
    b1 = np.random.randn(M)

    # weights and bias for the output layer
    W2 = np.random.randn(M, K)
    b2 = np.random.randn(K)

    Y_hat = forward(X, W1, b1, W2, b2)
    class_rate = classification_rate(Y, Y_hat)
    print("Classification rate: %s" % class_rate)

    # by c=Y we assign each point in the scatter a colormap value of its class (Y)
    # plt.scatter(X[:, 0], X[:, 1], c=Y, alpha=0.5)
    # plt.show()

def forward(X, W1, b1, W2, b2):
    """
    Feed forward X in a network with a single hidden layer
    :param X: Input dataset
    :param W1: Weights of first hidden layer
    :param b1: bias for first hidden layer
    :param W2: weights for the output layer (aka V)
    :param b2: bias for the output layer
    :return: Matrix with probabilities of each sample belong to each k (group)
    """

    # First hidden layer, each row has M values per each activation unit (will use sigmoid)
    Z = X.dot(W1) + b1
    Z = 1 / (1 + np.exp(-1 * Z))  # sigmoid

    # Second layer (output layer), each row has K values per each class prediction probability (we'll use softmax)
    A = Z.dot(W2) + b2
    expA = np.exp(A)
    Y = expA / expA.sum(axis=1, keepdims=True)

    return Y

def classification_rate(Y_act, Y_hat):
    """
    Calculate the classification error
    :param Y_act: The actual class of each sample (nX1)
    :param Y_hat: The probability of each sample belongs to each k (nXk)
    :return:
    """

    # find the index of the maximum value per sample
    Y_hat = np.argmax(Y_hat, axis=1)
    class_rate = np.sum(Y_hat == Y_act)
    return class_rate / Y_act.size

if __name__ == '__main__':
    main()


import numpy as np

def mse(actual, predicted):
    """
    https://ml-cheatsheet.readthedocs.io/en/latest/linear_regression.html#cost-function
    MSE = the mean of (actual_outcome - predicted_outcome) squared
    """
    return np.mean(np.power(actual - predicted, 2))

def prime_mse(actual, predicted):
    """
    Derivate of mse for use with the Gradient Descent optimizer.
    Output error is calculated either as the result of the derivative
    of the cost function or as the result of the backpropagation
    of the previous layer.
    """
    return 2 * (predicted - actual) / actual.size


import numpy as np

# def find_bmu_act(vec, act):
#     """  """
#     for node in act:
#         for data in node[2]:
#             if vec in data:
#                 return node

# def dist(a, b):
#     """ Return euclidean distance """
#     return np.sqrt(np.sum(np.square(np.subtract(a, b))))

""" Error metric per node """

def qE_node(act):
    """ Return list of mean quantization error by node """
    return [np.mean([qE(data, node[1]) for data in node[2]]) for node in act]

def MAE_node(act):
    """ Return list of mean MAE by node """
    return [np.mean([MAE(data, node[1]) for data in node[2]]) for node in act]

def MSE_node(act):
    """ Return list of mean MSE by node """
    return [np.mean([MSE(data, node[1]) for data in node[2]]) for node in act]

def RMSE_node(act):
    """ Return list of mean RMSE by node """
    return [np.mean([RMSE(data, node[1]) for data in node[2]]) for node in act]

def MAPE_node(act):
    """ Return list of mean MAPE by node """
    return [np.mean([MAPE(data, node[1]) for data in node[2]]) for node in act]

""" Error metrics """

def qE(a, b):
    """ Return quantization error """
    return np.sqrt(np.sum(np.square(np.subtract(a, b))))

def MAE(a, b):
    """ Return Mean absolute error """
    return abs(np.subtract(a, b)).mean()

def MSE(a, b):
    """ Return Mean squared error """
    return np.square(np.subtract(a, b)).mean()

def RMSE(a, b):
    """ Return Root mean squared error """
    return np.sqrt(np.square(np.subtract(a, b)).mean())

def MAPE(a, b):
    """ Return Mean absolute percentage error """
    return abs(np.divide(np.subtract(a, b),a))*100


import numpy as np

def euclidean_distance(x: np.array, y: np.array) -> float:
    """Calculates euclidean distance.

    This function calculates euclidean distance between
    two points x and y in Euclidean n-space.

    Args:
        x, y: points in Euclidean n-space.

    Returns:
        length of the line segment connecting given points.

    """

    return np.sqrt(np.sum((x - y) ** 2))

def euclidean_similarity(x: np.array, y: np.array) -> float:
    """Calculates euclidean similarity.

    This function calculates euclidean similarity
    between points x and y in Euclidean n-space
    that based on euclidean distance between this points.

    Args:
        x, y: two points in Euclidean n-space.

    Returns:
        similarity between points x and y.

    """

    return 1 / (1 + euclidean_distance(x, y))

def pearson_similarity(x: np.array, y: np.array) -> float:
    """Calculates Pearson correlation coefficient.

    This function calculates Pearson correlation coefficient
    for given 1-D data arrays x and y.

    Args:
        x, y: two 1-D data arrays with float values.

    Returns:
        Pearson correlation between x and y.

    """

    x_b, y_b = x - x.mean(), y - y.mean()

    denominator = np.sqrt(np.sum(x_b ** 2) * np.sum(y_b ** 2))

    if denominator == 0:
        return np.nan

    return np.sum(x_b * y_b) / denominator

def recsys_euclidean_similarity(x: np.array, y: np.array) -> float:
    """Calculates euclidean similarity of two users/items.

    This function calculates users or items similarity based on
    euclidean similarity. The similarity between two users/items,
    that represented here as two 1-D arrays where each value
    is score for some item (from some user), is calculated only for
    those indices i for which there is score both
    for first and second user/item. It's assumed that zero values
    in arrays are equal to lack of score for some items (from some users).

    Args:
        x, y: two 1-D data arrays that represent user's/item's scores.

    Returns:
        euclidean similarity between two users/items x and y.

    """

    x_new, y_new = x[(x != 0) & (y != 0)], y[(x != 0) & (y != 0)]

    if x_new.shape[0] == 0:
        return -np.inf

    return euclidean_similarity(x_new, y_new)

def recsys_pearson_similarity(x: np.array, y: np.array) -> float:
    """Calculates pearson similarity of two users/items.

    This function calculates users or items similarity based on
    pearson similarity. The similarity between two users/items,
    that represented here as two 1-D arrays where each value
    is score for some item (from some user), is calculated only for
    those indices i for which there is score both
    for first and second user/item. It's assumed that zero values
    in arrays are equal to lack of score for some items (from some users).

    Args:
        x, y: two 1-D data arrays that represent user's/item's scores.

    Returns:
        pearson similarity between two users\items x and y.

    """

    x_new, y_new = x[(x != 0) & (y != 0)], y[(x != 0) & (y != 0)]

    if x_new.shape[0] == 0:
        return -np.inf

    return pearson_similarity(x_new, y_new)

def apk(actual: np.array, predicted: np.array, k: int=10) -> float:
    """Calculates the average precision at k.

    This function calculates the average precision at k
    for given predicted elements by actual elements.

    Args:
        actual: array of relevant elements in any order.
        predicted: array of predicted elements that are sorted
            by relevance in descending order.
        k: number of predicted elements.

    Returns:
        The average precision at k over the input lists.

    """

    if len(predicted) < k:
        k = len(predicted)

    precision_at_k = np.array([np.in1d(predicted[:i], actual).sum() / i for i in range(1, k+1)])
    rel = np.array([1 if p in actual else 0 for p in predicted[:k]])

    return (precision_at_k * rel).mean()

def mapk(actual: np.array, predicted: np.array, k: int=10) -> float:
    """Calculates the mean average precision at k.

    This function calculates the mean average precision at k
    for given predicted elements for multiple users by
    actual elements.

    Args:
        actual: 2-D array of relevant elements.
        predicted: 2-D array of predicted elements.
        k: number of predicted elements.

    Returns:
        The mean average precision at k over the input arrays.

    """

    sum = 0
    U = len(predicted)

    for i in range(U):
        sum += apk(actual[i], predicted[i], k)

    return sum / U


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

# parameter
k, m = sp.symbols("k m")

# time
t = sp.Symbol("t")

# generalized coordinate
q_fn = sp.Function("q")
q = q_fn(t)
q_dot = q.diff(t)

# cartesian coordinates in terms of q
x = q
y = 0
z = 0
print("generalized coordinates:")
print("x =", x, "\ny =", y, "\nz =", z)

# compute cartesian derivates in terms of q
x_dot = sp.diff(x, t)
y_dot = sp.diff(y, t)
z_dot = sp.diff(z, t)
print("x_dot =", x_dot, "\ny_dot =", y_dot, "\nz_dot =", z_dot)

# construct lagrangian
T = m*(x_dot**2 + y_dot**2 + z_dot**2)/2
V = k*x**2/2
L = T - V
print("lagrangian:", L)

# compute lagrange equation
lagrange_eq = sp.Eq(L.diff(q_dot).diff(t) - L.diff(q), 0)
print("equation of motion:", lagrange_eq)

# general solution
q_general_sol = sp.dsolve(lagrange_eq, q).rhs
q_dot_general_sol = q_general_sol.diff(t)
print("solution:")
print("q(t) =", q_general_sol)
print("q_dot(t) =", q_dot_general_sol)
C1, C2 = sp.symbols("C1 C2")

# solve initial conditions
q0 = 0
q_dot_0 = 1
eq1 = sp.Eq(q_general_sol.subs(t, 0), q0)
eq2 = sp.Eq(q_dot_general_sol.subs(t, 0), q_dot_0)
sol = sp.solve([eq1, eq2], [C1, C2])
print("parameters for the initial conditions:")
print("C1 =", sol[C1])
print("C2 =", sol[C2])
q_sol = q_general_sol.subs(C1, sol[C1]).subs(C2, sol[C2])
q_dot_sol = q_sol.diff(t)
print("solutions for initial conditions:")
print("q(t) =", q_sol)
print("q_dot(t) =", q_dot_sol)

# choose parameters
time = np.linspace(0, 10, 500)
k_val = 1.0
m_val = 1.0
q_vals = sp.lambdify(t, q_sol.subs(k, k_val).subs(m, m_val))(time).real
plt.plot(time, q_vals)
plt.xlabel("t [s]")
plt.ylabel("q [m]")
plt.title("q(0) = %.2f, q_dot(0) = %.2f, k = %.2f, m = %.2f" % (q0, q_dot_0, k_val, m_val))
plt.grid()
plt.show()


"""
A program that will allow the user to input
any two single-variable functions of x and
print the enclosed area between the two
"""

from sympy import Symbol, sympify, Integral, SympifyError

def area(expr1, expr2, var, lower, upper):
    _area = Integral(expr1 - expr2, (var, lower, upper)).doit()
    return _area

if __name__ == "__main__":
    try:
        expr1 = sympify(input("Enter the upper function in one variable: "))
        expr2 = sympify(input("Enter the lower function in one variable: "))
        var = Symbol(input("Enter variable: "))
        lower = float(input("Enter lower bound of the enclosed region: "))
        upper = float(input("Enter upper bound of the enclosed region: "))
    except SympifyError:
        print("Invalid input")
    else:
        result = area(expr1, expr2, var, lower, upper)
        if result:
            print("Area enclosed by {} and {} is equals to: {:.2f}".format(expr1, expr2, result))


import numpy as np

class ActivationFunction:
    """Abstract class to represent activation functions"""

    def apply(self, x):
        pass

    def derivative(self, x):
        pass

class Step(ActivationFunction):
    """The step funtion"""

    def apply(self, x):
        if x < 0:
            return 0
        return 1

    def derivative(self, x):
        if x == 0:
            raise ValueError("Derivative in zero is infinite")
        return 0

class Sigmoid(ActivationFunction):
    """The sigmoid function"""

    def apply(self, x):
        return 1 / (1 + np.exp(-x))

    def derivative(self, x):
        return self.apply(x) * (1 - self.apply(x))

class Tanh(ActivationFunction):
    """The tanh function"""

    def apply(self, x):
        return np.tanh(x)

    def derivative(self, x):
        return 1 - np.tanh(x)**2


# Simulates a homogeneous Poisson point process on a circle.
# This code positions the points uniformly around a circle, which can be
# achieved by either using polar coordinates or normal random variables.
# Author: H. Paul Keeler, 2020.
# Website: hpaulkeeler.com
# Repository: github.com/hpaulkeeler/posts
# For more details, see the post:
# hpaulkeeler.com/simulating-a-poisson-point-process-on-a-circle/

import numpy as np;  # NumPy package for arrays, random number generation, etc
import matplotlib.pyplot as plt  # for plotting
from numpy import linalg as la #linear algebra pack

plt.close('all');  # close all figures

r = 1;  # radius of circle

# centre of circle
xx0 = 0;
yy0 = 0;

# Point process parameters
lambda0 = 10;  # intensity (ie mean density) of the Poisson process

lengthTotal=2*np.pi*r; #circumference of circle

# Simulate Poisson point process
numbPoints = np.random.poisson(lambda0 * lengthTotal);  # Poisson number of points

#METHOD 1 for positioning points: Use polar coodinates
theta = 2 * np.pi * np.random.uniform(0, 1, numbPoints);  # angular coordinates
rho = r ;  # radial coordinates

# Convert from polar to Cartesian coordinates
xx = rho * np.cos(theta);
yy = rho * np.sin(theta);

#METHOD 2 for positioning points: Use normal random variables
xxRand=np.random.normal(0,1,size=(numbPoints,2)); #generate two sets of normal variables
normRand=la.norm(xxRand,2,1); #Euclidean norms
xxRandBall=xxRand/normRand[:,None]; #rescale by Euclidean norms
xxRandBall=r*xxRandBall; #rescale for non-unit sphere
#retrieve x and y coordinates
xx= xxRandBall[:,0];
yy= xxRandBall[:,1];

# Shift centre of circle to (xx0,yy0)
xx = xx + xx0;
yy = yy + yy0;

# Plotting
plt.scatter(xx, yy, edgecolor='b', facecolor='none', alpha=0.5);
plt.xlabel('x');
plt.ylabel('y');
plt.axis('equal');


import numpy as np

def recursiveIntegral(v0,v1,v2,f,tol) :
    int0 = triMidPntInt(v0,v1,v2,f)

    w0 = ( (v0[0]+v1[0])/2.0, (v0[1]+v1[1])/2.0 )
    w1 = ( (v1[0]+v2[0])/2.0, (v1[1]+v2[1])/2.0 )
    w2 = ( (v2[0]+v0[0])/2.0, (v2[1]+v0[1])/2.0 )

    int1 = triMidPntInt(v0,w0,w2,f)
    int2 = triMidPntInt(w0,v1,w1,f)
    int3 = triMidPntInt(w0,w1,w2,f)
    int4 = triMidPntInt(w2,w1,v2,f)

#    int1 = triVertAvg(v0,w0,w2,f)
#    int2 = triVertAvg(w0,v1,w1,f)
#    int3 = triVertAvg(w0,w1,w2,f)
#    int4 = triVertAvg(w2,w1,v2,f)

    intRef = int1+int2+int3+int4
    if intRef < tol :
        return (intRef, 1)

    if abs((int0 - intRef)/intRef) > tol :
        (int1,d1) = recursiveIntegral(v0,w0,w2,f,tol)
        (int2,d2) = recursiveIntegral(w0,v1,w1,f,tol)
        (int3,d3) = recursiveIntegral(w0,w1,w2,f,tol)
        (int4,d4) = recursiveIntegral(w2,w1,v2,f,tol)
        intRef = int1+int2+int3+int4
        d = max(d1,d2,d3,d4)+1
    else :
        d = 1

    return (intRef, d)

def triMidPntInt(v0,v1,v2,f) :
    A = triArea(v0,v1,v2)
    g = ( (v0[0]+v1[0]+v2[0])/3, (v0[1]+v1[1]+v2[1])/3 )
    return A*f(g[0],g[1])

def triVertAvg(v0,v1,v2,f) :
    A = triArea(v0,v1,v2)
    return A*(f(v0[0],v0[1])+f(v1[0],v1[1])+f(v2[0],v2[1]))/3.0

def triArea(v0,v1,v2) :
    return abs(v0[0]*(v1[1]-v2[1]) - v0[1]*(v1[0]-v2[0]) + v1[0]*v2[1] - v2[0]*v1[1])/2.0

def test() :
    v0 = [0.0, 0.0]
    v1 = [1.0, 0.0]
    v2 = [0.2,-1.0]
    def f(x,y) : return np.sin(x*np.pi/10)

    (intRef,d) = recursiveIntegral(v0,v1,v2,f,1.0e-6)
    A = triArea(v0,v1,v2)
    print intRef/A,d


from numpy import *
import numpy as np

def compute_error_for_line_given_points(b, m, points):
    totalError = 0
    for i in range(0, len(points)):
        x = points[i, :-1]
        y = points[i, -1]
        totalError += (y - (m * x + b)) ** 2
    return totalError / float(len(x))

def step_gradient(b_current, m_current, points, learningRate):
    b_gradient = 0
    m_gradient = 0
    N = float(len(points))
    for i in range(0, len(points)):
        x = points[i, :-1]
        y = points[i, -1]
        b_gradient += -(2/N) * (y - ((m_current * x) + b_current))
        m_gradient += -(2/N) * x * (y - ((m_current * x) + b_current))
    new_b = b_current - (learningRate * b_gradient)
    new_m = m_current - (learningRate * m_gradient)
    return [new_b, new_m]

def gradient_descent(points, starting_b, starting_m, learning_rate, num_iterations):
    b = starting_b
    m = starting_m
    for i in range(num_iterations):
        b, m = step_gradient(b, m, array(points), learning_rate)
    return [b, m]

# b, m = gradient_descent_runner(points, 0, 0, 0.01,10000)
# m = m.reshape(2, 1)
# # # #print(compute_error_for_line_given_points(b, m, points))
# print("b----------->>>>",b ,"m----------->>>>",m.reshape(2, 1))
# print("---------------", (m).shape)
# #print(points[:, (0, 1)])
# print((points[:, :-1].dot(m)) + min(b))


#! /usr/bin/env python

"""
File: integrate_exp.py

Copyright (c) 2016 Taylor Patti

License: MIT

This module calculates the integral value of the Gaussian function on various intervals with
various mesh sizes and then outputs comparitive tables of the function values and the error
of the function.

"""

import numpy as np
import matplotlib.pylab as mp
import calculus as integrater

def exp_func(x):
    """Provides function for the module."""
    return np.exp(-x**2)

def plotter(func_array, mesh):
    """Plots a given function along with its generating mesh."""
    mp.plot(mesh, func_array, 'b-')
    mp.xlim([-10, 10])
    mp.ylim([-0.01, 1.01])
    mp.title('Gaussian Function is Even')
    mp.xlabel('x')
    mp.ylabel('Gaussian Plot')

def tabler():
    "Outputs two tables, one of the comparitive values and one of the comparitive errors."
    n_list = [100, 200, 300, 400, 500]
    L_list = [2, 4, 6, 8, 10]
    value_list = []
    for L in L_list:
        for n in n_list:
            value_list.append(2 * integrater.trapezoidal_matrix(exp_func, 0, L, n))
    error_list = np.sqrt(np.pi) - value_list
    print
    print '%40s' % 'Value Table'
    print
    print '%10s %10s %10s %10s %10s %10s' % ('', 'n = 100', 'n = 200', 'n = 300', 'n = 400', 'n = 500')
    print
    count = 0
    for L in L_list:
        L_line = 'L = ' + str(L)
        print '%10s %10f %10f %10f %10f %10f' % (L_line, value_list[count], value_list[count + 1], value_list[count + 2], value_list[count + 3], value_list[count + 4])
        count = count + 5
    print
    print
    print '%40s' % 'Error Table'
    print
    print '%10s %10s %10s %10s %10s %10s' % ('', 'n = 100', 'n = 200', 'n = 300', 'n = 400', 'n = 500')
    print
    count = 0
    for L in L_list:
        L_line = 'L = ' + str(L)
        print '%10s %10f %10f %10f %10f %10f' % (L_line, error_list[count], error_list[count + 1], error_list[count + 2], error_list[count + 3], error_list[count + 4])
        count = count + 5

def test_exp_func_values():
    """Ensures that the function has the correct value at x = 0."""
    apt = np.fabs(exp_func(0) - 1) < 1e-5
    msg = 'Exponential Gaussian function improperly defined. Function at value is not correct for Gaussian.'
    assert apt, msg


Table of Contents

1  Vectors and Matrices

1.1  Vectors

1.2  Matrix

1.3  Matrix Order

1.4  Create a  matrix using matrix()

1.5  Create a using array()

1.6  Matrix Properties

1.7  Shape

1.8  Size

1.9  Modifying matrix using insert()

1.10  Modifying matrix using index

1.11  Matrix Operations

1.11.1  Addition

1.11.2  Subtraction

1.11.3  Transpose

1.11.4  Multiplication

1.11.5  Element-wise multiplication

1.11.6  Division

1.12  References

# Vectors and Matrices

## Vectors
- A vector has magnitude (size) and direction
- Use NumPy to create a one-dimensional array
- Vector can be created as row or column using NumPy
![vectors](../img/vector-mag-dir.svg)

__See More__
* https://www.mathsisfun.com/algebra/vectors.html
* https://en.wikipedia.org/wiki/Euclidean_vector

# Load NumPy Library
import numpy as np

# Create a vector as row
vector_row = np.array([1, 2, 3])
print(vector_row)

# Create a vector as column
vector_column = np.array([[1], [2], [3]])
print(vector_column)

## Matrix
- In mathematics, a matrix is a rectangular array of numbers, symbols, or expressions, arranged in rows and columns
- Rows tun horizontally and columns run vertically
- Use NumPy to create a two-dimensional array

![matrix](../img/Matris.png)

## Matrix Order
- You can think of an $r x c$ matrix as a set of r row vectors, each having c elements; or you can think of it as a set of c column vectors, each having r elements.
- The rank of a matrix is defined as (a) the maximum number of linearly independent column vectors in the matrix or (b) the maximum number of linearly independent row vectors in the matrix. Both definitions are equivalent.
- If r is less than c, then the maximum rank of the matrix is r.
- If r is greater than c, then the maximum rank of the matrix is c.
![matrix](../img/Matrix_1000.gif)

__See More__
* https://en.wikipedia.org/wiki/Matrix_(mathematics)
* https://mathworld.wolfram.com/Matrix.html
* https://stattrek.com/matrix-algebra/matrix-rank.aspx

## Create a  matrix using `matrix()`
- Returns a matrix from an array type object ir string of data.
- **Syntax:** `np.matrix(data)`

mat1 = np.matrix("1, 2, 3, 4; 4, 5, 6, 7; 7, 8, 9, 10")
print(mat1)

## Create a using `array()`
- Returns a matrix
- **Syntax:** `np.array(object)`

mat2 = np.array([[1, 2], [3,4], [4, 6]])
print(mat2)

## Matrix Properties

## Shape
- Returns number of rows and columns from a matrix
- **Syntax:** `mat.shape`
    - shape[0] - returns the number of rows
    - shape[1] - returns the number of columns

mat3 = np.matrix("1, 2, 3, 4; 4, 5, 6, 7; 7, 8, 9, 10")

# shape
mat3.shape

# rows
mat3.shape[0]

# columns
mat3.shape[1]

## Size
- Returns the number of elements from a matrix
- **Syntax:** `array.size`

mat4 = np.matrix("1, 2, 3, 4; 4, 5, 6, 7; 7, 8, 9, 10")

# size
mat4.size

## Modifying matrix using `insert()`
- Adds values at a given position and axis in a matrix
- **Syntax:** `np.insert(matrix, object, values, axis)`
    - matrix - input matrix
    - object - index position
    - values - matrix of values to be inserted

mat5 = np.matrix("1, 2, 3, 4; 4, 5, 6, 7; 7, 8, 9, 10")
print(mat5)

# adding a new matrix `col_new` as a new column to mat5
col_new = np.matrix("1, 1, 1")
print(col_new)

# insert at column
mat6 = np.insert(mat5, 0, col_new, axis=1)
print(mat6)

# adding a new matrix `row_new` as a new row to mat5
row_new = np.matrix("0, 0, 0, 0")
print(row_new)

# insert at row
mat7 = np.insert(mat5, 0, row_new, axis=0)
print(mat7)

## Modifying matrix using `index`
- Elements of matrix can be modified using index number
- **Syntax:**: `mat[row_index, col_index)`

mat_a = np.matrix("1, 2, 3, 4, 5; 5, 6, 7, 8, 9; 9, 10, 11, 12, 13")
print(mat_a)

# change 6 with 0
mat_a[1, 1] = 0

# show mat_a
print(mat_a)

# extract 2nd row
mat_a[1, :]

# extract 3rd column
mat_a[:, 2]

# extract elements
mat_a[1, 2]

## Matrix Operations

A = np.arange(0, 20).reshape(5,4)
print(A)

B = np.arange(20, 40).reshape(5,4)
print(B)

### Addition
- `np.add()`- performs element-wise addition between two matrices
- **Syntax:** `np.add(matrix_1, matrix_2)`
![add](../img/Matrix_Addition.png)

# addition
np.add(A, B)

### Subtraction
- `np.subtract()` - performs element-wise subtraction between two matrices.
- **Syntax:** `np.subtract(matrix_1, matrix_2`)
![sub](../img/Matrix_Subtraction.png)

# subtraction
np.subtract(A,B)

### Transpose
- `np.transpose()` - Permute the dimensions of an array.
- Transposing an $M \times N$ matrix flips it around the center diagonal and results in an $N \times M$ matrix.
- **Syntax:** `np.transpose(matrix)`
![transpose](../img/Matrix_Transpose.png)

A = np.arange(0, 20).reshape(5,4)
print(A)

# transpose
np.transpose(A)

### Multiplication
- `np.dot()` - performs matrix multiplication between two matrices.
- **Syntax:** `np.dot(matrix_1, matrix_2)`
![mul](../img/Matrix_Multiplication.png)

# multiplication
np.dot(A,B)

__Note__
- For matrix multiplication the number of **columns** in matrix $A$ should be equal to the number of **rows** in matrix $B$
- Here, Order of matrix $A$ = $5 \times 4$ and order of matrix $B$ = $5 \times 4$
- So, $5 \neq 4$
- That's why it shows *ValueError: shapes (5,4) and (5,4) not aligned: 4 (dim 1) != 5 (dim 0)*

# transpose matrix B to make it 4x5 in dimension
T = np.transpose(B)
print(T)

# now we can perform multiplication
np.dot(A,T)

# using matmul
np.matmul(A, T)

# using @ operator
A @ T

### Element-wise multiplication
- `np.multiply()` - performs element-wise multiplication
between two matrices.
- **Syntax:** `np.multiply(matrix1, matrix2)`

# element-wise multiplication
np.multiply(A, B)

### Division
- `np.divide()` - performs element-wise division between two matrices.
- **Syntax:** `np.divide(matrix_1, matrix_2)`

# division
np.divide(A, B)

## References
- https://numpy.org/
- https://www.edureka.co/blog/python-numpy-tutorial/
- https://github.com/enthought/Numpy-Tutorial-SciPyConf-2019
- [Python Machine Learning Cookbook](https://www.amazon.com/Python-Machine-Learning-Cookbook-Prateek/dp/1786464470)

*This notebook was created by [Jubayer Hossain](https://jhossain.me/) | Copyright © 2020, [Jubayer Hossain](https://jhossain.me/)*


import numpy as np
import matplotlib.pyplot as plt

from scipy import integrate

import numba
from numba import jit

u_inf = 1

# defines the cylinder
R = 1.0
theta = np.linspace(0, 2 * np.pi, 100)

# coordinates of the cylinder
x_cylinder, y_cylinder = R * np.cos(theta), R * np.sin(theta)

size = 4
plt.figure(figsize=(size, size))

plt.grid(True)
plt.xlabel('x', fontsize=16)
plt.ylabel('y', fontsize=16)

plt.plot(x_cylinder, y_cylinder, color='b', linestyle='-', linewidth=2)

plt.xlim(-1.1, 1.1)
plt.ylim(-1.1, 1.1)

plt.show()

class Panel:

    def __init__(self, xa, ya, xb, yb):

        self.xa, self.ya = xa, ya
        self.xb, self.yb = xb, yb

        self.xc, self.yc = (xa + xb) / 2, (ya + yb) / 2

        self.length = np.sqrt((xb - xa)**2 + (yb - ya)**2)

        # We are doing the panels counterclock-wise
        if xb - xa <= 0.0:

            self.beta = np.arccos((yb - ya) / self.length)

        elif xb - xa > 0.0:

            self.beta = np.pi + np.arccos(-(yb - ya) / self.length)

        self.sigma = 0.0
        self.vt = 0.0
        self.cp = 0.0

N_panels = 10

# defining the end-points of the panels
x_ends = R * np.cos(np.linspace(0, 2 * np.pi, N_panels + 1))
y_ends = R * np.sin(np.linspace(0, 2 * np.pi, N_panels + 1))

# defining the panels
panels = np.empty(N_panels, dtype=object)
for i in range(N_panels):
    panels[i] = Panel(x_ends[i], y_ends[i], x_ends[i + 1], y_ends[i + 1])

# plotting the panels
size = 6
plt.figure(figsize=(size, size))
plt.grid(True)
plt.xlabel('x', fontsize=16)
plt.ylabel('y', fontsize=16)
plt.plot(x_cylinder, y_cylinder, color='b', linestyle='-', linewidth=1)
plt.plot(x_ends, y_ends, color='#CD2305', linestyle='-', linewidth=2)
plt.scatter([p.xa for p in panels], [
            p.ya for p in panels], color='#CD2305', s=40)
plt.scatter([p.xc for p in panels], [p.yc for p in panels],
            color='k', s=40, zorder=3)
plt.legend(['cylinder', 'panels', 'end-points', 'center-points'],
           loc='best', prop={'size': 16})
plt.xlim(-1.1, 1.1)
plt.ylim(-1.1, 1.1)

plt.show()

def integral_normal(p_i, p_j):

    def func(s):
        return ((+(p_i.xc - (p_j.xa - np.sin(p_j.beta) * s)) *
                 np.cos(p_i.beta) +
                 (p_i.yc - (p_j.ya + np.cos(p_j.beta) * s)) *
                 np.sin(p_i.beta)) /
                ((p_i.xc - (p_j.xa - np.sin(p_j.beta) * s))**2 +
                 (p_i.yc - (p_j.ya + np.cos(p_j.beta) * s))**2))

    return integrate.quad(lambda s: func(s), 0.0, p_j.length)[0]

A = np.empty((N_panels, N_panels), dtype=float)
np.fill_diagonal(A, 0.5)

for i, p_i in enumerate(panels):
    for j, p_j in enumerate(panels):
        if i != j:
            A[i, j] = 0.5 / np.pi * integral_normal(p_i, p_j)

b = - u_inf * np.cos([p.beta for p in panels])

sigma = np.linalg.solve(A, b)

for i, panel in enumerate(panels):
    panel.sigma = sigma[i]

def integral_tangential(p_i, p_j):

    def func(s):
        return ((-(p_i.xc - (p_j.xa - np.sin(p_j.beta) * s)) *
                 np.sin(p_i.beta) +
                 (p_i.yc - (p_j.ya + np.cos(p_j.beta) * s)) *
                 np.cos(p_i.beta)) /
                ((p_i.xc - (p_j.xa - np.sin(p_j.beta) * s))**2 +
                 (p_i.yc - (p_j.ya + np.cos(p_j.beta) * s))**2))

    return integrate.quad(lambda s: func(s), 0., p_j.length)[0]

A = np.empty((N_panels, N_panels), dtype=float)
np.fill_diagonal(A, 0.0)

for i, p_i in enumerate(panels):
    for j, p_j in enumerate(panels):
        if i != j:
            A[i, j] = 0.5 / np.pi * integral_tangential(p_i, p_j)

b = - u_inf * np.sin([panel.beta for panel in panels])

vt = np.dot(A, sigma) + b

for i, panel in enumerate(panels):
    panel.vt = vt[i]

for panel in panels:
    panel.cp = 1.0 - (panel.vt / u_inf)**2

cp_analytical = 1.0 - 4 * (y_cylinder / R)**2

# plots the surface pressure coefficient
plt.figure(figsize=(10, 6))
plt.grid(True)
plt.xlabel('x', fontsize=16)
plt.ylabel('$C_p$', fontsize=16)
plt.plot(x_cylinder, cp_analytical, color='b',
         linestyle='-', linewidth=1, zorder=1)
plt.scatter([p.xc for p in panels], [p.cp for p in panels],
            color='#CD2305', s=40, zorder=2)
plt.title('Number of panels : %d' % N_panels, fontsize=16)
plt.legend(['analytical', 'source panel method'],
           loc='best', prop={'size': 16})
plt.xlim(-1.0, 1.0)
plt.ylim(-4.0, 2.0)

plt.show()

import numpy,from scipy,import numba,from numba


#!/usr/bin/env python
"""

https://stackoverflow.com/questions/33976911/generate-a-random-sample-of-points-distributed-on-the-surface-of-a-unit-sphere

"""
import numpy as np

def sample_trig(npoints):
    theta = 2*np.pi*np.random.rand(npoints)
    phi = np.arccos(2*np.random.rand(npoints)-1)
    x = np.cos(theta) * np.sin(phi)
    y = np.sin(theta) * np.sin(phi)
    z = np.cos(phi)
    return np.array([x,y,z])

def sample_normals(npoints):
    vec = np.random.randn(3, npoints)
    vec /= np.linalg.norm(vec, axis=0)
    return vec

def sample_reject(npoints):
    vec = np.zeros((3,npoints))
    abc = 2*np.random.rand(3,npoints)-1
    norms = np.linalg.norm(abc,axis=0)
    mymask = norms<=1
    abc = abc[:,mymask]/norms[mymask]
    k = abc.shape[1]
    vec[:,0:k] = abc
    while k<npoints:
       abc = 2*np.random.rand(3)-1
       norm = np.linalg.norm(abc)
       if 1e-5 <= norm <= 1:
           vec[:,k] = abc/norm
           k = k+1
    return vec

if __name__ == '__main__':

    n = 10
    a = sample_trig(n)
    b = sample_normals(n)
    c = sample_reject(n)


# -*- coding: utf-8 -*-
"""
Created on Thu Jul 12 11:56:48 2018

@author: lijie
"""

from numpy import *

#model file input function
def loadDataSet(fileName, delim='\t'):
    fr = open(fileName)
    stringArr = [line.strip().split(delim) for line in fr.readlines()]
    datArr = [list(map(float,line)) for line in stringArr]
    return mat(datArr)
#pca
def pca(dataMat, topNfeat=9999999): #topNfeat: number of feature
    meanVals = mean((dataMat), axis=0)# calc mean
    meanRemoved = dataMat - meanVals #remove mean
    covMat = cov(meanRemoved, rowvar=0)#calc covariance
    eigVals,eigVects = linalg.eig(mat(covMat))
    eigValInd = argsort(eigVals)            #sort
    eigValInd = eigValInd[:-(topNfeat+1):-1]  #last N largest number
    redEigVects = eigVects[:,eigValInd]       #reorganize eig vects largest to smallest
    lowDataMat = meanRemoved * redEigVects #transform data into new dimensions
    reconMat = (lowDataMat * redEigVects.T) + meanVals #reconstruct data
    return lowDataMat, reconMat

import matplotlib
import matplotlib.pyplot as plt
#plot original data & reconstructed data to make a comparison
def plotdata(data1,data2):
    fig=plt.figure()
    ax=fig.add_subplot(111)
    ax.scatter(data1[:,0].flatten().A[0],data1[:,1].flatten().A[0],marker='x',s=90,c='yellow')
    ax.scatter(data2[:,0].flatten().A[0],data1[:,1].flatten().A[0],marker='o',s=50,c='red')

'''data cleaning on complex dataset'''
# replace NAN value (with mean  → do not influence the result)
def replaceNanWithMean():
    datMat = loadDataSet('secom.data', ' ')
    numFeat = shape(datMat)[1]
    for i in range(numFeat):
        meanVal = mean(datMat[nonzero(~isnan(datMat[:,i].A))[0],i]) #calc mean on values that are not NaN (a number)
        datMat[nonzero(isnan(datMat[:,i].A))[0],i] = meanVal  #set NaN values to mean
    return datMat

if __name__=='__main__' :

#test
    #dataMat=loadDataSet('testSet.txt')
    dataMat=replaceNanWithMean()
    lowDMat, reconMat=pca(dataMat,20)
    print('shape(lowDMat):\t',shape(lowDMat))
    #plotdata(dataMat,reconMat)


'''
# Linear Regression: Tensorflow Way
#----------------------------------
#
# This function shows how to use Tensorflow to
# solve linear regression.
# y = Ax + b
#
# We will use the iris data, specifically:
#  y = Sepal Length
#  x = Petal Width
'''
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
from sklearn import datasets
from tensorflow.python.framework import ops
ops.reset_default_graph()
sess=tf.Session()
# Load the data
# iris.data = [(Sepal Length, Sepal Width, Petal Length, Petal Width)]
iris=datasets.load_iris()
x_vals=np.array([x[3] for x in iris.data])
y_vals=np.array([y[0] for y in iris.data])
# Declare batch size
batch_size = 25
# Initialize placeholders
x_data=tf.placeholder(shape=[None,1],dtype=tf.float32)
y_=tf.placeholder(shape=[None,1], dtype=tf.float32)

#create variable for linear regression
A=tf.Variable(tf.random_normal(shape=[1,1]))
b=tf.Variable(tf.random_normal(shape=[1,1]))
#declare model operations
y=tf.add(tf.matmul(x_data,A),b)
#declare loss functions  (1/2/m)  (y_-y)^2
loss=tf.reduce_mean(tf.square(y_- y))
#Declare optimizer
op=tf.train.GradientDescentOptimizer(0.05)
train_step=op.minimize(loss)
#initialize variables
init=tf.global_variables_initializer()
sess.run(init)
#training loop
loss_vec=[]
for i in range(100):
    rand_index=np.random.choice(len(x_vals),size=batch_size)#随机从len(x_vals)中选取25个下标
    rand_x=np.transpose([x_vals[rand_index]])
    rand_y=np.transpose([y_vals[rand_index]])
    sess.run(train_step,feed_dict={x_data:rand_x,y_:rand_y})
    temp_loss=sess.run(loss,feed_dict={x_data:rand_x,y_:rand_y})
    loss_vec.append(temp_loss)
    if (i+1)%25==0:
        print('Step #' + str(i+1) + ' A = ' + str(sess.run(A)) + ' b = ' + str(sess.run(b)))
        print('Loss = ' + str(temp_loss))
#get the optimal coefficients
[A_final]=sess.run(A) #[A_final] if not get the []  ,cannot plot best_fit_y
[b_final]=sess.run(b)
#get the best fit line
best_fit_y=[]
for i in x_vals:
    best_fit_y.append(A_final*i+b_final)

    #best_fit=(np.add(np.dot(x_vals,np.matrix(A_final)),b_final)).tolist()
#plot the result
# Plot the result
plt.plot(x_vals, y_vals, 'o', label='Data Points')
plt.plot(x_vals, best_fit_y, 'r-', label='Best fit line', linewidth=3)
plt.legend(loc='upper left')
plt.title('Sepal Length vs Pedal Width')
plt.xlabel('Pedal Width')
plt.ylabel('Sepal Length')
plt.show()
#plot loss over time(steps)
plt.plot(loss_vec, 'k-')
plt.title('L2 Loss per Generation')
plt.xlabel('Generation')
plt.ylabel('L2 Loss')
plt.show()

cookbook/3 Linear Regression/TensorFlow Way.py


#Program to perform cross correlation

import numpy as np
import scipy as sy
from matplotlib import pyplot as plt

#input sequences

x = eval(input('Enter the input sequence x[n]='))
N1 = len(x)
h = eval(input('Enter the input sequence h[n]='))
N2 = len(h)
N = N1+N2-1
y = np.zeros(N)
for i in range (N2):
    h[N2-1-i]=h[i]

#Correlation using Linear convolution built-in function in NumPy
y1 = np.convolve(x,h)
#Correlation using Correlation built-in function in NumPY
y2 = np.correlate(x,h,'full')
print('Auto correlation using NumPy Linear convolution built-in function -correlation result y=\n',y1)
print('Auto correlation using NumPy correlation built-in function - correlation result  y=\n',y2)

m = N-N1
n = N-N2
#Padding zeros to x and h to make their length to N
x =np.pad(x,(0,m),'constant')
h =np.pad(h,(0,n),'constant')

#correlation using formula
for n in range (N):
    for k in range (N):
        if n >= k:
             y[n] = y[n]+x[n-k]*h[k]

print('correlation using formula - correlation result y =\n',y)

#RESULT
##Enter the input sequence x[n]=[1,2,1,1]
##Enter the input sequence h[n]=[1,1,2,1]
##Auto correlation using NumPy Linear convolution built-in function -correlation result y=
## [1 3 4 5 4 2 1]
##Auto correlation using NumPy correlation built-in function - correlation result  y=
## [1 3 4 5 4 2 1]
##correlation using formula - correlation result y =
## [1. 3. 4. 5. 4. 2. 1.]


"""
Use sympy to compute the recurrence relation:

    seq[n] = f*seq[n-2] - seq[n-1]

Output:

0	1
1	x
2	0
3	x**2
4	-x**2
5	x**3 + x**2
6	-2*x**3 - x**2
7	x**4 + 3*x**3 + x**2
8	-3*x**4 - 4*x**3 - x**2
9	x**5 + 6*x**4 + 5*x**3 + x**2
----------------------------------------
0	x**2
1	x
2	10*x**2 - x
3	-10*x**2 + 11*x
4	110*x**2 - 21*x
5	-210*x**2 + 131*x
6	1310*x**2 - 341*x
7	-3410*x**2 + 1651*x
8	16510*x**2 - 5061*x
9	-50610*x**2 + 21571*x
"""
from itertools import islice

import sympy

x = sympy.symbols('x')

def seq(T0=x**0, T1=x, mult_factor=x):
    pprev = T0
    prev = T1
    yield pprev
    yield prev
    while True:
        cur = mult_factor*pprev - prev
        yield cur
        pprev, prev = prev, cur

if __name__ == "__main__":
    NUM_TERMS = 10
    for idx, val in enumerate(islice(seq(), NUM_TERMS)):
        print(f"seq[{idx}]", val.expand(), sep='\t')

    print("-"*40)

    for idx, val in enumerate(islice(seq(T0=x**2, T1=x, mult_factor=10), NUM_TERMS)):
        print(f"seq[{idx}]", val.expand(), sep='\t')


def max_val_rec(alist):
    """
    For 1D array
    What if there is unsorted array?
    I doubt Binary Search would work.
    Doing a max peak value search by recursive divide.
    Not Binary Search.
    """
    ln = len(alist)
    mid = ln//2
    if ln > 2:
        left = max_val_rec(alist[:mid])
        right = max_val_rec(alist[mid:])
        return left if left > right else right
    else:
        return max(alist)

def max_val_rec_2d(arr):
    """
    For 2D array
    What if there is unsorted array matrix?
    I doubt Greedy Ascent would work, efficiently.
    Breaking in O(n) time each row
    and THEN
    Doing a max peak value search by recursive divide,
    using max_val_rec should make it O(n)+O(nlogn);
    """
    return max_val_rec([max_val_rec(each_list) for each_list in arr])

def max_val_rec_2d_fast(arr):
    """
    For NxN 2D matrix using numpy 2D array.
    because indexing is easier and faster.
    Splitting by half just liek in 1D case.
    See max_val_rec for that.
    and THEN
    Doing a max peak value search by recursive divide,
    using max_val_rec should make it O(logn);
    and Total Order is - O(log col.log row)
    """
    shape = arr.shape
    mid = shape[1]//2
    if mid > 0:
        left = max_val_rec_2d_fast(arr[:, :mid])
        right = max_val_rec_2d_fast(arr[:, mid:])
        return left if left > right else right
    else:
        return max_val_rec(arr[:,0])

if __name__ == "__main__":
    import time
    import numpy as np
    from numpy.random import randint
    """
    #For 1D
    n = 0
    tmp = []
    for i in xrange(2, 1002):
        up = randint(2, i+1)
        alist = [randint(1,up) for _ in xrange(i)]
        assert max(alist) == max_val_rec(alist)
        n = len(alist)
        start = time.time()
        max_val_rec(alist)
        end = time.time() - start
        tmp.append((n, end))
    tmp = sorted(tmp, key= lambda x: x[1])
    x,y = zip(*tmp)
    #and now you can plot using matplotlib
    """
    n = 0
    tmp = []
    for i in xrange(2, 400):
        up = randint(2, i+1)
        mat_arr=randint(up, i+up, size=(i,i))
        assert mat_arr.max() == max_val_rec_2d_fast(mat_arr)
        start = time.time()
        max_val_rec_2d_fast(mat_arr)
        end = time.time() - start
        n = mat_arr.shape[0]
        tmp.append((n, (np.log2(n))**2, end))
    tmp = sorted(tmp, key= lambda x: x[0])
    x,y,z = zip(*tmp)
    #and now you can plot using matplotlib


import numpy as np
import pandas as pd
from scipy.spatial import distance
import matplotlib.pyplot as plt

def k_means_mio(X, k, max_iter=100):
    ''' It performs out version of kmeans '''

    if isinstance(X, pd.DataFrame):  # True if it is a dataframe
        X = X.values

    # Pick indices of k random point without replacement
    idx = np.random.choice(len(X), k, replace=False)
    centroids = X[idx, :]

    # Calculate the class of each point using euclidean distance
    matrice = distance.cdist(X, centroids, 'euclidean')
    C = np.argmin(matrice, axis=1)
    for _ in range(max_iter):
        centroids = np.vstack([X[C == i, :].mean(axis=0) for i in range(k)])
        matrice_def = distance.cdist(X, centroids, 'euclidean')
        t = np.argmin(matrice_def, axis=1)

        # Stop when C matrix doesn't change
        if np.array_equal(C, t):
            break

        C = t

    # Return an array containg class of each data point, and the centroids
    return C, centroids, matrice_def

def gap_stat(data_cluster, wcss):
    ''' It performs gap statistic '''
    randomunif = np.random.random_sample(size=data_cluster.shape)
    cost_u = []
    gaps = []
    s_k = []
    for i in range(3, 15):
        # Compute k-means and get only the distance metrix and the disctionary

        _, _, matrice_dist_unif = k_means_mio(randomunif, i)
        costo = sum(matrice_dist_unif.min(axis=1)**2)

        cost_u.append(costo)
        # Compute the gap statistic
        gap = np.log(np.mean(cost_u)) - np.log(wcss[i-3])

        # Keep the value of gap statistic for each value of k
        gaps.append(gap)

        # Compute the standard deviation (of the random part)
        s_k.append(np.std(np.log(np.mean(cost_u)))*np.sqrt(1+(1/len(cost_u))))

    # Plot the curve
    plt.figure(figsize=(12, 5))
    plt.plot(list(range(3, 15)), gaps, linestyle='-', marker='o',
             color='lightseagreen', lw=3, alpha=.7, markersize=6)
    plt.xlabel("Numbers of clusters")
    plt.ylabel("Gap Stistics")

    # Get the better value of k according to gap statistics
    # By definition k_star is the min {k | G[k] >= G[k+1] - s_k[k+1]
    k_ = []
    for j in range(0, 15-4):
        if (gaps[j] >= gaps[j+1] - s_k[j+1]):
            k_.append(j)
    k_star = min(k_)
    plt.plot(k_star+3, gaps[k_star],  marker='o',
             markerfacecolor="darkcyan", markersize=10)
    plt.show()
    print(k_star+3)


# coding: utf-8

# A [Mandelbrot set](https://en.wikipedia.org/wiki/Mandelbrot_set) is the set of complex numbers c where:
# $$
# \begin{array}{c}
# c \in \mathbb{C} \\\
# z_0 = 0 \\\
# z_{n+1} = z_n^2 + c \\\
# \lim_{n\to \infty} \lvert z_{n+1}\rvert \le 2
# \end{array}
# $$
#

# In[1]:

get_ipython().magic('matplotlib inline')

import numpy as np
from itertools import product
import matplotlib.pyplot as plt
from matplotlib import colors

# In[2]:

def mset_draw(mset, x=None, y=None):
    if x is not None and y is not None:
        plt.imshow(mset, norm=colors.PowerNorm(0.3), cmap='cubehelix', extent=[x[0], x[-1], y[0], y[-1]]);
    else:
        plt.imshow(mset, norm=colors.PowerNorm(0.3), cmap='cubehelix');
        plt.axis('off');

# In[3]:

def create_intervals(xmin, xmax, ymin, ymax, width, height):
    return np.linspace(xmin, xmax, width), np.linspace(ymin, ymax, height)

# In[4]:

# Mandelbrot set iteration
def mset_iteration(c, maxiter=256):
    z = c
    for n in range(maxiter):
        if abs(z) > 2:
            return n
        z = z**2 + c
    return n

# In[5]:

def mandelbrot_set_list_comp(xmin, xmax, ymin, ymax, width, height, maxiter=256):
    real_range, imaginary_range = create_intervals(xmin, xmax, ymin, ymax, width, height)

    m = [mset_iteration(r + s*1j, maxiter) for r in real_range for s in imaginary_range]
    return m, real_range, imaginary_range

# In[6]:

mset, r, i = mandelbrot_set_list_comp(-2.0,0.5,-1.25,1.25, 600, 600)
mset_draw(np.array(mset).reshape(600, 600).T, r, i);

# In[7]:

get_ipython().magic('timeit mandelbrot_set_list_comp(-2.0,0.5,-1.25,1.25, 600, 600)')

# In[8]:

def mandelbrot_set_numpy(xmin, xmax, ymin, ymax, width, height, maxiter=256):
    m = np.empty((height, width), dtype=np.uint8)
    real_range, imaginary_range = create_intervals(xmin, xmax, ymin, ymax, width, height)

    for j, i in product(range(height), range(width)):
        x = real_range[i]
        y = imaginary_range[j]
        c = x + y*1j
        m[j,i] = mset_iteration(c, maxiter)

    return m, real_range, imaginary_range

# In[9]:

#mset_draw(mandelbrot_set_numpy(-2.0,0.5,-1.25,1.25, 600, 600)[0])

# In[10]:

get_ipython().magic('timeit mandelbrot_set_numpy(-2.0,0.5,-1.25,1.25, 600, 600)')

# In[11]:

from numba import jit

@jit
def mset_iteration_numba(c, maxiter=256):
    z = c
    for n in range(maxiter):
        if abs(z) > 2:
            return n
        z = z**2 + c
    return n

@jit
def mandelbrot_set_numba(xmin, xmax, ymin, ymax, width, height, maxiter=256):
    m = np.empty((height, width), dtype=np.uint8)
    real_range, imaginary_range = create_intervals(xmin, xmax, ymin, ymax, width, height)

    for j, i in product(range(height), range(width)):
        x = real_range[i]
        y = imaginary_range[j]
        c = x + y*1j
        m[j,i] = mset_iteration_numba(c, maxiter)

    return m, real_range, imaginary_range

# In[12]:

#mset_draw(mandelbrot_set_numba(-2.0,0.5,-1.25,1.25, 600, 600)[0])

# In[13]:

get_ipython().magic('timeit mandelbrot_set_numba(-2.0,0.5,-1.25,1.25, 600, 600)')

# In[14]:

def mandelbrot_vectors(c, maxiter):
    output = np.zeros(c.shape)
    z = np.zeros(c.shape, np.complex64)
    for it in range(maxiter):
        notdone = np.less(z.real*z.real + z.imag*z.imag, 4.0)
        output[notdone] = it
        z[notdone] = z[notdone]**2 + c[notdone]
    output[output == maxiter-1] = maxiter-1
    return output

def mandelbrot_set_vectors(xmin, xmax, ymin, ymax, width, height, maxiter=256):
    real_range, imaginary_range = create_intervals(xmin, xmax, ymin, ymax, width, height)

    c = real_range + imaginary_range[:,None]*1j
    return mandelbrot_vectors(c, maxiter)

# In[15]:

#mset_draw(mandelbrot_set_vectors(-2.0,0.5,-1.25,1.25, 600, 600))

# In[16]:

get_ipython().magic('timeit mandelbrot_set_vectors(-2.0,0.5,-1.25,1.25, 600, 600)')

# In[17]:

get_ipython().magic('load_ext Cython')

# In[18]:

get_ipython().run_cell_magic('cython', '', '\nimport cython\nimport numpy as np\ncimport numpy as np\n\ncdef np.uint8_t cp_mset_iteration(double complex c, int maxiter=256):\n    cdef:\n        double complex z\n        int n\n        \n    z = c\n    for n in range(maxiter):\n        if z.real**2 + z.imag**2 > 4.0:\n            return n\n        z = z**2 + c\n    return n\n\n@cython.boundscheck(False)\ncpdef cp_mandelbrot_set_loop(double xmin, double xmax, double ymin, double ymax, int width, int height, int maxiter=256):\n    cdef:\n        int j, i\n        double x, y\n        double[:] real_range = np.linspace(xmin, xmax, width)\n        double[:] imaginary_range = np.linspace(ymin, ymax, height)\n        double complex c\n        np.uint8_t[:,:] m = np.empty((height, width), dtype=np.uint8)\n        \n    for j in range(height):\n        for i in range(width):\n            x = real_range[i]\n            y = imaginary_range[j]\n            c = x + y*1j\n            m[j,i] = cp_mset_iteration(c, maxiter)\n\n    return m')

# In[19]:

#mset_draw(cp_mandelbrot_set_loop(-2.0,0.5,-1.25,1.25, 600, 600))

# In[20]:

get_ipython().magic('timeit cp_mandelbrot_set_loop(-2.0,0.5,-1.25,1.25, 600, 600)')

# In[ ]:

# seahorses?!
mset = cp_mandelbrot_set_loop(-0.745625,-0.7449749,0.1121549, 0.112805, 15000, 15000)
plt.figimage(mset, norm=colors.PowerNorm(0.3), cmap='cubehelix', resize=True);
#plt.imshow(mset, norm=colors.PowerNorm(0.3), cmap='cubehelix');
plt.savefig('mandelbrot.png', format='png');

# In[ ]:


"""
Author : Achintya Gupta
Date Created : 24-09-2020
"""

"""
Problem Statement
------------------------------------------------
Q)  The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:
            1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
    Let us list the factors of the first seven triangle numbers:
            1: 1
            3: 1,3
            6: 1,2,3,6
            10: 1,2,5,10
            15: 1,3,5,15
            21: 1,3,7,21
            28: 1,2,4,7,14,28
    We can see that 28 is the first triangle number to have over five divisors.
    What is the value of the first triangle number to have over five hundred divisors?
"""

from utils import timing_decorator, find_divisors
import numpy as np

@timing_decorator
def tiangle_divisor_count(N=500):
    num=0
    factors=[]
    while True:
        num+=1
        traingle_num = int(0.5*num*(num+1))
        factors = list(find_divisors(traingle_num))
        if len(factors)>N:
            break

    print(f'First triangle number with over {N} divisors: {traingle_num}, with {len(factors)} factors')

tiangle_divisor_count(500)


import numpy as np
import matplotlib.pyplot as plt
from tictoc import *
from plot import plot
#from RFA import newton
def newton(f,fp,x0,TOL,NMAX):
    #INPUT : f , fp , x0 , TOL , NMAX
    # f : function / polynomial
    # fp : derivative of f
    # x0 : initial guess
    # TOL : tolerance value
    # NMAX : maximum number of iterations

    #Approximates root using Newton's Method
    #Recursive Program

    #Print Header
    print('--------------------------------------------------------------------------')
    print('iter \t\t xi \t\t   correction \t\t   rdiff        ')
    print('--------------------------------------------------------------------------')
    # initiate values for  iteration loop:
    rdiff = 1
    xi = x0
    counter = 0
    while rdiff > TOL and counter < NMAX:
        # get the number of necessary iterations at that particular x0
        # compute relative difference
        rdiff = np.abs(f(xi)/fp(xi)/xi)
        # next xi:
        x1 = xi - f(xi)/fp(xi)
        N.append(counter+1)
        f_x.append(f(x1))
        # print iteration data:
        print('%i \t %15.12f \t %15.12f \t %15.12f' % (counter+1, x1, np.abs(f(xi)/fp(xi)),  rdiff))
        # prepare for the next iteration:
        xi = x1
        counter += 1
        if counter == NMAX:
            print("MAX NUMBER OF ITERATIONS REACHED!")
            print('Approximaiton to the Root after max iterations is : ' , x1)
            exit()

    print('------------------------------------------------------------------------')
    print('Root Found: ', x1)

f1 = lambda x: x**3 - 3*(x**2) - x + 9
f1p = lambda x: 3*(x**2) - 6*x -1
f2 = lambda x: np.exp(x)*(x**3 - 3*(x**2) - x + 9)
f2p = lambda x:  np.exp(x)*((x**3 - 3*(x**2) - x + 9)+(3*(x**2) - 6*x -1))
f3 = lambda x: x**3 - 2*x + 2
f3p = lambda x: 3*(x**2) - 2
x01 = -2
x02 = 5

N = []
f_x = []
tic()
newton(f3,f3p,0,1.e-10,1000)
toc()
plot(N,f_x,'b',3)
plt.show()

N = []
f_x = []
tic()
newton(f1,f1p,x01,1.e-10,1000)
toc()
plot(N,f_x,'b',1)

N = []
f_x = []
tic()
newton(f1,f1p,x02,1.e-10,1000)
toc()
plot(N,f_x,'r',1)
plt.legend(['x01 = -2','x02 = +5'])
plt.show()

N = []
f_x = []
tic()
newton(f2,f2p,x01,1.e-10,1000)
toc()
plot(N,f_x,'b',2)

N = []
f_x = []
tic()
newton(f2,f2p,x02,1.e-10,1000)
toc()
plot(N,f_x,'r',2)
plt.legend(['x01 = -2','x02 = +5'])
plt.show()


# 행렬의 곱셈

import numpy as np
def solution(arr1, arr2):
    arr1 = np.array(arr1)
    arr2 = np.array(arr2)
    answer = np.dot(arr1, arr2).tolist()
    return answer

'''
채점을 시작합니다.
정확성  테스트
테스트 1 〉	통과 (0.53ms, 27.3MB)
테스트 2 〉	통과 (1.48ms, 28.2MB)
테스트 3 〉	통과 (2.45ms, 28.8MB)
테스트 4 〉	통과 (0.58ms, 27.8MB)
테스트 5 〉	통과 (1.18ms, 28.3MB)
테스트 6 〉	통과 (0.77ms, 28.5MB)
테스트 7 〉	통과 (0.45ms, 27.5MB)
테스트 8 〉	통과 (0.08ms, 27.8MB)
테스트 9 〉	통과 (0.07ms, 28MB)
테스트 10 〉	통과 (1.98ms, 28.2MB)
테스트 11 〉	통과 (0.22ms, 27.6MB)
테스트 12 〉	통과 (0.09ms, 27.5MB)
테스트 13 〉	통과 (1.39ms, 28.4MB)
테스트 14 〉	통과 (1.68ms, 28.4MB)
테스트 15 〉	통과 (0.68ms, 28MB)
테스트 16 〉	통과 (0.62ms, 28.1MB)
채점 결과
정확성: 100.0
합계: 100.0 / 100.0
'''

def solution(arr1, arr2):
    answer = []
    for i in range(len(arr1)):
        tmp = []
        for j in range(len(arr2[0])):
            tmp_sum = 0
            for k in range(len(arr1[0])):
                tmp_sum += (arr1[i][k] * arr2[k][j])
            tmp.append(tmp_sum)
        answer.append(tmp)
    return answer

'''
채점을 시작합니다.정확성  테스트
테스트 1 〉통과 (3.30ms, 10.3MB)
테스트 2 〉통과 (54.93ms, 10.8MB)
테스트 3 〉통과 (59.77ms, 11.4MB)
테스트 4 〉통과 (1.71ms, 10.3MB)
테스트 5 〉통과 (40.36ms, 11MB)
테스트 6 〉통과 (23.34ms, 11.1MB)
테스트 7 〉통과 (1.65ms, 10.3MB)
테스트 8 〉통과 (0.85ms, 10.3MB)
테스트 9 〉통과 (0.63ms, 10.2MB)
테스트 10 〉통과 (42.27ms, 10.7MB)
테스트 11 〉통과 (4.41ms, 10.3MB)
테스트 12 〉통과 (1.11ms, 10.2MB)
테스트 13 〉통과 (30.27ms, 11MB)
테스트 14 〉통과 (61.05ms, 11.1MB)
테스트 15 〉통과 (19.21ms, 10.6MB)
테스트 16 〉통과 (5.75ms, 10.8MB)
채점 결과정확성: 100.0
합계: 100.0 / 100.0
'''


import numpy as np
import scipy.stats as stats
import math
import matplotlib.pyplot as plt
from math import factorial as f

def find_mean(data_lst):
    '''Write a function that takes a list of numbers as input and returns
    the mean of that input list.

    In: List of integers
    Out: The mean as an integer or float

    Ex: find_mean([1,4,3,6,3,7,6,5,8,12])
    >>> 5.5'''

    # Two ways
    np_mean = np.mean(np.array(data_lst))
    py_mean = sum(data_lst) / len(data_lst)

    return py_mean

def find_median(data_lst):

    '''Write a function that takes a list of numbers as input and returns
    the median of that input list. Account for both even and odd length lists.

    In: List of integers
    Out: The median as an integer or float

    Ex: find_median([1,4,3,6,3,7,6,5,8,12,9])
    >>> 6'''

    # With NumPy
    np_med = np.median(np.array(data_lst))

    # Without NumPy
    sort_lst = sorted(data_lst)
    if len(sort_lst) % 2 == 0:
        mid1 = sort_lst[:len(sort_lst)//2][-1]
        mid2 = sort_lst[len(sort_lst)//2:][0]
        median = (mid1 + mid2) / 2
    else:
        median = sort_lst[len(sort_lst)//2]

    return median

def find_mode(data_lst):

    '''Write a function that takes a list of numbers as input and returns
    the mode of that input list. Assume there is only one mode.

    In: List of integers
    Out: The mode as an integer or float

    Ex: find_mode([1,4,3,6,3,7,5,8,12,11])
    >>> 3'''

    # With ScipyStats
    stats_mode = stats.mode(np.array(data_lst))[0][0]

    # The hard way
    counts_dict = {}
    for each in data_lst:
        if each in counts_dict.keys():
            counts_dict[each] += 1
        else:
            counts_dict[each] = 1

    py_mode = max(counts_dict, key=counts_dict.get)

    return py_mode

def find_variance(data_lst, population=True):

    '''Write a function that takes a list of numbers as input and returns
    the variance of that input list. Notice the population=True argument:
    write your code so that it calculates population variance if that argument
    is True, and sample variance if it is False.

    In: List of integers
    Out: The variance as an integer or float

    Ex: find_variance([1,4,3,6,3,7,5,8,12,11,0,34])
    >>>74.4722222222'''

    # With NumPy (this defaults to population variance)
    np_var = np.var(np.array(data_lst))

    # The hard way
    mn = find_mean(data_lst)

    dist = []
    for each in data_lst:
        dist.append(each - mn)

    squares = []
    for each in dist:
        squares.append(each**2)

    sums = sum(squares)

    if population:
        v = sums / len(data_lst)
    else:
        v = sums / len(data_lst) - 1
    return v

def find_stand_dev(data_lst):

    '''Write a function that takes a list of numbers as input and returns
    the standard deviation of that input list. Use your variance function.

    In: List of integers
    Out: The standard deviation as an integer or float

    Ex: find_stand_dev([1,4,3,6,3,7,5,8,12,11,0,34])
    >>>8.629728977333079'''

    # Two ways
    np_std = np.sqrt(find_variance(data_lst))
    py_std = find_variance(data_lst)**(1/2)

    # Alicia, np and regular are a few digits off from each other
    # in the tens of thousands decimal place, maybe we should add round for
    # any in which the students might use either np or regular?
    return round(py_std, 3)

def bernoulli_pmf(p, n, k):

    '''Given the probability of success, p and the possible outcomes, k
    (1 or 0), and the number of trials, n (1), calculate the PMF, the E(X), and the Var(X) for
    a binomial distribution.

    In: p: probability of success, k: possible outcomes, n: num trials; all ints or floats
    Out: PMF, E(X), Var(X), all integers or floats

    Ex: bernoulli_pmf(0.4, 1, 1)
    >>>0.4, 0.4, 0.24'''

    p_s = p
    p_f = (1-p)
    ex = p
    varx = p_s * p_f

    pmf = (p_s**k) * (p_f**(n-k))

    return pmf, ex, varx

def binomial_pmf(p, n, k):

    '''Given the probability of success, the total number of trials, and
    the number of successful trials, calculate the PMF, E(X) and
    Var(X) for the binomial distribution.

    In: p: probability of success, k: possible outcomes; both ints or floats
    Out: PMF, E(X), Var(X), all ints or floats.

    Ex: binomial_pmf(0.6, 300, 24)
    >>>8.207452839437304e+58, 13.600000000000001, 8.16'''

    combs = (f(n)) / ((f(k))*(f(n-k)))
    bern_pmf = bernoulli_pmf(p, n, k)[0]
    pmf = combs * bern_pmf

    ex = n*p
    var = (n*p)*(1-p)

    return pmf, ex, var

def poisson_pmf(rate, k):

    '''Given the rate, and k, the number of successes, write a function that
    calculates the PMF, E(X) and Var(X) of the Poisson distribution.

    In: The rate, k: number of successes; both ints or floats
    Out: PMF, E(X), Var(X); all ints or floats

    Ex: poisson_pmf(5, 0)
    >>>0.006737946999085469, 5, 5'''

    e = math.e

    numer = (rate**k) * (e**-rate)
    denom = f(k)

    pmf = numer / denom
    ex = rate
    varx = rate

    return pmf, ex, varx

if __name__ == '__main__':

    even_lst = [1,4,3,6,3,7,5,8,12,11,0,34]
    odd_lst = [1,4,3,6,3,7,6,5,8,12,9]

    mn = find_mean(even_lst)
    med = find_median(even_lst)
    mod = find_mode(even_lst)
    var = find_variance(even_lst)
    std = find_stand_dev(even_lst)

    bern_pmf, bern_ex, bern_varx = bernoulli_pmf(0.4, 1, 1)
    binom_pmf, binom_ex, binom_varx = binomial_pmf(0.4, 34, 5)
    poisson_pmf, poisson_ex, poisson_varx = poisson_pmf(5, 0)

#


import numpy as np
from scipy.optimize import fsolve
from scipy.special import lambertw

w = lambertw(1)
print(w)
print(w * np.exp(w))

alpha1 = 5
alpha2 = 4
beta = 0.1
cost1 = 0
cost2 = 0

def func(p):
    return [p[0] - (1 + lambertw(np.exp(alpha1 - 1 - cost1*beta)/(1 + np.exp(alpha2 - beta*p[1])))) / beta + cost1,
            p[1] - (1 + lambertw(np.exp(alpha2 - 1 - cost2*beta)/(1 + np.exp(alpha1 - beta*p[0])))) / beta + cost2]

optimalprices = fsolve(func, [0,0])
print(optimalprices)

p = [0, optimalprices[0], optimalprices[1]]
print(p)

prob = [0,0,0]
prob[0] = np.exp(0) / (np.exp(0) + np.exp(alpha1 - beta*p[1]) + np.exp(alpha2 - beta*p[2]))
prob[1] = np.exp(alpha1 - beta*p[1]) / (np.exp(0) + np.exp(alpha1 - beta*p[1]) + np.exp(alpha2 - beta*p[2]))
prob[2] = np.exp(alpha2 - beta*p[2]) / (np.exp(0) + np.exp(alpha1 - beta*p[1]) + np.exp(alpha2 - beta*p[2]))

print(prob)

print(np.multiply(prob,p))


#***********************************************************************
#           OPERANDO VARIÁVEIS SIMBÓLICAS NO PYTHON
#***********************************************************************
# Editor GNU Nano 2.9.3
# Interpretador Python Ver 3.6.7

#Trata s,t,x,y,z como variáveis simbólicas, ou seja, variáveis
#matemáticas que podem ser operadas
#Se quiser variávei simbólicas com mais de um caractere use, por exemplo:
# R1, C1, Lb = symbols('R1 C1 Lb')
from sympy.abc import s,t,x,y,z

from sympy import *  #Importa a biblioteca sympy

Z1 = t+1/(x*s)      #Expressão 1
Z2 = 1/(y*s+1/z)    #Expressão 2

print(Z1)
print(Z2)

FT = (Z2/Z1)+1          #Opeando as expressões
print(FT)

#Utilizando o comando simplify, note que tanto o numerador quanto o denominador
#não são expandidos.
FT_simp = simplify(FT)
print(FT_simp)

#A função cancel() mostra a expressão na formatação padrão p/q expandindo
#o numerador e o denominador
print(cancel(FT_simp))

#A função expand() expande a expressão fatorada
FT_exp = expand((x+3)*(x-2))
print(FT_exp)

#Cast string para simbólico(sympy)
>>> from sympy.abc import x
>>> a = x
>>> type(a)
<class 'sympy.core.symbol.Symbol'>
>>> from sympy.parsing.sympy_parser import parse_expr
>>> parse_expr('x')
x
>>> type(_)
<class 'sympy.core.symbol.Symbol'>


'''
statstools.py

Statistical tools for analyzing data

author: Bongsoo Suh
created: 2015-03-08

(C) 2015 bongsoos
'''

import numpy as _np
from numpy.linalg import eig as _eig

def corrcoef(x, y):
    '''
    computes correlation coefficient (pearson's r)
    '''

    V = _np.sqrt(_np.array([_np.var(x, ddof=1), _np.var(y, ddof=1)])).reshape(1, -1)
    cc = (_np.matrix(_np.cov(x, y)) / (V*V.T + 1e-12))

    return cc[0,1]

def variance_explained(y, y_est):
    '''
    Computes explained variance
    '''
    SYY = sum((y - _np.mean(y))**2)
    RSS = sum((y - y_est)**2)

    R2 = 1 - RSS/SYY

    return R2

def normalizeX(X, testvec=None, unnormalize=False):
    '''
    Normalize data matrix
    mean subtraction, and variance normalization

    Inputs
    ------
    X (ndarray): mxn data matrix(each column feature, each row is one data point)

    Outputs
    -------
    Bn (ndarray): mxn normalized matrix
    '''
    mu = _np.mean(X, axis=0)
    B = X-_np.outer(_np.ones(X.shape[0]), mu)
    sigma = _np.sqrt(_np.var(B, axis=0))
    Bn = B/_np.outer(_np.ones(B.shape[0]), sigma)

    if testvec is None:
        return Bn
    else:
        if len(testvec.shape) > 1:
            testvec_ = testvec - _np.outer(_np.ones(testvec.shape[0]), mu)
            testvec_ = testvec_/_np.outer(_np.ones(testvec.shape[0]), sigma)
        elif len(testvec.shape) == 1:
            if unnormalize:
                testvec_ = testvec*sigma
                testvec_ = testvec_ + mu
            else:
                testvec_ = testvec - mu
                testvec_ = testvec_/sigma
        return testvec_

def cov(X):
    '''
    Compute covariance matrix
    (mean subtraction, and variance normalization)

    Inputs
    ------
    X (ndarray): mxn data matrix(each column feature, each row is one data point)

    Outputs
    -------
    C (ndarray): nxn covariance matrix
    '''
    Bn = normalizeX(X)

    C = _np.dot(Bn.T, Bn) / (Bn.shape[0]-1)

    return C

def eig(X):
    '''
    Inputs
    ------
    X (ndarray): nxn square matrix
    '''
    eigval, eigvec = _eig(X)
    idx = _np.argsort(eigval)[::-1]
    eigval = eigval[idx]
    eigvec = eigvec[:,idx]

    return eigvec, eigval

def pca(X, testvec=None):
    '''
    Principal Component Analysis
    Inputs
    ------
    X (ndarray): mxn data matrix(each column feature, each row is one data point)

    Outputs
    -------
    eigvec (ndarray): nxn eigenvector matrix, each column is the eigenvector corresponding to the eigen values
    eigval (ndarray): n eigenvalues, from highest to lowest
    proj (ndarray): mxn projection matrix, each column is the projection of the data points to the corresponding eigenvectors
    '''
    Bn = normalizeX(X)
    C = _np.dot(Bn.T, Bn) / (Bn.shape[0]-1)
    eigvec, eigval = eig(C)

    if testvec is None:
        proj = _np.dot(Bn, eigvec)
    else:
        testvec_ = normalizeX(X, testvec)
        proj = _np.dot(testvec_, eigvec)

    return eigvec, eigval, proj


import scipy as sp
import scipy.linalg as la
import numpy.linalg as npla

#Problem 1
A = sp.array([[.75,.50],[.25,.50]])
npla.matrix_power(A,2)[0,0]#Part a: 0.6875
npla.matrix_power(A,100)[0,0]#Part b: 66.7%

#Problem 2
A = sp.array([[1./4,1./3,1./2],[1./4,1./3,1./3],[1./2,1./3,1./6]]);A #Part a
npla.matrix_power(A,2)[1,0]#Part b: 0.3125
V = la.eig(A)[1]
x = V[:,0]
la.eig(A)[1]
x = x/sp.sum(x);x #Part c: array([ 0.35955056,  0.30337079,  0.33707865])

#Problem 3
bucky = sp.loadtxt ( "bucky.csv" , delimiter = "," )

sp.count_nonzero(bucky)
sp.count_nonzero(npla.matrix_power(bucky,2))
sp.count_nonzero(npla.matrix_power(bucky,3))

sp.count_nonzero(npla.matrix_power(bucky,9)) #3600, all atoms are connected, so path length 9


import numpy as np

def torus(theta, phi, R, r):
    '''

    '''

    if R<=r:
        print "ERROR: R must be larger than r"
        pass

    else:
        x = (R + r*np.cos(theta))*np.cos(phi)
        y = (R + r*np.cos(theta))*np.sin(phi)
        z = r*np.sin(phi)
        return (x,y,z)

def inside_torus(point, R=3, r=2):

    # distance to z-axis
    u = np.sqrt(point[0]**2 + point[1]**2)

    if u < 1.0E-07:
        # point is along z-axis
        return 0

    else:
        # project point to point-z plane: (u,v)
        v = point[2]

        # translate u by R
        u = u - R

        # Check if (u,v) inside circle of radius r
        if u**2 + v**2 > r**2:
            return 0
        else:
            return 1

# ### Umbilic torus

# In[12]:

def umbilic_torus(u,v):

    x = np.sin(u)*(
    7 + np.cos((u/3.0)-2.0*v) + 2.0*np.cos((u/3.0)+v)
    )

    y = np.cos(u)*(
    7 + np.cos((u/3.0)-2.0*v) + 2.0*np.cos((u/3.0)+v)
    )

    z = np.sin((u/3.0)-2.0*v) + 2.0*np.cos((u/3.0)+v)

    return (x,y,z)


__author__ = 'Prateek'
from sympy import isprime

def quadraticResidues(n):
    residues = set()
    for i in range(1, n / 2 + 1):
        residues.add(i ** 2 % n)
    return residues

# if __author__ == 'Prateek':
#    n=11
#    if isprime(n):
#        print quadraticResidues(n)
#    else:
#        print "N is not prime"


import numpy as np

class GradientDescent:
    """
    *****************************************************
     Batch Gradient Descent Implementation In Python 2.7
    *****************************************************

    Dependency: numpy

    GradientDescent Class
    =====================================
    get_beta()                                  // receive the betas
    get_mse()                                   // receive the mean squared error
    summary()                                   // print out the gradient search iteration summary
    run(max_iter = 2000, alpha = 1e-4)          // run gradient descent iterations and returns the betas and mse
    __gradient_step(alpha, step)                // internal function to make a gradient step

    Author: Joon Lim <powerlim2@gmail.com>

    """
    def __init__(self, x, y):
        if not any(isinstance(i, list) for i in x):
            assert len(x) == len(y)

            self.x = np.array([np.ones(len(x)), x]).transpose()
        else:
            assert len(x[0]) == len(y)

            temp = [np.ones(len(x[0]))]
            temp.extend(x)
            self.x = np.array(temp).transpose()
        self.y = np.array(y)
        self.__mse = None
        self.__beta = np.ones(self.x.shape[1])  # initial guess of beta set to 1
        self.__summary = "Gradient Search Iteration Summary\n\n"

    def summary(self):
        print self.__summary

    def run(self, max_iter = 2000, alpha = 1e-4):
        """
        if MSE converges during the iteration, finish the iteration and return the beta and MSE.
        """
        converge = False
        previous_mse = 99999
        step = 0
        while (not converge and step < max_iter):
            mse = self.__gradient_step(alpha, step)
            if abs(previous_mse - mse) * 2 < 1e-3:
                converge = True
            previous_mse = mse
            step += 1

        return self.__beta, self.__mse * 2

    def __gradient_step(self, alpha, step):
        """
        batch gradient descent iteration step
        """
        y_hat = self.x.dot(self.__beta)
        error = y_hat - self.y
        self.__mse = 1. / (2 * len(y_hat)) * np.sum(error ** 2)
        gradient = 1. / len(y_hat) * self.x.transpose().dot(error)
        self.__beta -= alpha * gradient
        self.__summary += "Iter: {}, mse: {}, beta: {}\n".format(step, self.__mse * 2, self.__beta)

        return self.__mse

    def get_beta(self):
        if self.__mse is not None:
            return self.__beta
        return

    def get_mse(self):
        if self.__mse is not None:
            return self.__mse * 2
        return

def main():
    speed = [4,	4,	7,	7,	8,	9,	10,	10,	10,	11,	11,	12,	12,	12,	12,	13,	13,	13,	13,	14,	14,	14,	14,
    15,	15,	15,	16,	16,	17,	17,	17,	18,	18, 18,	18,	19,	19,	19,	20, 20,	20,	20,	20,	22,	23,	24,	24,	24,	24,	25]
    break_distance = [2, 10, 4,	22,	16,	10,	18,	26,	34,	17,	28,	14,	20,	24,	28,	26,	34,	34,	46,	26,	36,	60,	80,
    20,	26,	54,	32,	40,	32,	40, 50,	42,	56,	76,	84, 36,	46,	68,	32,	48, 52,	56,	64,	66,	54,	70, 92,	93,	120, 85]

    SLR = GradientDescent(speed, break_distance)
    beta, mse = SLR.run(max_iter = 2000, alpha = 1e-4)

    SLR.summary()
    print "\n"
    print "break_distance = {} + {} * speed".format(beta[0], beta[1])

if __name__ == "__main__":
    main()


import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from multi_var_gradient_decent import LinearRegressionUsingGD
from mpl_toolkits.mplot3d import axes3d
from sklearn.metrics import mean_squared_error, r2_score

def create_mesh_grid(start, end):
    theta_1 = np.linspace(start, end, 30)
    theta_2 = np.linspace(start, end, 30)
    theta_1, theta_2 = np.meshgrid(theta_1, theta_2)
    return theta_1, theta_2

def plot_result(x, y, y_pred):
    fig = plt.figure()
    plt.scatter(x, y)
    plt.scatter(x, y_pred, color='red')
    plt.xlabel('\u03B80')
    plt.ylabel('\u03B81')
    plt.show()

def plot_cost_function_2d(theta_1, theta_2, cost):
    fig, ax = plt.subplots(1, 1)
    ax.contourf(theta_1,
                theta_2,
                cost,
                levels=[0, 1, 2, 4, 6, 8, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
                cmap=cm.coolwarm,
                antialiased=True)

    plt.xlabel('\u03B81')
    plt.ylabel('\u03B82')
    plt.show()

def get_cost_function(theta_1, theta_2, x1, y, points_n):
    m = theta_1.shape[0]
    cost = np.zeros([theta_1.shape[0], theta_1.shape[1]])
    for i in range(points_n):
        residuals = ((theta_1 * x1[i] + theta_2) - y[i]) ** 2
        cost += residuals
    cost = cost / (2 * m)
    return cost

def plot_cost_function(x, y, points_n):
    theta_1, theta_2, = create_mesh_grid(0, 30)
    cost = get_cost_function(theta_1, theta_2, x, y, points_n)
    plot_cost_function_2d(theta_1, theta_2, cost)

def plot_raw_data(x, y):
    fig = plt.figure()
    plt.scatter(x,y)
    plt.xlabel('\u03B80')
    plt.ylabel('\u03B81')
    plt.show()

def create_data(points_n):
    np.random.seed(0)
    x = np.random.rand(points_n, 2)
    x1 = x[:, 0].reshape(points_n, 1)
    x2 = x[:, 0].reshape(points_n, 1) ** (8)

    x[:, 0] = x1.reshape(points_n,)
    x[:, 1] = x2.reshape(points_n,)

    x1 = x1 / x1.max()
    x2 = x2 / x2.max()

    y = 2 + 3 * x1 + np.random.rand(points_n, 1) + 32 * x2 + np.random.rand(points_n, 1)

    return x, x1, x2, y

def main():
    points_n = 100
    x, x1, x2, y = create_data(points_n)

    plot_raw_data(x1, y)
    plot_cost_function(x1, y, points_n)
    plot_cost_function(x2, y, points_n)

    # Model initialization
    regression_model = LinearRegressionUsingGD(lr=0.05, n_iterations=10000)
    # Fit the data(train the model)
    regression_model.fit(x, y)
    # Predict
    y_predicted = regression_model.predict(x)

    # model evaluation
    rmse = mean_squared_error(y, y_predicted)
    r2 = r2_score(y, y_predicted)

    # For sci-kit learn implementation:
    print('Weights:', regression_model.w)
    print('Root mean squared error: ', rmse)
    print('R2 score: ', r2)

    # plot
    plot_result(x1, y, y_predicted)

if __name__ == '__main__':
    main()


import pandas as pd
import numpy as np

class linear_regression_model:
    def __init__(self,help=False,math_breakdown=False) -> None:
        self.help=help
        self.math_breakdown=math_breakdown
        self.general_info=f"""
        Linear regression is a regression technique that assumes that the data is linearly related to eachother.
        A few key terms that we will need to know are Mean, Variance, Covariance.

        Mean: Calculated as sum(inputs)/len(inputs). This gives us a single value that is the average of all data points.
        Variance: Calculated as sum((x-mean(x)**2)). Sum of squared difference from value and mean.
        Covariance: Calculated as sum((x(i) - mean(x)) * (y(i) - mean(y)). Describes how numbers change relationally to one another.

        Our goal with a simple linear regression is estimatinmg two coefficients: B0 and B1.

        """
        if self.help:
            print(self.general_info)
        self.steps=""
        self.trained=False

    def mean(self,values):
        means=np.mean(values)
        if self.math_breakdown:
            self.steps+=f"\nWe will find the mean of our input data (first few items:{values [:3]}) which gives us {means}"
        return means

    def variance(self,values,mean):
        var=sum([(x-mean)**2 for x in values])
        if self.math_breakdown:
            self.steps+=f"\nWe will find the variance of our input data (first few items: {values[:3]}) which gives us {var}"
        return var

    def covariance(self,x,mean_x,y,mean_y):
        covar=0.0
        self.steps+='\n\ncovariance steps:'
        self.itterative_covar=[] #store co variances for later graphing
        for i in range(len(x)):
            covar+=(x[i]-mean_x)*(y[i]-mean_y)
            self.itterative_covar.append(covar)
            if self.math_breakdown:
                self.steps+=f"\n    covariance now equals: {covar}"
        return covar

    def simple_dataset(self):
        self.dataset=[[1,1],[2,3],[4,3],[3,2],[5,5]]
        self.x=[row[0] for row in self.dataset]
        self.y=[row[1] for row in self.dataset]

    def train(self,dataset=None):
        if dataset is None:
            self.simple_dataset()
        else:
            self.dataset=dataset
        if isinstance(dataset, list):
            x=[row[0]for row in self.dataset]
            y=[row[1]for row in self.dataset]
        else:
            raise TypeError("Be sure you pass in a list of lists of data.")
        x_mean=self.mean(x)
        y_mean=self.mean(y)
        self.b1=self.covariance(x,x_mean,y,y_mean)/self.variance(x,x_mean)
        self.b0=y_mean-self.b1*x_mean
        if self.math_breakdown:
            self.steps+=f"\ntaking the covariance of X, X mean, Y, and Y mean divided by the variance of x and x mean to get our b1 score:{self.b1}"
            self.steps+=f"\nTaking the y_mean - b1 score and multiplying by x_mean to get b0 score:{self.b0}"
        self.trained=True
        return [self.b0,self.b1]
    def predict(self,samples):
        if self.trained==False:
            # with
            raise ValueError("Be sure to train your model before predicting.")
        preds=[self.b0 + self.b1 * i[0] for i in samples]
        return preds

if __name__=="__main__":
    c=linear_regression(help=True,math_breakdown=True)
    c.simple_dataset()
    c.train()
    print(c.predict([[1,3]]))
    print(c.steps)


import numpy as np

def newton(f,fprime,x0,epsilon=1.0e-6, LOUD=False):
    """Find the root of the function f via Newton-Raphson method
    Args:
        f: function to find root of
        fprime: derivative of f
        x0: initial guess
        epsilon: tolerance

    Returns:
        estimate of root
    """
    x = x0
    if (LOUD):
        print("x0 =",x0)
    iterations = 0
    while (np.fabs(f(x)) > epsilon):

        if (LOUD):
            print("x_",iterations+1,"=",x,"-",f(x),"/",fprime(x),"=",x - f(x)/fprime(x))
        x = x - f(x)/fprime(x)
        iterations += 1
    print("It took",iterations,"iterations")
    return x #return estimate of root

def inexact_newton(f,x0,delta = 1.0e-7, epsilon=1.0e-6, LOUD=False):
    """Find the root of the function f via Newton-Raphson method
    Args:
        f: function to find root of
        x0: initial guess
        delta: finite difference parameter
        epsilon: tolerance

    Returns:
        estimate of root
    """
    x = x0
    if (LOUD):
        print("x0 =",x0)
    iterations = 0
    while (np.fabs(f(x)) > epsilon):
        fx = f(x)
        fxdelta = f(x+delta)
        slope = (fxdelta - fx)/delta
        if (LOUD):
            print("x_",iterations+1,"=",x,"-",fx,"/",slope,"=",x - fx/slope)
        x = x - fx/slope
        iterations += 1
    print("It took",iterations,"iterations")
    return x #return estimate of root

def secant(f,x0,delta = 1.0e-7, epsilon=1.0e-6, LOUD=False):
    """Find the root of the function f via Newton-Raphson method
    Args:
        f: function to find root of
        x0: initial guess
        delta: finite difference parameter
        epsilon: tolerance

    Returns:
        estimate of root
    """
    x = x0
    if (LOUD):
        print("x0 =",x0)
    #first time use inexact Newton
    x_old = x
    fold = f(x_old)
    fx = fold
    slope = (f(x_old+delta) - fold)/delta
    x = x - fold/slope
    if (LOUD):
        print("Inexact Newton\nx_",1,"=",x,"-",fx,"/",slope,"=",x - fx/slope,"\nStarting Secant")
    fx = f(x)
    iterations = 1
    while (np.fabs(fx) > epsilon):
        slope = (fx - fold)/(x - x_old)
        fold = fx
        x_old = x
        if (LOUD):
            print("x_",iterations+1,"=",x,"-",fx,"/",slope,"=",x - fx/slope)
        x = x - fx/slope
        fx = f(x)
        iterations += 1
    print("It took",iterations,"iterations")
    return x #return estimate of root

def newton_system(f,x0,delta = 1.0e-7, epsilon=1.0e-6, LOUD=False):
    """Find the root of the function f via inexact Newton-Raphson method
    Args:
        f: function to find root of
        x0: initial guess
        delta: finite difference parameter
        epsilon: tolerance

    Returns:
        estimate of root
    """
    def Jacobian(f,x,delta = 1.0e-7):
        N = x0.size
        J = np.zeros((N,N))
        idelta = 1.0/delta #division is slower than multiplication
        x_perturbed = x.copy() #copy x to add delta
        fx = f(x) #only need to evaluate this once
        for i in range(N):
            x_perturbed[i] += delta
            col = (f(x_perturbed) - fx) * idelta
            x_perturbed[i] = x[i]
            J[:,i] = col
        return J

    x = x0
    if (LOUD):
        print("x0 =",x0)
    iterations = 0
    fx = f(x)
    while (np.linalg.norm(fx) > epsilon):
        J = Jacobian(f,x,delta)

        RHS = -fx;
        delta_x = GaussElimPivotSolve(J,RHS)
        x = x + delta_x
        fx = f(x)
        if (LOUD):
            print("Iteration",iterations+1,": x =",x," norm(f(x)) =",np.linalg.norm(fx))
        iterations += 1
    print("It took",iterations,"iterations")
    return x #return estimate of root