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

# # my lession 1 on Linear Algebra
#
# https://github.com/engineersCode/EngComp4_landlinear

# In[23]:

import numpy
get_ipython().run_line_magic('matplotlib', 'inline')
from matplotlib import pyplot

# In[24]:

import sys
sys.path.append('../scripts/')

# Our helper with the functions
# plot_vector, plot_linear_transformation, plot_linear_transformations
from plot_helper import *

# In[25]:

vectors = [(2,2)]
tails = [(-3, -2), (-3, 1), (0, 0), (1, -3)]

# In[26]:

plot_vector(vectors, tails)

# In[27]:

vectors = [(2, 4)]
tails = [(0,0), (-1, 1)]
plot_vector(vectors, tails)

# Vector addition

# In[34]:

a = numpy.array((-2, 1))
b = numpy.array((1, -3))
origin = numpy.array((0, 0))
vectors = [a, b, a+b]
tails = [origin, a, origin]
plot_vector(vectors, tails)

# Vector scaling

# In[29]:

c = numpy.array((2, 1))
vectors = [c, 2*c]
plot_vector(vectors)

# In[30]:

c = numpy.array((2, 1))
vectors = [c, -2*c]
plot_vector(vectors)

# In[31]:

i = numpy.array((1, 0))
j = numpy.array((0, 1))

vec = 3*1 + 2*j

vectors = [i, j, 3*i, 2*j, vec]
plot_vector(vectors)

# **Linear combinations** -- adding together two vectors that were each scaled
#
# **Span** -- set of all possible linear combinations

# In[32]:

from numpy.random import randint

vectors = []
for _ in range(40):
    m = randint(-10, 10)
    n = randint(-10, 10)
    vectors.append(m*i + n*j)

plot_vector(vectors)

# In[36]:

from numpy.random import randint

vectors = []
for _ in range(40):
    m = randint(-10, 10)
    n = randint(-10, 10)
    vectors.append(m*a + n*b)

plot_vector(vectors)

# In[37]:

d = numpy.array((-1, 0.5))

# In[38]:

vectors = []
for _ in range(40):
    m = randint(-10, 10)
    n = randint(-10, 10)
    vectors.append(m*a + n*d)

plot_vector(vectors)

# In[39]:

a

# In[40]:

d

# a and d share the same span because they describe the same line.  d is a multiple of a. therefore, they are linearly dependent.

# In[43]:

a

# In[41]:

b

# In[42]:

c

# We have vectors $\mathbf{a}$, and $\mathbf{b}$
#
# $\mathbf{c}= 2*\mathbf{i} + 1*\mathbf{j}$
#
# Use the components of $\mathbf{c}$ to make a linear combination of $\mathbf{a}$ and $\mathbf{b}$

# In[47]:

c_prime = 2*a + 1*b
c_prime

# In[48]:

# c_prime has the coordinates (2,1), i.e. c, in the a,b system of coordinates, wherein a,b are the basis vectors
# c_prime has the coordinate (-3,-1), in the i,j system of coordinates

# In[50]:

2*a

# In[51]:

1*b

# In[53]:

A = [[-2,1], [1,-3]]
A = numpy.array(A)
print(A)

# In[54]:

print(c)

# In[55]:

A.dot(c)

# In[56]:

A.dot(i) #=> a

# In[58]:

A.dot(j) #=> b

# In[59]:

plot_linear_transformation(A)

# In[60]:

M = [[1,2], [2,1]]
M = numpy.array(M)
print(M)

# In[61]:

M.dot(i)

# In[62]:

M.dot(j)

# In[63]:

plot_linear_transformation(M)

# In[65]:

x = numpy.array((0.5, 1))
vectors = [x, M.dot(x)]
plot_vector(vectors)

# In[67]:

N = numpy.array([[1,2], [-1,2]])
print(N)

# In[68]:

plot_linear_transformation(N)

# In[69]:

X = numpy.array([[2,3], [1,3]])
print(X)

# In[70]:

plot_linear_transformation(X)

# In[71]:

X = numpy.array([[-1,2], [2,-1]])
print(X)

# In[72]:

plot_linear_transformation(X)

# In[74]:

rotation = numpy.array([[0, -1], [1, 0]])
print(rotation)

# In[75]:

plot_linear_transformation(rotation)

# In[77]:

shear = numpy.array([[1,1], [0, 1]])
print(shear)

# In[78]:

plot_linear_transformation(shear)

# In[79]:

scaling = numpy.array([[2, 0], [0, 0.5]])
print(scaling)

# In[80]:

plot_linear_transformation(scaling)

# Special scaling matric that leaves the unit vectors the same length:
# **identity** matrix

# In[81]:

rotation_90_clockwise = numpy.array([[0, 1], [-1, 0]])
print(rotation_90_clockwise)

# In[82]:

plot_linear_transformation(rotation_90_clockwise)

# In[83]:

print(shear@rotation)

# In[84]:

plot_linear_transformation(shear@rotation)

# In[85]:

plot_linear_transformation(rotation@shear)

# **Inverse of a matrix** undoes the effect of the linear transformation

# In[88]:

from numpy.linalg import inv

# In[89]:

M

# In[93]:

M_inv = inv(M)

# In[91]:

plot_linear_transformations(M, M_inv)

# In[ ]:


  # -*- coding: utf-8 -*-
"""
Created on Sun Aug 25 19:14:27 2019

@author: Browsing
"""
import numpy as np
import matplotlib.pyplot as plt

def f(x, y):
    return (x+20.0*y)*np.sin(x*y)
#    return 3*x

def RK2(startX , startY , endX , h , a2):
    a1 = 1.0- a2
    p1 = 0.5/a2
    q11 = 0.5/a2
    x = list()
    y = list()
    while startX <= endX:
        x.append(startX)
        y.append(startY)
        k1 = f(startX , startY)
        k2 = f(startX +p1 *h , startY + q11 * k1 * h)
        startY = startY + (a1 * k1 + a2 * k2 ) * h
        startX = startX + h
    return x,y

def Euler(startX , startY , endX , h ):
    x = list()
    y = list()
    while startX <= endX:
        x.append(startX)
        y.append(startY)
        startY = startY + f(startX , startY ) * h
        startX = startX + h
    return x,y

def Heun( startX , startY , endX , h ):
    return RK2(startX , startY , endX , h , 0.5 )

def MidPoint( startX , startY , endX , h ):
    return RK2(startX , startY , endX , h , 1.0 )

def Ralston( startX , startY , endX , h ):
    return RK2(startX , startY , endX , h , 2.0/3.0 )

def RK4(startX , startY , endX , h):
    x = list()
    y = list()
    while startX <= endX:
        x.append(startX)
        y.append(startY)
        k1 = f(startX, startY)
        k2 = f( startX + 0.5 * h , startY + 0.5 * k1 * h)
        k3 = f(startX + 0.5 * h , startY +  0.5 * k2 * h)
        k4 = f(startX + h , startY + k3* h )
        startY = startY + (k1 + 2 *k2 + 2* k3 + k4 ) * h /6.0
        startX = startX + h
    return x,y

def SubPlot1(startX , startY , endX , hs , Title , func ):

    plt.title(Title)
    for h in hs:
        x , y = func(startX , startY , endX , h)
#        plt.ylim(-200.0 , 200.0)
        plt.plot(x,y , label = "h = %f"%(h))
    plt.legend()

def SubPlot2(startX , startY , endX , h , Title ):
    plt.title(Title)
    x,y= Euler(startX , startY , endX , h )
    plt.plot( x, y , label = "Euler method")

    x,y= Heun(startX , startY , endX , h )
#    plt.ylim(-200.0 , 200.0)
    plt.plot( x, y , label = "Heun's Method")

    x,y= MidPoint(startX , startY , endX , h )
#    plt.ylim(-200.0 , 200.0)
    plt.plot( x, y , label = "Midpoint Method")

    x,y= Ralston(startX , startY , endX , h )
#    plt.ylim(-200.0 , 200.0)
    plt.plot( x, y , label = "Ralston’s Method")

    x,y= RK4(startX , startY , endX , h )
#    plt.ylim(-200.0 , 200.0)
    plt.plot( x, y , label = "4th order RK Method")

    plt.legend()

def Plot1(startX , startY , endX , hs):
    plt.figure(1,[10,10] )
    SubPlot1(startX,startY , endX , hs , "Euler Method" ,Euler )
    plt.figure(2,[10,10] )
    SubPlot1(startX,startY , endX , hs , "Heun's Method" ,Heun )
    plt.figure(3,[10,10] )
    SubPlot1(startX,startY , endX , hs , "Midpoint Method" ,MidPoint )
    plt.figure(4,[10,10] )
    SubPlot1(startX,startY , endX , hs , "Ralston’s Method" ,Ralston )
    plt.figure(5,[10,10] )
    SubPlot1(startX,startY , endX , hs , "4th order RK Method" ,RK4 )

def Plot2(startX , startY , endX , hs):

    for i in range( len(hs) ):
        plt.figure(i+6,[10, 10])
        h=hs[i]
        SubPlot2(startX , startY , endX , h , "h = %f"%(h)   )

if __name__ == '__main__':
#    print(RK2(0.0 , 1.0 , 10.0 , 0.5 , 0.5))

    Plot1(0.0 , 4.0 , 10.0 ,[0.01, 0.05, 0.1, 0.5 ])
    Plot2(0.0 , 4.0 , 10.0 ,[0.01, 0.05, 0.1, 0.5 ])

Numerical/Offline 5 on ODE/Numerical Offline RK method.py


%matplotlib inline

from matplotlib import pyplot as plt
import numpy as np

# define activation function and its derivative
def sigmoid(x):
    return 1/(1+np.exp(-x))

def sigmoid_p(x):
    return sigmoid(x)*(1-sigmoid(x))

T = np.linspace(-5,5,100)
plt.plot(T,sigmoid(T),c='r')
plt.plot(T,sigmoid_p(T),c='b')

## Assignment a)
data = [0.5, 1.5]
w1 = 1.0
w2 = 1.0
learning_rate = 1#?
b = 2.0
# calculate initial output
y = data[0]*w1 + data[1]*w2 + b
z = sigmoid(y)
z_ = 1.0
#cost function
cost = (z_-z)
# derivatives of the cost function w.r.t. weights
dcost_prediction = -1
dpred_dy = sigmoid_p(y)
dy_dw1 = data[0]
dy_dw2 = data[1]
dy_db = 1

# applying chain rule
dcost_dw1 = dcost_prediction * dpred_dy * dy_dw1
dcost_dw2 = dcost_prediction * dpred_dy * dy_dw2
dcost_db = dcost_prediction * dpred_dy * dy_db

# updating weights
w1 = w1 - learning_rate * dcost_dw1
w2 = w2 - learning_rate * dcost_dw2
b = b - learning_rate * dcost_db

#check output with new weights
y = data[0]*w1 + data[1]*w2 + b
z = sigmoid(y)
print(f"The error of the simple network a) with updated weights is:\n {str(z_-z)}")
print(f"\nThe values of the updated weights are:\n w1={str(w1)} w2={str(w2)} b={str(b)}")

##Assignment b)
data = [0.5, 1.5]
w1 = 1.0
w2 = 1.0
learning_rate = 1#?
b = 2.0
# calculate initial output
y = data[0]*w1 + data[1]*w2 + b
z = sigmoid(y)
z_ = 1.0
#cost function
cost = np.square((z_-z))/2
# derivatives of the cost function w.r.t. weights
dcost_prediction = (z_-z)
dpred_dy = sigmoid_p(y)
dy_dw1 = data[0]
dy_dw2 = data[1]
dy_db = 1

# applying chain rule
dcost_dw1 = dcost_prediction * dpred_dy * dy_dw1
dcost_dw2 = dcost_prediction * dpred_dy * dy_dw2
dcost_db = dcost_prediction * dpred_dy * dy_db

# updating weights
w1 = w1 - learning_rate * dcost_dw1
w2 = w2 - learning_rate * dcost_dw2
b = b - learning_rate * dcost_db

#check output with new weights
y = data[0]*w1 + data[1]*w2 + b
z = sigmoid(y)
print(f"The error of the simple network b) with updated weights is:\n {np.square((z_-z))/2}")
print(f"\nThe values of the updated weights are:\n w1={str(w1)} w2={str(w2)} b={str(b)}")


#This function gives the approximate derivative of a user defined function or any function from Numpy at a point x = a
#Call the function as follows: derivative(function, a, Number step size) example:print(derivative(np.sin,np.pi,0.00001))
#Number step size (h) should tend to zero for a better approximate

import numpy as np

def derivative(f,a,h):

	return (f(a + h) - f(a - h))/(2*h)


from sympy.core.numbers import igcd
from primetest import isprime
from factor_ import factorint

def totient_(n):
    """returns the number of integers less than n
    and relatively prime to n"""
    if n < 1:
        raise ValueError("n must be a positive integer")
    tot = 0
    for x in xrange(1, n):
        if igcd(x, n) == 1:
            tot += 1
    return tot

def n_order(a, n):
    """ returns the order of a modulo n
    Order of a modulo n is the smallest integer
    k such that a^k leaves a remainder of 1 with n.
    """
    if igcd(a, n) != 1:
        raise ValueError("The two numbers should be relatively prime")
    group_order = totient_(n)
    factors = factorint(group_order)
    order = 1
    if a > n:
        a = a % n
    for p, e in factors.iteritems():
        exponent = group_order
        for f in xrange(0, e + 1):
            if (a ** (exponent)) % n != 1:
                order *= p ** (e - f + 1)
                break
            exponent = exponent // p
    return order

def is_primitive_root(a, p):
    """
    returns True if a is a primitive root of p
    """
    if igcd(a, p) != 1:
        raise ValueError("The two numbers should be relatively prime")
    if a > p:
        a = a % p
    if n_order(a, p) == totient_(p):
        return True
    else:
        return False

def is_quad_residue(a, p):
    """
    returns True if a is a quadratic residue of p
    p should be a prime and a should be relatively
    prime to p
    """
    if not isprime(p) or p == 2:
        raise ValueError("p should be an odd prime")
    if igcd(a, p) != 1:
        raise ValueError("The two numbers should be relatively prime")
    if a > p:
        a = a % p

    def square_and_multiply(a, n, p):
        if n == 0:
            return 1
        elif n == 1:
            return a
        elif n % 2 == 1:
            return ((square_and_multiply(a, n // 2, p) ** 2) * a) % p
        else:
            return (square_and_multiply(a, n // 2, p) ** 2) % p

    return (square_and_multiply(a, (p - 1) // 2, p) % p) == 1

def legendre_symbol(a, p):
    """
    return 1 if a is a quadratic residue of p
    else return -1
    p should be an odd prime by definition
    """
    if not isprime(p) or p == 2:
        raise ValueError("p should be an odd prime")
    if igcd(a, p) != 1:
        raise ValueError("The two numbers should be relatively prime")
    if a > p:
        a = a % p
    if is_quad_residue(a, p):
        return 1
    else:
        return -1


import numpy as np
import sympy as sp
from sympy.core import S, Dummy
from sympy.polys.orthopolys import (legendre_poly, laguerre_poly,
                                    hermite_poly, jacobi_poly)
from sympy.polys.rootoftools import RootOf

def symbolic_gauss_legendre(n):
    """
    Computes the symbolic Gauss-Legendre quadrature points and weights.

    Parameters
    ----------
    n : Integer
        Number of integration points.
    x : Symbol
        Symbolic sysmbol.

    Returns
    -------
    xi : Abscisca
        Symbolic location of roots.
    wi : Weights
        Symbolic weights of roots.

    """
    x = Dummy("x")
    Pnx = sp.legendre(n,x)
    Pp = sp.diff(Pnx,x)
    xi = sp.solve( Pnx, x )
    wi = [ sp.simplify(2/(1 - xj**2)/(Pp.subs(x,xj))**2) for xj in xi ]
    return xi, wi

def gauss_legendre(n, n_digits):
    r"""
    Computes the Gauss-Legendre quadrature [1]_ points and weights.

    The Gauss-Legendre quadrature approximates the integral:

    .. math::
        \int_{-1}^1 f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i)

    The nodes `x_i` of an order `n` quadrature rule are the roots of `P_n`
    and the weights `w_i` are given by:

    .. math::
        w_i = \frac{2}{\left(1-x_i^2\right) \left(P'_n(x_i)\right)^2}

    Parameters
    ==========

    n : the order of quadrature

    n_digits : number of significant digits of the points and weights to return

    Returns
    =======

    (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats.
             The points `x_i` and weights `w_i` are returned as ``(x, w)``
             tuple of lists.

    Examples
    ========

    >>> from sympy.integrals.quadrature import gauss_legendre
    >>> x, w = gauss_legendre(3, 5)
    >>> x
    [-0.7746, 0, 0.7746]
    >>> w
    [0.55556, 0.88889, 0.55556]
    >>> x, w = gauss_legendre(4, 5)
    >>> x
    [-0.86114, -0.33998, 0.33998, 0.86114]
    >>> w
    [0.34785, 0.65215, 0.65215, 0.34785]

    See Also
    ========

    gauss_laguerre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/Gaussian_quadrature
    .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/legendre_rule/legendre_rule.html
    """
    x = Dummy("x")
    p = legendre_poly(n, x, polys=True)
    pd = p.diff(x)
    xi = []
    wi = []
    for r in p.real_roots():
        if isinstance(r, RootOf):
            r = r.eval_rational(S(1)/10**(n_digits+2))
        xi.append(r.n(n_digits))
        wi.append((2/((1-r**2) * pd.subs(x, r)**2)).n(n_digits))
    return xi, wi

digits = 36
npoints = list(range(1,17))

for n in npoints:
    xi, wi = gauss_legendre(n, digits)

    print('\nN = %3d'%(n))
    for i in range(0,n):
        print('%3d %40.36f %40.36f'%(i+1,xi[i],wi[i]))


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

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

'''
Interpolation is the process of
finding a value between two points on a line
or a curve.
'''

kinds = ('nearest',
         'zero',
         'linear',
         'slinear',
         'quadratic',
         'cubic')

''' x- axis values '''
x = np.array([0.0,1.0,2.0,3.0,
              4.0,5.0,6.0,7.0,
              8.0,9.0])

''' y- axis values '''
y = np.array([10,5,39,3,6,9,41,73,57,88])

''' plot original values '''
plt.plot(x, y, 'o')

''' new x-axis values to be interpolated '''
new_x = np.linspace(0.0, 9.0, 25)

''' interpolate for kind = 'nearest' '''
new_y = interpolate.interp1d(x,y,kind='nearest')(new_x)
plt.plot(new_x, new_y, color='C1', linewidth=1)

''' interpolate for kind = 'zero' '''
new_y = interpolate.interp1d(x,y,kind='zero')(new_x)
plt.plot(new_x, new_y, color='C2', linewidth=1)

''' interpolate for kind = 'linear' '''
new_y = interpolate.interp1d(x,y,kind='linear')(new_x)
plt.plot(new_x, new_y, color='C3', linewidth=1)

''' interpolate for kind = 'slinear' '''
new_y = interpolate.interp1d(x,y,kind='slinear')(new_x)
plt.plot(new_x, new_y, color='C4', linewidth=1)

''' interpolate for kind = 'cubic' '''
new_y = interpolate.interp1d(x,y,kind='cubic')(new_x)
plt.plot(new_x, new_y, color='C5', linewidth=1)

plt.legend(['original','nearest','zero',
            'linear','slinear','cubic'])
plt.show()

''' plotting all types in single graph '''
fig, axs = plt.subplots(
        nrows=len(kinds)+1,
        sharex=True)
axs[0].plot(x, y, 'bo-')
axs[0].set_title('raw')
for ax, kind in zip(axs[1:], kinds):
    new_y = interpolate.interp1d(
            x,
            y,
            kind=kind)(new_x)
    ax.plot(new_x, new_y, 'ro-')
    ax.set_title(kind)
plt.show()

''' spliners '''
''' to draw smooth curves through data points '''
from scipy.interpolate import UnivariateSpline

''' x- axis values '''
x = np.array([0.0,1.0,2.0,3.0,
              4.0,5.0,6.0,7.0,
              8.0,9.0])

''' y- axis values '''
y = np.array([10,25,39,58,16,91,41,73,57,88])
''' plot original values '''
plt.plot(x, y, 'o')

new_x = np.linspace(0.0, 9.0, 25)
new_y = interpolate.interp1d(x,y,kind='nearest')(new_x)
spl = UnivariateSpline(new_x, new_y)
spl.set_smoothing_factor(0.001)
plt.plot(new_x, spl(new_x), color='C6', linewidth=2)


import cupy as cp

class root_finders():

    def __init__(self):
        pass

    def bisection(self, fn,x0,x1,e):
        """
        Bisection Method for finding real root of nonlinear
        equation in python programming language.
        In this python program, x0 and x1 are two initial guesses,
        e is tolerable error and nonlinear function f(x) is defined
        using python function definition.

        Algorithm:

        1. start

        2. Define function f(x)

        3. Choose initial guesses x0 and x1 such that f(x0)f(x1) < 0

        4. Choose pre-specified tolerable error e.

        5. Calculate new approximated root as x2 = (x0 + x1)/2

        6. Calculate f(x0)f(x2)
            a. if f(x0)f(x2) < 0 then x0 = x0 and x1 = x2
            b. if f(x0)f(x2) > 0 then x0 = x2 and x1 = x1
            c. if f(x0)f(x2) = 0 then goto (8)

        7. if |f(x2)| > e then goto (5) otherwise goto (8)

        8. Display x2 as root.

        9. Stop
        """
        step = 1

        condition = True
        while condition:
            x2 = (x0 + x1)/2
            print('Iteration-%d, x2 = %0.6f and f(x2) = %0.6f' % (step, x2, fn(x2)))

            if fn(x0) * fn(x2) < 0:
                x1 = x2
            else:
                x0 = x2

            step = step + 1
            condition = abs(fn(x2)) > e

        print('\nRequired Root is : %0.8f' % x2)

    def newton_raphson(self,fn,d_fn,x0,e,N):
        """
        Newton Raphson method for finding real root of nonlinear function in python
        programming language.
        x0 is initial guess, e
        is tolerable error, fn(x) is non-linear function whose
        root is being obtained using Newton Raphson method.
        1. Start

        2. Define function as fn(x)

        3. Define first derivative of fn(x) as d_fn(x)

        4. Input initial guess (x0), tolerable error (e)
        and maximum iteration (N)

        5. Initialize iteration counter i = 1

        6. If d_fn(x0) = 0 then print "Mathematical Error"
        and goto (12) otherwise goto (7)

        7. Calcualte x1 = x0 - fn(x0) / d_fn(x0)

        8. Increment iteration counter i = i + 1

        9. If i >= N then print "Not Convergent"
        and goto (12) otherwise goto (10)

        10. If |fn(x1)| > e then set x0 = x1
            and goto (6) otherwise goto (11)

        11. Print root as x1

        12. Stop
        """

        step = 1
        flag = 1
        condition = True
        while condition:
            if d_fn(x0) == 0.0:
                print('Divide by zero error!')
                break

            x1 = x0 - fn(x0)/d_fn(x0)
            print('Iteration-%d, x1 = %0.6f and f(x1) = %0.6f' % (step, x1, fn(x1)))
            x0 = x1
            step = step + 1

            if step > N:
                flag = 0
                break

            condition = abs(fn(x1)) > e

        if flag==1:
            print('\nRequired root is: %0.8f' % x1)
        else:
            print('\nNot Convergent.')


# 1. Write a NumPy program to compute the multiplication of two given matrixes.
import numpy as np

p = [[1, 0], [0, 1]]
q = [[1, 2], [3, 4]]
print("original matrix:")
print(p)
print(q)
result1 = np.dot(p, q)
print("Result of the said matrix multiplication:")
print(result1)
# ----------------------------------------------------------------------------------#
# 2. Write a NumPy program to compute the outer product of two given vectors.
import numpy as np

p = [[1, 0], [0, 1]]
q = [[1, 2], [3, 4]]
print("original matrix:")
print(p)
print(q)
result = np.outer(p, q)
print("Outer product of the said two vectors:")
print(result)
# ----------------------------------------------------------------------------------#
# 3. Write a NumPy program to compute the cross product of two given vectors.
import numpy as np

p = [[1, 0], [0, 1]]
q = [[1, 2], [3, 4]]
print("original matrix:")
print(p)
print(q)
result1 = np.cross(p, q)
result2 = np.cross(q, p)
print("cross product of the said two vectors(p, q):")
print(result1)
print("cross product of the said two vectors(q, p):")
print(result2)
# ----------------------------------------------------------------------------------#
# 4. Write a NumPy program to compute the determinant of a given square array.
import numpy as np
from numpy import linalg as LA

a = np.array([[1, 0], [1, 2]])
print("Original 2-d array")
print(a)
print("Determinant of the said 2-D array:")
print(np.linalg.det(a))
# ----------------------------------------------------------------------------------#
# 5. Write a NumPy program to evaluate Einstein's summation convention of two given multidimensional arrays.
import numpy as np

a = np.array([1, 2, 3])
b = np.array([0, 1, 0])
print("Original 1-d arrays:")
print(a)
print(b)
result = np.einsum("n,n", a, b)
print("Einstein’s summation convention of the said arrays:")
print(result)
x = np.arange(9).reshape(3, 3)
y = np.arange(3, 12).reshape(3, 3)
print("Original Higher dimension:")
print(x)
print(y)
result = np.einsum("mk,kn", x, y)
print("Einstein’s summation convention of the said arrays:")
print(result)
# ----------------------------------------------------------------------------------#
# 6. Write a NumPy program to compute the inner product of vectors for 1-D arrays (without complex conjugation) and in higher dimension.
import numpy as np

a = np.array([1, 2, 5])
b = np.array([2, 1, 0])
print("Original 1-d arrays:")
print(a)
print(b)
print
result = np.inner(a, b)
print("Inner product of the said vectors:")
x = np.arange(9).reshape(3, 3)
y = np.arange(3, 12).reshape(3, 3)
print("Higher dimension arrays:")
print(x)
print(y)
result = np.inner(x, y)
print("Inner product of the said vectors:")
print(result)
# ----------------------------------------------------------------------------------#
# 7. Write a NumPy program to compute the eigenvalues and right eigenvectors of a given square array.
import numpy as np

m = np.mat("3 -2;1 0")
print("Original matrix:")
print("a\n", m)
w, v = np.linalg.eig(m)
print("Eigenvalues of the said matrix", w)
print("Eigenvectors of the said matrix", v)
# ----------------------------------------------------------------------------------#
# 8. Write a NumPy program to compute the Kronecker product of two given mulitdimension arrays.
import numpy as np

a = np.array([1, 2, 3])
b = np.array([0, 1, 0])
print("Original 1-d arrays:")
print(a)
print(b)
result = np.kron(a, b)
print("Kronecker product of the said arrays:")
print(result)
x = np.arange(9).reshape(3, 3)
y = np.arange(3, 12).reshape(3, 3)
print("Original Higher dimension:")
print(x)
print(y)
result = np.kron(x, y)
print("Kronecker product  of the said arrays:")
print(result)
# ----------------------------------------------------------------------------------#
# 9. Write a NumPy program to compute the condition number of a given matrix.
import numpy as np
from numpy import linalg as LA

a = np.array([[1, 0, -1], [0, 1, 0], [1, 0, 1]])
print("Original matrix:")
print(a)
print("The condition number of the said matrix:")
print(LA.cond(a))
# ----------------------------------------------------------------------------------#
# 10. Write a NumPy program to find a matrix or vector norm.
import numpy as np

v = np.arange(7)
result = np.linalg.norm(v)
print("Vector norm:")
print(result)
m = np.matrix('1, 2; 3, 4')
result1 = np.linalg.norm(m)
print("Matrix norm:")
print(result1)
# ----------------------------------------------------------------------------------#
# 11. Write a NumPy program to compute the determinant of an array.
import numpy as np

a = np.array([[1, 2], [3, 4]])
print("Original array:")
print(a)
result = np.linalg.det(a)
print("Determinant of the said array:")
print(result)
# ----------------------------------------------------------------------------------#
# 12. Write a NumPy program to compute the inverse of a given matrix.
import numpy as np

m = np.array([[1, 2], [3, 4]])
print("Original matrix:")
print(m)
result = np.linalg.inv(m)
print("Inverse of the said matrix:")
print(result)
# ----------------------------------------------------------------------------------#
# 13. Write a NumPy program to calculate the QR decomposition of a given matrix.
import numpy as np

m = np.array([[1, 2], [3, 4]])
print("Original matrix:")
print(m)
result = np.linalg.qr(m)
print("Decomposition of the said matrix:")
print(result)
# ----------------------------------------------------------------------------------#
# 14. Write a NumPy program to compute the condition number of a given matrix.
import numpy as np

m = np.array([[1, 2], [3, 4]])
print("Original matrix:")
print(m)
result = np.linalg.cond(m)
print("Condition number of the said matrix:")
print(result)
# ----------------------------------------------------------------------------------#
# 15. Write a NumPy program to compute the sum of the diagonal element of a given array.
import numpy as np

m = np.arange(6).reshape(2, 3)
print("Original matrix:")
print(m)
result = np.trace(m)
print("Condition number of the said matrix:")
print(result)
# ----------------------------------------------------------------------------------#
# 16. Write a NumPy program to get the lower-triangular L in the Cholesky decomposition of a given array.
import numpy as np

a = np.array([[4, 12, -16], [12, 37, -53], [-16, -53, 98]], dtype=np.int32)
print("Original array:")
print(a)
L = np.linalg.cholesky(a)
print("Lower-trianglular L in the Cholesky decomposition of the said array:")
print(L)
# ----------------------------------------------------------------------------------#
# 17. Write a NumPy program to get the qr factorization of a given array.
import numpy as np

a = np.array([[4, 12, -14], [12, 37, -53], [-14, -53, 98]], dtype=np.int32)
print("Original array:")
print(a)
q, r = np.linalg.qr(a)
print("qr factorization of the said array:")
print("q=\n", q, "\nr=\n", r)
# ----------------------------------------------------------------------------------#
# 18. Write a NumPy program to compute the factor of a given array by Singular Value Decomposition.
import numpy as np

a = np.array([[1, 0, 0, 0, 2], [0, 0, 3, 0, 0], [0, 0, 0, 0, 0], [0, 2, 0, 0, 0]], dtype=np.float32)
print("Original array:")
print(a)
U, s, V = np.linalg.svd(a, full_matrices=False)
q, r = np.linalg.qr(a)
print("Factor of a given array  by Singular Value Decomposition:")
print("U=\n", U, "\ns=\n", s, "\nV=\n", V)
# ----------------------------------------------------------------------------------#
# 19. Write a NumPy program to calculate the Frobenius norm and the condition number of a given array.
import numpy as np

a = np.arange(1, 10).reshape((3, 3))
print("Original array:")
print(a)
print("Frobenius norm and the condition number:")
print(np.linalg.norm(a, 'fro'))
print(np.linalg.cond(a, 'fro'))
# ----------------------------------------------------------------------------------#

NumPy Linear Algebra: Exercises & solutions.py


import numpy as np

# This function returns a value closer to the limit
def x2(x1): return x1 + (x1 * (10**-10))

# This function calculates de variation when we move x closer to the limit
# It is a good approximation for the derivative
def derivative(f, x): return (f(x2(x))-f(x))/(x2(x)-x)

# Sample and test data

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

# Test the derivative for x**2
print("Testing x**2 ...")
func = derivative(lambda x: x**2, x)
_derivative = np.round(func, 3)
print(_derivative)
error = (np.sum(np.round(func - 2*x, 3)))
print("PASSED:", error == 0.0, "\n")

# Test the derivative for x**3
print("Testing x**3 ...")
func = derivative(lambda x: x**3, x)
_derivative = np.round(func, 3)
print(_derivative)
error = (np.sum(np.round(func - 3*x**2, 3)))
print("PASSED:", error == 0.0, "\n")

# Test the derivative for sin(x)
print("Testing sin(x) ...")
func = derivative(lambda x: np.sin(x), x)
_derivative = np.round(func, 3)
print(_derivative)
error = (np.sum(np.round(derivative(lambda x: np.sin(x), x) - np.cos(x), 3)))
print("PASSED:", error == 0.0, "\n")


# -*- coding: utf-8 -*-
"""
Created on Sun Jan 16 14:53:16 2022

"""
import numpy as np
from MyQR import QR_householder
from Mychol import mychol

def ls_with_qr(C,b):
    A = C.copy()
    m = A.shape[0]
    n = A.shape[1]

    [Q,R,rank] = QR_householder(A)

    b = np.matmul(Q.T,b)
    min_dim = min(m,n)

    if rank < min_dim: # rank A < min_dim; Minimum norm solution is needed
        ReducedR = R[0:rank,:]
        L = mychol(np.matmul(ReducedR,ReducedR.T)) # L is a lower triangular matrix such that LL' = reducedA

        w = forward(L,b[:rank]) # solve L w = b;; note that b is Q'b.

        z = backward(L.T,w)  # solve L'z = w;
        x = np.matmul(ReducedR.T,z)

    else:      # R is nonsingular and square
        x = backward(R,b[:n])
    return(x)

def forward(A,b):
    n = A.shape[1]
    bn = b.shape[0]
    if n != bn:
        print("Number of rows of A  and b must be equal and A must be square");

    x = np.zeros((n,1))

    x[0] = b[0]/A[0,0]

    for i in range(1,n):
        sum = np.matmul(A[i,:i],x[:i])
        x[i] = (b[i] - sum)/A[i,i]

    return x

def backward(A,b):

    n = A.shape[1]
    bn = b.shape[0]
    if n != bn:
        print("Number of rows of A  and b must be equal and A must be square")

    x = np.zeros((n,1))

    x[n-1] = b[n-1]/A[n-1,n-1]

    for i in range(n-2,-1,-1):
        sum = np.matmul(A[i,i+1:n],x[i+1:n])
        x[i] = (b[i] - sum)/A[i,i]
    return x

'''
The main code
'''
def main():
    # A = np.array([[1.,2.,3.],[4.,5.,6.],[7.,8.,9.],[10.,11.,12.]])
    # print(A)
    # b = np.reshape(np.array([-1.,-5.,2.,1.]),(4,1))
    # print(b)
    # x = ls_with_qr(A,b)
    # print(x)
    A = np.array([[1.8162 ,   0.7361 ,  -1.6029],
                 [1.7961,    0.3619 ,  -0.6157],
                 [1.4627 ,  -0.0455  ,  0.3997],
                 [4.8991  ,  1.1483  , -2.1063]])
    print(A)
#    b = np.reshape(np.array([-1.,-5.,2.,1.]),(4,1))
    b = np.reshape(np.array([-0.0301, -0.1649, 0.6277, 1.0933]),(4,1))
    print(b)
    x = ls_with_qr(A,b)
    print(x)
if __name__ == "__main__":  ## This command executes the main function
    main()


import numpy as np

def riemann(func,a,b,n=10):
    """A simple Riemann-sum approximation to the integral of a function

Parameters
----------
func: callable
    Function to integrate, should be a function of one parameter
a: float
    Lower limit of the integration range
b: float
    Upper limit of the integration range
n: int, optional
    Number of intervals to split [a,b] into for the Riemann sum

Returns
-------
float
    Integral of func(x) over [a,b]
"""
    return np.sum(func(np.linspace(a,b,n))*(b-a)/n)

def simps(func,a,b,n=10):
    """Integrate a function using Simpson's rule

Parameters
----------
func: callable
    Function to integrate, should be a function of one parameter
a: float
    Lower limit of the integration range
b: float
    Upper limit of the integration range
n: int, optional
    Number of major intervals to split [a,b] into for the Simpson rule

Returns
-------
float
    Integral of func(x) over [a,b]

Notes
-----
Applies Simpson's rule as

.. math::

    \\int_a^b \\mathrm{d}x f(x) \\approx \\frac{(b-a)}{6n}\\,\\left[f(a)+4f(a+h/2)+2f(a+h)+4f(a+3h/2)+

    \ldots+2f(b-h)+4f(b-h/2)+f(b)\\right]

See Also
--------
exampy.integrate.riemann: Integrate a function with a simple Riemann sum
"""
    try:
        return (2.*np.sum(func(np.linspace(a,b,n+1)))
                -func(a)-func(b) # adjust double-counted first and last
                +4.*np.sum(func(np.linspace(a+(b-a)/n/2,b-(b-a)/n/2,n))))\
                *(b-a)/n/6.
    except TypeError:
        raise TypeError("Provided func needs to be callable on arrays of inputs")


import random
import numpy as np
from statistics import mean

# Using "random" to create a dataset
def create_dataset(hm, variance, step=2, correlation=False):
    val = 1
    sy = []
    for i in range(hm):
        y = val + random.randrange(-variance, variance)
        sy.append(y)
        if correlation and correlation == 'pos':
            val += step
        elif correlation and correlation == 'neg':
            val -= step

    sx = [i for i in range(len(sy))]

    return np.array(sx, dtype=np.float64), np.array(sy, dtype=np.float64)

# finding best fit slope and intercept of dataset
def best_fit_slope_and_intercept(sx, sy):
    m = (((mean(sx) * mean(sy)) - mean(sx * sy)) /
         ((mean(sx) * mean(sx)) - mean(sx * sx)))

    b = mean(sy) - m * mean(sx)

    return m, b

# dataset - coefficient of determination
def coefficient_of_determination(sy_orig, sy_line):
    y_mean_line = [mean(sy_orig) for y in sy_orig]

    squared_error_regr = sum((sy_line - sy_orig) * (sy_line - sy_orig))
    squared_error_y_mean = sum((y_mean_line - sy_orig) * (y_mean_line - sy_orig))

    print(squared_error_regr)
    print(squared_error_y_mean)

    r_squared = 1 - (squared_error_regr / squared_error_y_mean)

    return r_squared

def get_result():
    sx, sy = create_dataset(20, 10, 3)
    m, b = best_fit_slope_and_intercept(sx, sy)
    regression_line = [(m * x) + b for x in sx]
    r_squared = coefficient_of_determination(sy, regression_line)
    print('Rsquared result: ')
    return r_squared


from sympy.abc import x
import sympy as sp
import math

def improved_Newton_iteration(x0, func, tol=1e-9, Max_iter=100):
    """ Solve non-linear equation by improved Newton iteration method.

    Args:
        x0: double, iteration initial value
        func: function object, the function to be solved
        tol: double, iteration accuracy
        Max_iter: int, maximum iteration number

    Returns:
        k: int, iteration number
        z: double, root of the non-linear equation
    """
    # derivative
    y_diff = sp.diff(func(x))

    # first iteration
    k = 1
    u = x0
    v = u - func(u) / y_diff.subs(x, u)
    z = u - 2 * func(u) / (y_diff.subs(x, u) + y_diff.subs(x, v))

    # iteration
    while math.fabs(z - u) >= tol and y_diff.subs(x, z) != 0 and k < Max_iter:
        k += 1
        u = z
        v = u - func(u) / y_diff.subs(x, u)
        z = u - 2 * func(u) / (y_diff.subs(x, u) + y_diff.subs(x, v))

    return k, z

def f(x):
    return sp.Pow(x, 3) + sp.Pow(x, 2) - 3 * x - 3

if __name__ == '__main__':
    n, root = improved_Newton_iteration(2.0, f, 1e-6)
    print(f"The root of the non-linear equation is {root:.7f} by improved Newton iteration method.")
    print(f"Iteration number is {n}")


"""
# !/usr/bin/env python
# -*- coding: utf-8 -*-
@Time        : 2022/3/26 18:13
@File        : softmax.py
"""

# Solution is available in the other "solution.py" tab
import numpy as np

def softmax(x):
    """Compute softmax values for each sets of scores in x."""
    # TODO: Compute and return softmax(x)

    return np.exp(x) / np.sum(np.exp(x), axis=0)
    # x = np.divide(np.exp(x), np.sum(np.exp(x)))
    # return x

logits = [3.0, 1.0, 0.2]
print(softmax(logits))
# [0.8360188  0.11314284 0.05083836]
# [0.8360188  0.11314284 0.05083836]

udacity-program_self_driving_car_engineer_v1.0/part01-computer vision and deep learning/module03-deep learning/lesson03-introduction to tensorflow/exercise17-softmax/softmax.py


import numpy as np
import math
from copy import deepcopy

def ReadMatrixAndVec():
    matrixSize = int(input())

    matrix = [list(map(float, input().split())) for i in range(matrixSize)]
    vec = list(map(float, input().split()))

    return matrix, vec

def swapLines(matrix, idxFrom, idxTo):
    matrix[idxFrom], matrix[idxTo] = matrix[idxTo], matrix[idxFrom]

def pivot(matrix):
    p = []
    mtrx = matrix.copy()
    for j in range(len(mtrx)):
        tmp = [(mtrx[i][j], i) for i in range(j, len(mtrx))]
        idx = max(tmp, key=lambda x: abs(x[0]))[1]
        if idx != j:
            p.append((j, idx))
            swapLines(mtrx, j, idx)
    return p, mtrx

def LUDecomp(matrix):
    shape = len(matrix)
    lower = np.zeros((shape, shape))
    upper = np.zeros((shape, shape))
    pivo, pMtx = pivot(matrix)

    for i in range(shape):
        lower[i][i] = 1.0

        for j in range(i + 1):
            upper[j][i] = pMtx[j][i] - math.fsum([lower[j][k] * upper[k][i] for k in range(j)])
        for j in range(i, shape):
            lower[j][i] = (pMtx[j][i] - math.fsum([lower[j][k] * upper[k][i] for k in range(i)])) / upper[i][i]

    return lower, upper, pivo

def DirectSubstit(lowerMatrix, valVec):
    res = deepcopy(valVec)

    for i in range(1, len(valVec)):
        res[i] = valVec[i] - math.fsum([lowerMatrix[i][j] * res[j] for j in range(i)])

    return res

def InverseSubstit(upperMatrix, valVec):
    res = [0 for i in range(len(valVec))]
    res[-1] = valVec[-1] / upperMatrix[-1][-1]

    for i in reversed(range(len(valVec) - 1)):
        res[i] = (valVec[i] - math.fsum([upperMatrix[i][j] * res[j] for j in range(i + 1, len(valVec))])) / upperMatrix[i][i]

    return res

def pivotVec(vec, pivo):
    res = vec.copy()

    for i in range(len(pivo)):
        fromIdx, toIdx = pivo[i]
        swapLines(res, fromIdx, toIdx)

    return res

def SolveSLAU(matrix, valVec, isSingle):
    lower, upper, pivo = LUDecomp(matrix)

    if isSingle:
        print("Lower:")
        print(lower)
        print("Upper:")
        print(upper)

    pVec = pivotVec(valVec, pivo)

    if isSingle:
        print("Pivoted vector:")
        print(pVec)

    rhsVec = DirectSubstit(lower, pVec)

    if isSingle:
        print("rhsVec:")
        print(rhsVec)

    solVec = InverseSubstit(upper, rhsVec)

    return solVec

def InverseMtx(matrix):
    res = [[] for i in range(len(matrix))]
    eVec = [0.0 for i in range(len(matrix))]

    for i in range(len(matrix)):
        eVec[i] = 1.0
        tmp = SolveSLAU(matrix, eVec, False)
        for j in range(len(tmp)):
            res[j].append(tmp[j])
        eVec[i] = 0

    return res

def submatrix(M, c):
    B = [[1] * len(M) for i in range(len(M))]

    for l in range(len(M)):
        for k in range(len(M)):
            B[l][k] = M[l][k]

    B.pop(0)

    for i in range(len(B)):
        B[i].pop(c)
    return B

def det(mtx):
    res = 0

    if len(mtx) <= 2:
        return mtx[0][0] * mtx[1][1] - mtx[0][1] * mtx[1][0]
    else:
        for i in range(len(mtx)):
            res += ((-1) ** (i)) * mtx[0][i] * det(submatrix(mtx, i))

    return res

if __name__ == "__main__":
    matrix, vec = ReadMatrixAndVec()
    print("Orig Matrix:")
    print(matrix)
    print("valVec:")
    print(vec)

    result = np.matrix(SolveSLAU(matrix, vec, True)).transpose()
    npMtx = np.matrix(matrix)
    npVec = np.matrix(vec).transpose()

    print("Result:")
    print(result)
    print("matrix determinant:")
    print(det(matrix))
    print("matrix inverse:")
    print(np.matrix(InverseMtx(matrix)))


import numpy as np
import numpy.linalg as linalg
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.stats import chi2

x, y = np.random.normal(size=(2, 100))
z = x + y + np.random.normal(size=(1, 100))
points = np.array([x, y, z.squeeze()])

A = np.cov(points)

center = points.mean(axis=1)

# your ellispsoid and center in matrix form
# A = np.array([[10,0,0],[0,2,0],[0,0,2]])

# A = np.array([[ 0.00009, -0.00024, -0.00014],
#        [-0.00024,  0.00095,  0.00068],
#        [-0.00014,  0.00068,  0.00063]])

# center = [0,0,0]

# find the rotation matrix and radii of the axes
U, s, rotation = linalg.svd(A)
radii = np.sqrt(s)

# multiply sizes by desired percentile from chi square dist
chi_dist = chi2(3)
mag = np.sqrt(chi_dist.ppf(.95))
radii = radii * mag

# todo no scaling based on confidence interval yet -- test this but with points and confidence intervals
# see https://www.mathworks.com/matlabcentral/fileexchange/4705-error_ellipse

# now carry on with EOL's answer
u = np.linspace(0.0, 2.0 * np.pi, 100)
v = np.linspace(0.0, np.pi, 100)
x = radii[0] * np.outer(np.cos(u), np.sin(v))
y = radii[1] * np.outer(np.sin(u), np.sin(v))
z = radii[2] * np.outer(np.ones_like(u), np.cos(v))
for i in range(len(x)):
    for j in range(len(x)):
        [x[i,j],y[i,j],z[i,j]] = np.dot([x[i,j],y[i,j],z[i,j]], rotation) + center

# plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

ax.scatter(points[0], points[1], points[2])

ax.plot_wireframe(x, y, z,  rstride=1, cstride=1, color='b', alpha=0.2)

# lim = 2
# ax.set_xlim([-lim, lim])
# ax.set_ylim([-lim, lim])
# ax.set_zlim([-lim, lim])

# with points
p = points
ax.set_xlim([p[0].min() - .1, p[0].max() + .1])
ax.set_ylim([p[1].min() - .1, p[1].max() + .1])
ax.set_zlim([p[2].min() - .1, p[2].max() + .1])

plt.show()
plt.close(fig)
del fig


import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

def helper_best_rank_k_approximation(input_matrix, k, print_result=False):
    """
    Helper function for best_rank_k_approximation.
    Performs SVD on a given matrix and creates lower (k) dim matrix.

    Args:
    input_matrix (np.ndarray): a matrix representing one of r/g/b image
    k (int): the desired rank of out_matrix
    print_result (bool): default False

    Returns:
        out_matrix
    """
    matrix = np.array(input_matrix)
    u, singular_values, v = np.linalg.svd(matrix, full_matrices=False)
    rows = np.ma.size(matrix, 0)
    columns = np.ma.size(matrix, 1)
    out_matrix = np.zeros((rows, columns))

    for i in range(k):
        temp = (singular_values[i]*u[:, i:i+1])
        out_matrix += (np.matmul(temp, v[i:i+1, :]))

    singular_values_squared = singular_values*singular_values
    calculated_rate = sum(singular_values_squared[k:]) / sum(singular_values_squared)

    if print_result:
        print("When k is ", k, ", error of red matrix is ", calculated_rate)

    return out_matrix, calculated_rate

def best_rank_k_approximation(image_name, k_list):
    """
    Creates 'compressed' images of lower resolution from a given image.
    Each k value in k_list will create a save a new image with corresponding name.
    Args:
    image_name (str): file location, assumes location same folder.
    k_list (list): the desired k values to be used.
    """
    image = Image.open(image_name)
    b, g, r = image.split()
    rates_b = []
    rates_r = []
    rates_g = []

    for k_value in k_list:
        r_new, rate_r = helper_best_rank_k_approximation(r, k_value, print_result=True)
        g_new, rate_g = helper_best_rank_k_approximation(g, k_value)
        b_new, rate_b = helper_best_rank_k_approximation(b, k_value)
        image_r_new = Image.fromarray(r_new.clip(0, 255).astype('uint8'))
        image_g_new = Image.fromarray(g_new.clip(0, 255).astype('uint8'))
        image_b_new = Image.fromarray(b_new.clip(0, 255).astype('uint8'))
        image_new = Image.merge("RGB", (image_b_new, image_g_new, image_r_new))
        image_new.save(str(k_value)+"_approximation_"+image_name)
        rates_b.append(rate_b*100)
        rates_g.append(rate_g*100)
        rates_r.append(rate_r*100)

    plt.plot(k_list, rates_b, 'b', k_list, rates_r, 'r', k_list, rates_g, 'g')
    plt.xlabel('k (values)')
    plt.ylabel('Error Rate (percentage)')
    plt.title('Best Rank K Approximation')
    plt.show()

def main():
    k = list(range(5, 165, 5))
    best_rank_k_approximation("cute_dog.jpg", k)

main()


# sample 2d objective function
from numpy import arange
from numpy import meshgrid

# objective function
def objective(x, y):
	return x**2.0 + y**2.0

# define range for input
r_min, r_max = -5.0, 5.0
# sample input range uniformly at 0.1 increments
xaxis = arange(r_min, r_max, 0.1)
yaxis = arange(r_min, r_max, 0.1)
# create a mesh from the axis
x, y = meshgrid(xaxis, yaxis)
# summarize some of the input domain
print(x[:5, :5])
# compute targets
results = objective(x, y)
# summarize some of the results
print(results[:5, :5])
# create a mapping of some inputs to some results
for i in range(5):
	print('f(%.3f, %.3f) = %.3f' % (x[i,0], y[i,0], results[i,0]))


'''quadrature.py
Author: Huaiyu Duan (UNM)
Description: Python module that define the mesh and weights of various quadrature rules.
'''
import numpy as np

RULES = {} # dictionary of the quadrature rules

def mesh(a, b, n, rule='midpoint'):
    '''Compute the abscissas x[n] and weights w[n] using n nodes and the specified rule.
    The sum of f(x[i]) * w[i] gives an approximation of integral of f(x) for x from a to b.
    a : lower limit of the integral
    b : upper limit of the integral
    n : number of nodes
    rule : name of the quadrature rule

    return : x[n], w[n]
    '''
    assert rule in RULES, f"Unknown quadrature rule '{rule}''. The available choices are {list(RULES)}."
    return RULES[rule](a, b, n)

def _midpoint(a, b, n):
    '''Compute the mesh points x[n] and weights w[n] using the (composite) midpoint rule.
    The sum of f(x[i]) * w[i] gives an approximation of integral of f(x) for x from a to b.
    a : lower limit of the integral
    b : upper limit of the integral
    n : number of points

    return : x[n], w[n]
    '''
    n = int(n)
    assert n >= 1, "Number of abscissas should be at least 1 for the midpoint rule."
    dx = (b - a) / n # mesh interval
    x = a + (np.arange(n) + 0.5) * dx
    w = np.ones_like(x) * dx
    return x, w
RULES['midpoint'] = _midpoint

def _trapezoid(a, b, n):
    '''Compute the mesh points x[n] and weights w[n] using the (composite) trapezoid rule.
    The sum of f(x[i]) * w[i] gives an approximation of integral of f(x) for x from a to b.
    a : lower limit of the integral
    b : upper limit of the integral
    n : number of points

    return : x[n], w[n]
    '''
    n = int(n)
    assert n >= 2, "Number of abscissas should be at least 2 for the trapezoid rule."
    x = np.linspace(a, b, n)
    w = np.ones_like(x) * (x[1] - x[0])
    w[0] *= 0.5; w[-1] *= 0.5
    return x, w
RULES['trapezoid'] = _trapezoid

def _simpson(a, b, n):
    '''Compute the mesh points x[n] and weights w[n] using the (composite) Simpson's rule.
    The sum of f(x[i]) * w[i] gives an approximation of integral of f(x) for x from a to b.
    a : lower limit of the integral
    b : upper limit of the integral
    n : number of points

    return : x[n], w[n]
    '''
    n = int(n)
    assert n >= 3 and n%2 ,  "The number of abscissas should be an odd number larger than or equal to 3 for Simpson's rule."
    x = np.linspace(a, b, n)
    w = np.ones_like(x) * (x[1] - x[0])
    w[0] *= 1/3; w[-1] *= 1/3
    w[1:-1:2] *= 4/3; w[2:-2:2] *= 2/3
    return x, w
RULES['simpson'] = _simpson

def _simpson2(a, b, n):
    '''Compute the mesh points x[n] and weights w[n] using an alternative Simpson's rule that works better for functions with narrow peaks.
    The sum of f(x[i]) * w[i] gives an approximation of integral of f(x) for x from a to b.
    a : lower limit of the integral
    b : upper limit of the integral
    n : number of points

    return : x[n], w[n]
    '''
    n = int(n)
    assert n >= 6,  "The number of abscissas should be at least 6 for the alternative Simpson's rule."
    x = np.linspace(a, b, n)
    w = np.ones_like(x) * (x[1] - x[0])
    w[0] *= 9/24; w[-1] *= 9/24
    w[1] *= 28/24; w[-2] *= 28/24
    w[2] *= 23/24; w[-3] *= 23/24
    return x, w
RULES['simpson2'] = _simpson2

def _chebyshev(a, b, n):
    '''Compute the mesh points x[n] and weights w[n] using the Chebyshev-Gaussian quadrature.
    The sum of f(x[i]) * w[i] gives an approximation of integral of f(x) for x from a to b.
    a : lower limit of the integral
    b : upper limit of the integral
    n : number of points

    return : x[n], w[n]
    '''
    from scipy.special import roots_chebyt
    y, w = roots_chebyt(n)
    x = (b-a)*0.5*np.array(y) + (b+a)*0.5 # transform from [-1, 1] to [a, b]
    w *= 0.5 * (b - a) * np.sqrt(1 - y**2)
    return x, w
#     # y = [np.cos(np.pi*(j+0.5)/n) for j in range(n)] # Chebyshev nodes
#     # x = (b-a)*0.5*np.array(y) + (b+a)*0.5 # transform from [-1, 1] to [a, b]
#     # w = [np.sqrt(1-y[j]**2) for j in range(n)]
#     # w = 0.5*(b-a)*(np.pi/n)*np.array(w) # weights
#     # return x, w
RULES['chebyshev'] = _chebyshev

def _legendre(a, b, n):
    '''Compute the mesh points x[n] and weights w[n] using the Legendre-Gaussian quadrature.
    The sum of f(x[i]) * w[i] gives an approximation of integral of f(x) for x from a to b.
    a : lower limit of the integral
    b : upper limit of the integral
    n : number of points

    return : x[n], w[n]
    '''
    from scipy.special import roots_legendre
    y, w = roots_legendre(n)
    x = (b-a)*0.5*np.array(y) + (b+a)*0.5 # transform from [-1, 1] to [a, b]
    w *= 0.5 * (b - a)
    return x, w
RULES['legendre'] = _legendre


"""
This script demonstrates the implementation of the Sigmoid function.

The function takes a vector of K real numbers as input and then 1 / (1 + exp(-x)).
After through Sigmoid, the element of the vector mostly 0 between 1. or 1 between -1.

Script inspired from its corresponding Wikipedia article
https://en.wikipedia.org/wiki/Sigmoid_function
"""

import numpy as np

def sigmoid(vector: np.array) -> np.array:
    """
    Implements the sigmoid function

    Parameters:
        vector (np.array): A  numpy array of shape (1,n)
        consisting of real values

    Returns:
        sigmoid_vec (np.array): The input numpy array, after applying
        sigmoid.

    Examples:
    >>> sigmoid(np.array([-1.0, 1.0, 2.0]))
    array([0.26894142, 0.73105858, 0.88079708])

    >>> sigmoid(np.array([0.0]))
    array([0.5])
    """
    return 1 / (1 + np.exp(-vector))

if __name__ == "__main__":
    import doctest

    doctest.testmod()


import numpy as np

class Regularizations:

    @staticmethod
    def lasso_l1(w,lambda_):
        """Computes lasso regularization

        Args:
            w (np.ndarray): matrix of layer's weights
            lambda_ (float): regularization hyperparameter

        Returns:
            np.float64: value of regularization/penalty term
        """
        return lambda_ * np.linalg.norm(w,1)

    @staticmethod
    def lasso_l1_der(w,lambda_):
        """Computes lasso regularization's derivative

        Args:
            w (np.ndarray): matrix of layer's weights
            lambda_ (float): regularization hyperparameter

        Returns:
            np.ndarray: derivative of lasso regularization
        """
        return lambda_ * np.sign(w)

    @staticmethod
    def ridge_regression_l2(w,lambda_):
        """Computes ridge regression

        Args:
            w (np.ndarray): matrix of layer's weights
            lambda_ (float): regularization hyperparameter

        Returns:
            np.float64: value of regularization/penalty term
        """
        return 1/2 * lambda_ * np.linalg.norm(w,2) * np.linalg.norm(w,2)

    @staticmethod
    def ridge_regression_l2_der(w,lambda_):
        """Computes ridge regression's derivative

        Args:
            w (np.ndarray): matrix of layer's weights
            lambda_ (float): regularization hyperparameter

        Returns:
            np.ndarray: derivative of ridge regression
        """
        return lambda_ * w

    @staticmethod
    def init_regularization(name):
        if name == "lasso":
            return Regularizations.lasso_l1, Regularizations.lasso_l1_der, name
        elif name == "ridge_regression":
            return Regularizations.ridge_regression_l2, Regularizations.ridge_regression_l2_der, name
        else:
            raise NameError(name+ " is not recognized! Check for correct names and possible regularizations in init_regularization!")


# model fitting problem with logistic loss and L1 regularization.
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
import cvxpy as cp

# In this example, we use CVXPY to train a logistic regression classifier with ℓ1 regularization. We are given data (xi,yi), i=1,…,m. The xi∈Rn are feature vectors, while the yi∈{0,1} are associated boolean classes.
# Our goal is to construct a linear classifier ŷ =𝟙[βTx>0], which is 1 when βTx is positive and 0 otherwise. We model the posterior probabilities of the classes given the data linearly, with
# logPr(Y=1∣X=x)Pr(Y=0∣X=x)=βTx.
# This implies that
# Pr(Y=1∣X=x)=exp(βTx)1+exp(βTx),Pr(Y=0∣X=x)=11+exp(βTx).
# We fit β by maximizing the log-likelihood of the data, plus a regularization term λ‖β‖1 with λ>0:
# ℓ(β)=∑i=1myiβTxi−log(1+exp(βTxi))−λ‖β‖1.
# Because ℓ is a concave function of β, this is a convex optimization problem.

# Construct Z given X.
def pairs(Z):
    m, n = Z.shape
    k = n * (n + 1) // 2
    X = np.zeros((m, k))
    count = 0
    for i in range(n):
        for j in range(i, n):
            X[:, count] = Z[:, i] * Z[:, j]
            count += 1
    return X

# Generate data for logistic model fitting problem.
np.random.seed(1)
n = 10
k = n * (n + 1) // 2
m = 200
TEST = 100
sigma = 1.9
DENSITY = 1.0
theta_true = np.random.randn(n, 1)

idxs = np.random.choice(range(n), int((1 - DENSITY) * n), replace=False)
for idx in idxs:
    beta_true[idx] = 0

Z = np.random.binomial(1, 0.5, size=(m, n))
Y = np.sign(Z.dot(theta_true) + np.random.normal(0, sigma, size=(m, 1)))
X = pairs(Z)
X = np.hstack([X, np.ones((m, 1))])
Z_test = np.random.binomial(1, 0.5, size=(TEST, n))
Y_test = np.sign(Z_test.dot(theta_true) + np.random.normal(0, sigma, size=(TEST, 1)))
X_test = pairs(Z_test)
X_test = np.hstack([X_test, np.ones((TEST, 1))])

theta = cp.Variable((k + 1, 1))
lambd = cp.Parameter(nonneg=True)
loss = cp.sum(
    cp.log_sum_exp(cp.hstack([np.zeros((m, 1)), -cp.multiply(Y, X @ theta)]), axis=1)
)
reg = cp.norm(theta[:k], 1)
prob = cp.Problem(cp.Minimize(loss / m + lambd * reg))
# Compute a trade-off curve and record train and test error.
TRIALS = 100
train_error = np.zeros(TRIALS)
test_error = np.zeros(TRIALS)
lambda_vals = np.logspace(-4, 0, TRIALS)
for i in range(TRIALS):
    lambd.value = lambda_vals[i]
    prob.solve(solver=cp.SCS)
    train_error[i] = (
        np.sign(Z.dot(theta_true)) != np.sign(X.dot(theta.value))
    ).sum() / m
    test_error[i] = (
        np.sign(Z_test.dot(theta_true)) != np.sign(X_test.dot(theta.value))
    ).sum() / TEST
# Plot the train and test error over the trade-off curve.

plt.plot(lambda_vals, train_error, label="Train error")
plt.plot(lambda_vals, test_error, label="Test error")
plt.xscale("log")
plt.legend(loc="upper left")
plt.xlabel(r"$\lambda$", fontsize=16)
plt.show()

# Below we plot |θk|, k=1,…,55, for the λ that minimized the test error. Each |θk| is placed at position (i,j) where zizj=xk. Notice that many θk are 0, as we would expect with ℓ1 regularization.

# Solve model fitting problem with the lambda that minimizes test error.
idx = np.argmin(test_error)
lambd.value = lambda_vals[idx]
prob.solve(solver=cp.SCS)

# Plot the absolute value of the entries in theta corresponding to each feature.
P = np.zeros((n, n))
count = 0
for i in range(n):
    for j in range(i, n):
        P[i, j] = np.abs(theta.value[count])
        count += 1
row_labels = range(1, n + 1)
column_labels = range(1, n + 1)

fig, ax = plt.subplots()
heatmap = ax.pcolor(P, cmap=plt.cm.Blues)

# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(P.shape[1]) + 0.5, minor=False)
ax.set_yticks(np.arange(P.shape[0]) + 0.5, minor=False)

# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.tick_top()

ax.set_xticklabels(column_labels, minor=False)
ax.set_yticklabels(row_labels, minor=False)

plt.xlabel(r"$z_i$", fontsize=16)
ax.xaxis.set_label_position("top")
plt.ylabel(r"$z_j$", fontsize=16)
plt.show()


# ==============================================================================
# Author: Eddie Guo
# Date: November 6, 2021
#
# Author's notes:
# You may share and modify (and do whatever you want) with this code.
# I hope this helps you with your assignments :)
#
# This script creates a linear regression model and plots the output.
# ==============================================================================

import matplotlib.pyplot as plt  # for plotting
import numpy as np               # for arrays
import pandas as pd              # for data manipulation

# Ordinary Least Squares (OLS): y = A + Bx
def Delta(x):
	# N \sum x^2 - \left( \sum x \right)^2
	return len(x) * np.sum(x**2) - np.sum(x)**2

def A(x, y):
	# A = \frac{(\sum x^2 \sum y - \sum x \sum xy)}{\Delta}
	return (np.sum(x**2)*np.sum(y)-np.sum(x)*np.sum(x*y)) / Delta(x)

def B(x, y):
	# B = \frac{N \sum xy - \sum x \sum y}{\Delta}
	return (len(x)*np.sum(x*y)-np.sum(x)*np.sum(y)) / Delta(x)

# Step 1. Read in the data.
df = pd.read_csv('cheese_and_deaths.csv')
print(df.head())

# Step 2. Visualize the data and verify a linear relationship.
plt.scatter(df['year'], df['deaths'])
plt.show()

# Step 3. Create the OLS model.
intercept = A(df['year'], df['deaths'])
slope = B(df['year'], df['deaths'])
# I love Python f-strings
# https://www.geeksforgeeks.org/formatted-string-literals-f-strings-python/
print(f'The slope is {slope} and the intercept is {intercept}.')

# Step 4. Re-visualize with your model.
x = np.linspace(2000, 2010, 10)  # 10 equally spaced points btw 2000 and 2010
y = slope*x + intercept
plt.scatter(df['year'], df['deaths'], color='black')
plt.plot(x, y, color='black')
plt.xlabel('Year')
plt.ylabel('Bedide tanglies (deaths)')
# Uncomment the line below to save the figure.
# plt.savefig('my_figs_name.png', dpi=250)
plt.show()

# Fun aside ====================================================================
# Question: What is the correlation between per capita cheese consumption and
# number of people who die by becoming tangled in their bedsheets?

# Answer: Let's visualize it!
intercept_cheese = A(df['year'], df['cheese_consumption'])
slope_cheese = B(df['year'], df['cheese_consumption'])
y1 = slope_cheese*x + intercept_cheese

fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.plot(x, y, color='red')
ax2.plot(x, y1, color='black')

ax1.scatter(df['year'], df['deaths'], color='red')
ax2.scatter(df['year'], df['cheese_consumption'], color='black')

ax1.set_xlabel('Year')
ax1.set_ylabel('Besheet tanglies (deaths)', color='red')
ax2.set_ylabel('Cheese consumed (lbs)')
plt.tight_layout()
plt.show()

# Answer 2: r = 0.9471 (or 94.71%)
# Correlation != causation (or does it... haha)


import numpy as np

def diff_of_means(data_1, data_2):
    """Difference in means of two arrays."""

    # The difference of means of data_1, data_2: diff
    diff = np.mean(data_1) - np.mean(data_2)

    return diff

def _permutation_sample(data):

    permuted_data = np.random.permutation(data)

    return permuted_data

def permutation_over_two_series(data1, data2):
    """Generate a permutation sample from two data sets."""

    # Concatenate the data sets: data
    data = np.concatenate((data1, data2))

    # Permute the concatenated array: permuted_data
    permuted_data = _permutation_sample(data)

    # Split the permuted array into two: perm_sample_1, perm_sample_2
    perm_sample_1 = permuted_data[:len(data1)]
    perm_sample_2 = permuted_data[len(data1):]

    return perm_sample_1, perm_sample_2

def draw_perm_reps(data_1, data_2, func, size=1):
    """Generate multiple permutation replicates."""

    # Initialize array of replicates: perm_replicates
    perm_replicates = np.empty(size)

    for i in range(size):
        # Generate permutation sample
        perm_sample_1, perm_sample_2 = permutation_over_two_series(data_1, data_2)

        # Compute the test statistic
        perm_replicates[i] = func(perm_sample_1, perm_sample_2)

    return perm_replicates

def eval_permutation_p_value(samples_A, samples_B, reducer=diff_of_means, size=10000, condition='gt'):

    # Compute difference of mean impact force from experiment: empirical_diff_means
    empirical_diff_means = reducer(samples_A, samples_B)

    # Draw 10,000 permutation replicates: perm_replicates
    perm_replicates = draw_perm_reps(samples_A, samples_B,
                                     reducer, size=size)

    # Compute p-value:
        # the p_value is the sum of all positive cases divided by the
        #number of samples
        # the positive cases are those whose perm_replicate value is equal
        #or higher (more extreme) than the observed value.

    if condition.lower() == 'gt':

        p_value = np.mean(perm_replicates >= empirical_diff_means)

    elif condition.lower() == 'lt':
        p_value = np.mean(perm_replicates <= empirical_diff_means)

    else:
        mask1 = perm_replicates <= empirical_diff_means

        mask2 = perm_replicates >= empirical_diff_means

        Conditional = perm_replicates[mask1 | mask2]
        p_value = np.sum(Conditional)/len(perm_replicates)

    return {'p_value':p_value,
            'perm_replicates':perm_replicates,
            'empirical_diff_means':empirical_diff_means}

if '__main__' == __name__:
    """
    Description:

        Assuming that we wish to evaluate the probability that two
        populations have same statistics (i.e.: mean).

        A possible solution for this hypothesis test is the t-statistics.

        Another solution is the permutation replicate technique using a
        mean difference as a reducer function.

    Case example:
        samples_A: samples from population A (i.e.: petal length without treatment)
        samples_B: samples from population B (i.e.: petal length with treatment)

        Reducer: diff_of_means. It evaluates the difference between
        Population Means

        H0: Population means are the same
        Ha: Population means are not equal

    Result:
        p_value (reprents the probability of retrieving a value more extreme
                 than the observed, assuming that hypothesis null is True.

        When we assume alpha == 0.05, if p_value < alpha, we reject H0,
        and accept the alternative (Ha).

    """

    print('''Case example:
        samples_A: samples from population A (i.e.: petal length without treatment)
        samples_B: samples from population B (i.e.: petal length with treatment)

        '''
        )

    samples_A = np.random.normal(4, 5, size=500)

    samples_B = np.random.normal(3.7, 7.5, size=500)

    # Compute difference of mean impact force from experiment: empirical_diff_means
    empirical_diff_means = diff_of_means(samples_A, samples_B)

    # Draw 10,000 permutation replicates: perm_replicates
    perm_replicates = draw_perm_reps(samples_A, samples_B,
                                     diff_of_means, size=10000)

    # Compute p-value: p
    p_value = np.mean(perm_replicates >= empirical_diff_means)

    print(perm_replicates)
    # Print the result
    print('p-value =', p_value)

if '__main__' == __name__:
    # Case 2 (Bernoulli situation)

    """
    Description:

        Assume that a given population A (democrats - dems) have a
        certain tendency towards voting in favor (boolean False X True)
        for a given Legislation, and population B (republicans - reps)
        have a second tendency.

        We wish to evaluate the probability that the populations have equal
        tendency in the voting.

    Conditions:

        Since it is a Bernoulli situation, the differences in population
        does no longer apply for this test.

        It is necessary to evaluate the respective frequencies of voting
        per group:

    """
    print('''
          \n\n

          ---------------------------------------------------

          Description:

        Assume that a given population A (democrats - dems) have a
        certain tendency towards voting in favor (boolean False X True)
        for a given Legislation, and population B (republicans - reps)
        have a second tendency.

        We wish to evaluate the probability that the populations
        have equal tendency in the voting.

        \n\n

        ------------------------------------ \n'''
        )

    # Construct arrays of data: dems, reps
    dems = np.array([True] * 153 + [False] * 91)
    reps = np.array([True] * 136 + [False] * 35)

    def frac_yea_dems(group_A, group_B=None):
        """Compute fraction of group_A."""
        frac = group_A[group_A==True].size / (group_A.size)
        return frac

    # Acquire permutation samples: perm_replicates
    perm_replicates = draw_perm_reps(dems, reps, frac_yea_dems, 10000)
    real_fraction = frac_yea_dems(dems)
    # Compute and print p-value: p
    p = np.sum(perm_replicates <= real_fraction) / len(perm_replicates)
    print('p-value =', p)

if '__main__' == __name__:
    """
    Description:

        population A: each sample from population A represents the
        amount of time (in accumulated months) that a given event reoccurs.

        After a given treatment, which could have changed the rates
        in the events of population A, a second sample set (Population B)
        was evaluated.

    Question:
        Is there a significant statistical change prior and after the
        treatment?

        In another words: what is the probability that the treatment
        causes a negative change in the event occurence given that the null hypothesis is true

    Condition:
        since the treatment changed the rates in the events in a negative
        way (i.e., longer average time between event occurrence), we are interested in the "<=" condition for p-value test statistics

    Hypothesis:
        H0: treatment does not change the rates in the events occurence.
        In another words, rates of Population A are equal to Population B:
        Ha: the treatment does change the rates
    """

    print('''
          \n\n

          Description:

        population A: each sample from population A represents the
        amount of time (in accumulated months) that a given event reoccurs.

        After a given treatment, which could have changed the rates in
        the events of population A, a second sample set (Population B)
        was evaluated.

    Question:
        Is there a significant statistical change prior and after the treatment?

        In another words: what is the probability that the treatment
        causes a negative change in the event occurence given that
        the null hypothesis is true

        \n\n

        ------------------------------------ \n'''
        )

    eval_permutation_p_value(samples_A, samples_B, reducer=diff_of_means, size=10000, condition='gt')

if '__main__' == __name__:
    """
    Correlation test statistics

    Description:

        In this example, the statistical confidence (p-value) of the
        correlation coefficient is evaluated.

    The condition evaluated is:
        what is the probability of getting a correlation
        coefficient equal or higher than the observed?

    """

    def pearson_r (x,y):

        return np.corrcoef(x,y)[0][1]

    Result = eval_permutation_p_value(samples_A, samples_B, reducer=pearson_r, size=10000, condition='gt')

    print('p_value =', Result['p_value'])


import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
import math

def predict_using_sklean():
    df = pd.read_csv("exe_gradent_decent.csv")
    r = LinearRegression()
    r.fit(df[['math']],df.cs)
    return r.coef_, r.intercept_

def gradient_descent(x,y):
    m_curr = 0
    b_curr = 0
    iterations = 1000000
    n = len(x)
    learning_rate = 0.0002

    cost_previous = 0

    for i in range(iterations):
        y_predicted = m_curr * x + b_curr
        cost = (1/n)*sum([value**2 for value in (y-y_predicted)])
        md = -(2/n)*sum(x*(y-y_predicted))
        bd = -(2/n)*sum(y-y_predicted)
        m_curr = m_curr - learning_rate * md
        b_curr = b_curr - learning_rate * bd
        if math.isclose(cost, cost_previous, rel_tol=1e-20):
            break
        cost_previous = cost
        print ("m {}, b {}, cost {}, iteration {}".format(m_curr,b_curr,cost, i))

    return m_curr, b_curr

if __name__ == "__main__":
    df = pd.read_csv("exe_gradent_decent.csv")
    x = np.array(df.math)
    y = np.array(df.cs)

    m, b = gradient_descent(x,y)
    print("Using gradient descent function: Coef {} Intercept {}".format(m, b))

    m_sklearn, b_sklearn = predict_using_sklean()
    print("Using sklearn: Coef {} Intercept {}".format(m_sklearn,b_sklearn))


import numpy as np

def rotation_x(phi: float) -> np.ndarray:
    """
    Return the Rotation matrix around the X-axis for phi radians.
    """
    R_rot = np.array([[1, 0, 0],
                      [0, np.cos(phi), -np.sin(phi)],
                      [0, np.sin(phi), np.cos(phi)]])
    return R_rot

def rotation_y(theta: float) -> np.ndarray:
    """
    Return the Rotation matrix around the Y-axis for theta radians.
    """
    R_rot = np.array([[np.cos(theta), 0, -np.sin(theta)],
                      [0, 1, 0],
                      [np.sin(theta), 0, np.cos(theta)]])
    return R_rot

def rotation_z(psi: float) -> np.ndarray:
    """
    Return the Rotation matrix around the Z-axis for psi radians.
    """
    R_rot = np.array([[np.cos(psi), -np.sin(psi), 0],
                      [np.sin(psi), np.cos(psi), 0],
                      [0, 0, 1]])
    return R_rot

def euler_rotation(roll: float, pitch: float, yaw: float, is_radians: bool = False) -> np.ndarray:
    """
    Returns the Euler rotation matrix for 3 rotation angles around X-Y-Z
    """
    # Convert to Radians:
    if not is_radians:
        roll, pitch, yaw = np.deg2rad(roll), np.deg2rad(pitch), np.deg2rad(yaw)

    R = rotation_z(yaw) @ rotation_y(pitch) @ rotation_x(roll)
    return R


"""
This file is some side functions that allows for the conversion of cordinate
systems.
"""

import numpy as np

########################################################################
##########                From Cartesian to ***               ##########
########################################################################

def cartesian_to_polar_2d(x, y):
    """Convert cartesian points to polar points.

    Convert cartesian coordinate points in 2D to polar coordinate points in 2D.
    This function uses the notation convention of ISO 80000-2:2009 and its
    related successors.

    Parameters
    ----------
    x : array_like
        The x values of the points to be transformed.
    y : array_like
        The y values of the points to be transformed.

    Returns
    -------
    rho : array_like
        The rho (radial) values of the points after transformation.
    phi : array_like
        The phi (angular) values of the points after transformation.
    """

    # Basic validation
    x = np.array(x, dtype=float)
    y = np.array(y, dtype=float)

    # Convert to polar coordinates.
    rho = np.hypot(x, y)
    phi = np.arctan2(y, x)

    return rho, phi

def cartesian_to_cylindrical_3d(x, y, z):
    """Convert cartesian points to cylindrical points.

    Convert cartesian coordinate points in 3D to cylindrical coordinate points
    in 3D. This function uses the notation convention of ISO 80000-2:2009 and
    its related successors.

    Parameters
    ----------
    x : array_like
        The x values of the points to be transformed.
    y : array_like
        The y values of the points to be transformed.
    z : array_like
        The z values of the points to be transformed.

    Returns
    -------
    rho : array_like
        The rho (radial) values of the points after transformation.
    phi : array_like
        The phi (angular) values of the points after transformation.
    z : array_like
        The z (height) values of the points after transformation.
    """

    # Basic validation.
    x = np.array(x, dtype=float)
    y = np.array(y, dtype=float)
    z = np.array(z, dtype=float)

    # Convert to cylindrical coordinates.
    rho = np.hypot(x, y)
    phi = np.arctan2(y, z)
    z = z

    return rho, phi, z

def cartesian_to_spherical_3d(x, y, z):
    """Convert cartesian points to cylindrical points.

    Convert cartesian coordinate points in 3D to cylindrical coordinate points
    in 3D. This function uses the notation convention of ISO 80000-2:2009 and
    its related successors.

    Parameters
    ----------
    x : array_like
        The x values of the points to be transformed.
    y : array_like
        The y values of the points to be transformed.
    z : array_like
        The z values of the points to be transformed.

    Returns
    -------
    r : array_like
        The rho (radial) values of the points after transformation.
    theta : array_like
        The theta (azimuthal angle) values of the points after the
        transformation.
    phi : array_like
        The phi (polar angle) values of the points after the transformation.
    """

    # Basic validation.
    x = np.array(x, dtype=float)
    y = np.array(y, dtype=float)
    z = np.array(z, dtype=float)

    # Convert to spherical coordinates.
    r = np.sqrt(x**2 + y**2 + z**2)
    theta = np.arccos(z/r)
    phi = np.arctan2(y, x)

    return r, theta, phi

########################################################################
##########                  From Polar to ***                 ##########
########################################################################

def polar_to_cartesian_2d(rho, phi):
    """Convert polar points to cartesian points.

    Convert polar coordinate points in 2D to cartesian coordinate points in 2D.
    This function uses the notation convention of ISO 80000-2:2009 and its
    related successors.

    Parameters
    ----------
    rho : array_like
        The rho values of the points to be transformed.
    phi : array_like
        The phi values of the points to be transformed.

    Returns
    -------
    x : array_like
        The x values of the points after transformation.
    y : array_like
        The y values of the points after transformation.
    """

    # Basic type checking
    rho = np.array(rho, dtype=float)
    phi = np.array(phi, dtype=float)

    # Convert
    x = rho * np.cos(phi)
    y = rho * np.sin(phi)

    return x, y

########################################################################
##########               From Cylindrical to ***              ##########
########################################################################

def cylindrical_to_cartesian_3d(rho, phi, z):
    """Convert cylindrical points to cartesian points.

    Convert cylindrical coordinate points in 3D to cartesian coordinate points
    in 3D. This function uses the notation convention of ISO 80000-2:2009 and
    its related successors.

    Parameters
    ----------
    rho : array_like
        The rho values of the points to be transformed.
    phi : array_like
        The phi values of the points to be transformed.
    z : array_like
        The z values of the points to be transformed.

    Returns
    -------
    x : array_like
        The x values of the points after transformation.
    y : array_like
        The y values of the points after transformation.
    z : array_like
        The z values of the points after transformation.
    """

    # Basic type checking
    rho = np.array(rho, dtype=float)
    phi = np.array(phi, dtype=float)
    z = np.array(z, dtype=float)

    # Convert
    x = rho * np.cos(phi)
    y = rho * np.sin(phi)
    z = z

    return x, y, z

def cylindrical_to_spherical_3d(rho, phi, z):
    """Convert cylindrical points to spherical points.

    Convert cylindrical coordinate points in 3D to spherical coordinate points
    in 3D. This function uses the notation convention of ISO 80000-2:2009 and
    its related successors.

    Parameters
    ----------
    rho : array_like
        The rho values of the points to be transformed.
    phi : array_like
        The phi values of the points to be transformed.
    z : array_like
        The z values of the points to be transformed.

    Returns
    -------
    r : array_like
        The rho (radial) values of the points after transformation.
    theta : array_like
        The theta (azimuthal angle) values of the points after the
        transformation.
    phi : array_like
        The phi (polar angle) values of the points after the transformation.
    """

    # Basic type checking
    rho = np.array(rho, dtype=float)
    phi = np.array(phi, dtype=float)
    z = np.array(z, dtype=float)

    # Convert
    r = np.hypot(rho, z)
    theta = np.arccos(z/r)
    phi = phi

    return r, theta, phi

########################################################################
##########                From Spherical to ***               ##########
########################################################################

def spherical_to_cartesian_3d(r, theta, phi):
    """Convert spherical points to cartesian points.

    Convert spherical coordinate points in 3D to cartesian coordinate points
    in 3D. This function uses the notation convention of ISO 80000-2:2009 and
    its related successors.

    Parameters
    ----------
    r : array_like
        The r values of the points to be transformed.
    theta : array_like
        The theta values of the points to be transformed.
    phi : array_like
        The phi values of the points to be transformed.

    Returns
    -------
    x : array_like
        The x values of the points after transformation.
    y : array_like
        The y values of the points after transformation.
    z : array_like
        The z values of the points after transformation.
    """

    # Basic type checking
    r = np.array(r, dtype=float)
    theta = np.array(theta, dtype=float)
    phi = np.array(phi, dtype=float)

    # Convert
    x = r * np.sin(theta) * np.cos(phi)
    y = r * np.sin(theta) * np.sin(phi)
    z = r * np.cos(theta)

    return x, y, z

def spherical_to_cylindrical_3d(r, theta, phi):
    """Convert cylindrical points to cartesian points.

    Convert cylindrical coordinate points in 3D to cartesian coordinate points
    in 3D. This function uses the notation convention of ISO 80000-2:2009 and
    its related successors.

    Parameters
    ----------
    r : array_like
        The r values of the points to be transformed.
    theta : array_like
        The theta values of the points to be transformed.
    phi : array_like
        The phi values of the points to be transformed.

    Returns
    -------
    rho : array_like
        The rho values of the points after transformation.
    phi : array_like
        The phi (angular) values of the points after transformation.
    z : array_like
        The z values of the points after transformation.
    """

    # Basic type checking
    r = np.array(r, dtype=float)
    theta = np.array(theta, dtype=float)
    phi = np.array(phi, dtype=float)

    # Convert
    rho = r * np.sin(theta)
    phi = phi
    z = r * np.cos(theta)

    return rho, phi, z


# Import required libraries:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
from sklearn.metrics import r2_score

# Generating dataset:
# Y = A*sin(B(X + C)) + D
# A = Amplitude
# Period = 2*pi/B
# Period = Length of One Cycle
# C = Phase Shift (In Radian)
# D = Vertical Shift

X = np.linspace(0,1,100)             #(Start,End,Points)

# Here…
# A = 1
# B= 2*pi
# B = 2*pi/Period
# Period = 1
# C = 0
# D = 0

Y = 1*np.sin(2*np.pi*X)

# Adding some Noise :
Noise = 0.4*np.random.normal(size=100)
Y_data = Y + Noise
plt.scatter(X,Y_data,c="r")

# Calculate the value:
def calc_sine(x,a,b,c,d):
  return a * np.sin(b* ( x + np.radians(c))) + d

# Finding optimal parameters :
popt,pcov = curve_fit(calc_sine,X,Y_data)

# Plot the main data :
plt.scatter(X,Y_data)# Plot the best fit curve :
plt.plot(X,calc_sine(X,*popt),c="r")
plt.show()

# Check the accuracy :
Accuracy =r2_score(Y_data,calc_sine(X,*popt))
print (Accuracy)

# Function to calculate the value :
def calc_line(X,m,b):
  return b + X*m

# It returns optimized parametes for our function :
# popt stores optimal parameters
# pcov stores the covarience between each parameters.
popt,pcov = curve_fit(calc_line,X,Y_data)

# Plot the main data :
plt.scatter(X,Y_data)

# Plot the best fit line :
plt.plot(X,calc_line(X,*popt),c="r")
plt.show()

# Check the accuracy of model :
Accuracy =r2_score(Y_data,calc_line(X,*popt))
print ("Accuracy of Linear Model : ",Accuracy)


# Plot ridge regression applied to  1d polynomial problem
# Based on https://github.com/probml/pmtk3/blob/master/demos/polyfitRidgeLasso.m

import numpy as np
import matplotlib.pyplot as plt
from pyprobml_utils import save_fig

from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import Ridge
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error as mse

def make_1dregression_data(n=21):
    np.random.seed(0)
    xtrain = np.linspace(0.0, 20, n)
    xtest = np.arange(0.0, 20, 0.1)
    sigma2 = 4
    w = np.array([-1.5, 1/9.])
    fun = lambda x: w[0]*x + w[1]*np.square(x)
    ytrain = fun(xtrain) + np.random.normal(0, 1, xtrain.shape) * \
        np.sqrt(sigma2)
    ytest= fun(xtest) + np.random.normal(0, 1, xtest.shape) * \
        np.sqrt(sigma2)
    return xtrain, ytrain, xtest, ytest

xtrain, ytrain, xtest, ytest = make_1dregression_data(n=21)

#Rescaling data
scaler = MinMaxScaler(feature_range=(-1, 1))
Xtrain = scaler.fit_transform(xtrain.reshape(-1, 1))
Xtest = scaler.transform(xtest.reshape(-1, 1))

deg = 14
alphas = np.logspace(-10, 1.3, 10)
nalphas = len(alphas)
mse_train = np.empty(nalphas)
mse_test = np.empty(nalphas)
ytest_pred_stored = dict()
for i, alpha in enumerate(alphas):
    model = Ridge(alpha=alpha, fit_intercept=False)
    poly_features = PolynomialFeatures(degree=deg, include_bias=False)
    Xtrain_poly = poly_features.fit_transform(Xtrain)
    model.fit(Xtrain_poly, ytrain)
    ytrain_pred = model.predict(Xtrain_poly)
    Xtest_poly = poly_features.transform(Xtest)
    ytest_pred = model.predict(Xtest_poly)
    mse_train[i] = mse(ytrain_pred, ytrain)
    mse_test[i] = mse(ytest_pred, ytest)
    ytest_pred_stored[alpha] = ytest_pred

# Plot MSE vs degree
fig, ax = plt.subplots()
mask = [True]*nalphas
ax.plot(alphas[mask], mse_test[mask], color = 'r', marker = 'x',label='test')
ax.plot(alphas[mask], mse_train[mask], color='b', marker = 's', label='train')
ax.set_xscale('log')
ax.legend(loc='upper right', shadow=True)
plt.xlabel('L2 regularizer')
plt.ylabel('mse')
save_fig('polyfitVsRidge.pdf')
plt.show()

# Plot fitted functions
chosen_alphas = alphas[[0,5,8]]
for i, alpha in enumerate(chosen_alphas):
    fig, ax = plt.subplots()
    ax.scatter(xtrain, ytrain)
    ax.plot(xtest, ytest_pred_stored[alpha])
    plt.title('L2 regularizer {:0.5f}'.format(alpha))
    save_fig('polyfitRidge{}.pdf'.format(i))
    plt.show()


from scipy import stats
import numpy as np

############################
# CALCULATING CORRELATIONS #
############################

array_1 = np.array([1,2,3,4,5,6])  # Create a numpy array from a list
array_2 = array_1  # Create another array with the same values

print(stats.pearsonr(array_1, array_2))  # Calculate the correlation which will be 1 since the values are the same

#######################
# NORMAL DISTRIBUTION #
#######################
x = stats.norm.rvs(loc=0, scale=10, size=10)  # Generate 10 values randomly sampled from a normal distribution with mean 0 and standard deviation of 10

print(x)

################################
# PROBABILITY DENSITY FUNCTION #
################################
p1 = stats.norm.pdf(x=-100, loc=0, scale=10)  # Get probability of sampling a value of -100
p2 = stats.norm.pdf(x=0, loc=0, scale=10)     # Get probability of sampling a value of 0

print(p1)
print(p2)

####################################
# CUMULATIVE DISTRIBUTION FUNCTION #
####################################
p1 = stats.norm.cdf(x=0, loc=0, scale=10)  # Get probability of sampling a value less than or equal to 0

print(p1)

######################################
# CALCULATING DESCRIPTIVE STATISTICS #
######################################
print(stats.describe(stats.norm.rvs(loc=0, scale=1, size=500)))  # Calculate descriptive statistics for 500 data points sampled from normal distribution with mean 0 and standard deviation of 1


import sympy as sp

x = sp.Symbol('x')
f = (x**3)/(1+x**(1/2))
print('Integrate the following algebraic expression from 1 to 2')
sp.pprint(f)

lim_inf=1
lim_sup=2
# Numerical integration by Simpson 1/3 method
print('\nSimpson 1/3\n')
n = 2   # For Simpson 1/3 n=2
h = (lim_sup-lim_inf)/n
x0 = lim_inf
f0 = f.subs(x,x0)
x1 = x0+h
f1 = f.subs(x,x1)
x2 = x1+h
f2 = f.subs(x,x2)
print('h = ',h,'\nx0 = ',x0,'\nf0 = ',f0,'\nx1 = ',x1,'\nf1 = ',f1,'\nx2 = ',x2,'\nf2 = ',f2)
I = (h/3)*(f0+4*f1+f2)
print('Result = ',I)

# Numerical integration by Simpson 3/8 method
print('\nSimpson 3/8\n')
n = 3   # For Simpson 3/8 n=3
h = (lim_sup-lim_inf)/n
x0 = lim_inf
f0 = f.subs(x,x0)
x1 = x0+h
f1 = f.subs(x,x1)
x2 = x1+h
f2 = f.subs(x,x2)
x3 = x2+h
f3 = f.subs(x,x3)
print('h = ',h,'\nx0 = ',x0,'\nf0 = ',f0,'\nx1 = ',x1,'\nf1 = ',f1,'\nx2 = ',x2,'\nf2 = ',f2,'\nx3 = ',x3,'\nf3 = ',f3)
I = (3*h/8)*(f0+3*f1+3*f2+f3)
print('Result = ',I)


#Python3 Steven
import numpy as np
import matplotlib.pyplot as plt

def plotPowerFuc():
    x = np.linspace(-4,4,100)
    e = range(-1,4)
    for i in e:
        y = x**i
        plt.plot(x,y,label='y=x**%s'%i,linewidth=2)

    plt.xlim(x[0],x[-1])
    plt.ylim(-20,20)
    plt.legend()
    plt.show()

def plotLine(n=80):
    for k in range(n):
        #plt.plot([0, np.cos(2*np.pi*k/n)], [0, np.sin(2*np.pi*k/n)])
        plt.plot([0, np.cos(2*np.pi*k/n)], [0, np.sin(2*np.pi*k/n)],color=[k/n,k/n,k/n])
        #plt.plot([0,k*np.cos(2*np.pi*k/n)], [0, k*np.sin(2*np.pi*k/n)],color=[k/n,k/n,k/n])
        #plt.plot([0,k*np.cos(2*np.pi*k/n)], [0, k*np.sin(2*np.pi*k/n)])

    plt.axis('square')
    plt.show()

def complexRoot(n=2):
    #Z**n=1
    for k in range(n):
        yield np.exp(2*np.pi*1j*k/n)

def plotCompexRoot(n=50):
    for k in range(n):
        #z = np.exp(2*np.pi*1j*k/n)
        z = k*np.exp(2*np.pi*1j*k/n)
        #plt.plot([0,np.real(z)], [0,np.imag(z)])
        plt.plot([0,np.real(z)], [0,np.imag(z)],color=[0,0,0])

    plt.axis('square')
    plt.show()

def plotTrigonometry():
    t = np.linspace(0,8*np.pi,1000)
    r1 = np.random.rand()
    r2 = np.random.rand()

    x = np.cos(r1*t)
    y = np.cos(r2*t)
    plt.plot(x,y,'k')
    plt.title('r1=%s,r2=%s'%(np.round(r1,2),np.round(r2,2)))
    plt.axis('square')
    plt.show()

def derivative(f,x,h=0.0001): #slop
    return (f(x+h)-f(x))/h

def func(x):
    return x**8
    #return x**3

def plotTangent():
    x = np.linspace(-1,1,50)
    xT = np.linspace(-1,1,100)
    bound=[-2,2]
    for i in xT:
        y=func(i)
        slope = derivative(func,i)
        b = y-slope*i
        plt.plot([bound[0],bound[1]],[slope*bound[0]+b,slope*bound[1]+b],color=[abs(i)/3,abs(i)/2,abs(i)/3])
    #plt.axis('square')
    plt.axis('off')
    plt.plot(x,func(x))
    plt.xlim(x[0],x[-1])
    plt.ylim(-3,3)
    plt.show()

def main():
    #plotPowerFuc()
    #plotLine()
    #plotCompexRoot()
    #plotTrigonometry()
    plotTangent()

if __name__=='__main__':
    main()


import numpy as np

"""This program aim to:
    1) on the fly construct a list of prime number
    2) strip out all the prime factor from target """

input_num = 600851475143
#input_num = 13195

#INT
primes = np.empty(1000,dtype=int)
counters = np.empty(1000,dtype=int)
target = input_num
factors = []
n = 0

print("TARGET = ", target)

#manual check 2
while(target % 2 == 0):
    target //= 2
    factors.append(2)

print("Try dividing by: 2, remainder =",target)

# Loop through all the odd numbers to find primes
# until all the factors are found
i = 3
while i*i <= target:
    for j in range(n):
        counters[j] += 2
        if(counters[j] >= primes[j]):
            counters[j] -= primes[j]

# if none of the counters are zero, it is a prime
    if not any(counters[:n] == 0):
        primes[n] = i
        counters[n] = 0
        n += 1

# try strip factors from target using the newly found prime
        while(target % i == 0):
            target //= i
            factors.append(i)

        print("Try dividing by:",i, ", remainder =",target)

    i += 2

# OUTPUT
if(target == 1):
# write a pythonic statement in case my TA complains I am writing C
    print(input_num, "=", " x ".join([str(x) for x in factors]))
    print("LARGEST PRIME FACTOR = ", primes[n-1])
else:
    factors.append(target)
    print(input_num, "=", " x ".join([str(x) for x in factors]))
    print("LARGEST PRIME FACTOR = ", target)


import numpy as np
from numpy.lib.function_base import append

# 传入源数据，源数据是n×m的数据矩阵，n是事务个数，m是事务特征个数
# k是降维后的维度，当k=-1是默认值,k=其它值时代表它传入了这个参数，否则k值由程序决定
# 返回降维后的数据，它是n×k的矩阵
def PCA(src_data,k=-1):
    # 求均值
    avg = np.array([np.mean(src_data[:, i]) for i in range(len(src_data[0]))])
    src_sub=src_data-avg
    print(1)
    # 求协方差矩阵
    C=np.dot(np.transpose(src_sub),src_sub)
    print(2)
    # C=np.divide(C,len(src_data))
    # 求特征值，特征向量
    val, vec = np.linalg.eig(C)
    print(3)
    # 将特征值和特征向量组合
    characteristic=[]
    for i in range(len(val)):
        characteristic.append([val[i],vec[:,i]])
    print(4)
    # 然后排序
    characteristic.sort(key=lambda characteristic: characteristic[0], reverse=True)
    print(5)
    # 当k=-1时，意味着我们要自己决定k
    if k==-1:
        # stop为阈值
        stop=0.95
        sum=0
        for i in range(len(characteristic)):
            sum=sum+characteristic[i][0]
        stop=stop*sum
        for i in range(len(characteristic)-1,-1,-1):
            if sum-characteristic[i][0]>=stop:
                sum=sum-characteristic[i][0]
            else:
                break
        k=i+1

    # 获得前k个特征向量，组成矩阵
    vec=[]
    for i in range(k):
        vec.append(characteristic[i][1])

    # 与减去平均值的矩阵相乘，获得降维后的数据
    data=np.dot(src_sub,np.transpose(vec))
    return data


import numpy as np
from findiff import FinDiff
from scipy.special import factorial

def taylor_approximate(pars, x0s, derivs, order=None):
    '''
    Computes the nth order Taylor series approximation to a function given
    - derivs: a list of n derivatives
    - x0s: the point about which we are expanding
    - pars: the coordinates at which we want to expand the function
    If order is specified it will go to that order instead of using the full list of derivatives.
    '''
    Nparams = len(x0s)
    output_shape = derivs[0].shape

    if order is None:
        order = len(derivs) - 1
        print("Taking the order %d Taylor series."%(order))

    Fapprox = np.zeros(output_shape)
    diffs =  [ (pars[ii] - x0s[ii]) for ii in range(Nparams) ]

    for oo in range(order+1):
        if oo == 0:
            Fapprox += derivs[oo]
        else:
            param_inds = np.meshgrid( * (np.arange(Nparams),)*oo, indexing='ij')
            PInds = [ind.flatten() for ind in param_inds]

            term = 0

            for iis in zip(*PInds):
                term += derivs[oo][iis] * np.prod([ diffs[ii] for ii in iis ])

            Fapprox += 1/factorial(oo) * term

    return Fapprox

def compute_derivatives(Fs, dxs, center_ii, order):
    '''
    Computes all the partial derivatives up to order 'order' given a function on a grid Fs
    The grid separation is given by dxs, and the derivatives are computed at the grid point 'center_ii.'

    Assumes that Fs is gridded in the standard matrix way (i.e. indexing = 'ij' in numpy) as
    opposed to Cartesian indexing that one uses for plotting.
    '''

    # assume the structure of the input is
    # [Npoints,]*Nparams + output_shape, where Nparams is also the length of dxs

    Nparams = len(dxs)
    output_shape = Fs.shape[len(dxs):]

    derivs = []

    for oo in range(order+1):
        if oo == 0:
            derivs += [Fs[center_ii]]
        else:
            dnFs = np.zeros( (Nparams,)*oo + output_shape)

            # Want to get a list of all the possible d/dx_i dx_j dx_k ...
            param_inds = np.meshgrid( * (np.arange(Nparams),)*oo, indexing='ij')
            PInds = [ind.flatten() for ind in param_inds]

            for iis in zip(*PInds):
                # build a string of (xk, dxk, 1) for taking the d/dxk derivative in sequence
                deriv_tuple = []
                for ii in iis:
                    deriv_tuple += [(ii, dxs[ii],1),]

                dndx = FinDiff(*deriv_tuple)

                dnFs[iis] += dndx(Fs)[center_ii]

            derivs += [dnFs]

    return derivs


import numpy as np
from ._Regularization import _L1Reg,_L2Reg

def MeanSquareCost(h,y,ThetaW,L1=0.0,L2=0.0):
	m = y.shape[0]
	#diff = (h-y)**2
	#print(h.dtype,y.dtype,diff.dtype,h.min(),h.max(),y.min(),y.max(),diff.min(),diff.max(),np.sum(diff))
	#J = np.sum((h - y)**2)/(2*m)
	J = np.mean((h - y)**2)/2

	if L1 > 0.0:
		L1Reg = _L1Reg(ThetaW,L1,m)
	else:
		L1Reg = 0.0

	if L2 > 0.0:
		L2Reg = _L2Reg(ThetaW,L2,m)
	else:
		L2Reg = 0.0

	J = J + L1Reg + L2Reg
	return J

def MeanSquareDelta(h,y,InvAFgrad):

	return (h - y)*InvAFgrad(h)


#!/usr/bin/env python
#   Author: Christopher Bull.
#   Affiliation:  British Antarctic Survey
#                 Cambridge, UK
#   Contact: chbull@bas.ac.uk
#   www:     christopherbull.com.au
#   Date created: Sun, 13 Mar 2022 14:29:36
#   Machine created on: SB2Vbox
"""
Step 1: 1-D Linear Convection
"""
from cb2logger import *
import numpy                       #here we load numpy
from matplotlib import pyplot      #here we load matplotlib
import matplotlib.pyplot as plt
import time, sys                   #and load some utilities

if __name__ == "__main__":
    LogStart('',fout=False)
    #Now let's define a few variables; we want to define an evenly spaced grid of points within a spatial domain that is 2 units of length wide, i.e., 𝑥𝑖∈(0,2). We'll define a variable nx, which will be the number of grid points we want and dx will be the distance between any pair of adjacent grid points.

    nx = 41  # try changing this number from 41 to 81 and Run All ... what happens?
    #CB: seems like '81' is the necessary amount of resolution required to not difuse the bump, 61 does better but not as good as 81

    dx = 2 / (nx-1)
    nt = 25    #nt is the number of timesteps we want to calculate
    dt = .025  #dt is the amount of time each timestep covers (delta t)
    c = 1      #assume wavespeed of c = 1

    #We also need to set up our initial conditions. The initial velocity 𝑢0 is given as 𝑢=2 in the interval 0.5≤𝑥≤1 and 𝑢=1 everywhere else in (0,2) (i.e., a hat function).
    u = numpy.ones(nx)      #numpy function ones()
    u[int(.5 / dx):int(1 / dx + 1)] = 2  #setting u = 2 between 0.5 and 1 as per our I.C.s

    pyplot.plot(numpy.linspace(0, 2, nx), u)
    #Why doesn't the hat function have perfectly straight sides? Think for a bit.

    #cb: b/c nx has a small number of points (goes to vertical as nx--> \infinity)
    #plt.show()

    un = numpy.ones(nx) #initialize a temporary array

    for n in range(nt):  #loop for values of n from 0 to nt, so it will run nt times
        un = u.copy() ##copy the existing values of u into un
        for i in range(1, nx): ## you can try commenting this line and...
        #for i in range(nx): ## ... uncommenting this line and see what happens!
            u[i] = un[i] - c * dt / dx * (un[i] - un[i-1])

    pyplot.plot(numpy.linspace(0, 2, nx), u)
    plt.show()

    lg.info('')
    localtime = time.asctime( time.localtime(time.time()) )
    lg.info("Local current time : "+ str(localtime))
    lg.info('SCRIPT ended')


import numpy as np
import matplotlib.pyplot as plt

def P_cumulativa(pi):
  ''' Calcula a CDF F(x) de uma PMF P(x) '''
  pif = [pi[0]]
  for i in range(1, len(pi)):
    pif.append( pif[-1] + pi[i])
  return pif

def escolhe_estado(S, fpi):
  ''' Dada uma Cadeia de Markov com vetor de estados S e CDF F(i), escolhe aleatoriamente o próximo estado '''
  r = np.random.rand(1)[0]
  for i in range(len(S)):
    if fpi[i] >= r:
      return S[i]

def simular_cadeia_markov(S, pi, P, n, m):
  '''
  Realiza m simulações numéricas com n instâncias de uma Cadeia de Markov com estados S,
  probabilidades iniciais pi e matriz de transição P
  '''
  processo = np.zeros((m,n))
  for j in range(m):
    pi_t = pi
    pif = P_cumulativa(pi_t)
    processo[j, 0] = escolhe_estado(S, pif)
    for i in range(1, n):
      p = P[ int(processo[j, i - 1]) , : ]
      pf = P_cumulativa(p)
      processo[j, i] = escolhe_estado(S, pf)
  return processo

def mat_pot(mat, n):
  ''' Função atalho para a exponenciação de matrizes '''
  return np.linalg.matrix_power(mat, n)

def e_regular(mat, n):
  ''' Indica se a matriz mat elevada à potência n é regular, isto é, todos os seus valores são maiores que zero. '''
  return np.all(mat_pot(mat,n) > 0)

def transicao(pi, P, n):
  ''' Calcula analiticamente o vetor de estados após n transições de uma Cadeia de Markov com matriz de transição P '''
  return pi.dot(mat_pot(P, n))

def simular_convergencia(S, pi, P, n, nomes=None):
  '''
  Avalia numericamente e visualmente a convergência para n passos de uma Cadeia de Markov com estados S,
  probabilidades iniciais pi e matriz de transição P
  '''
  pit = pi
  ns = pi.shape[0]
  pis = np.zeros((n,ns))
  for i in range(n):
    pit = pit.dot(P)
    pis[i,:] = pit
  for i in range(ns):
    plt.plot(pis[:,i], label="{}".format(i if nomes is None else nomes[i]))
  plt.legend()
  plt.tight_layout()

def dist_estacionaria(S, P):
  '''
  Calcula analiticamente a distribuição estacionária de uma Cadeia de Markov com estados S,
  e matriz de transição P
  '''
  m = len(S)
  A = np.append(P.T - np.identity(m), np.ones((1,m)),axis=0)
  b = np.zeros(m+1)
  b[-1] = 1
  b = b.T
  return np.linalg.solve(A.T.dot(A), A.T.dot(b))