#!/usr/bin/env python

from neml.math import matrix

import common

import unittest
import numpy as np

class TestVector(unittest.TestCase):
  def setUp(self):
    self.a_data = [1.0,1.1,2.3]
    self.a = matrix.FlatVector(self.a_data)

  def test_definition(self):
    self.assertTrue(np.allclose(self.a_data, self.a))

  def test_size(self):
    self.assertEqual(self.a.n, len(self.a_data))

class TestBasicMatrix(unittest.TestCase):
  def setUp(self):
    self.np_mat = np.array([[2.0,3.0,1.0],[7.1,3.1,-1.0],[2.0,-1.2,8.1]])
    self.M = matrix.SquareMatrix(3, type = "dense",
        data = list(self.np_mat.flatten()))

  def test_definition(self):
    self.assertTrue(np.allclose(self.np_mat, self.M))

  def test_size(self):
    self.assertEqual(self.M.m, self.np_mat.shape[0])
    self.assertEqual(self.M.n, self.np_mat.shape[1])

  def test_index(self):
    for i in range(3):
      for j in range(3):
        self.assertAlmostEqual(self.M(i,j), self.np_mat[i,j])

class TestMatVec(unittest.TestCase):
  def setUp(self):
    self.a_data = [1.0,1.1,2.3]
    self.a = matrix.FlatVector(self.a_data)

    self.b_data = [-8.0,1.1,2.2,3.3]
    self.b = matrix.FlatVector(self.b_data)

    self.M_data = np.array([[2.0,3.0,1.0],[7.1,3.1,-1.0],[2.0,-1.2,8.1]])
    self.M = matrix.SquareMatrix(3, type = "dense",
        data = list(self.M_data.flatten()))

  def test_correct(self):
    self.assertTrue(np.allclose(self.M.dot(self.a), np.dot(self.M_data,
      self.a_data)))

  def test_bad_size(self):
    with self.assertRaises(ValueError):
      self.M.dot(self.b)

class TestMatDefinition(unittest.TestCase):
  def test_zero(self):
    self.assertTrue(np.allclose(matrix.SquareMatrix(4), np.zeros((4,4))))

  def test_identity(self):
    self.assertTrue(np.allclose(matrix.SquareMatrix(4, type = "identity"),
      np.eye(4)))

  def test_diagonal(self):
    self.assertTrue(np.allclose(matrix.SquareMatrix(4, type = "diagonal",
      data = [1,2,3,4]), np.diag([1,2,3,4])))

  def test_block_diagonal(self):
    self.assertTrue(np.allclose(matrix.SquareMatrix(4, type = "diagonal_blocks",
      data = [1,2], blocks = [3,1]), np.array([
        [1,0,0,0],
        [0,1,0,0],
        [0,0,1,0],
        [0,0,0,2]])))

  def test_blocks(self):
    self.assertTrue(np.allclose(matrix.SquareMatrix(4, type = "block",
      data = [1,2,3,4], blocks=[3,1]),
      np.array([
        [1,1,1,2],
        [1,1,1,2],
        [1,1,1,2],
        [3,3,3,4]])))


import numpy as np

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

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

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

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

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

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

    return (intRef, d)

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

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

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

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

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


from numpy import *
import numpy as np

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

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

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

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


#! /usr/bin/env python

"""
File: integrate_exp.py

Copyright (c) 2016 Taylor Patti

License: MIT

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

"""

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

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

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

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

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


Table of Contents

1  Vectors and Matrices

1.1  Vectors

1.2  Matrix

1.3  Matrix Order

1.4  Create a  matrix using matrix()

1.5  Create a using array()

1.6  Matrix Properties

1.7  Shape

1.8  Size

1.9  Modifying matrix using insert()

1.10  Modifying matrix using index

1.11  Matrix Operations

1.11.1  Addition

1.11.2  Subtraction

1.11.3  Transpose

1.11.4  Multiplication

1.11.5  Element-wise multiplication

1.11.6  Division

1.12  References

# Vectors and Matrices

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

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

# Load NumPy Library
import numpy as np

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

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

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

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

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

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

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

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

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

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

## Matrix Properties

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

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

# shape
mat3.shape

# rows
mat3.shape[0]

# columns
mat3.shape[1]

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

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

# size
mat4.size

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

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

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

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

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

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

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

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

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

# show mat_a
print(mat_a)

# extract 2nd row
mat_a[1, :]

# extract 3rd column
mat_a[:, 2]

# extract elements
mat_a[1, 2]

## Matrix Operations

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

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

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

# addition
np.add(A, B)

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

# subtraction
np.subtract(A,B)

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

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

# transpose
np.transpose(A)

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

# multiplication
np.dot(A,B)

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

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

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

# using matmul
np.matmul(A, T)

# using @ operator
A @ T

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

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

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

# division
np.divide(A, B)

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

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


import numpy as np
import matplotlib.pyplot as plt

from scipy import integrate

import numba
from numba import jit

u_inf = 1

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

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

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

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

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

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

plt.show()

class Panel:

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

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

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

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

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

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

        elif xb - xa > 0.0:

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

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

N_panels = 10

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

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

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

plt.show()

def integral_normal(p_i, p_j):

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

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

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

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

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

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

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

def integral_tangential(p_i, p_j):

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

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

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

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

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

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

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

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

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

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

plt.show()

import numpy,from scipy,import numba,from numba


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

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

"""
import numpy as np

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

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

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

if __name__ == '__main__':

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


import numpy as np
from prml.nn.tensor.constant import Constant
from prml.nn.tensor.tensor import Tensor
from prml.nn.function import Function

class Softplus(Function):

    def forward(self, x):
        x = self._convert2tensor(x)
        self.x = x
        output = np.maximum(x.value, 0) + np.log1p(np.exp(-np.abs(x.value)))
        if isinstance(x, Constant):
            return Constant(output)
        return Tensor(output, function=self)

    def backward(self, delta):
        dx = (np.tanh(0.5 * self.x.value) * 0.5 + 0.5) * delta
        self.x.backward(dx)

def softplus(x):
    """
    smoothed rectified linear unit
    log(1 + exp(x))
    """
    return Softplus().forward(x)


import numpy as np
from typing import List
from puffmarker.domain.datapoint import DataPoint
from numpy.linalg import norm

def magnitude(data: List[DataPoint]):

    input_sample = np.array([i.sample for i in data])

    mag_sample = norm(input_sample, axis=1).tolist()

    result = [DataPoint(start_time=v.start_time, offset=v.start_time, sample=mag_sample[i]) for i, v in enumerate(data)]

    return result

def smooth(data: List[DataPoint],
           span: int = 5) -> List[DataPoint]:

    """
    Smooths data using moving average filter over a span.
    The first few elements of data_smooth are given by
    data_smooth(1) = data(1)
    data_smooth(2) = (data(1) + data(2) + data(3))/3
    data_smooth(3) = (data(1) + data(2) + data(3) + data(4) + data(5))/5
    data_smooth(4) = (data(2) + data(3) + data(4) + data(5) + data(6))/5

    for more details follow the below links:
    https://www.mathworks.com/help/curvefit/smooth.html
    http://stackoverflow.com/a/40443565

    :return: data_smooth
    :param data:
    :param span:
    """

    if data is None or len(data) == 0:
        return []

    sample = [i.sample for i in data]
    sample_middle = np.convolve(sample, np.ones(span, dtype=int), 'valid') / span
    divisor = np.arange(1, span - 1, 2)
    sample_start = np.cumsum(sample[:span - 1])[::2] / divisor
    sample_end = (np.cumsum(sample[:-span:-1])[::2] / divisor)[::-1]
    sample_smooth = np.concatenate((sample_start, sample_middle, sample_end))

    data_smooth = []

    if len(sample_smooth) == len(data):
        for i, item in enumerate(data):
            dp = DataPoint.from_tuple(sample=sample_smooth[i], start_time=item.start_time, end_time=item.end_time)
            data_smooth.append(dp)
    else:
        raise Exception("Smoothed data length does not match with original data length.")

    return data_smooth

def moving_average_curve(data: List[DataPoint],
                         window_length: int) -> List[DataPoint]:
    """
    Moving average curve from filtered (using moving average) samples.

    :return: mac
    :param data:
    :param window_length:
    """
    if data is None or len(data) == 0:
        return []

    sample = [i.sample for i in data]
    mac = []
    for i in range(window_length, len(sample) - (window_length + 1)):
        sample_avg = np.mean(sample[i - window_length:i + window_length + 1])
        mac.append(DataPoint.from_tuple(sample=sample_avg, start_time=data[i].start_time, end_time=data[i].end_time))

    return mac


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

@author: lijie
"""

from numpy import *

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

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

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

if __name__=='__main__' :

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


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

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

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

cookbook/3 Linear Regression/TensorFlow Way.py


#Program to perform cross correlation

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

#input sequences

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

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

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

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

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

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


"""
Use sympy to compute the recurrence relation:

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

Output:

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

import sympy

x = sympy.symbols('x')

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

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

    print("-"*40)

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


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

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

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

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


from random import uniform
from unittest import TestCase

from scipy.stats import norm

from numerical.integration import std_norm_cdf, gauss_quad_2

class IntegrationTest(TestCase):

    def test_cdf_negative_input(self):
        self.assertAlmostEqual(norm.cdf(-1), std_norm_cdf(-1), places=10)

    def test_cdf_zero_input(self):
        self.assertAlmostEqual(norm.cdf(0), std_norm_cdf(0), places=10)

    def test_cdf_positive_input(self):
        self.assertAlmostEqual(norm.cdf(1), std_norm_cdf(1), places=10)

    def test_cdf_one(self):
        self.assertAlmostEqual(norm.cdf(1e8), std_norm_cdf(1e8), places=10)

    def test_cdf_zero(self):
        self.assertAlmostEqual(norm.cdf(-1e8), std_norm_cdf(-1e8), places=10)

    def test_cdf_half(self):
        self.assertAlmostEqual(0.5, std_norm_cdf(0), places=10)

    def test_cdf_minus_three(self):
        self.assertAlmostEqual(norm.cdf(-3), std_norm_cdf(-3), places=10)

    def test_cdf_three(self):
        self.assertAlmostEqual(norm.cdf(3), std_norm_cdf(3), places=10)

    def test_cdf_rand(self):
        for _ in range(1000):
            x = uniform(-1e8, 1e8)
            self.assertAlmostEqual(norm.cdf(x), std_norm_cdf(x), places=10)

    def test_gauss_quad_2(self):
        self.assertEqual(gauss_quad_2(lambda x: x ** 2, -1, 1), 2 / 3)
        self.assertEqual(gauss_quad_2(lambda x: x ** 3, -1, 1), 0)

        def f(x): return x ** 3 - x ** 2 + x - 1
        self.assertEqual(gauss_quad_2(f, -1, 1), - 8 / 3)


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

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

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

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

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

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

        C = t

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

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

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

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

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

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

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

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


# coding: utf-8

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

# In[1]:

get_ipython().magic('matplotlib inline')

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

# In[2]:

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

# In[3]:

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

# In[4]:

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

# In[5]:

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

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

# In[6]:

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

# In[7]:

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

# In[8]:

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

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

    return m, real_range, imaginary_range

# In[9]:

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

# In[10]:

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

# In[11]:

from numba import jit

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

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

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

    return m, real_range, imaginary_range

# In[12]:

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

# In[13]:

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

# In[14]:

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

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

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

# In[15]:

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

# In[16]:

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

# In[17]:

get_ipython().magic('load_ext Cython')

# In[18]:

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

# In[19]:

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

# In[20]:

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

# In[ ]:

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

# In[ ]:


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

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

from utils import timing_decorator, find_divisors
import numpy as np

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

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

tiangle_divisor_count(500)


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

    #Approximates root using Newton's Method
    #Recursive Program

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

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

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

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

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

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

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

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


# 행렬의 곱셈

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

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

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

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


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

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

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

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

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

    return py_mean

def find_median(data_lst):

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

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

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

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

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

    return median

def find_mode(data_lst):

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

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

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

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

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

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

    return py_mode

def find_variance(data_lst, population=True):

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

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

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

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

    # The hard way
    mn = find_mean(data_lst)

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

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

    sums = sum(squares)

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

def find_stand_dev(data_lst):

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

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

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

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

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

def bernoulli_pmf(p, n, k):

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

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

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

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

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

    return pmf, ex, varx

def binomial_pmf(p, n, k):

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

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

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

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

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

    return pmf, ex, var

def poisson_pmf(rate, k):

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

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

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

    e = math.e

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

    pmf = numer / denom
    ex = rate
    varx = rate

    return pmf, ex, varx

if __name__ == '__main__':

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

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

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

#


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

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

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

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

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

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

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

print(prob)

print(np.multiply(prob,p))


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

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

from sympy import *  #Importa a biblioteca sympy

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

print(Z1)
print(Z2)

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

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

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

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

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


'''
statstools.py

Statistical tools for analyzing data

author: Bongsoo Suh
created: 2015-03-08

(C) 2015 bongsoos
'''

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

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

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

    return cc[0,1]

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

    R2 = 1 - RSS/SYY

    return R2

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

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

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

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

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

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

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

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

    return C

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

    return eigvec, eigval

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

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

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

    return eigvec, eigval, proj


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

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

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

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

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

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


# A company plans to enclose three parallel rectangular areas for sorting returned goods.
# The three areas are within one large rectangular area and 1400 yd of fencing is available. What is the largest total area that can be enclosed?

from sympy import symbols, solve, diff
import matplotlib.pyplot as plt
import numpy as np

x, y = symbols( 'x y', positive = True )

A = 2*x + 4*y - 1056

y_eq = solve( A, y )[ 0 ]

Ax = y_eq * x

dA = diff( Ax, x )

crit_val = solve( dA, x )[ 0 ]
short_side = y_eq.subs( { x: crit_val } )
total_area = Ax.subs( { x: crit_val } )

if __name__ == '__main__':
	print( 'Shorter Len: {0}'.format( short_side ) )
	print( 'Longer side: {0}'.format( crit_val ) )
	print( 'Total Area: {0}'.format( total_area ) )


import numpy as np

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

    '''

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

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

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

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

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

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

        # translate u by R
        u = u - R

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

# ### Umbilic torus

# In[12]:

def umbilic_torus(u,v):

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

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

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

    return (x,y,z)


import utils
import numpy as np
if __name__ == '__main__':
    # Filtering
    barbara = utils.load_image('barbara.jpg')
    barbara_gray = utils.convert2gray(barbara)
    I1 = np.array([[120, 110, 90, 115, 40],
                   [145, 135, 135, 65, 35],
                   [125, 115, 55, 35, 25],
                   [80, 45, 45, 20, 15],
                   [40, 35, 25, 10, 10]])
    I2 = np.array([[125, 130, 135, 110, 125],
                   [145, 135, 135, 155, 125],
                   [65, 60, 55, 45, 40],
                   [40, 35, 40, 25, 15],
                   [15, 15, 20, 15, 10]])
    filter1 = 1/3 * np.array(np.ones(3)).reshape((1, 3))
    filter2 = 1/3 * np.array(np.ones(3)).reshape((3, 1))
    filter3 = np.array(1/9 * np.ones((3,3)))
    matrix = [I1, I2]
    filters = [filter1, filter2, filter3]
    for i, matrix in enumerate(matrix):
        for j, fil in enumerate(filters):
            res = utils.matrix_filter(matrix, fil, flag=j)
            print(f'#matrix I{i+1} after filter {j+1} is \n {res}')

    # Apply filters
    utils.show_image(barbara_gray, gray=True)
    # cv2.filter2D()
    # See Exercise.m for the implementation of applying filters


__author__ = 'Prateek'
from sympy import isprime

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

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


import numpy as np
import matplotlib.pyplot as plt

from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

# 将Pipeline封装 方便使用
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import PolynomialFeatures

x = np.random.uniform(-5, 5, size=100)  # 生成 x 特征 -5 到 5， 共 100 个
X = x.reshape(-1, 1)                    # 将 x 编程 100 行 1 列的矩阵
y = 0.5 * x ** 2 + x + 2 + np.random.normal(0, 1, size=100)     # 模拟的是标记 y，对应的是 x 的二次函数

# 使用线性回归看下 score
reg = LinearRegression()
reg.fit(X, y)
reg.score(X, y)

# 画图
fig = plt.figure(figsize=(13, 4))

# 将预测值 y_pre 画图 对比真实 y
y_pre = reg.predict(X)
fig.add_subplot(1, 3, 1)
plt.scatter(x, y)
plt.plot(np.sort(x), y_pre[np.argsort(x)], color='r')
plt.title('Under-Fitting')
# plt.show()

# 查看MSE
y1_mse = mean_squared_error(y, y_pre)
print('y1_mse:', y1_mse)

def PolynomialRegression(degree):
    return Pipeline([                                   # 构建 Pipeline
        ("poly", PolynomialFeatures(degree=degree)),    # 构建 PolynomialFeatures
        ("std_scaler", StandardScaler()),               # 构建归一化 StandardScaler
        ("lin_reg", LinearRegression())                 # 构建线性回归 LinearRegression
    ])

# 设置 degree=2 进行 fit 拟合
poly2_reg = PolynomialRegression(2)
poly2_reg.fit(X, y)

# 将预测值 y2_pre 画图 对比真实 y
y2_pre = poly2_reg.predict(X)
fig.add_subplot(1, 3, 2)
plt.scatter(x, y)
plt.plot(np.sort(x), y2_pre[np.argsort(x)], color='r')
plt.title('Just-Right')
# plt.show()

# 求出MSE
y2_mse = mean_squared_error(y2_pre, y)
print('y2_mse:', y2_mse)

# 设置 degree=100 进行 fit 拟合
poly3_reg = PolynomialRegression(100)
poly3_reg.fit(X, y)

# 将预测值 y2_pre 画图 对比真实 y
y3_pre = poly3_reg.predict(X)
fig.add_subplot(1, 3, 3)
plt.scatter(x, y)
plt.plot(np.sort(x), y3_pre[np.argsort(x)], color='r')
plt.title('Over-Fitting')
plt.show()

# 求出MSE
y3_mse = mean_squared_error(y3_pre, y)
print('y3_mse:', y3_mse)


import numpy as np

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

    Dependency: numpy

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

    Author: Joon Lim <powerlim2@gmail.com>

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

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

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

    def summary(self):
        print self.__summary

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

        return self.__beta, self.__mse * 2

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

        return self.__mse

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

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

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

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

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

if __name__ == "__main__":
    main()


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

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

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

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

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

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

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

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

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

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

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

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

    return x, x1, x2, y

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

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

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

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

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

    # plot
    plot_result(x1, y, y_predicted)

if __name__ == '__main__':
    main()


import pandas as pd
import numpy as np

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

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

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

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

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

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

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

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

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

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


# Imports
import numpy as np
import pandas as pd
from sklearn import datasets

# Load iris dataset
iris = datasets.load_iris()
data1 = pd.DataFrame(data=np.c_[iris['data'], iris['target']],
                     columns=iris['feature_names'] + ['target'])

# print(data1)
# print(iris['target_names'])

# Mean gives a strong impression but is impacted by outliers
print(data1.apply(np.mean, axis=0))

# Median isn't as heavily impacted by outliers
print(data1.apply(np.median, axis=0))

# Custom percentiles can give you more information
percentiles = np.percentile(data1["sepal length (cm)"], [10,25,50,75,90])
print(percentiles)

# Calculating the variance 'by hand' and using numpy
# Array of differences to mean: differences
differences = versicolor_petal_length - np.mean(versicolor_petal_length)
diff_sq = differences ** 2

# Compute the mean square difference: this is the 'by hand' method
variance_explicit = np.mean(diff_sq)

# Compute the variance using NumPy: variance_np
variance_np = np.var(versicolor_petal_length)

# Compare the two resulting figures
print(variance_explicit, variance_np)

# Note the same can be done here with the standard deviation
# Print the square root of the variance
print(np.sqrt(variance_np))

# Print the standard deviation
print(np.std(versicolor_petal_length))

# Covariance calculations
# Compute the covariance matrix: covariance_matrix
# Note that where covariance_matrix[i, i] this represents the variance of that variable
covariance_matrix = np.cov(versicolor_petal_length, versicolor_petal_width)
print(covariance_matrix)

# Extract covariance of length and width of petals: petal_cov
petal_cov = covariance_matrix[0, 1]

# Print the length/width covariance
print(petal_cov)

# Specifying ddof=0 means that variance matches np.var(xi)
np.cov(versicolor_petal_length, versicolor_petal_width, ddof=0)


import numpy as np

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

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

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

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

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

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

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

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

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

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

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


# 1. Vectorized Linear algebra
import numpy as np
import time
import functools

x = np.random.randn(1000000)
y = np.random.randn(1000000)

# First versions: simple loop
t1 = time.time()
z1 = sum(x[i] * y[i] for i in range(len(x)))
print("Duration of sum(x[i] * y[i] for i in range(len(x))): {}".format(time.time() - t1))
# 521 ms ± 5.28 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

# Using numpy's dot product
t1 = time.time()
z2 = np.dot(x, y) # elapsed time: 0.0045 seconds
print("Duration of np.dot(x, y): {}".format(time.time() - t1))
# 2.69 ms ± 88.8 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

print("z1 - z2: {}".format(z1 - z2))
# 2.546585164964199e-11

####
# 2. Simulation
# Finding the mean and standard deviatoion of the number of heads after 10000 coin flips
np.random.seed(42)
samples = np.random.randint(0,2,10000)

print("\n\nMean and STD of binomial dist with numpy")

t1 = time.time()
np.mean(samples)
print("Duration of samples.mean(): {}".format(time.time() - t1))
# 30.5 µs ± 470 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

t1 = time.time()
np.std(samples)
print("Duration of samples.std(): {}".format(time.time() - t1))
# 94.4 µs ± 442 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

####
# 3. Recursion
print("\n\nRecursions")
# Fibonacci loop
def fib(n):
    if n < 2:
        return 1
    else:
        return fib(n-1) + fib(n-2)

t1 = time.time()
fib(30)
print("Duration of fib(30): {}".format(time.time() - t1))
# 493 ms ± 10.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

# Average number of heads
# Solving the above coin flipping problem with recursion
def average_heads(n):
    if n == 1:
        return 0.5
    else:
        return np.mean([average_heads(n-1) + 1./n, average_heads(n-1) - 1./n])

# Takes a lot of time even for 10 flips
t1 = time.time()
average_heads(10)
print("Duration of average_heads(10): {}".format(time.time() - t1))
# 11 ms ± 85.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

@functools.lru_cache()
def average_heads_m(n):
    if n == 1:
        return 0.5
    else:
        print("-"*20)
        print("average_heads_m(n-1):\n{}".format(average_heads_m(n-1)))
        print("average_heads_m(n-1):\n{}".format(average_heads_m(n-1)))
        print("1./n:\n{}".format(1./n))
        print("average_heads_m(n-1) + 1./n, average_heads_m(n-1) - 1./n:\n{}".format(average_heads_m(n-1) + 1./n, average_heads_m(n-1) - 1./n))
        print("np.mean([average_heads_m(n-1) + 1./n, average_heads_m(n-1) - 1./n]):\n{}".format(np.mean([average_heads_m(n-1) + 1./n, average_heads_m(n-1) - 1./n])))
        return np.mean([average_heads_m(n-1) + 1./n, average_heads_m(n-1) - 1./n])

t1 = time.time()
average_heads_m(10)
print("Duration of average_heads(10), memoized: {}".format(time.time() - t1))

# Graph traversal algorithm
print("Graph traversal algorithm")
# How many ways are there to get a given number by drawing coins and summing their values (if the order counts as well)?

coins = [1, 5, 10, 25, 50]
def count(remainder):
    if remainder < 0:
        return 0
        if remainder == 0:
            return 1
        return sum(count(remainder - coin) for coin in coins)

t1 = time.time()
count(50)
print("Duration of count(50):{}".format(time.time() - t1))

####
# 4. Memoization
## Manually
known = {0:1, 1:1}
def fib_man(n):
    if n in known:
        return known[n]
    else:
        known[n] = fib_man(n-2) + fib_man(n-1)
        return known[n]

## With decorator: DOES NOT WORK?
# @memoized Does not work

@functools.lru_cache()
def fib_dec(n):
    if n < 2:
        return 1
    else:
        return fib_dec(n-2) + fib_dec(n-1)

t1 = time.time()
fib_man(30)
print("Duration of manual memoization, fib_man(30): {}".format(time.time() - t1))
# 269 ns ± 1.22 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

t1 = time.time()
fib_dec(30)
print("Duration of functools memoization, fib_dec(30): {}".format(time.time() - t1))
# 204 ns ± 3.01 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

####
# 5. Divide and conquer
M = np.matrix([[1,1], [1,0]])

def fib_dc(n):
    if n < 2:
        return 1

    MProd = M.copy()
    for _ in range(n-2):
        MProd *= M

    return MProd[0,0] + MProd[0,1]

t1 = time.time()
fib_dc(30)
print("Duration of, divide an conquer fib_dc(30): {}".format(time.time() - t1))
# 330 µs ± 1.83 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)


#
import numpy as np
import matplotlib.pyplot as plt

def powerResidue(N, seed=None, a=273673163155, c=13, M=2**48):
    """ Calculate a series of random numbers
    """
    import datetime
    if seed == None:
        #print("Seed value set to NONE, defaulting to system time.")
        seed=int(datetime.datetime.now().strftime("%Y%M%d%H%M%S"))
    else:
        pass

    r = seed
    rand = []
    for i in range(N):
        rand.append(((a*r + c) % M)/M)
        r = (a*r + c) % M
    return rand[0:N]

#Generate a seq of random numbers and print them, also plotted
first_seq = powerResidue(50)
print(first_seq)
x_values = np.arange(0,50)
plt.plot(x_values, first_seq)
plt.title("First Sequence Test")
plt.show()
#The list when printed seems somewhat random

#Change value of constants and seed value to produce a sequence that repeats itself
#We can change the values of a and M to see if we can get a repeating pattern
#Initial values
#a = 273673163155
#M = 2**48

second_seq = powerResidue(50,a=27367, M=2**12)
print(second_seq)

plt.plot(x_values, second_seq)
plt.title("Second Sequence Test with Changes in a and M")
plt.show()

#Now change the seed value to see if we can produce a sequence that repeats itself
third_seq = powerResidue(50,seed=9729834523)
print(third_seq)
plt.plot(x_values, third_seq)
plt.title("Third Sequence Test with Changes in Seed")
plt.show()

#Now change all three values to see if we can produce a seq that repeats
fourth_seq = powerResidue(50, seed=987087257133932, a=273, M=2**4)
print(fourth_seq)
plt.plot(x_values, fourth_seq)
plt.title("Fourth Sequence Test Looking for Patterns")
plt.show()

def new_pResidue(N, seed=None, a=273673163155, c=13, M=2**48):
    """ Calculate a series of random numbers
    """
    #import datetime
    #if seed == None:
        #print("Seed value set to NONE, defaulting to system time.")
        #seed=int(datetime.datetime.now().strftime("%Y%M%d%H%M%S"))
    #else:
        #seed = seed + 23
    r = seed
    rand = []
    for i in range(N):
        rand.append(((a*r + c) % M)/M)
        r = (a*r + c) % M
    return rand[0:N]

import datetime
seed = seed=int(datetime.datetime.now().strftime("%Y%M%d%H%M%S"))
for each_one in range(4):
    new_seq = new_pResidue(50,seed)
    seed = seed+23
    plt.plot(new_seq)
    plt.title("Multiple Sequences at same length")

plt.show()
#When looking at the plot with multiple sequences, There seems to be random sequences
    #when you look closer, you can notice there are times in all of the sequences that
    #each tend to drop in values or climb in values. Otherwise the sequences seem to vary
    #in decreasing or increasing successive values and their severity of the jumps as well.

#To try and fix the times where all sequences tend to drop in values at the same time, we can
    #try changing the values of the constants. Seems like increasing a and M worked, or at least
    #made it difficult to see a pattern.
for each_one in range(4):
    new_seq = new_pResidue(50,seed, a=70928509284734092, M=7**48)
    seed = seed+23
    plt.plot(new_seq)
    plt.title('Fixed Multiple Sequences at same length')

plt.show()

#Now use the numpy random function and scatter-plot against this function to see difference
xvalues = np.arange(0,75)
random_values = np.random.random(75)
our_values = powerResidue(75)
plt.scatter(xvalues,random_values,s=2, color = "blue", label="Numpy Function")
plt.scatter(xvalues,our_values,s=2, color = "red", label="Our Function")
plt.title("Numpy Random function versus Our function")
plt.xlim(0,80)
plt.ylim(0.0,1.25)
plt.legend()

#When looking at the distribution of values for the numpy random function and our function
#I believe our function almost seems better at the "randomness" Our function does not seem
#to have as many values clumped together like the numpy function does. There seems to be
#a more uniform distribution to the values for our function. THen again, uniform is not necessarily
#random, and random values can occur in clumps. So perhaps with that point stated, numpy
#function could actually be better at generating random values.


from numpy import array, linalg, dot
from scipy.linalg import lu

# System of Equations
A = array([[3,  -.1, -.2],
           [.1,  7,  -.3],
           [.3, -.2, 10]], float)
B = array([10.3, 33.6, 60.2], float)

# Linalg.Solve Function:

X = linalg.solve(A, B)
print("linalg.solve(A, B) = ", X, end='\n\n')

# Dot and Linalg.inv Function:

X = dot(linalg.inv(A), B)
print("dot(linalg.inv(A), B)", X, end='\n\n')

# Scipy.linalg.lu Function:

P, L, U = lu(A)
print("P, L, U = lu(A)")
print("[P] =\n", P, sep='')
print("[L] =\n", L, sep='')
print("[U] =\n", U, sep='')

5. Systems of Linear Equations/0. Linear System solving functions of SciPy.py


import numpy as np

def pca_train(raw_data, k):
    """
    输入：原始数据矩阵raw_data、降维后的维度k
    输出：样本均值和投影向量
    参考：https://www.cnblogs.com/lzllovesyl/p/5235137.html
    """
    # 计算均值向量
    mean_vecs = np.mean(raw_data, axis=0)
    # 样本中心化
    centralized_data = raw_data - mean_vecs
    # 计算协方差矩阵
    cov_mat = np.cov(centralized_data, rowvar=False)
    # 计算特征值和特征向量
    eig_vals, eig_vecs = np.linalg.eig(np.mat(cov_mat))
    # 特征值排序
    eig_vals_idx = np.argsort(eig_vals)
    topk_idx = eig_vals_idx[:-(k+1):-1]
    # 取对应的特征向量
    topk_eig_vecs= eig_vecs[:,topk_idx]
    return mean_vecs, topk_eig_vecs

def pca_test(new_data, mean_vecs, eig_vecs):
    """
    输入：新样本new_data、均值向量mean_vec、和投影向量eig_vec
    输出：投影后的数据
    """
    # 数据中心化
    centralized_data = new_data - mean_vecs
    # 降维
    return centralized_data.dot(eig_vecs)


import numpy as np

def linear_kernel(x, y, **kwargs):
    return np.dot(x, y)

def polynomial_kernel(x, y, **kwargs):
    degree = kwargs['degree']
    gamma = kwargs['gamma']
    coef0 = kwargs['coef0']
    return (coef0 + gamma * np.dot(x, y)) ** degree

def gaussian_kernel(x, y, **kwargs):
    gamma = kwargs['gamma']
    return np.exp(-gamma * (np.linalg.norm(x-y)**2))


# basic implementation of explicit extrapolation with Euler's and midpoint methods
# a convergence test on the example y' = lam*y is preformed at the end of this file

from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
import math

debugging = False

# solve the first order ODE y' = f(y, t) on the interval [t0, tf] with
# the initial value y(t0) = y0 and time step size h
def euler_method (f, y0, t0, tf, h):
    assert abs(((tf -t0)/h) % 1) < 1.e-15, "Step size %r does not divide \
        the interval [%r, %r] evenly." %(h,t0,tf)

    ts = np.linspace(t0, tf, (tf-t0)/h + 1)
    ys = np.zeros(len(ts), dtype=complex)
    ys[0] = y0

    for i in range(len(ts) - 1):
        ys[i+1] = ys[i] + h*f(ys[i], ts[i])
    return (ts, ys)

# solve the first order ODE y' = f(y, t) on the interval [t0, tf] with
# the intial value y(t0) = y0  and time step size h
def midpoint_method (f, y0, t0, tf, h):
    assert abs(((tf -t0)/h) % 1) < 1.e-15, "Step size %r does not divide \
        the interval [%r, %r] evenly." %(h,t0,tf)
    ts = np.linspace(t0, tf, (tf-t0)/h + 1)
    ys = np.zeros(len(ts), dtype=complex)
    ys[0] = y0
    ys[1] = ys[0] + h*f(ys[0], ts[0]) # use Euler to get second initial value
    for i in range(len(ts) - 2):
        ys[i+2] = ys[i] + 2*h*f(ys[i+1], ts[i+1])
    return (ts, ys)

# preforms a convergence test solving the IVP y' = f(y) and y(t0) = y0 with
# the [method] provided, where the function exact is the solution the IVP.
# The function plots the ||error|| vs time step size, and a reference line
# of the given order to compare. The graph is titled with graph_title
def test_convergence(f, exact, t0, tf, y0, method, order, graph_title):
    hs = np.asarray([2**(-k) for k in range(1, 16)])
    err = np.zeros(len(hs))

    for i in range(len(hs)):
        ts, ys = method(f, y0, t0, tf, hs[i])
        err[i] = abs(ys[-1] - exact(tf))

    plt.hold('true')
    method_err,  = plt.loglog(hs, err, 's-')
    order_line,  = plt.loglog(hs, (hs**order)*(err[5]/hs[5]))
    plt.legend([method_err, order_line], ['Method Error', 'order ' + str(order)], loc=2)
    plt.title(graph_title)
    plt.ylabel('||error||')
    plt.xlabel('time step size')

    plt.show()

# Convergence Tests
if debugging:
    #### test 1 ####
    lam = -2
    f = lambda y,t: lam*y
    y0 = 1
    exact = lambda t: y0*np.exp(lam*t)
    t0 = 1
    tf = 5
    test_convergence(f, exact, t0, tf, exact(t0), euler_method, 1, "TEST 1: euler_method")
    test_convergence(f, exact, t0, tf, exact(t0), midpoint_method, 2, "TEST 1: midpoint_method")

    ### test 2 ####
    f = lambda y,t: 4.*y*float(np.sin(t))**3*np.cos(t)
    y0 = 1
    exact = lambda t: y0*np.exp((np.sin(t))**4)
    t0 = 0
    tf = 5
    test_convergence(f, exact, t0, tf, exact(t0), euler_method, 1, "TEST 2: euler_method")
    test_convergence(f, exact, t0, tf, exact(t0), midpoint_method, 2, "TEST 2: midpoint_method")

    #### test 3 ####
    f = lambda y,t: 4.*t*np.sqrt(y)
    y0 = 1
    exact = lambda t: (1.+t**2)**2
    t0 = 0
    tf = 5
    test_convergence(f, exact, t0, tf, exact(t0), euler_method, 1, "TEST 3: euler_method")
    test_convergence(f, exact, t0, tf, exact(t0), midpoint_method, 2, "TEST 3: midpoint_method")

    #### test 4 ####
    f = lambda y,t:  y/t*np.log(y)
    y0 = np.exp(1.)
    exact = lambda t: np.exp(2.*t)
    t0 = 0.5
    tf = 5
    test_convergence(f, exact, t0, tf, exact(t0), euler_method, 1, "TEST 4: euler_method")
    test_convergence(f, exact, t0, tf, exact(t0), midpoint_method, 2, "TEST 4: midpoint_method")

if __name__ == "__main__":
    import doctest
    doctest.testmod()


import numpy as np
import math
from scipy import stats

# ------------------------ EXPONENTIALS AND LOGARITHMS ----------------------- #
def fexponential(x, a, b, c):
    return a * np.exp(-b * x) + c

def exponential(x, a, b, c, d):
    return a * np.exp(-c * (x - b)) + d

def logarithmic(x, a, b, c):
    return a * np.log(b * x) + c

# --------------------------------- SIGMOIDS --------------------------------- #
def logistic(x, L, x0, k, b):
    """
    L -> shirnks the function on the Y axis.
    x0 -> x shift.
    k  -> slope. the smaller the flatter. Vals > 5 are good
    b -> y shift. Shifts thw whole curve up and donw
    """
    y = L / (1 + np.exp(-k * (x - x0))) + b
    return y

def centered_logistic(x, L, x0, k):
    """
    L -> shirnks the function on the Y axis.
    x0 -> x shift.
    k  -> slope. the smaller the flatter. Vals > 5 are good
    """
    b = (1 - L) / 2
    y = L / (1 + np.exp(-k * (x - x0))) + b
    return y

def hill_function(x, n, L, b):  # ? no work
    return L / (1 + x ** -n) + b

def hyperbolic_tangent(x, L=1, b=0, x0=0):
    return np.tanh(x - x0) / L + b

def arctangent(x, L=2, b=0, x0=0):
    return np.arctan(x - x0) / L + b

def gudermannian(x, L=2, b=0, x0=0):
    return L * np.arctan(np.tanh((x - x0) / L)) + b

def generalised_logistic(x, a, x0):  # ? no work
    """
        a > 0
    """
    if a <= 0:
        raise ValueError("Paramter 'a' should be > 0")
    return (1 + np.exp(-(x - x0))) ** -a

def algebraic_sigmoid(x, L=1, b=0, x0=0):
    return (x - x0 / (math.sqrt(1 + (x - x0) ** 2))) / L + b

def error_function(x, x0=0, scale=1, L=1, b=0):
    norm = stats.norm(x0, scale)
    return norm.cdf(x) * L + b

def centered_error_function(x, x0=0, scale=1, L=1):
    b = (1 - L) / 2
    norm = stats.norm(x0, scale)
    return norm.cdf(x) * L + b

# ------------------------------ OTHER FUNCTIONS ----------------------------- #
def linear_func(x, a, b):
    return x * a + b

def step_function(x, a, b, c):
    # Step function
    """
    a: value at x = b
    f(x) = 0 if x<b, a if x=b and 2*a if  x > a
    """
    return a * (np.sign(x - b) + c)


import numpy as np
from scipy.spatial.distance import cdist

class KMeans:
    def __init__(
            self,
            k: int,
            metric: str = "euclidean",
            tol: float = 1e-6,
            max_iter: int = 100):
        """
        inputs:
            k: int
                the number of centroids to use in cluster fitting
            metric: str
                the name of the distance metric to use
            tol: float
                the minimum error tolerance from previous error during optimization to quit the model fit
            max_iter: int
                the maximum number of iterations before quitting model fit
        """
        self.k = k
        self.metric = metric
        self.tol = tol
        self.max_iter = max_iter

        # model should not run if k<=0
        if self.k<=0:
            raise ValueError("k must be greater than zero")

    def fit(self, mat: np.ndarray):
        """
        fits the kmeans algorithm onto a provided 2D matrix

        inputs:
            mat: np.ndarray
                A 2D matrix where the rows are observations and columns are features
        """

        # model should not run if k > number of observations
        if self.k > np.shape(mat)[0]:
            raise ValueError("k must be less than the number of observations in the array")

        # create random centers
        self.centers = np.random.uniform(np.min(mat), np.max(mat), size=(self.k,2))

        # set baseline values
        i=1
        mse=1
        mse_diff=1
        self.mat = mat # necessary to access mat in get_centroids

        # iteratively select new centers
        while i<self.max_iter and mse_diff>self.tol:
            # assign points to each cluster based on their distance to the centers
            self.dist_mat = self._calc_distances(mat, self.centers)
            self.labels = self.predict(mat)

            # calculate error - calculate squared distance from each point to its corresponding centroid,
            # using the supplied metric, then take the mean of those values
            old_mse = mse
            mse = self.get_error()
            mse_diff = abs(old_mse-mse)

            # update centers based on cluster membership of datapoints
            self.centers = self.get_centroids()

            # increment
            i+=1

    def predict(self, mat: np.ndarray) -> np.ndarray:
        """
        predicts the cluster labels for a provided 2D matrix

        inputs:
            mat: np.ndarray
                A 2D matrix where the rows are observations and columns are features

        outputs:
            np.ndarray
                a 1D array with the cluster label for each of the observations in `mat`
        """
        return np.argmin(self.dist_mat, axis=1) # find index of minmum value in each row

    def get_error(self) -> float:
        """
        returns the final squared-mean error of the fit model

        outputs:
            float
                the squared-mean error of the fit model
        """
        return np.mean(np.square(np.choose(self.labels, self.dist_mat.T))) # numpy.choose which constructs an array from an index array - https://stackoverflow.com/questions/17074422/select-one-element-in-each-row-of-a-numpy-array-by-column-indices

    def get_centroids(self) -> np.ndarray:
        """
        returns the centroid locations of the fit model

        outputs:
            np.ndarray
                a `k x m` 2D matrix representing the cluster centroids of the fit model
        """
        return np.array([self.mat[self.labels==j].mean(0) for j in range(self.k)])

    def _calc_distances(self, mat: np.ndarray, centers: np.ndarray) -> np.ndarray:
        """
        calculates the distance from each point to each center
        """
        return cdist(mat, centers, metric=self.metric)


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

import numpy as np
import sklearn.metrics as skm

def rmspe_error(y_true, y_pred):
    rmspe_val = np.sqrt(
        np.mean(np.square(((y_true - y_pred) / y_true)), axis=0)
    )
    return rmspe_val * 100

def smape_error(y_true, y_pred):
    n = len(y_pred)
    num = np.abs(y_pred - y_true)
    denom = np.abs(y_pred) + np.abs(y_true)
    smape_val = (200 * np.sum(num / denom)) / n
    return smape_val

def score_predictions(y_true, y_pred, prediction_type="pred", get_r2=False):
    rmse_score = skm.mean_squared_error(y_true, y_pred, squared=False)
    mse_score = skm.mean_squared_error(y_true, y_pred)
    # mape_score = skm.mean_absolute_percentage_error(y_true, y_pred) * 100
    mae_score = skm.mean_absolute_error(y_true, y_pred)
    smape_score = smape_error(y_true, y_pred)
    scores = {
        "rmse": rmse_score,
        "mae": mae_score,
        # "mape(%)": mape_score,
        "smape(%)": smape_score,
        "mse": mse_score,
        "type": prediction_type,
    }
    if get_r2:
        scores.update({"r2": skm.r2_score(y_true, y_pred)})
    if y_true.min() > 0:
        scores.update({"rmspe(%)": rmspe_error(y_true, y_pred)})
    return scores