import numpy as np
import sys

matrix = None
def main():
    global matrix
    matrix = np.array([[1,1,-1],[6,2,2],[-3,4,1]],dtype=float)
    aug_matrix = np.concatenate((matrix,identity_matrix(3)),axis=1)
    #gaussian2(aug_matrix) #gaussian elimination with maximum pivoting
    LUdecomp(matrix) #LU decompose a square matrix

def identity_matrix(n):
    m = np.empty([n,n],dtype=float)
    for i in range (0,n):
        for j in range (0,n):
            if(i==j): m[i][j] = 1
            else: m[i][j] = 0

    return m

def gaussian2(m):
    print()
    print("Gaussian Elimination 2.0:")
    print()

    for j in range (0,m.shape[0]):
        max_pivot_row = j
        max_pivot = m[j][j]
        for a in range (1, m.shape[0]-j):
            if(m[j+a][j]>max_pivot):
                max_pivot_row = j+a
                print("maximum pivoting: R",(j+1),"<->","R",(max_pivot_row+1))
                print()

        m[[j,max_pivot_row]] = m[[max_pivot_row,j]]

        if(m[j][j]==0):
            print("no unique solution")
            break

        for i in range (j+1, m.shape[0]):
            c = (m[i][j])/(m[j][j])
            if(c==0):
                print("c==0!!")
                continue
            for a in range (0, m[j].shape[0]):
                m[i][a]=m[i][a]-c*(m[j][a])

            print("row operation: R",(i+1),"-",c,"*R",(j+1))
            print(m)
            print()

def LUdecomp(m):
    L = identity_matrix(m.shape[0])

    for j in range (0, m.shape[0]):
        for i in range (j+1, m.shape[0]):
            c = (m[i][j])/(m[j][j])
            if(c==0):
                continue
            for a in range (0, m[j].shape[0]):
                m[i][a]=m[i][a]-c*(m[j][a])
            L[i][j] = c

            print("row operation: R",(i+1),"-",c,"*R",(j+1))
            print(m)
            print()

    print("matrix L is:")
    print(L)
    print("matrix U is:")
    print(m)

main()


from numpy import *
from newton import *
from quasi_newton import *
from steepest_descent import *
from conjugate_gradient import *

if __name__ == '__main__':
  def f(x): return 100 * math.pow(x[1] - math.pow(x[0], 2), 2) + math.pow(1 - x[0], 2)
  def df_dx1(x): return 400*math.pow(x[0], 3) - 400*x[0]*x[1] + 2*x[0] - 2
  def df_dx2(x): return 200*x[1] - 200*math.pow(x[0], 2)
  def fd(x): return array([ df_dx1(x), df_dx2(x) ])

  def df_dx1_dx1(x): return 1200*math.pow(x[0], 2) - 400*x[1] + 2
  def df_dx1_dx2(x): return-400*x[0]

  def fdd(x):
    return array([
        [df_dx1_dx1(x), df_dx1_dx2(x)],
        [df_dx1_dx2(x), 200]])

  def print_error(i, direction, alpha, x):
    opt = f(array([1,1]))
    print("%d, %.20f" % (i, f(x)-opt))

  def print_gradient(i, direction, alpha, x):
    print("%d, %.20f" % (i, linalg.norm(fd(x))))

  def print_all(i, direction, alpha, x):
    print("iteration %d: \t direction: %s \t alpha: %.7f \t x: %s"
        % (i, ["%.7f" % _ for _ in direction], alpha, ["%.7f" % _ for _ in x]))

  x = array([0, 0])
  precision = 10e-6
  max_iterations = 100
  callback = print_all

  print("steepest descent:")
  steepest_descent(f, fd, x, max_iterations, precision, callback)

  print("\nnewton:")
  newton(f, fd, fdd, x, max_iterations, precision, callback)

  print("\nquasi newton:")
  quasi_newton(f, fd, x, max_iterations, precision, callback)

  print("\nconjugate gradient:")
  conjugate_gradient(f, fd, x, max_iterations, precision, callback)

Computational Mathematics | Python/Rosenbrock.py


"""
Given an array of positive integers arr, calculate the sum of all possible odd-length subarrays.
A subarray is a contiguous subsequence of the array.
Return the sum of all odd-length subarrays of arr.

Constraints:
    * 1 <= arr.length <= 100
    * 1 <= arr[i] <= 1000
"""
from typing import List
import numpy as np

class Solution:
    def sumOddLengthSubarrays(self, arr: List[int]) -> int:
        result = 0
        arr_np = np.array(arr)
        for k in range(1, len(arr), 2):
            for i in range(len(arr) - k + 1):
                result += sum(arr_np[i : (i+k)])
        if len(arr_np) % 2 == 1:
            result += sum(arr_np)
        return result

if __name__ == "__main__":
    arr = [1,4,2,5,3]
    out = 58
    res = Solution().sumOddLengthSubarrays(arr)
    assert res == out, (res, out)

    arr = [1,2]
    out = 3
    res = Solution().sumOddLengthSubarrays(arr)
    assert res == out, (res, out)

    arr = [10,11,12]
    out = 66
    res = Solution().sumOddLengthSubarrays(arr)
    assert res == out, (res, out)


#!/usr/bin/python3
# -*- coding: utf-8 -*-

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

def testGeom():# {{{
    """
    Geometric Distribution (discrete)

    Notes
    -----
        伯努利事件进行k次, 第一次成功的概率

    为什么是几何分布呢, 为什么不叫几毛分布?
    与几何数列有关 (乘积倍数)

    p: 成功的概率
    q: 失败的概率(1-p)
    k: 第一次成功时的经历的次数 (前k-1次是失败的)
        geom.pmf(k, p), (1-p)**(k-1)*p)
    """

    # 准备数据: 已知 p.
    # X轴: 第k次才成功
    # Y轴: 概率
    p = 0.4
    xs = np.arange(geom.ppf(0.01, p), geom.ppf(0.99, p), step = 1)

    # E(X) = 1/p, D(X) = (1-p)/p**2
    mean, var, skew, kurt = geom.stats(p, moments='mvsk')
    print("mean: %.2f, var: %.2f, skew: %.2f, kurt: %.2f" % (mean, var, skew, kurt))

    fig, axs = plt.subplots(2, 2)

    # 显示pmf1
    ys = geom.pmf(xs, p)
    axs[0][0].plot(xs, ys, 'bo', markersize=5, label='geom pmf')
    axs[0][0].vlines(xs, 0, ys, colors='b', linewidth=5, alpha=0.5, label='vline pmf')
    axs[0][0].legend(loc='best', frameon=False)

    # 显示pmf2
    ys = (1-p)**(xs-1)*p
    axs[0][1].plot(xs, ys, 'bo', markersize=5, label='geom pmf')
    axs[0][1].vlines(xs, 0, ys, colors='b', linewidth=5, alpha=0.5, label='vline pmf')
    axs[0][1].legend(loc='best', frameon=False)
    axs[0][1].set_title('ys = (1-p)**(xs-1)*p')

    # 显示cdf P(X<=x)
    ys = geom.cdf(xs, p)
    axs[1][0].plot(xs, ys, 'bo', markersize=5, label='geom cdf')
    axs[1][0].legend(loc='best', frameon=False)
    print(np.allclose(xs, geom.ppf(ys, p))) # ppf:y-->x cdf:x-->y

    # 生成随机数据(random variables)
    data = geom.rvs(p, size=1000)
    import sys
    sys.path.append("../../thinkstats")
    import Pmf
    pmf = Pmf.MakePmfFromList(data)
    xs, ys = pmf.Render()
    axs[1][1].plot(xs, ys, 'bo', markersize=5, label='rvs-pmf')

    plt.show()

# }}}

if __name__ == "__main__":
   testGeom()


import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score

X = np.array([258.0, 270.0, 294.0,
              320.0, 342.0, 368.0,
              396.0, 446.0, 480.0, 586.0])\
             [:, np.newaxis]

y = np.array([236.4, 234.4, 252.8,
              298.6, 314.2, 342.2,
              360.8, 368.0, 391.2,
              390.8])

lr = LinearRegression()
pr = LinearRegression()
quadratic = PolynomialFeatures(degree=2)
X_quad = quadratic.fit_transform(X)

# fit linear features
lr.fit(X, y)
X_fit = np.arange(250, 600, 10)[:, np.newaxis]
y_lin_fit = lr.predict(X_fit)

# fit quadratic features
pr.fit(X_quad, y)
y_quad_fit = pr.predict(quadratic.fit_transform(X_fit))

# plot results
plt.scatter(X, y, label='Training points')
plt.plot(X_fit, y_lin_fit, label='Linear fit', linestyle='--')
plt.plot(X_fit, y_quad_fit, label='Quadratic fit')
plt.xlabel('Explanatory variable')
plt.ylabel('Predicted or known target values')
plt.legend(loc='upper left')

plt.tight_layout()
plt.show()

y_lin_pred = lr.predict(X)
y_quad_pred = pr.predict(X_quad)

print('Training MSE linear: %.3f, quadratic: %.3f' % (
        mean_squared_error(y, y_lin_pred),
        mean_squared_error(y, y_quad_pred)))
print('Training R^2 linear: %.3f, quadratic: %.3f' % (
        r2_score(y, y_lin_pred),
        r2_score(y, y_quad_pred)))

Chapter 10/Turning a linear regression model into a curve - polynomial regression/program1.py


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

df = pd.read_csv("china_gdp.csv")
df.head(10)

plt.figure(figsize=(8,5))
x_data, y_data = (df["Year"].values, df["Value"].values)
plt.plot(x_data, y_data, 'ro')
plt.ylabel('GDP')
plt.xlabel('Year')
plt.show()

X = np.arange(-5.0, 5.0, 0.1)
Y = 1.0 / (1.0 + np.exp(-X))

plt.plot(X,Y)
plt.ylabel('Dependent Variable')
plt.xlabel('Indepdendent Variable')
plt.show()

def sigmoid(x, Beta_1, Beta_2):
    y = 1 / (1 + np.exp(-Beta_1 * (x - Beta_2)))
    return y

beta_1 = 0.10
beta_2 = 1990.0

#logistic function
Y_pred = sigmoid(x_data, beta_1 , beta_2)

#plot initial prediction against datapoints
plt.plot(x_data, Y_pred*15000000000000.)
plt.plot(x_data, y_data, 'ro')

# Lets normalize our data
xdata =x_data/max(x_data)
ydata =y_data/max(y_data)

from scipy.optimize import curve_fit
popt, pcov = curve_fit(sigmoid, xdata, ydata)
#print the final parameters
print(" beta_1 = %f, beta_2 = %f" % (popt[0], popt[1]))

x = np.linspace(1960, 2015, 55)
x = x/max(x)
plt.figure(figsize=(8,5))
y = sigmoid(x, *popt)
plt.plot(xdata, ydata, 'ro', label='data')
plt.plot(x,y, linewidth=3.0, label='fit')
plt.legend(loc='best')
plt.ylabel('GDP')
plt.xlabel('Year')
plt.show()

# PRACTICE: Accuracy Test

# split data into train/test
msk = np.random.rand(len(df)) < 0.8
train_x = xdata[msk]
test_x = xdata[~msk]
train_y = ydata[msk]
test_y = ydata[~msk]

# build the model using train set
popt, pcov = curve_fit(sigmoid, train_x, train_y)

# predict using test set
y_hat = sigmoid(test_x, *popt)
print(y_hat)

# evaluation
print("Mean absolute error: %.2f" % np.mean(np.absolute(y_hat - test_y)))
print("Residual sum of squares (MSE): %.2f" % np.mean((y_hat - test_y) ** 2))
from sklearn.metrics import r2_score
print("R2-score: %.2f" % r2_score(y_hat , test_y) )


import numpy as np

def nb_path_maze(maze):
	"""
	Given a maze with 0 as paths and 1 as walls, beginning at top left,
	with only possibilities to go down or right. Return the number of possible paths.

	O(n) time and space
	"""
	I,J = maze.shape
	sheet = np.zeros((I,J))

	sheet[0,0] = 1

	for i in range(I):
		for j in range(J):
			if maze[i,j] == 0 and (i,j) != (0,0) :
				sheet[i,j] = sheet[max(0,i-1),j] + sheet[i,max(0,j-1)]

	return sheet[i,j]

maze = np.array(
	[[0,1,0],
	 [0,0,1],
	 [0,0,0]]
	)
print(maze)
print(f"{nb_path_maze(maze)}, expected 2")

maze = np.array(
	[[0,1,0,0],
	 [0,0,0,0],
	 [1,0,1,0],
	 [0,0,0,0]]
	)
print(maze)
print(f"{nb_path_maze(maze)}, expected 2")

maze = np.array(
	[[0,0,1,0],
	 [0,0,0,0],
	 [1,0,1,0],
	 [0,0,0,0]]
	)
print(maze)
print(f"{nb_path_maze(maze)}, expected 4")

maze = np.array(
	[[0,0,0,0],
	 [0,0,1,0],
	 [0,1,0,0],
	 [0,0,0,0]]
	)
print(maze)
print(f"{nb_path_maze(maze)}, expected 2")


import numpy as np

def euclidean(u, v):
    """
    Calculates the euclidean distance between vectors u an v

    precondition:
        u.shape == v.shape

    :param u: vector of numbers
    :param v: vector of numbers
    :return: euclidean distance between u and v
    """

    if u.shape != v.shape:
        raise ValueError("The size of u and v differs")

    return np.sqrt(np.power(u - v, 2).sum())

def manhattan(u, v):
    """
    Calculates the manhattan distance (also known as taxicab geometry) between
    vectors u an v.

    precondition:
        u.shape == v.shape

    :param u: vector of numbers
    :param v: vector of numbers
    :return: manhattan distance between u and v
    """

    if u.shape != v.shape:
        raise ValueError("The size of u and v differs")

    return np.abs(u - v).sum()

def cosine(u, v):
    """
    Calculates the cosine distance (1 - cosine similarity) between two vectors

    precondition:
        u.shape == v.shape

    :param u: vector of numbers
    :param v: vector of numbers
    :return: cosine distance between u and v
    """

    if u.shape != v.shape:
        raise ValueError("The size of u and v differs")

    return 1 - u.dot(v) / np.sqrt(u.dot(u)*v.dot(v))


import numpy as np
import time

def monte_carlo(func, low, high, scale_coefficient=None, random_generator=None, sample_numbers=None, density_func=None):
    start_time = time.time()
    integral_func = func
    if density_func is not None:
        integral_func = lambda x: func(x) / density_func(x)

    if sample_numbers is None:
        sample_numbers = int(np.abs((high - low) * 1000))

    if random_generator is None:
        random_generator = lambda n: (high - low) * np.random.rand(n) + low

    if scale_coefficient is None:
        scale_coefficient = high - low

    random_x = random_generator(sample_numbers)
    func_values = integral_func(random_x)
    integral_value = scale_coefficient * np.mean(func_values)
    value_error = scale_coefficient * np.std(func_values) / np.sqrt(sample_numbers)

    end_time = time.time()

    return integral_value, value_error, (end_time - start_time)

if __name__ == "__main__":
    func = lambda x: np.exp(-(x ** 2))
    low = 0
    high = 2
    sample_numbers = 10 ** np.arange(3, 9)

    for sample in sample_numbers:
        simple_sampling_value, simple_sampling_error, simple_sampling_runtime = monte_carlo(
            func, low, high, sample_numbers=sample)

        random_generator_1 = lambda n: -np.log(np.exp(-low) - (np.exp(-low) - np.exp(-high)) * np.random.rand(n))
        density_func_1 = lambda x: np.exp(-x)
        scale_coefficient_1 = np.exp(-low) - np.exp(-high)
        important_sampling_value_1, important_sampling_error_1, important_sampling_runtime_1 = monte_carlo(
            func, low, high, scale_coefficient_1, random_generator_1, sample, density_func_1)

        random_generator_2 = lambda n: np.tan((np.arctan(high) - np.arctan(low)) * np.random.rand(n))
        density_func_2 = lambda x: 1 / (x ** 2 + 1)
        scale_coefficient_2 = np.arctan(high) - np.arctan(low)
        important_sampling_value_2, important_sampling_error_2, important_sampling_runtime_2 = monte_carlo(
            func, low, high, scale_coefficient_2, random_generator_2, sample, density_func_2)

        print(f'Sample Numbers: {sample}:')

        print(f'Simple Sampling:\n'
              f'\tvalue: {simple_sampling_value}\n'
              f'\terror: {simple_sampling_error}\n'
              f'\ttime: {simple_sampling_runtime}')

        print(f'Important Sampling: g(x) = e^(-x)\n'
              f'\tvalue: {important_sampling_value_1}\n'
              f'\terror: {important_sampling_error_1}\n'
              f'\ttime: {important_sampling_runtime_1}')

        print(f'Important Sampling: g(x) = 1 / (x^2 + 1)\n'
              f'\tvalue: {important_sampling_value_2}\n'
              f'\terror: {important_sampling_error_2}\n'
              f'\ttime: {important_sampling_runtime_2}')

        print(end='\n')


import numpy as np
from math import *
import matplotlib.pyplot as plt

''' The problem is: dy/dt = f(t,y).'''

def f(t, y):
    return 0.5*y

# We will use RK4 to compute some intiall values needed to Adams-Bashforth Method
## a,b: edges of the interval, w0:ititial value, h:step
def RungeKutta4(a, b, w0, h):
    n = ceil((b-a) / h)

    w, t = np.zeros(n+1), np.zeros(n+1)
    w[0], t[0] = w0, a

    for i in range(n):
        k1 = h*f(t[i], w[i])
        k2 = h*f(t[i] + h/2, w[i] + k1/2)
        k3 = h*f(t[i] + h/2, w[i] + k2/2)
        k4 = h*f(t[i] + h, w[i] + k3)
        w[i+1] = w[i] + 1/6*(k1 + 2*k2 + 2*k3 + k4)
        t[i+1] = t[i] + h

    return w, t

# a,b: edges of the interval, w0,w1,w2,w3:ititial value, h:step
def AdamsBashforth(a, b, w0, w1, w2, w3, h):
    n = ceil((b-a) / h)

    w, t = np.zeros(n+1), np.zeros(n+1)
    t[0], t[1], t[2], t[3] = a, a+h, a+2*h, a+3*h
    w[0], w[1], w[2], w[3] = w0, w1, w2, w3

    for i in range(3, n):
        w[i+1] = w[i] + h/24*(55*f(t[i],w[i]) - 59*f(t[i-1],w[i-1]) + 37*f(t[i-2],w[i-2]) - 9*f(t[i-3],w[i-3]))
        t[i+1] = t[i] + h

    return w, t

if __name__ == '__main__':

    a, b, w0, h = 0, 2, 1, 0.2
    w = RungeKutta4(a, b, w0, h)[0]
    print("\n", AdamsBashforth(a, b, w0, w[1], w[2], w[3], h)[0])

    # Visualization
    x = np.linspace(0, 2, 100)

    y = np.zeros(len(x))

    for j in range(len(x)):
        y[j] = exp(0.5*x[j])

    plt.plot(x, y, color="black", label="Solution")
    plt.plot(AdamsBashforth(a, b, w0, w[1], w[2], w[3], h)[1], AdamsBashforth(a, b, w0, w[1], w[2], w[3], h)[0], label="Adams-Bashforth")
    plt.xlabel("t")
    plt.ylabel("y")
    plt.legend()
    plt.show()


import numpy as np

def sigmoid(z):
    """
    Return:
    s -- sigmoid(z)
    """

    s = 1./(1+np.exp(-z))

    return s

def RELU(z):
    """
    Return:
    s -- RELU(z)
    """
    s = np.maximum(z,0)
    return s
def Parametric_RELU(z, a):
    """
    z -- vector
    a -- parameter int
    Return:
    s -- Parametric_RELU(z)
    """
    s = np.maximum(z, z*a )
    return s

def Leaky_RELU(z):
    """
    Return:
    s -- RELU(z)
    """
    # s = np.where( z>0 , z, 0.01*z)
    s = np.maximum(z, z*0.01 )
    return s

def Tanh(z):
    """
    Return:
    s -- tanh(z)
    """
    s = (np.exp(z) - np.exp(-z))/(np.exp(z) + np.exp(-z))

    return s

def Silu(z):
    """
    Return:
    s -- sigmoid(z)*z
    """
    s = z*sigmoid(z)

    return s


import math
import unittest

import numpy as np
import numpy.testing as npt

from . import vector_utils as vu

class TestVectorUtils(unittest.TestCase):
    tol = 0.0001

    def test_normalize(self):
        vector = np.asarray([1, 1, 1, 1], dtype=np.float32)
        npt.assert_allclose([0.5, 0.5, 0.5, 0.5], vu.normalize(vector).tolist(), rtol=self.tol)

    def test_cosine_similarity(self):
        npt.assert_almost_equal(vu.cosine_similarity([1, 0], [0, 1]), 0)
        npt.assert_almost_equal(vu.cosine_similarity([1, 1], [0, 1]), math.sqrt(2)/2)

    def test_circular_convolution(self):
        npt.assert_allclose([1, 1], vu.circular_convolution([1, 0], [1, 1]),  rtol=self.tol)
        npt.assert_allclose([-1., 2., -1.], vu.circular_convolution([0, -1, 1], [1, 2, 3]),  rtol=self.tol)

    def test_create_vector(self):
        vec = vu.create_dense_random_vector(5, seed=2)
        npt.assert_allclose([-0.1280102, -0.94814754, 0.09932496, -0.12935521, -0.1592644], vec, rtol=self.tol)

        # Do it again to be sure.
        vec2 = vu.create_dense_random_vector(5, seed=2)
        npt.assert_allclose(vec, vec2, rtol=self.tol)

        # Make sure a different seed gives a different answer.
        vec3 = vu.create_dense_random_vector(5, seed=3)
        npt.assert_allclose([ 0.101596,  0.416296, -0.418191,  0.021655,  0.785894], vec3, rtol=self.tol)

    def test_get_k_neighbors_from_pairs(self):
        pairs = [('x', (1, 0, 0)), ('y', (0, 1, 0)), ('z', (0, 0, 1))]
        nearest = vu.get_k_neighbors_from_pairs(pairs, (0.9, 0.2, 0.1), 2)
        self.assertListEqual([nearest[0][0], nearest[1][0]], ['x', 'y'])
        npt.assert_allclose([0.971, 0.216], [nearest[0][1], nearest[1][1]], rtol=0.01)

        # Check no overflow
        nearest = vu.get_k_neighbors_from_pairs(pairs, (0.9, 0.2, 0.1), 10)
        self.assertIsNotNone(nearest)


import matplotlib.pyplot as plt
from matplotlib import collections  as mc
import numpy as np
from scipy import stats
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

def kNN_plot(n_neighbors):
    # fetch data
    iris = load_iris()
    # decompose with PCA
    pca = PCA(n_components=2)
    pca.fit(iris.data)
    iris_data_pca = pca.transform(iris.data)
    # query point
    pt = np.array([-1,.5])#np.array([1.5,0])
    # get n smallest
    d = np.sqrt(((iris_data_pca - pt)**2).sum(axis=1))
    idx = np.argpartition(d, n_neighbors)
    neighbors = iris_data_pca[idx[:n_neighbors]]
    # get label
    pt_target = stats.mode(iris.target[idx[:n_neighbors]]).mode[0]
    pt_label = iris.target_names[pt_target]
    # plot
    fig, ax = plt.subplots()
    for target in np.unique(iris.target):
        i = np.where(target == iris.target)
        ax.scatter(iris_data_pca[i,0], iris_data_pca[i,1], label=iris.target_names[target])
    ax.scatter(*pt, c='black', label='?')
    lines = [[pt, neighbors[i,:]] for i in range(n_neighbors)]
    lc = mc.LineCollection(lines, colors='black', linewidths=2, alpha=.1)
    ax.add_collection(lc)
    ax.set_xlabel('PC1 [%5.3f%%]' % (pca.explained_variance_ratio_[0] * 100))
    ax.set_ylabel('PC2 [%5.3f%%]' % (pca.explained_variance_ratio_[1] * 100))
    ax.legend()
    fig.savefig('notebooks/knn_iris/knn_iris_data/knn_points.png')
    plt.show()

    #print(pca.explained_variance_ratio_)

def objective_function(x, type = 'train'):
    iris = load_iris()
    xtrain, xtest, ytrain, ytest = train_test_split(iris.data, iris.target, train_size=.75, random_state=12345)
    knn = KNeighborsClassifier(n_neighbors=int(x))
    knn.fit(xtrain, ytrain)
    if type == 'train':
        return 1 - (knn.predict(xtrain) == ytrain).mean()
    elif type == 'test':
        return 1 - (knn.predict(xtest) == ytest).mean()
    else:
        raise NotImplementedError(f'type {type} not recognized')
    #return np.abs(x - 10) + 4*np.sin(x) + 3

def _plot_objective_function(ax):
    xgrid = np.array(range(1,100))#np.linspace(0,100, 1000)
    fx_train = [objective_function(x,'train') for x in xgrid]
    fx_test = [objective_function(x,'test') for x in xgrid]
    # plot
    ax.plot(xgrid, fx_train, label='Train set')
    ax.plot(xgrid, fx_test, label='Test set')

def plot_grid_search(n = 10, ax = None):
    # create grid
    xgrid = np.linspace(1,100,n)
    fx_train = [objective_function(x,'train') for x in xgrid]
    fx_test = [objective_function(x,'test') for x in xgrid]
    min_idx = np.argmin(fx_test)
    # plot
    if ax is None:
        fig,ax = plt.subplots()
    else:
        fig = None
    _plot_objective_function(ax)
    ax.scatter(xgrid, fx_train)
    ax.scatter(xgrid, fx_test)
    for x in xgrid:
        ax.axvline(x, alpha=.1)
    ax.scatter(xgrid[min_idx], fx_train[min_idx], c='red')
    ax.scatter(xgrid[min_idx], fx_test[min_idx], c='red')
    ax.set_title('Grid search')
    ax.legend()
    if fig is not None:
        fig.savefig('notebooks/knn_iris/knn_iris_data/grid_search.png')

def plot_random_search(n = 10, ax = None):
    # create grid
    np.random.seed(54321)
    xgrid = np.random.uniform(0,100,n)
    fx_train = [objective_function(x,'train') for x in xgrid]
    fx_test = [objective_function(x,'test') for x in xgrid]
    min_idx = np.argmin(fx_test)
    # plot
    if ax is None:
        fig,ax = plt.subplots()
    else:
        fig = None
    _plot_objective_function(ax)
    ax.scatter(xgrid, fx_train)
    ax.scatter(xgrid, fx_test)
    for x in xgrid:
        ax.axvline(x, alpha=.1)
    ax.scatter(xgrid[min_idx], fx_train[min_idx], c='red')
    ax.scatter(xgrid[min_idx], fx_test[min_idx], c='red')
    ax.set_title('Random search')
    ax.legend()
    if fig is not None:
        fig.savefig('notebooks/knn_iris/knn_iris_data/random_search.png')

def plot_search():
    # plot
    fig,(ax1,ax2) = plt.subplots(1,2, sharey='row', figsize=(15,5))
    plot_grid_search(ax = ax1)
    plot_random_search(ax = ax2)

    ax1.set_xlabel('Hyperparameter value')
    ax2.set_xlabel('Hyperparameter value')
    ax1.set_ylabel('Objective function value')
    fig.savefig('notebooks/knn_iris/knn_iris_data/grid_random.png')
    plt.show()
if __name__ == '__main__':
    #kNN_plot(5)
    plot_search()


# Gradient descent method of univariate linear regression.

import numpy as np
import matplotlib.pyplot as plt

class LinearRegression:
    def __init__(self):
        self._X = None
        self._y = None
        self._beta0 = 0.
        self._beta1 = 0.
        self._correlation = 0.

    def _mean(self, arr):
        return np.mean(arr)

    def _diff(self, arr, num):
        return np.subtract(arr, num)

    def _run_epoch(self, X, y, num_epochs, lr):
        curr_error = 0.
        n = len(y)
        for i in range(num_epochs):
            curr_prediction = self.predict(X)
            curr_error = self._rmse_error(y, curr_prediction)
            beta0_grad = (2. / n) * np.sum(np.subtract(curr_prediction, y))
            beta1_grad = (2. / n) * np.sum(np.dot(np.subtract(curr_prediction, y), X))

            self._beta0 -= lr * beta0_grad
            self._beta1 -= lr * beta1_grad

            print('Loss at {} epoch: {}'.format((i + 1), round(curr_error, 5)))
        return curr_error

    def fit(self, X, y, num_epochs, lr, seed=np.random.randint(0, 1000000)):
        self._X = X
        self._y = y
        self._compute_correlation()
        np.random.seed(seed)
        self._beta0 = np.random.uniform(-0.1, 0.1)
        self._beta1 = np.random.uniform(-0.1, 0.1)
        rmse_error = self._run_epoch(self._X, self._y, num_epochs, lr)
        return rmse_error

    def _rmse_error(self, y, y_pred):
        return np.sqrt(np.mean(np.subtract(y, y_pred) ** 2))

    def predict(self, input):
        return np.add(self._beta0, np.dot(self._beta1, input))

    def weight_coefficients(self, decimal=4):
        return round(self._beta0, decimal), round(self._beta1, decimal)

    def _compute_correlation(self):
        sum_x = np.sum(self._X)
        sum_y = np.sum(self._y)
        sum_xy = np.sum(np.multiply(self._X, self._y))
        sum_xsquare = np.sum(np.multiply(self._X, self._X))
        sum_ysquare = np.sum(np.multiply(self._y, self._y))
        n = len(self._X)
        self._correlation = (n * sum_xy - sum_x * sum_y) / np.sqrt(((n * sum_xsquare - sum_x ** 2) * (n * sum_ysquare - sum_y ** 2)))

    def correlation(self, decimal=4):
        return round(self._correlation, decimal)

    def plot_regression(self, X, y):
        plt.scatter(X, y, color="red", marker="x", s=20)

        y_pred = self._beta0 + np.multiply(self._beta1, X)

        plt.plot(X, y_pred, color="green")

        plt.xlabel('X')
        plt.ylabel('y')

        plt.show()

def main():
    linear_reg = LinearRegression()
    X = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    y = np.array([6, 8, 9, 11, 13, 16, 17, 19, 20, 24])

    rmse_error = linear_reg.fit(X, y, 200, 0.03, seed=12345)
    weights = linear_reg.weight_coefficients()
    print 'Weight coefficients for y = mx + c: m = {}, c = {}\n'.format(weights[1], weights[0])
    print 'Correlation between X and y: {}\n'.format(linear_reg.correlation())
    print 'Root mean-squared error for training: {}\n'.format(rmse_error)

    test_y = [3, 5, 10]
    print 'Prediction of {}: {}'.format(test_y, (linear_reg.predict(test_y)))
    linear_reg.plot_regression(X, y)

if __name__ == '__main__':
    main()


# arrays
# python has inbuilt arrays and well as numpy arrays
# we just use numpy array as the inbuilt ones are less flexible
l=[546,375,254,651,781,569,454,564]

import numpy as np
a=np.array(l)
# if we convert a list with multiple data types (such as int, string, boolean, etc.)
# the numpy.array() function will convery all elements into a string, so it becomes an array of strings
# so data type of all elements in an array are same

print(a)

# when you slice an array you dont create a copy of an array
# so any modification to the slice of an array will be reflected in the actual array
a=[1,2,3,4]
a=np.array(a) # array([1, 2, 3, 4])
b=a[0:2]
b[:]=111 # array([1, 2])
# now, b becomes array([111, 111])
# but c also becomes array([111, 111,   3,   4])

# lets say we have an array a
a=[1,2,3,4]
np.where(a == np.max(a))
# numpy.where() function iterates over a bool array, and for every True, it yields corresponding the element array x, and for every False, it yields corresponding item from array y. So, it returns an array of elements from x where the condition is True and elements from y elsewhere.
# in our example we get (array([x,y,z,..], dtype=int64),) as output
# this means, max value of the array exists at following indices array([x,y,z,..],)
# if max value exists in muliple places then all indices where it exists will be returned

# building your first matrix
import numpy as np
a=np.arange(0,20)
np.reshape(a,(5,4),order='F') # order is optional, if not specified then 'C' is the default order
# we could also do
a.reshape(5,4)
# C (default behavior) - matrix gets filled row by row, similar to C
# F - matrix gets filled column by column, similar to Fortran

# INDEXING
# MULTI DIMENTIONAL LIST  -  CONVERT INTO A NUMPY ARRAY AND THEN INDEXING
L= [ [1,2,3], [4,5,6] , [7,8,9] ] # this list has 3 rows and 3 columns
L=np.array(L)
L[1,1] # returns 5
L[0,:] # returns first row; we could also just say L[0]
L[:,0] # returns first column

# Dictionary is quite useful in matrix indexing, example
m=np.array([[1,2,3],[4,5,6],[7,8,9]])
col_names={'age':0,'weight':1,'height':2}
row_names={'vivek':0,'ale':1,'neety':2}
# now we can get weight of ale using actual indexes or dict indexes
m[1,1] # 5
m[row_names['ale'],col_names['weight']] # 5

# arithmetic operation is element by element
# division by zero shows a warning, and the result of div by zero is nan
# result can be rounded using matrix.round method
A=np.array([[1,2,3],[4,5,6],[7,8,9]])
B=np.array([[1,2,3],[4,5,6],[7,8,9]])
A+B
A-B
A*B
np.matrix.round(A/B)
A**B

# visualization
import numpy as np
import matplotlib.pyplot as plt
# in jupyter notebook we need to specify %matplotlib inline
plt.rcParams['figure.figsize']=8,4 # just need to set it once, can alter the size of plots

plt.plot(m[0], c='Blue',ls='--',marker='s',ms=17,label='vivek') # c is color, ls - line style, marker='s' - square marker, marker size=17
plt.plot(m[1], c='Magenta',ls='--',marker='s',ms=17,label='ale')
plt.plot(m[2], c='Green',ls='--',marker='s',ms=17,label='neety')
plt.legend(loc='upper left', bbox_to_anchor=(1,1))
plt.xticks([0,1,2],['age','weight','height'],rotation='vertical') #xticks replaces 0,1,2 in x-axis with 'age','weight','height'. We could also specify [0,1,2] using range function like list(range(0,3))
plt.show()

# Covariance matrix
data = np.array([[45,37,42,35,39],
                [38,31,26,28,33],
                [10,15,17,21,12]])
covMatrix = np.cov(data,bias=True)
sns.heatmap(covMatrix, annot=True, fmt='g')

# Create a Correlation Matrix using Pandas
df = pd.DataFrame({'A': [45,37,42,35,39],
        'B': [38,31,26,28,33],
        'C': [10,15,17,21,12]})
corrMatrix=df.corr()
sns.heatmap(corrMatrix, annot=True)


#!/bin/env python3
# -*- coding:utf-8 -*-

# def p(date):
#     print(date)

def create_array():
    from numpy import arange, uint16, array

    a = arange(5)
    print("a = ",a," a.dtype = ",a.dtype," a.shape  = ",a.shape)

    m = array([arange(5),arange(10)])
    print("m = ",m," m.dtype = ",m.dtype," m.shape  = ",m.shape)

    t = arange(7, dtype = uint16)
    print("t = ",t," t.dtype = ",t.dtype)

def array_property():
    from numpy import arange

    a = arange(27).reshape(3,3,3)
    print("a = ", a)
    print("a.ndim = ",a.ndim)
    print("a.size = ",a.size)
    a.resize(3,9)
    # print("a.resize = ", a.resize(3,9))
    print("a = ", a)
    print("a.T = ", a.T)
    # p("a.T = ", a.T)

def lissajout():
    import sys
    from matplotlib.pyplot import plot,show
    from numpy import linspace,pi,sin

    a = float(sys.argv[1] )
    b = float(sys.argv[2] )

    t = linspace(-pi, pi, 201)
    x = sin(a + t + pi / 2)
    y = sin(b * t)
    plot(x,y)
    show()

def fourier():
    from numpy.fft import fft, ifft
    from matplotlib.pyplot import plot, show
    from numpy import linspace, pi, cos, abs, all

    x = linspace(0, 2 * pi, 30)
    wave = cos(x)
    transformed = fft(wave)
    print(all(abs(ifft(transformed) -wave) < 10 ** -9))
    plot(transformed)
    show()

def fourier2():
    from numpy.fft import fft, ifft
    from matplotlib.pyplot import plot, show
    import numpy as np

    x = np.linspace(0, 2 * np.pi, 30)
    wave = np.cos(x)
    transformed = fft(wave)
    print(np.all(np.abs(ifft(transformed) -wave) < 10 ** -9))
    plot(transformed)
    show()

def plot_sinc():
    from numpy import sinc, linspace
    from matplotlib.pyplot import plot, show

    x = linspace(0, 4, 100)
    vals = sinc(x)

    plot(x, vals)
    show()

def plot_sinc2d():
    from numpy import linspace, outer, sinc
    from matplotlib.pyplot import imshow, show

    x = linspace(0, 4, 100)
    xx = outer(x,x)
    vals = sinc(xx)

    print("x = ", x, " xx = ", xx, "vals = ", vals)
    imshow(vals)
    show()

def kaiser():
    from numpy import kaiser
    from matplotlib.pyplot import plot, show

    window = kaiser(42,14)
    plot(window)
    show()

if __name__ == '__main__':
    # create_array()
    # array_property()
    # lissajout()
    # print(sin(4))  # undefined
    # fourier()
    # fourier2()
    # plot_sinc()
    # plot_sinc2d()
    kaiser()


import numpy as np

#x should be [.....,1] for the bias term
def logit(x,theta):
    return 1/(1+1/np.exp(x@theta))

def get_single_loss(x,y,theta,epsilon):
    return y*np.log(max(logit(x,theta),epsilon))+(1-y)*np.log(max(1-logit(x,theta),epsilon))

def get_gradient(x,y,theta):
    return y*x-x*logit(x,theta)

def get_loss(X,Y,theta,epsilon):
    n=len(X[0])
    loss=[]
    for i in range(n):
        loss.append(get_single_loss(X[i],Y[i],theta,epsilon))
    return loss

class logistic_model:
    def __init__(self):
        self.theta=[]

    def fit(self,X,Y,lr=0.01,limit=10000,epsilon=1e-4,verbose=True):

        #initialize weights

        n=len(X[0])
        self.theta=np.random.rand(n)
        # e is scalar
        k=0
        while k<limit:
            for i in range(n):
#                 print(X[i]@self.theta)
#                 print(logit(X[i],self.theta))
                self.theta=self.theta+lr*get_gradient(X[i],Y[i],self.theta)
                k+=1
                if k>limit:
                    break
#             print(X[0]@self.theta)
#             print(logit(X[0],self.theta))
#             print(get_gradient(X[0],Y[0],self.theta))
#             print(logit(X[8],self.theta))
            if verbose:
                print(sum(get_loss(X,Y,self.theta,epsilon)))
#             print(self.theta[:5])
        return

    def predict(self,X):
        n=len(X)
        res=[]
        for i in range(n):
            ind=logit(X[i],self.theta)
            res.append(ind)
        return res


from sympy import *
from quaternion_R_utils import *

fx,fy,cx,cy = symbols('fx fy cx cy');
px, py, pz = symbols('px py pz')
q0, q1, q2, q3 = symbols('q0 q1 q2 q3')
tie_px, tie_py, tie_pz = symbols('tie_px tie_py tie_pz');
u_kp, v_kp = symbols('u_kp v_kp')

position_symbols = [px, py, pz]
quaternion_symbols = [q0, q1, q2, q3]
tie_point_symbols = [tie_px, tie_py, tie_pz]
all_symbols = position_symbols + quaternion_symbols + tie_point_symbols

RT_wc = matrix44FromQuaternion(px, py, pz, q0, q1, q2, q3)
R_cw=RT_wc[:-1,:-1].transpose()
T_wc=Matrix([px, py, pz]).vec()
T_cw=-R_cw*T_wc

point_global=Matrix([tie_px, tie_py, tie_pz]).vec()
point_local = R_cw * point_global + T_cw;
s = 1.0 / point_local[2];
u = s * fx * point_local[0] + cx;
v = s * fy * point_local[1] + cy;
u_delta = u_kp - u;
v_delta = v_kp - v;

obs_eq = Matrix([u_delta, v_delta]).vec()
obs_eq_jacobian = obs_eq.jacobian(all_symbols)

print(obs_eq)
print(obs_eq_jacobian)

with open("perspective_camera_quaternion_wc_jacobian.h",'w') as f_cpp:
    f_cpp.write("inline void observation_equation_perspective_camera_quaternion_wc(Eigen::Matrix<double, 2, 1> &delta, double fx, double fy, double cx, double cy, double px, double py, double pz, double q0, double q1, double q2, double q3, double tie_px, double tie_py, double tie_pz, double u_kp, double v_kp)\n")
    f_cpp.write("{")
    f_cpp.write("delta.coeffRef(0,0) = %s;\n"%(ccode(obs_eq[0,0])))
    f_cpp.write("delta.coeffRef(1,0) = %s;\n"%(ccode(obs_eq[1,0])))
    f_cpp.write("}")
    f_cpp.write("\n")
    f_cpp.write("inline void observation_equation_perspective_camera_quaternion_wc_jacobian(Eigen::Matrix<double, 2, 10, Eigen::RowMajor> &j, double fx, double fy, double cx, double cy, double px, double py, double pz, double q0, double q1, double q2, double q3, double tie_px, double tie_py, double tie_pz)\n")
    f_cpp.write("{")
    for i in range (2):
        for j in range (10):
            f_cpp.write("j.coeffRef(%d,%d) = %s;\n"%(i,j, ccode(obs_eq_jacobian[i,j])))
    f_cpp.write("}")


import argparse
from math import pi
import numpy as np
import os
import pandas as pd

MIN_RADIUS = 0.5
MAX_RADIUS = 2.0
MIN_HEIGHT = 0.5
MAX_HEIGHT = 2.0
ADDED_ERROR = 0.1
NUM_DECIMALS = 1

def generate_cylinder_df(size):
    """Generate a dataframe of cylinders where the radius and height of
    each cylinder are both in the range 0.5 to 2.0 and the volume equals
    (pi * r^2) * h. Then add up to a 10% error (uniformly distributed) to
    the volume, followed by rounding off radius, height and volume to the
    nearest 0.1.
    """

    # Generate radiuses and heights
    radius = np.random.uniform(MIN_RADIUS, MAX_RADIUS, size=size)
    height = np.random.uniform(MIN_HEIGHT, MAX_HEIGHT, size=size)

    # Calculate the correct volumes with those radiuses and heights
    volume = (pi * radius ** 2) * height

    # Add the error to the volumes
    volume = volume * np.random.uniform(
        1 - ADDED_ERROR,
        1 + ADDED_ERROR,
        size=size)

    # Then round off radius, height and volume
    radius = np.round(radius, decimals=NUM_DECIMALS)
    height = np.round(height, decimals=NUM_DECIMALS)
    volume = np.round(volume, decimals=NUM_DECIMALS)

    df = pd.DataFrame({
        'volume': volume,
        'radius': radius,
        'height': height, })

    return df

if __name__ == '__main__':
    if ('get_ipython' not in dir()) & ('PYCHARM_HOSTED' not in os.environ):
        # i.e. if run from the command line

        # Handle command line arguments
        parser = argparse.ArgumentParser()
        parser.add_argument(
            '--filename',
            type=str,
            help='the filename to save the cylinders to',
            required=True)
        parser.add_argument(
            '--size',
            type=int,
            help='the number of cylinders to generate',
            required=True)
        # parser.add_argument(
        #     '--job-dir',
        #     help='this model ignores this field, but it is required by gcloud',
        #     default='junk')
        args = parser.parse_args()
        arguments = args.__dict__
        # arguments.pop('job_dir', None)

        # Generate cylinders and write them to file
        generate_cylinder_df(arguments['size']).to_csv(
            arguments['filename'],
            index=False)

        print('saved {} cylinders to {}'.format(
            arguments['size'],
            arguments['filename']))

    else:  # if run from a notebook or IDE
        files_to_generate = {
            'input/cylinders_train.csv': 8000,
            'input/cylinders_eval.csv': 1000,
            'input/cylinders_test.csv': 1000,}

        for filename, size in files_to_generate.items():
            generate_cylinder_df(size=size).to_csv(
                filename,
                index=False)

            print('saved {} cylinders to {}'.format(
                size,
                filename))


import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import simps
from numpy import trapz
from scipy.integrate import quad
x1= np.array([0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0])
y1=np.array([0.0,0.5,2.0,4.05,8.0,12.5,18.0,24.5,32.0,40.5,50.0])
h=0.1 ; a=x1[0] ; b=x1[9]
n=int((b-a)/h) ; S=0.5*(y1[0]+y1[10]) ; S1 = y1[0]+y1[10]
for i in range(1,10):
       if i%2 == 0:
           S1 = S1 + 2 * y1[i]
       else:
           S1 = S1 + 4 * y1[i]
       S+= y1[i]
Integral = S1 * h/3 ; Power = S * h
print("Power using trapezoidal and simpson",("%f"%Power,"%f"%Integral))
def trap(f,a,b,n):
    h=(b-a)/n
    S=0.5*(f(a)+f(b))
    for i in range(1,n):
        S+= f(a+i*h)
    Integral = S * h
    return Integral
def simpson(f,a,b,n):
    h=(b-a)/n
    S = f(a) + f(b)
    for i in range(1,n):
        if i%2 == 0:
            S = S + 2 * f(a + i*h)
        else:
            S = S + 4 * f(a + i*h)
    Integral = S * h/3
    return Integral

def integration(f,a,b,n):
    print("a =",a,"; b =" ,b, " ; Number of intervals =",n)
    h=(b-a)/n
    x = np.linspace(a,b,n+1)
    y = f(x)
    inte , err = quad(f, a, b)   #absolute value taken for comparing my results
    Integral_trap= trap(f,a,b,n)
    Integral_simp=simpson(f,a,b,n)
    print("Integral using scipy function (Quad) = ",inte)
    print("Integral (using composite trapezoidal formula) = %f" %Integral_trap)
    print("Error in composite trapezoidal (by subtracting from the one i got from inbuilt quad)= ",abs(Integral_trap-inte))
    print("Integral (using composite simpson formula) = %f" %Integral_simp)
    print("Error in composite simpson (by subtracting from the one i got from inbuilt quad) = ",abs(Integral_simp-inte))
    y_data_2,y_data,y_data_3=[],[],[]
    geo= np.array([10**i for i in range(4) ])
    n_array=np.arange(30,400,2)
    h_array=(b-a)/n_array
    for n in n_array:
        x_data=np.linspace(a,b,n+1)
        y_data.append(trap(f,a,b,n))
        y_data_2.append(simpson(f,a,b,n))
    d=[inte]*len(h_array)
    y_data_3=np.array(d)
    plt.plot(h_array,y_data,label="Trapezoidal rule")
    plt.scatter(h_array,y_data,label="Trapezoidal rule")
    plt.plot(h_array,y_data_2,label="Simpson's rule")
    plt.scatter(h_array,y_data_2,label="Trapezoidal rule")
    plt.plot(h_array,y_data_3,linestyle='--',label="scipy's simpson implementation")
    plt.xlabel("h")
    plt.ylabel("I(h)")
    plt.title("I(h) vs h plot [Convergence Test]")
    plt.legend()
    plt.grid()
    plt.xscale('log')
    plt.show()
f = lambda x : x*x
integration(f,0,10,100)


import numpy as np

from network.my_types import Data

# Activation Functions

def null(_: float) -> float:
    """
    Function that always returns 0
    :param _: Input value to function
    :type _: int
    :return: Always 0
    :rtype: int
    """
    return 0

def sigmoid(x: float) -> float:
    """
    Implementation of the Sigmoid activation function
    :param x: Input value to function
    :type x: float
    :return: sigmoid(x)
    :rtype: float
    """
    return 1 / (1 + np.exp(-x))

def gaussian(x: float) -> float:
    """
    Implementation of the Gaussian activation function
    :param x: Input value to function
    :type x: float
    :return: gaussian(x)
    :rtype: float
    """
    return np.exp(-(x**2/2))

def identity(x: float) -> float:
    """
    Identity function to be used in place of no activation function
    :param x: Input value to function
    :type x: float
    :return: x
    :rtype: float
    """
    return x

# Training Functions
def cubic(x: float) -> float:
    """
    Cubic training function
    :param x: Input value to function
    :type x: float
    :return: x^3
    :rtype: float
    """
    return x ** 3

def xor(x1: int, x2: int) -> int:
    """
    xor training function
    :param x1: Input value to function
    :param x2: Input value to function
    :type x1: int
    :type x2: int
    :return: x1 XOR x2
    :rtype: int
    """
    return x1 ^ x2

def complex_train(x1: float, x2: float) -> float:
    """
    complex training function
    :param x1: Input value to function
    :param x2: Input value to function
    :type x1: float
    :type x2: float
    :return: 1.9{ 1.35 + e^x1-x2 sin[13(x1 -0.6)^2]sin[7x2] }
    :rtype: int
    """
    return 1.9 * (1.35 + np.exp(x1 - x2) * np.sin(13*((x1-0.6)**2)) * np.sin(7*x2))

# Error Functions
def mean_squared_error(predictions: Data, ground_truth: Data) -> float:
    """
    Function to take the MSE (Mean Squared Error) of two equal length lists of output vectors.
    Commonly used to take get the MSE of predictions from a network and the ground truth. All vectors in the list must
    have equal length. While the order of the supplied lists doesn't matter, they are named for clarity and convention.
    :param predictions: The predictions from a network
    :type predictions: Data
    :param ground_truth: The ground truths to compare against
    :type ground_truth: Data
    :return: The MSE (Mean Squared Error) of all supplied samples
    :rtype: float
    """
    # Ensure arguments are of the same length
    if len(ground_truth) != len(predictions):
        raise ValueError(f"Number of predictions ({len(predictions)}) does not match ground "
                         f"truth ({len(ground_truth)})")

    # As the function accepts single vectors or lists of vectors, make the arguments conform to expectations
    if type(predictions[0]) == int:
        predictions = [predictions]
    if type(ground_truth[0]) == int:
        ground_truth = [ground_truth]

    # Create a list of the absolute summed error between corresponding vectors
    per_sample_error = [sum(np.absolute(np.array(x) - np.array(y))) for x, y in zip(ground_truth, predictions)]

    # Square error between samples and take the mean
    return sum(np.array(per_sample_error) ** 2) / len(ground_truth)


#Una caja contiene n_total transistores de los cuales n_funciona
#funcionan correctamente y n_no_funciona no funcionan
#correctamente. Los transistores se van probando uno a uno para ver si
#funcionan. Una vez se prueba un transistor se retira de la caja y no
#se devuelve. Sea N_1 el número de pruebas que se hicieron hasta
#encontrar el primer transistor dañado y N_2 el número de pruebas
#realizadas hasta encontrar el segundo transistor dañado. Escriba una
#función de Python que encuentre la probabilidad conjunta de N_1 y N_2
#usando un método Monte Carlo usando un número total de diez mil
#iteraciones.

#La función debe llamarse probabilidad_conjunta.  La función toma como
#entrada dos variables enteras n_funciona y n_no_funciona (en ese
#orden). La función debe devolver un array bidimensional de numpy
#(i.e. con filas y columnas). En cada dirección el array tiene
#dimensión n_total+1. Al calificar la entrega vamos a llamar a la
#función de la siguiente manera:

# p = probabilidad_conjunta(n_funciona, n_no_funciona)

# print(p[N_1, N_2])

#donde n_funciona, n_no_funciona, N_1, y N_2 son variables enteras que
#se inicializan al momento de calificar.

# La función debe estar en un archivo llamado
# "ApellidoNombre_Ejercicio09.py" donde Apellido y Nombre
# debe reemplazarlos con su apellido y nombre.  Suba ese archivo como
# respuesta a esta actividad.

#Al ejecutar "python ApellidoNombre_Ejercicio09.py" o al
#llamar la funci ón no se debe producir ningún error.

# Solamente puede utilizar las funciones y métodos vistas en clase
# (videos o clases sincrónicas, o que ya se encuentren en el
# repositorio) .

import numpy as np

def probabilidad_conjunta(n_funciona, n_no_funciona):
    funciona = 0
    no_funciona = 1

    transistores = np.array(n_funciona*[funciona] + n_no_funciona*[no_funciona])

    n_total = n_funciona + n_no_funciona
    probabilidad = np.zeros([n_total+1, n_total+1])
    n_realizaciones = 100000
    for i in range(n_realizaciones):
        np.random.shuffle(transistores)

        intentos = np.arange(len(transistores))+1

        intentos_sin_funcionar = intentos[transistores==no_funciona]

        N_1 = intentos_sin_funcionar[0]
        N_2 = intentos_sin_funcionar[1]

        probabilidad[N_1, N_2] += 1

    probabilidad /= n_realizaciones
    return probabilidad


from timeit import timeit
from statistics import stdev, mean
from typing import List, Tuple
from itertools import combinations
import numpy as np
import csv

def read_prices(name: str) -> List[float]:
	result = []
	with open(f'data/{name}.csv', newline='') as file:
		reader = csv.reader(file)
		next(reader)  # Skip header
		for row in reader:
			result.append(float(row[5]))

	return result

def correlation_using_stdlib(x_prices: List[float], y_prices: List[float]) -> float:
	x_mean = mean(x_prices)
	y_mean = mean(y_prices)

	numerator = 0
	for x, y in zip(x_prices, y_prices):
		numerator += (x - x_mean) * (y - y_mean)

	return numerator / ((len(x_prices) - 1) * stdev(x_prices) * stdev(y_prices))

def correlation(x_prices: List[float], y_prices: List[float]) -> float:
	return np.divide(
		np.multiply(
			np.array(x_prices) - np.array(x_prices).mean(),
			np.array(y_prices) - np.array(y_prices).mean(),
		).sum(),
		(len(x_prices) - 1) * np.array(x_prices).std(ddof=1) * np.array(y_prices).std(ddof=1),
	)

def print_correlations(correlations: List[Tuple[Tuple[str, str], float]]):
	for ((x_name, y_name), corr) in correlations:
		print(f'{x_name}:{y_name} = {corr}')

if __name__ == '__main__':
	stock_prices = [
		(s, read_prices(s))
		for s in ['AAPL', 'AMZN', 'FB', 'GOOG', 'IBM', 'MSFT', 'NFLX', 'ORCL', 'SAP', 'TSLA']
	]

	correlations_stdlib = [
		((x_name, y_name), correlation_using_stdlib(x_prices, y_prices))
		for ((x_name, x_prices), (y_name, y_prices)) in combinations(stock_prices, 2)
	]
	correlations_stdlib.sort(key=lambda item: item[1], reverse=True)

	print('non-NumPy version')

	print_correlations(correlations_stdlib)

	correlations_numpy = [
		((x_name, y_name), correlation(x_prices, y_prices))
		for ((x_name, x_prices), (y_name, y_prices)) in combinations(stock_prices, 2)
	]
	correlations_numpy.sort(key=lambda item: item[1], reverse=True)

	print('\nNumPy version')

	print_correlations(correlations_numpy)

	executions = 100
	stdlib_duration = timeit(
		lambda: correlation_using_stdlib(stock_prices[0][1], stock_prices[1][1]),
		number=executions,
	) / executions
	print(f'\nnon-NumPy version execution time: {stdlib_duration:.6f}s')

	numpy_duration = timeit(
		lambda: correlation(stock_prices[0][1], stock_prices[1][1]),
		number=executions,
	) / executions
	print(f'NumPy version execution time: {numpy_duration:.6f}s')


# Inverse Kinematics
# Analytical Solution
# Given in "Intro to Robotics by craig" p.109

import numpy as np

def R3robot_IK(T_0N, output_unit='deg', solution1or2=1):
    """
    TODO
    """

    # constants
    L1 = 4 # m
    L2 = 3 # m
    L3 = 2 # m

    # 3 parameters for Planar Robots
    # x, y, phi
    cos_phi = T_03[0,0]
    sin_phi = T_03[0,1]
    phi = np.arccos(cos_phi)
    x = T_03[0,3]
    y = T_03[1,3]
    if x==0 and y==0:
        return "theta 1 is arbitrary for (x,y)=(0,0)"
    cos_theta2 = (x**2 + y**2 - L1**2 - L2**2) / (2*L1*L2)
    if cos_theta2<-1 or cos_theta2>1:
        return "solution does not exist"
    if solution1or2==1: # first solution
        sin_theta2 = (1 - (cos_theta2**2))**0.5
        theta2 = np.arctan2(sin_theta2, cos_theta2)
        k2 = L2*sin_theta2
    elif solution1or2==2: # seconds solution
        sin_theta2 = -1*(1 - (cos_theta2**2))**0.5
        theta2 = np.arctan2(sin_theta2, cos_theta2) # second solution
        k2 = L2*sin_theta2
    k1 = L1 + L2*cos_theta2
    theta1 = np.arctan2(y,x) - np.arctan2(k2,k1)
    theta3 = phi - theta1 - theta2

    if output_unit.lower()=="deg":
        return np.rad2deg(theta1), np.rad2deg(theta2), np.rad2deg(theta3)
    return theta1, theta2, theta3

if __name__ == "__main__":
    from R3robot_FK import R3robot_FK
    # T_03 = R3robot_FK(10,20,30,unit='deg')
    # print(T_03)
    T_03 = np.array([[1,0,0,9],[0,1,0,0],[0,0,1,0],[0,0,0,1]])
    print(R3robot_IK(T_03,solution1or2=2))


import numpy as np
import scipy

def question_1_1(l=84):
    A = np.zeros((l, l))
    b = np.zeros(l)

    for i in range(l):
        A[i, i] = 6
        if i != 0: A[i, i-1] = 8
        if i != l-1: A[i, i+1] = 1

        if i == 0: b[i] = 7
        elif i == l-1: b[i] = 14
        else: b[i] = 15

    A = A.astype(np.float64)
    b = b.astype(np.float64)
    x = np.ones(l)
    return A, b, x

def question_1_2_1(l=100):
    A = np.zeros((l, l))
    for i in range(l):
        A[i, i] = 10
        if i != 0: A[i, i-1] = 1
        if i != l-1: A[i, i+1] = 1
    b = np.random.rand(100)
    x = scipy.linalg.solve(A, b) # scipy as the ground truth
    return A, b, x

def question_1_2_2(l=40):
    A = np.zeros((l, l))
    b = np.zeros(l)
    for i in range(l):
        for j in range(l):
            A[i, j] = 1 / (i + j + 1);
            b[i] += A[i, j]
    x = np.ones(l)
    return A, b, x

def question_4_1(n=100, a=1/2, epsilon=1):
    def get_res(x):
        return (1-a)/(1-np.e**(-1/epsilon))*(1-np.e**(-x/epsilon))+a*x
    h = 1 / n
    A = np.zeros((n-1, n-1))
    b = np.zeros(n-1)
    x = np.zeros(n-1)
    for i in range(n-1):
        b[i] = a * h**2
        if i == n-2: b[i] -= epsilon + h # x[-1] = 0, x[n] = 1
        x[i] = get_res((i+1)*h)
        for j in range(n):
            if i>0: A[i, i-1] = epsilon
            A[i, i] = - (2 * epsilon + h)
            if i<n-2: A[i, i+1] = epsilon + h
    return A, b, x

def question_6_1(a=[3, -5, 1]):
    n = len(a)
    A = np.zeros((n,n))
    A[n-1, 0] = 1
    A[n-1, n-1] = -a[n-1]
    for i in range(1, n):
        A[0, i] = -a[i-1]
        if i > 1: A[i-1, i] = 1
    return A


import numpy as np
import math
import scipy.stats as stats

'''
Module for misc. statistical methods
for time series data
'''

# Detrends the target values of a time series
# by subtracting the residuals resulting
# from linear regression.
# Returns a 3-tuple
# containing the vector of the detrended time series,
# and the slope and intercept of the regression line
def detrend(x,y):
	result = stats.linregress(x,y)
	slope = result[0]
	intercept = result[1]
	detrended = []
	for val in range(len(y)):
		pred = slope*val+intercept
		residual = y[val]-pred
		detrended.append(residual)
	return (detrended,slope,intercept)

# Applies a linear trend to a series of data points
# i.e. a[z] = y[z] + trend
#           = y[z] + slope*x[z] + intercept
def reapplyTrend(x,y,slope,intercept):
	rev = np.zeros(len(y))
	for dex in range(len(y)):
		rev[dex] = y[dex] + (slope*x[dex]+intercept)
	return rev

# Performs linear regression on univariate time
# series repr. by xTrain,yTrain, and then makes predictions
# for xTest
# Returns a 1-d vector representing predictions
def predictLinearRegression(xTrain,yTrain,xTest):
	result = stats.linregress(xTrain,yTrain)
	slope = result[0]
	intercept = result[1]
	predict = np.zeros(len(xTest))
	for x in range(len(xTest)):
		predict[x] = slope*xTest[x]+intercept
	return predict

# Performs linear regression on univariate time
# series repr. by xTrain,yTrain, and then makes predictions
# for xTest
# Returns a 1-d vector representing predictions
def predictPolyRegression(xTrain,yTrain,xTest,deg):
	coeff = np.polyfit(xTrain,yTrain,deg)
	predict = np.zeros(len(xTest))
	for x in range(len(xTest)):
		for c in range(len(coeff)):
			predict[x] += coeff[c]*math.pow(xTest[x],len(coeff)-c-1)
	return predict

# Computes the Mean Squared Error for predicted values against
# actual values
def meanSquareError(actual,pred):
	if (not len(actual) == len(pred) or len(actual) == 0):
		return -1.0
	total = 0.0
	for x in range(len(actual)):
		total += math.pow(actual[x]-pred[x],2)
	return total/len(actual)

# Computes Normalized Root Mean Square Error (NRMSE) for
# predicted values against actual values
def normRmse(actual,pred):
	if (not len(actual) == len(pred) or len(actual) == 0):
		return -1.0
	sumSquares = 0.0
	maxY = actual[0]
	minY = actual[0]
	for x in range(len(actual)):
		sumSquares += math.pow(pred[x]-actual[x],2.0)
		maxY = max(maxY,actual[x])
		minY = min(minY,actual[x])
	return math.sqrt(sumSquares/len(actual))/(maxY-minY)

# Computes Mean Absolute Percent Error (MAPE) for predicted
# values against actual values
def mape(actual,pred):
	if (not len(actual) == len(pred) or len(actual) == 0):
		return -1.0
	total = 0.0
	for x in range(len(actual)):
		total += abs((actual[x]-pred[x])/actual[x])
	return total/len(actual)

# Estimates missing data denoted by <targ> in
# a list of lists <data> by averaging the neighboring
# values if they exist, otherwise the mean of the entire
# list (i.e. if a missing value is at the start or end of
# a list)
def estimateMissing(data,targ):
    for x in range(len(data)):
        for y in range(len(data[x])):
            if (data[x][y] == targ):
                if (y > 0 and y < len(data[x])-1):
                    data[x][y] = (data[x][y-1]+data[x][y+1])/2.0
                else:
                    data[x][y] = np.mean(data[x])


import matplotlib.pyplot as plt
import matplotlib.ticker as mtick

import numpy as np
from scipy.stats import norm

# Create an array of points to use as the x-coordinates for plotting the normal distribution
x_min = norm.ppf(0.00005) # we will plot 99.99 % of the normal curve.
x_max = norm.ppf(0.99995)
x = np.linspace(x_min, x_max, 201)

plt.style.use('seaborn-whitegrid')

# paramaters for the normal distribution
mu = 2
sigma = 3

# how to translate between different scales on the x-axis'
def toZscore(x):
    return ((x - mu) / sigma)

def fromZscore(x):
    return ((sigma * x) + mu)

# get a reference to a frozen version of the normal function with the loc and scale paramaters set.
n = norm(loc=mu, scale=sigma)

# Rebuild the array of points to use as the x-coordinates for plotting the normal distribution
x_min = n.ppf(0.000005) # we will plot 99.999 % of the normal curve.
x_max = n.ppf(0.999995)
x = np.linspace(x_min, x_max, 201)

# create a figure and an axes
fig, ax = plt.subplots()
fig.set_figheight(6)
fig.set_figwidth(8)

# Create an Axes object that shares an x axis with the ax Axes that we just created above.
ax2 = ax.twinx()

# format that axis as a percentage.
ax2.yaxis.set_major_formatter(mtick.PercentFormatter(1.0))

# the second curve we want to plot, the CDF.
ax2.plot(x,
         n.cdf(x),
         label='Cumulative Distribution\n Function norm.cdf(x, loc={}, scale={})'.format(mu, sigma),
         lw=2,
         color='green'
        )

# plot our normal function.
ax.plot(x,
        n.pdf(x),
        label='Normal Distribution\n norm.pdf(x, loc={}, scale={})'.format(mu, sigma)
       )

# add our points of interest
ax.plot(fromZscore(-1.96),
        n.pdf(fromZscore(-1.96)),
        color='red',
        marker='o',
        alpha=0.5
       )
ax.plot(fromZscore(1.96),
        n.pdf(fromZscore(1.96)),
        color='red',
        marker='o',
        alpha=0.5
       )
# add vertical lines
ax.vlines(x=[fromZscore(-1.96), fromZscore(1.96)],
          ymin=[0, 0],
          ymax=[n.pdf(fromZscore(-1.96)), n.pdf(fromZscore(1.96))],
          color='red',
          alpha=0.5
         )

# add axis labels, title and legend
ax.set_xlabel('X')
ax.set_ylabel('Probability')
ax.set_title('The Normal (Gaussian) Distribution')

# customize our legend
fig.legend(
    fontsize='small',
    loc='upper left',
    framealpha=0.5,
    bbox_to_anchor=(0.15, 0.85) # note that here the coordinates are relative the the whole figure
)

# add some text.  By default the xy are in the axes coordinates
# but that can be changed with transformations
ax.text(-3.3*sigma,
        n.pdf(fromZscore(-1.96)),
        '$(-1.96\sigma, {0:.2})$'.format(n.pdf(fromZscore(-1.96)))
       )
ax.text(2.1 * sigma + mu,
        n.pdf(1.96*sigma + mu),
        '$(1.96\sigma, {0:.2})$'.format(n.pdf(fromZscore(1.96)))
       )

# add fill below the normal curve
# create an array of x-values to plot against
x2=np.linspace(x_min, n.ppf(0.025))
ax.fill_between(x2, n.pdf(x2), alpha=0.75, facecolor='lightblue')

# add annotation.  By default the xy are in the axes coordinates
# but that can be changed with transformations
text_string ='This area is equal to\nthe value of the CDF at\n'
text_string += 'the right boundary.\nIn this case the right\nboundary is at $-1.96\sigma$\n'
text_string += 'where $\sigma$ = {} and the\n area is $2.50\%$ of the\n area under the curve.'.format(sigma)
ax.annotate(
    text_string,
    xy=(-2.1*sigma + mu, n.pdf(fromZscore(-1.96))/3),
    xytext=(2*sigma + mu,0.05),
    arrowprops=dict(arrowstyle='->'))

# add a horizontal line from the CDF to the right axis and a point at the intersection
ax2.hlines(y=n.cdf(fromZscore(-1.96)),
           xmin=-1.96*sigma + mu,
           xmax=x_max,
           color='green',
           alpha=0.5
          )
# add our dot
ax2.plot(fromZscore(-1.96), n.cdf(fromZscore(-1.96)), marker='o', color='green', alpha=0.4)

# add text to highlight the value of the CDF at -0.96
ax2.text(x_max,0.04, '$2.5\%$'.format(n.cdf(fromZscore(-1.96))))

# adjust the transparency and color of the grids for each axex object
ax.grid(visible=True, color='blue', alpha=.2)
ax2.grid(visible=True, color='green', alpha=0.2)

# add a vertical dashed line at the mean, -sigma and sigma.
ax.vlines(x=mu, ymin=0, ymax=n.pdf(mu), linestyle='dotted')
ax.vlines(x=[mu-sigma, mu+sigma], ymin=0, ymax=n.pdf(mu+sigma), linestyle='dotted')
ax.text(mu+0.02,
        n.pdf(mu)/12,
        '$\mu$ = {}'.format(mu)
       )
ax.text(mu+sigma+0.02,
        n.pdf(mu)/12,
        '$\mu + \sigma$'
       )
ax.text(mu-sigma+0.02,
        n.pdf(mu)/12,
        '$\mu - \sigma$'
       )

# add an additional x-axis
# shift the original axes object up
fig.subplots_adjust(bottom=0.2)
ax3 = ax.secondary_xaxis(-0.08, functions=(toZscore, fromZscore))
ax3.set_xlabel('Standard Deviations')
ax3.xaxis.set_label_coords(-.11,-0.1)
ax3.set_xticks([x for x in range(-4,6)], minor=True)
ax3.tick_params(length = 10, which='major', direction='in')
ax3.tick_params(length= 10, which='minor', direction='inout')
# add tics to our primary x axis
ax.tick_params(length = 10, which='major', direction='in')
ax.tick_params(length= 5, which='minor', direction='inout')
ax.set_xticks([x for x in range(-10,16)], minor=True)

# move our initial x-axis label off the the left.
ax.xaxis.set_label_coords(-0.02, -0.025)

#plt.show()
plt.savefig('figure_3.png', bbox_inches='tight')


# -*- coding: utf-8 -*-
"""
Created on Mon May 11 17:30:16 2020

@author: Dilay Ercelik
"""

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

# Loads python pickle file
with open('c10p1.pickle', 'rb') as f:
    data = pickle.load(f)

c10p1 = data['c10p1']

print('Code for Question 1:', '\n')

# Given the input correlation matrix Q:
Q = np.array([[0.2, 0.1],[0.1, 0.3]])

# Calculates the eigenvalues ev and the eigenvectors e of the matrix Q:
ev, e = np.linalg.eig(Q)

print(ev)
print(e)

# If we allow learning to go on for a long period of time,
# w becomes the principal eigenvector of matrix Q
# i.e. the eigenvector e of Q with the greater corresponding eigenvalue ev

# Finds the index of the greatest eigenvalue of the 2 eigenvectors of Q
max_ev_index = ev.argmax()

# Prints the expected w for a learning for a long period of time
w_long_learning = 2 * e[:, max_ev_index]

print('If we allow learning to go on for a long period of time, w = {}'.format(w_long_learning))

# Question 1 is not related to Questions 7-8-9

print('Code for Question 7:', '\n')

def normal(data):
    """
    Performs a "zero-mean centering step", or normalisation, on the input data

    Parameters
    ----------
    data : float
        Input data (x, y).

    Returns
    -------
    normal_data : float
        Normalised input data.

    """
    mean = np.mean(data, axis = 0)

    normal_data = data - mean

    return normal_data

# Creates our_normal_data from the raw data c10p1
our_normal_data = normal(c10p1)

# Visualisation of our_normal_data
# To make sure our transformed data is zero-mean centered
plt.figure(1)
plt.scatter(our_normal_data[:, 0], our_normal_data[:, 1], c = 'r', marker = 'o')
plt.title('Oja\'s rule: data cloud centered around (0,0)')
plt.xlabel('u1 (input 1)')
plt.ylabel('u2 (input 2)')

# Implements the update rule for Oja's rule
eta = 1
alpha = 1
delta_t = 0.01

# Creates our random first w value: w_zero
w_zero = w = np.random.rand(2)

# Implementing the updating rule to update w for a number of iterations (e.g. 500).
# Oja's rule for updating w
for step in np.arange(0, 500, 1):

    plt.figure(1)
    u = our_normal_data[np.remainder(step, our_normal_data.shape[0]), :]
    v = u @ w     # @ is used for matrix multiplication
    w = w + delta_t * eta * (v * u - alpha * v * v * w)
    plt.plot(v, marker = '^',  c = 'g')
    plt.plot(w[0], w[1], marker = '*', c = 'b')

# Calculates the correlation matrix C (formula given in the quiz)
# Because our_normal_data is mean_centered, C is also its covariance matrix.
# our_normal_data.shape[0] gives the number M of lines (the number of samples in our_normal_data)
C = np.dot(our_normal_data.T, our_normal_data) / our_normal_data.shape[0]

# Prints the correlation/covariance matrix C of our_normal_data
print('This is the correlation/covariance matrix C of our mean-centered data (our_normal_data): {}'.format(C), '\n')

# Calculates the eigenvalues ev and the eigenvectors e of the matrix C:
ev, e = np.linalg.eig(C)

# Prints eigenvalues (ev) and eigenvectors (e: 2D vectors) of
# the correlation matrix C of the mean-centered data (our_normal_data)
print('The eigenvalues of the correlation/covariance matrix C of our_normal_data are {} and {}'.format(ev[0], ev[1]), '\n')

print('The eigenvectors of the correlation/covariance matrix C of our_normal_data are {} and {}'.format(e[0], e[1]), '\n')

# Answer to Question 7:
## "The correlation matrix C has only one principal eigenvector,
## but there two vectors of length 1/alpha that are parallel to this eigenvector.
## w can converge to either of these two vectors."

### Note to myself:
# The eigenvector corresponding to the eigenvalue of largest magnitude is called the principal eigenvector.

print('Code for Question 8:', '\n')

# Creates our_normal_data with adjusted mean: data2, not zero-mean centered
constants = [2, 2]
data2 = our_normal_data + np.tile(constants, (our_normal_data.shape[0], 1))

# Visualisation of data2
plt.figure(2)
plt.scatter(data2[:, 0], data2[:, 1], marker = 'o',  c = 'r')
plt.title('Oja\'s rule: data2 cloud')
plt.xlabel('u1 (input 1)')
plt.ylabel('u2 (input 2)')

# Creates our random first w value for the second data (not zero-mean centered data)
w2 = w_zero

# Implementing the updating rule to update w for a number of iterations (e.g. 500).
# Oja's rule for updating w
for step in np.arange(0, 500, 1):

    plt.figure(2)
    u = data2[np.remainder(step, data2.shape[0]), :]
    v = u @ w2
    w2 = w2 + delta_t * eta * (v * u - alpha * v * v * w2)
    plt.plot(v, marker = '^',  c = 'g')
    plt.plot(w2[0], w2[1], marker = '*',  c = 'b')

# Answer to question 8:
## "The two vectors that w (w2) converges to in different runs of the algorithm
## are parallel to the vector that points roughly towards the mean of the data (data2)."

print('Code for Question 9:', '\n')

# Visualisation
plt.figure(3)
plt.scatter(our_normal_data[:, 0], our_normal_data[:, 1], marker = 'o',  c = 'r')
plt.title('Data cloud for Hebb Rule')
plt.xlabel('u1 (input 1)')
plt.ylabel('u2 (input 2)')

# Creates our random first w value for the third data (our_normal_data with Hebb Rule)
w3 = w_zero

# Implementing the updating rule to update w for a number of iterations (e.g. 500).
# Hebb rule for updating w

for step in np.arange(0, 500, 1):

    plt.figure(3)
    u = our_normal_data[np.remainder(step, our_normal_data.shape[0]), :]
    v = u @ w3
    plt.plot(v, marker='^',  c='b')
    w3 = w3 + delta_t * eta * (v * u)  # Hebb Rule
    plt.plot(v, marker = '^',  c = 'g')
    plt.plot(w3[0], w3[1], marker = '*',  c = 'b')

plt.show()

# Answer to Question 9:
## "The vectors found by the Hebb learning rule have the same direction
## as those found by Oja's rule (on our_normal_data, in Question 7),
## but the length (of w3) grows without bound as a function of the number of iterations.


import numpy as np
from scipy.linalg import hilbert

def cholesky(A):
	# return np.linalg.cholesky(A)
	n = A.shape[0]
	L = np.zeros_like(A)
	for k in range(n):
		L[k, k] = (A[k, k] - ((L[k, :k] ** 2).sum() if k > 0 else 0)) ** .5
		for i in range(k + 1, n):
			L[i, k] = (A[i, k] - L[i, :k].dot(L[k, :k])) / L[k, k]
	return L

def solve(n, delta=0):
	print('n =', n, ', delta =', delta)
	H = hilbert(n)
	x = np.zeros(n) + 1 + delta
	b = H.dot(x)
	L = cholesky(H)
	# Hx = b, H = LL'
	# LL'x = b
	# x = L'^-1 L^-1 b
	xp = np.linalg.solve(L.T, np.linalg.solve(L, b))
	r = b - H.dot(xp)
	dx = xp - x
	print('||r||_inf:', abs(r).max())
	print('||dx||_inf:', abs(dx).max())

def gen36():
	print('t36 result'.center(30, '-'))
	solve(10)
	solve(10, 1e-7)
	solve(8)
	solve(12)
	print('end t36'.center(30, '-')+'\n')

if __name__ == '__main__':
	gen36()


"""
Optimizer Module
"""

import numpy as np

def derivative(f, x, epsilon = 1e-10):
    """
    Calculate derivative of f at x

    ...

    Parameters
    ---
    f : Function to calculate derivative for
    x : Value at which to calculate derivative
    epsilon(optional): Adjustable precision

    Returns
    ---
    value: Derivative of f at x
    """

    x_ = x + epsilon
    value = (f(x_) - f(x)) / epsilon

    return value

def newton_method(f, x_init = 0, epsilon = 1e-10):
    """
    Newton Raphson Optimizer

    ...

    Parameters
    ---
    f: Function to calculate root for
    x_init(optional) : initial value of x
    epsilon(optional): Adjustable precision

    Returns
    ---
    x: Value of root
    """
    prev_value = x_init + 2 * epsilon
    value = x_init

    iterations = 0
    while abs(prev_value - value) > epsilon:
        prev_value = value

        f_dash = derivative(f, value)
        value = value - f(value) / f_dash

        iterations += 1

    print(f"Newton Method converged in {iterations} iterations")

    return value


##### BT: y = 4 + 3x

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

np.random.seed(2)

X = np.random.rand(1000, 1)
y = 4 + 3*X + 0.2 * np.random.rand(1000, 1)     # noise added

# Building Xbar
matrixOne = np.ones((X.shape[0], 1))
Xbar = np.concatenate((matrixOne, X), axis = 1)
print Xbar

def grad(w):
    """ Dao ham """
    N = Xbar.shape[0]
    return 1/N * Xbar.T.dot(Xbar.dot(w) - y)

def cost(w):
    """ Cost function """
    N = Xbar.shape[0]
    return .5/N*np.linalg.norm(y - Xbar.dot(w), 2)**2

A = np.dot(Xbar.T, Xbar)
b = np.dot(Xbar.T, y)
w_lr = np.dot(np.linalg.pinv(A), b)

print('Solution found by formula: w = ',w_lr.T)

def numerical_grad(w, cost):
    eps = 1e-4
    g = np.zeros_like(w)
    for i in range(len(w)):
        w_p = w.copy()
        w_n = w.copy()
        w_p[i] += eps
        w_n[i] -= eps
        g[i] = (cost(w_p) - cost(w_n))/(2*eps)
    return g

def check_grad(w, cost, grad):
    w = np.random.rand(w.shape[0], w.shape[1])
    grad1 = grad(w)
    grad2 = numerical_grad(w, cost)
    return True if np.linalg.norm(grad1 - grad2) < 1e-6 else False

print( 'Checking gradient...', check_grad(np.random.rand(2, 1), cost, grad))

def myGD(w_init, grad, eta):
    w = [w_init]
    temp = 0
    for it in range(100):
        w_new = w[-1] - eta*grad(w[-1])
        temp += 1
        if np.linalg.norm(grad(w_new))/len(w_new) < 1e-3:
            break
        w.append(w_new)
    return (w, temp)

w_init = np.array([[2], [1]])
(w1, it1) = myGD(w_init, grad, 1)
print('Solution found by GD: w = ', w1[-1].T, ',\nafter %d iterations.' %(it1+1))

# Display result
w = w_lr
w_0 = w[0][0]
w_1 = w[1][0]
x0 = np.linspace(0, 1, 2, endpoint=True)
y0 = w_0 + w_1*x0

# Draw the fitting line
plt.plot(X.T, y.T, 'b.')     # data
plt.plot(x0, y0, 'y', linewidth = 2)   # the fitting line
plt.axis([0, 1, 0, 10])
plt.show()


# estimate delta, gamma, theta, veta
"""
  Name     : c10_39_greeks.py
  Book     : Python for Finance (2nd ed.)
  Publisher: Packt Publishing Ltd.
  Author   : Yuxing Yan
  Date     : 6/6/2017
  email    : yany@canisius.edu
             paulyxy@hotmail.com
"""

from scipy import log,exp,sqrt,stats
#
tiny=1e-9
S=40
X=40
T=0.5
r=0.01
sigma=0.2

def bsCall(S,X,T,r,sigma):
    d1=(log(S/X)+(r+sigma*sigma/2.)*T)/(sigma*sqrt(T))
    d2 = d1-sigma*sqrt(T)
    return S*stats.norm.cdf(d1)-X*exp(-r*T)*stats.norm.cdf(d2)

def delta1(S,X,T,r,sigma):
    d1=(log(S/X)+(r+sigma*sigma/2.)*T)/(sigma*sqrt(T))
    return stats.norm.cdf(d1)

def delta2(S,X,T,r,sigma):
    s1=S
    s2=S+tiny
    c1=bsCall(s1,X,T,r,sigma)
    c2=bsCall(s2,X,T,r,sigma)
    delta=(c2-c1)/(s2-s1)
    return delta

print("delta (close form)=", delta1(S,X,T,r,sigma))
print("delta (tiny number)=", delta2(S,X,T,r,sigma))


import numpy as np

### Function def
def sigmoid(x):
    """Sigmoid function"""
    return 1 / (1 + np.exp(-x))

def stable_log(x):
    """A more stable version of the log"""
    eps = 1e-15
    return np.log(x + eps)

### Loss functions
def compute_loss_ls(y, tx, w):
    """Computes the loss of the least squares"""
    N = len(y)
    e = y - tx @ w
    loss = 1/(2*N) * e.T @ e

    return loss

def compute_loss_ce(y, tx, w):
    """Computes the cross entropy loss for the sigmoid function"""
    eps = 1e-15
    N = len(y)
    Z = tx @ w
    y_ = sigmoid(Z)
    pos_mask = y > 0

    loss = -(1/N) * (stable_log(y_[pos_mask]).sum() + stable_log(1 - y_[~pos_mask]).sum())

    return loss

def compute_loss_reg_ce(y, tx, w, lambda_):
    """Loss of the regularised cross entropy"""
    return compute_loss_ce(y, tx, w)  + lambda_/2 * np.linalg.norm(w)**2

### Gradient of loss functions
def compute_gradient_ls(y, tx, w):
    '''Gradient of least squares'''
    N = len(y)
    e = y - tx @ w
    gradient = -(1/N) * tx.T @ e

    return gradient

def compute_gradient_logreg(y, tx, w):
    '''Gradient of logistic regression with cross entropy loss'''

    N = len(y)
    e = sigmoid(tx @ w) - y
    gradient = tx.T @ e

    return gradient

def compute_gradient_reg_logreg(y, tx, w, lambda_):
    '''Gradient of regularised logistic regression with cross entropy loss'''
    usual_grad = compute_gradient_logreg(y, tx, w)

    return usual_grad + lambda_*w


import numpy as np
from autodiff import jacobian, sin
def linfit(x, y, yerr=None):
    """
    Solves the linear least squares. That is solves the linear system

    A*p=y where A = [x 1]

    Using the QR-decomposition A=QR, the optimal b can be estimated as
    p = R^(-1)*Q^T*y
    """

    N = len(x)
    #If no errors specified, just set them all to 1
    if yerr is None:
        yerr = np.ones((N,1), dtype=np.float64)
    yerr = yerr.reshape(N,1)

    x = x.reshape(N,1)
    #W = np.matrix(np.diag(1/(yerr.flatten())))

    A = np.matrix(np.hstack((x,np.ones((N,1)))))
    #We want to calculate W*A, but W is just a diagonal matrix. If we just elementwise multiply the diagonal and A, this will be much faster
    #Q, R = np.linalg.qr(W*A)
    Q, R = np.linalg.qr(np.multiply(yerr,A))

    #Create these as matricies to make the multiplication prettier
    Q, R, y = np.matrix(Q), np.matrix(R), y.reshape(N,1)

    #Again, W*y is horribly inefficient. Just multiply yerr and y elementwise. Since they both are ndarrays, we can just * them to do this
    #p = R**(-1)*Q.T*W*y
    p = (R**(-1)*Q.T)*(yerr*y)

    chi2 = float(sum(np.power((y-x*p[0]+p[1]),2)/(yerr**2)))
    dof = N-1
    chi2_red = chi2/dof

    return {'p':p, 'chi2_red':chi2_red, 'f': lambda x: f(x, p)}

def nonlinfit(f, x, y, p, yerr=None, tol=1e-11, maxiter=50):
    """
    Finds the best parameters using least squares

    If J is the jacobian, W the weight, and Q*R=WJ the qr-decomposition, then the update vector p' is
    p' = R^-1 * Q^T* (y-f(x,p)).

    This is then used to update the estimate for the parameter p_i+1 = p_i + p'
    """

    if isinstance(f, str):
        f = eval('lambda x,p: '+ f)

    N = len(x)
    num_param = len(p)

    #Convert all input to numpy arrays of specific type and shape
    y = np.asarray(y, dtype=np.float64).reshape(N, 1)
    x = np.asarray(x, dtype=np.float64).reshape(N, 1)
    p = np.asarray(p, dtype=np.float64).reshape(num_param,1)

    #If no errors specified, just set them all to 1
    if yerr is None:
        yerr = np.ones((N,1), dtype=np.float64)
    yerr = yerr.reshape(N,1)

    chi2 = sum(np.power((y-f(x,p)),2)/(yerr**2))
    dof = N-num_param
    chi2_red = chi2/dof

    for _ in range(maxiter):
        delta_y = y-f(x,p)
        J = jacobian(f, x, p)

        #We want to calculate W*J, but W is just a diagonal matrix. If we just elementwise multiply the diagonal and J, this will be much faster
        #Q, R = np.linalg.qr(W*J)
        Q, R = np.linalg.qr(np.multiply(yerr,J))

        #Create these as matricies to make multiplication prettier
        Q, R, J = np.matrix(Q), np.matrix(R), np.matrix(J)

        #Again, W*delta_y is horribly inefficient. Just multiply yerr and delta_y elementwise. Since they both are ndarrays, we can just * them to do this
        #p = p + R**(-1)*Q.T*W*delta_y
        p = p + (R**(-1)*Q.T) * (yerr*delta_y)

        #p need to be in the right format
        p=np.asarray(p)

        #Check for convergence
        chi2_tmp = float(sum(np.power((y-f(x,p)),2)/(yerr**2)))
        chi2_red_tmp = chi2_tmp/(N-num_param)
        diff = abs(chi2_red-chi2_red_tmp)
        print("reduced chi2 = %0.4E   diff = %0.4E"%(chi2_red_tmp, diff))
        if diff<tol:
            print("Converged!")
            return {'p':p, 'chi2_red':chi2_red_tmp, 'f': lambda x: f(x, p)}

        #Update chi2 value, and print progress
        chi2_red = chi2_red_tmp

    print("Hit max number of iterations without converging!!")
    return {'p':p, 'chi2_red':chi2_red_tmp, 'f': lambda x: f(x, p)}

if __name__ == "__main__":
    def f(x,p):
        return p[0]*(x**2) + p[1]*x+p[2]*sin(x)

    x = np.arange(0,100,1/10)
    y = f(x,[3,5,1000]) + np.random.normal(0,1,len(x))

    pp=nonlinfit(f,x,y,[2,7,1000])


import numpy as np
import pandas as pd
from scipy.optimize import root
from scipy.integrate import odeint
from __future__ import division
from scipy import *
from pylab import *
import matplotlib.pyplot as plt
#%matplotlib inline

xo = 0.5
gamma = 0.8
yr = 0.1 #kg kgCO2 −1
TAO = 15

# en la matriz parametros se define cada conbinación (xk, A) como una fila de la matriz
parametros = np.array([[0.1, 1],[0.3, 2],[0.4, 4]])
parametros

def intervalosExtraccion(tao, xk, A):
    tao1 = (xo - xk) / (gamma * A * yr)
    tao2 = tao1 + xk / (gamma * A * yr) * np.log(xk / xo + (1 - xk / xo) * np.exp(xo / xk * A))
    zk = xk / (A * xo) * np.log((xo * np.exp(gamma * A * yr / xk * (tao - tao1)) - xk) / (xo - xk))

    return tao1, tao2, zk

def modeloLack(tao, xk, A):

    tao1, tao2, zk = intervalosExtraccion(tao, xk, A)

    if tao <= tao1 and tao < tao2:
        e = gamma * yr* tao * (1- np.exp(- A))
        print("tao < tao1 and tao < tao2")
        return e
    if tao > tao1 and tao <= tao2:
        zk = xk / (A * xo) * np.log((xo * np.exp(gamma * A * yr / xk * (tao - tao1)) - xk) / (xo - xk))
        e = gamma * yr * (tao - tao1 * np.exp(- A * (1 - zk)))
        print("tao >= tao1 and tao < tao2")
        return e
    if tao > tao2:
        e = xo - xk / A * np.log(1 + xk / xo * (np.exp(xo / xk * A) - 1) * np.exp(gamma * A * yr / xk * (tao1 - tao)))
        print("tao >= tao2")
        return e

rendimiento = [[modeloLack(tao, xk, A) for tao in np.linspace(0,TAO)] for xk, A in parametros]

def graficarLack():

	Tao = np.linspace(0,TAO)
	# plt.plot(Tao, caso1[2],label="xk=0.3")
	# plt.plot(Tao,caso2[2],label="xk=0.1")
	# plt.plot(Tao,caso3[2],label="xk=0.4")

	plt.plot(Tao, rendimiento[0],label="xk=0.3")
	plt.plot(Tao, rendimiento[1],label="xk=0.1")
	plt.plot(Tao, rendimiento[2],label="xk=0.4")
	plt.title("Modelo Lack")
	plt.xlabel(" $tao $ ")
	plt.ylabel("Rendimiento e")
	plt.legend()

	return 0


# -*- coding: UTF-8 -*-
import os
import numpy as np
def zeroMean(dataMat):
	meanVal = np.mean(dataMat, axis = 0)
	newData = dataMat - meanVal
	return newData,meanVal

def eigValPct(eigVals,percentage):
    sortArray = np.sort(eigVals)
    sortArray = sortArray[-1::-1]
    arraySum = np.sum(sortArray)
    tmpSum = 0
    num = 0
    for i in sortArray:
        tmpSum += i
        num += 1
        if tmpSum >= arraySum * percentage:
            return num

def pca(dataMat,percentage=0.95):
	meanRemoved, meanVals = zeroMean(dataMat)
	covMat = np.cov(meanRemoved,rowvar=0)
	eigVals, eigVects = np.linalg.eig(np.mat(covMat))
	k = eigValPct(eigVals,percentage)
	eigValInd = np.argsort(eigVals)
	eigValInd = eigValInd[-1:-(k+1):-1]
	redEigVects = eigVects[:,eigValInd]
	lowDDataMat = meanRemoved * redEigVects
	reconMat = (lowDDataMat * redEigVects.T) + meanVals
	return lowDDataMat, reconMat

def readData(filename):
	with open(filename, 'r') as f:
		f.readline()
		stringArr = [line.strip().split('\t')[1:] for line in f.readlines()]
		dataArr = [map(float, line) for line in stringArr]
		return np.mat(dataArr).T
def format(value):
    return "%.5f" % value

def writeData(filename, feature):
	feature = np.array(feature)
	formatted = [[format(v) for v in r] for r in feature]
	with open(filename, 'w') as f:
		for i in range(feature.shape[0]):
			for j in range(feature.shape[1]):
				f.write(formatted[i][j])
				f.write('\t')
			f.write('\n')

def check(filename):
	with open(filename, 'r') as f:
		f.readline()
		types = [line.strip().split('\t')[1] for line in f.readlines()]
	classType = list()
	for type in types:
		if type not in classType:
			classType.append(type)
	return classType

if __name__ == '__main__':
	filename = '../data/microarray.original.txt'
	#filename = '../data/finalData.txt'
	#filename = '../data/processedData_0.95.txt'
	labelfile = '../data/E-TABM-185.sdrf.txt'
	classType = check(labelfile)
	print "The number of class is {}".format(len(classType))
	print classType
	feature = readData(filename)
	print "Finish reading the data. The number is {}. The dimensions of feature are {}".format(feature.shape[0], feature.shape[1])
	filename = '../data/processedData_0.85.txt'
	new_feature, _ = pca(feature, 0.85)
	print "Feature is reduced to {} dimensions.".format(new_feature.shape[1])
	writeData(filename, new_feature)
	print "New feature has been written. The number is {}. The new dimensions are {}".format(new_feature.shape[0], new_feature.shape[1])


import numpy as np

def forrester(x: np.ndarray):
    """The forrester function.

    Parameters
    ----------
    x : np.ndarray of shape (n_samples, 1)
        The input locations.

    Returns
    -------
    np.ndarray of shape (n_samples,)
        The function values at `x`.
    """
    return ((6 * x - 2) ** 2 * np.sin(12 * x - 4)).flatten()

def bohachevsky(x: np.ndarray):
    """The bohachevsky function.

    Parameters
    ----------
    x : np.ndarray of shape (n_samples, 2)
        The input locations.

    Returns
    -------
    np.ndarray of shape (n_samples,)
        The function values at `x`.
    """
    x1 = x[:, 0]
    x2 = x[:, 1]

    return (
        x1 ** 2
        + 2 * x2 ** 2
        - 0.3 * np.cos(3 * np.pi * x1)
        - 0.4 * np.cos(4 * np.pi * x2)
        + 0.7
    )


# nelder-mead for multimodal function optimization
from scipy.optimize import minimize
from numpy.random import rand
from numpy import exp
from numpy import sqrt
from numpy import cos
from numpy import e
from numpy import pi

# objective function
def objective(v):
	x, y = v
	return -20.0 * exp(-0.2 * sqrt(0.5 * (x**2 + y**2))) - exp(0.5 * (cos(2 * pi * x) + cos(2 * pi * y))) + e + 20

# define range for input
r_min, r_max = -5.0, 5.0
# define the starting point as a random sample from the domain
pt = r_min + rand(2) * (r_max - r_min)
# perform the search
result = minimize(objective, pt, method='nelder-mead')
# summarize the result
print('Status : %s' % result['message'])
print('Total Evaluations: %d' % result['nfev'])
# evaluate solution
solution = result['x']
evaluation = objective(solution)
print('Solution: f(%s) = %.5f' % (solution, evaluation))


import sympy
from sympy.utilities import lambdify

# f(x) = (x**2 -2x)e**(3-x)

x = sympy.symbols('x')

f = (x**2 - 2*x)*sympy.exp(3 - x)

# differentiate
fp = sympy.simplify(sympy.diff(f))  # (x*(2 - x) + 2*x - 2)*exp(3 - x)

# Check differentiate mually
fp2 = (2*x - 2)*sympy.exp(3 - x) - (x**2 - 2*x)*sympy.exp(3 - x)
sympy.simplify(fp2 - fp) == 0  # True

# integrate
F = sympy.integrate(f, x)  # -x**2*exp(3 - x)

# This converts a SymPy expression to a numerical expression that uses the NumPy
# equivalents of the SymPy standard functions to evaluate the expressions numerically
lam_f = lambdify(x, f)
lam_fp = lambdify(x, fp)


# coding: utf-8
# linear_regression/regression.py
import numpy as np
import matplotlib as plt
import time

# compute execution time
def exeTime(func):
    def newFunc(*args, **args2):
        t0 = time.time()
        back = func(*args, **args2)
        return back, time.time() - t0
    return newFunc

# h(x)
def h(theta, x):
    return (theta.T*x)[0,0]

# cost function
def J(theta, X, y):
    m = len(X)
    return (X*theta-y).T*(X*theta-y)/(2*m)

# gradient descent optimizer function
@exeTime
def gradientDescentOptimizer(rate, maxLoop, epsilon, X, y):
    """
    Args:
    rate: learning rate
    maxLoop: maximum iteration number
    epsilon: precision

    Returns:
        (theta, errors, thetas), timeConsumed
    """
    m,n = X.shape
    # initialize theta
    theta = np.zeros((n,1))
    count = 0
    converged = False
    error = float('inf')
    errors = []
    thetas = {}
    for j in range(n):
        thetas[j] = [theta[j,0]]
    while count<=maxLoop:
        if(converged):
            break
        count = count + 1
        for j in range(n):
            ############################################
            # YOUR CODE HERE!
            # deriv = ??
            deriv = -(X*theta-y).T*X[:, j]/m
            ############################################
            theta[j,0] = theta[j,0]+rate*deriv
            thetas[j].append(theta[j,0])
        error = J(theta, X, y)
        errors.append(error[0,0])
        if(error < epsilon):
            converged = True
    return theta,errors,thetas

# standarize function
def standarize(X):
    m, n = X.shape
    # normalize each feature
    for j in range(n):
        features = X[:,j]
        meanVal = features.mean(axis=0)
        std = features.std(axis=0)
        if std != 0:
            X[:, j] = (features-meanVal)/std
        else:
            X[:, j] = 0
    return X


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

style.use('ggplot')

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

# noinspection PyPep8Naming,PyShadowingNames
def best_fit_slope_finder(features, labels):
    m = (((mean(XS) * mean(YS)) - mean(XS * YS)) /
         ((mean(XS) ** 2) - (mean(XS * XS))))
    return m

def y_intercept_finder(features, labels):
    b = (mean(YS) - m * mean(XS))
    return b

def squared_error(point, line):
    return sum((line - point) ** 2)

def coefficient_of_determination(point, line):
    global y_mean_line
    y_mean_line = [mean(point) for i in point]
    squared_error_regression = squared_error(point, line)
    squared_error_y_mean = squared_error(point, y_mean_line)
    return 1 - (squared_error_regression / squared_error_y_mean)

# noinspection PyPep8Naming,PyPep8Naming
def create_dataSet(hm, variance, step=2, correlation=False):
    val = 1
    # noinspection PyPep8Naming
    YS = []
    for i in range(hm):
        data = val + random.randrange(-variance, variance)
        YS.append(data)
        if correlation and correlation == 'pos':
            val += step
        elif correlation and correlation == 'neg':
            val -= step
    XS = [i for i in range(len(YS))]
    return np.array(XS, dtype=np.float64), np.array(YS, dtype=np.float64)

XS, YS = create_dataSet(1000, 500, 7, correlation='pos')

m = best_fit_slope_finder(XS, YS)

b = y_intercept_finder(XS, YS)

# Gets coordinates for best fit line plot
regression_line = []
for i in XS:
    ordinate = (m * i + b)
    regression_line.append(ordinate)

# Predictions
predict_x = np.array([120, 30, 92], dtype=np.float64)
predictions = []
for j in predict_x:
    predict_ordinate = (m * predict_x + b)
    predictions.append(predict_ordinate)

r_squared = coefficient_of_determination(YS, regression_line)

# Output:
print('Slope = ', m, 'Y intercept = ', b, 'Ordinates =', regression_line, 'Predict_Ordinates = ',
      predictions, 'R^2 = ', r_squared, sep='\n')

plt.scatter(XS, YS, color='b', label='data')
plt.scatter(predict_x, predict_ordinate, color='g', label='prediction')
plt.plot(XS, regression_line, label='regression_line')
plt.plot(YS, y_mean_line, label='y_mean_line')
plt.legend(loc=4)
plt.show()


import math
import numpy as np

from awesomediff.core import variable

def sin(x):
    """
        Helper function that calculates the sin of a variable or number.

        INPUTS:
            x : awesomediff.variable object or a number.

        OUTPUT:
            awesomediff.variable
    """

    try:
        # Assume object is a variable:
        val = x.val
        der = x.der
    except:
        # If not, treat it as a constant.
        try:
            float(x)
        except:
            raise ValueError("{} is not a number.".format(x))
        val = x
        der = 0  # Derivative of a constant is zero.
    # Calculate new value an derivative:
    new_val = np.sin(val)
    new_der = np.cos(val)*der
    # Return variable with new value an derivative:
    return variable(val=new_val,der=new_der)

def cos(x):
    """
        Helper function that calculates the sin of a variable or number.

        INPUTS:
            x : awesomediff.variable object or a number.

        OUTPUT:
            awesomediff.variable
    """

    try:
        # Assume object is a variable:
        val = x.val
        der = x.der
    except:
        # If not, treat it as a constant.
        try:
            float(x)
        except:
            raise ValueError("{} is not a number.".format(x))
        val = x
        der = 0  # Derivative of a constant is zero.
    # Calculate new value an derivative:
    new_val = np.cos(val)
    new_der = -np.sin(val)*der
    # Return variable with new value an derivative:
    return variable(val=new_val,der=new_der)

def tan(x):
    """
        Helper function that calculates the sin of a variable or number.

        INPUTS:
            x : awesomediff.variable object or a number.

        OUTPUT:
            awesomediff.variable
    """

    try:
        # Assume object is a variable:
        val = x.val
        der = x.der
    except:
        # If not, treat it as a constant.
        try:
            float(x)
        except:
            raise ValueError("{} is not a number.".format(x))
        val = x
        der = 0  # Derivative of a constant is zero.
    # Calculate new value an derivative:
    new_val = np.tan(val)
    new_der = ((1/np.cos(val))**2)*der
    # Return variable with new value an derivative:
    return variable(val=new_val,der=new_der)

def arcsin(x):
    """
        Helper function that calculates the arcsine of a variable or number.

        INPUTS:
            x : awesomediff.variable object or a number.

        OUTPUT:
            awesomediff.variable
    """
    try:
        # Assume object is a variable:
        val = x.val
        der = x.der
    except:
        # If not, treat it as a constant.
        try:
            float(x)
        except:
            raise ValueError("{} is not a number.".format(x))
        val = x
        der = 0  # Derivative of a constant is zero.
    # Calculate new value an derivative:
    new_val = np.arcsin(val)
    if(np.isnan(new_val)):
        raise ValueError("Please enter a number on the unit circle.")

    # if (np.sqrt(1-val**2)==0):
    #     new_der = 0
    # else:
    #     new_der = 1/np.sqrt(1-val**2)*der
    # print("new val", new_val)
    new_der = 1/np.sqrt(1-val**2)*der
    # Return variable with new value an derivative:
    return variable(val=new_val,der=new_der)

def arccos(x):
    """
        Helper function that calculates the arccos of a variable or number.

        INPUTS:
            x : awesomediff.variable object or a number.

        OUTPUT:
            awesomediff.variable
    """
    try:
        # Assume object is a variable:
        val = x.val
        der = x.der
    except:
        # If not, treat it as a constant.
        try:
            float(x)
        except:
            raise ValueError("{} is not a number.".format(x))
        val = x
        der = 0  # Derivative of a constant is zero.
    # Calculate new value an derivative:
    new_val = np.arccos(val)
    # print("new val", new_val)
    if(np.isnan(new_val)):
        raise ValueError("Please enter a number on the unit circle.")

    # if (np.sqrt(1-val**2)==0):
    #     new_der = 0
    # else:
    #     new_der = -1/np.sqrt(1-val**2)*der

    new_der = -1/np.sqrt(1-val**2)*der
    # Return variable with new value an derivative:
    return variable(val=new_val,der=new_der)

def arctan(x):
    """
        Helper function that calculates the arctan of a variable or number.

        INPUTS:
            x : awesomediff.variable object or a number.

        OUTPUT:
            awesomediff.variable
    """
    try:
        # Assume object is a variable:
        val = x.val
        der = x.der
    except:
        # If not, treat it as a constant.
        try:
            float(x)
        except:
            raise ValueError("{} is not a number.".format(x))
        val = x
        der = 0  # Derivative of a constant is zero.
    # Calculate new value an derivative:
    new_val = np.arctan(val)
    if(np.isnan(new_val)):
        raise ValueError("Please enter a number on the unit circle.")
    new_der = 1/(1+val**2)*der
    # Return variable with new value an derivative:
    return variable(val=new_val,der=new_der)

def log(x):
    """
        Helper function that calculates the natural log of a variable or number.

        INPUTS:
            x : AutoDiff.variable object or a number.

        OUTPUT:
            AutoDiff.variable
    """
    try:
        # x.val = np.log(x.val)
        # x.der = (1/x.val)*x.der
        new_val = np.log(x.val)
        new_der = (1/x.val)*x.der
        # return x
        return variable(val=new_val,der=new_der)
    except:
        new_val = np.log(x)
        new_der = 0
        return variable(val=new_val,der=new_der)

def logb(x, b):
    """
        Helper function that calculates the log of a variable or number with any base.

        INPUTS:
            x : AutoDiff.variable object or a number.
            b: a number

        OUTPUT:
            AutoDiff.variable
    """
    try:
        new_val = np.log(x.val)/np.log(b)
        new_der = (1/(np.log(b)*x.val))*x.der
        return variable(val=new_val,der=new_der)
    except:
        new_val = np.log(x)/np.log(b)
        new_der = 0
        return variable(val=new_val,der=new_der)

def sqrt(x):
    """
        Helper function that calculates the square root of a variable or number.

        INPUTS:
            x : AutoDiff.variable object or a number.

        OUTPUT:
            AutoDiff.variable
    """
    try:
        new_val = np.sqrt(x.val)
        new_der = (0.5/np.sqrt(x.val))*x.der
        return variable(val=new_val,der=new_der)
    except:
        new_val = np.sqrt(x)
        new_der = 0
        return variable(val=new_val,der=new_der)

def exp(x):
    """
        Helper function that calculates the exponential of a variable or number.

        INPUTS:
            x : AutoDiff.variable object or a number.

        OUTPUT:
            AutoDiff.variable
    """
    try:
        new_val = np.exp(x.val)
        new_der = np.exp(x.val)*x.der
        return variable(val=new_val,der=new_der)
    except:
        new_val = np.exp(x)
        new_der = 0
        return variable(val=new_val,der=new_der)

def sinh(x):
    """
        Helper function that calculates hyperbolic sine of a variable or number

        INPUTS:
            x : AutoDiff.variable object or a number.

        OUTPUT:
            AutoDiff.variable
    """
    return (exp(x) - exp(-x)) / 2

def cosh(x):
    """
        Helper function that calculates hyperbolic cosine of a variable or number

        INPUTS:
            x : AutoDiff.variable object or a number.

        OUTPUT:
            AutoDiff.variable
    """
    return (exp(x) + exp(-x)) / 2

def tanh(x):
    """
        Helper function that calculates hyperbolic tangent of a variable or number

        INPUTS:
            x : AutoDiff.variable object or a number.

        OUTPUT:
            AutoDiff.variable
    """
    return sinh(x) / cosh(x)

def logistic(x, L=1, k=1, x0=1):
    """
        Helper function that calculates the logistic of a variable or number.

        INPUTS:
            x : AutoDiff.variable object or a number.

        OUTPUT:
            AutoDiff.variable
    """
    try:
        val = x.val
        der = x.der
        logistic = L/(1+np.exp(-k*(val-x0)))
        new_val = logistic
        new_der = logistic*(1-logistic)*der
        return variable(val=new_val,der=new_der)
    except:
        new_val = L/(1+np.exp(-k*(x-x0)))
        new_der = 0
        return variable(val=new_val,der=new_der)