import numpy as np
import scipy.stats as sp

def cosd(angle):

    return np.cos(np.pi * angle/180)

def sind(angle):

    return np.sin(np.pi * angle/180)

def tand(angle):

    return np.tan(np.pi * angle/180)

def arctand(angle):

    return np.arctan(angle) * 180/np.pi

def cart2pol(x, y):

    rho = np.sqrt(x**2 + y**2)
    phi = np.arctan2(y, x)

    return phi, rho

def pol2cart(phi, rho):

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

    return x, y

def iqr(data):
    """This function computes the iqr consistent with Matlab"""

    # If 2-D array use only 1st row
    if len(data.shape) > 1:
        data_1d = data.flatten()
    else:
        data_1d = data

    # Remove nan elements
    idx = np.where(np.isnan(data_1d) == False)[0]
    data_1d = data_1d[idx]

    # Compute statistics
    q25, q50, q75 = sp.mstats.mquantiles(data_1d, alphap=0.5, betap=0.5)
    sp_iqr = q75 - q25
    return sp_iqr

def azdeg2rad(angle):
    direction = np.deg2rad(90-angle)
    idx = np.where(direction < 0)[0]
    if len(idx) > 0:
        direction[idx] = direction[idx] + 2 * np.pi

    return direction

def rad2azdeg(angle):
    if isinstance(angle, float):
        deg = np.rad2deg(angle)
        deg = 90 - deg
        if deg < 0:
            deg += 360

        return deg
    else:
        # Multiple values
        deg = np.rad2deg(angle)
        deg = 90 - deg
        sub_zero = np.where(deg < 0)
        deg[sub_zero] = deg[sub_zero] + 360

        return deg

def nandiff(values):

    final_values = []
    for n in range(len(values) - 1):

        if np.isnan(values[n]):
            final_values.append(np.nan)
        else:
            i = n + 1
            while np.isnan(values[i]) and i < len(values) - 1:
                i += 1

            final_values.append(values[i] - values[n])

    return np.array(final_values)

def get_object_values(list_in, item, checked=None):
    if checked is not None:
        working_list = list_in[checked is True]
    else:
        working_list = list_in

    if working_list is list:
        out = []
        for obj in working_list:
            temp = getattr(obj, item)
            out.append(temp)
    else:
        out = getattr(working_list, item)
    return np.array(out)

def sontek_3d_arrange(data_in):
    r1 = np.squeeze(data_in[:, 0, :])
    r2 = np.squeeze(data_in[:, 1, :])
    r3 = np.squeeze(data_in[:, 2, :])
    r4 = np.squeeze(data_in[:, 3, :])
    new_array = np.array([r1, r2, r3, r4])
    return new_array

def valid_number(data_in):
    """Check to see if data_in can be converted to float.

    Parameters
    ----------
    data_in: str
        String to be converted to float

    Returns
    -------
    data_out: float
        Returns a float of data_in or nan if conversion is not possible
    """

    try:
        data_out = float(data_in)
    except ValueError:
        data_out = np.nan
    return data_out

def nans(shape, dtype=float):
    a = np.empty(shape, dtype)
    a.fill(np.nan)
    return a


import numpy as np

# Entropy and Gini Calculations
def entropy(y_labels):
    _, fraud_count = np.unique(y_labels, return_counts=True)
    p_i = fraud_count / fraud_count.sum() # probability (array) of each class
    entropy = np.sum(p_i * -np.log2(p_i))
    return entropy

def gini(y_labels):
    _, fraud_count = np.unique(y_labels, return_counts=True)
    p_i = fraud_count / fraud_count.sum() # probability (array) of each class
    gini = 1 - np.sum(p_i**2)
    return gini

def total_entropy(partition_0, partition_1):
    n = len(partition_0) + len(partition_1)
    prob_part0 = len(partition_0) / n # probability of partition 0
    prob_part1 = len(partition_1) / n # probabiltiy of partition 1
    tot_entropy = (prob_part0 * entropy(partition_0)
        + prob_part1 * entropy(partition_1) )
    return tot_entropy


import numpy
def zscore(X, m=None, s=None, in_place=False, limit_memory=False):
	if (m is not None) and (s is not None):
		if in_place:
			for i in range(X.shape[0]):
				for j in range(X.shape[1]):
					X[i, j] = (X[i, j] - m[j]) / s[j]
			return (X, m, s)
		return ((X - m)/s, m, s)
	if limit_memory:
		m, s = compute_mean_std_limit_space(X)
	else:
		m = numpy.mean(X, axis=0)
		s = numpy.std(X, axis=0)
	return zscore(X, m, s, in_place)

def compute_mean_std_limit_space(X):
	m = numpy.mean(X, axis=0)
	s = numpy.zeros_like(m)

	for j in range(X.shape[1]):
		for i in range(X.shape[0]):
			s[j] += (X[i,j] - m[j]) ** 2
		s[j] /= X.shape[0]
	s = numpy.sqrt(s)

	return (m, s)

# if __name__ == '__main__':
# 	t = [[0.8147, 0.1576, 0.6557, 0.7060],
# 		[0.9058, 0.9706, 0.0357, 0.0318],
# 		[0.1270, 0.9572, 0.8491, 0.2769],
# 		[0.9134, 0.4854, 0.9340, 0.0462],
# 		[0.6324, 0.8003, 0.6787, 0.0971],
# 		[0.0975, 0.1419, 0.7577, 0.8235],
# 		[0.2785, 0.4218, 0.7431, 0.6948],
# 		[0.5469, 0.9157, 0.3922, 0.3171],
# 		[0.9575, 0.7922, 0.6555, 0.9502],
# 		[0.9649, 0.9595, 0.1712, 0.0344]]
# 	t = numpy.asarray(t)

# 	X, m, s = zscore(t)
# 	print X
# 	print m
# 	print s

# 	# X, m, s = zscore(t, in_place=True)
# 	# print X
# 	# print m
# 	# print s

# 	X, m, s = zscore(t, limit_memory=True)
# 	print X
# 	print m
# 	print s

# 	# X, m, s = zscore(t, in_place=True, limit_memory=True)
# 	# print X
# 	# print m
# 	# print s


import numpy

## array()

arr=numpy.array([1,2,3,4])
print(arr)
#[1 2 3 4]
print(arr.dtype)
#int32

arr=numpy.array([1,2,3.1,4])  # if we give one value in float type all will convert into float
print(arr)
#[1.  2.  3.1 4. ]    # implicity
print(arr.dtype)
#float64

arr=numpy.array([1,2,3.1,4],int) # int specify the type of an array
print(arr)
#[1 2 3 4]    # even float type value is given all are converted in int
print(arr.dtype)
#int32

###           linspace()

arr = numpy.linspace(0,15)
print(arr)
# [ 0.          0.30612245  0.6122449   0.91836735  1.2244898   1.53061224
#   1.83673469  2.14285714  2.44897959  2.75510204  3.06122449  3.36734694
#   3.67346939  3.97959184  4.28571429  4.59183673  4.89795918  5.20408163
#   5.51020408  5.81632653  6.12244898  6.42857143  6.73469388  7.04081633
#   7.34693878  7.65306122  7.95918367  8.26530612  8.57142857  8.87755102
#   9.18367347  9.48979592  9.79591837 10.10204082 10.40816327 10.71428571
#  11.02040816 11.32653061 11.63265306 11.93877551 12.24489796 12.55102041
#  12.85714286 13.16326531 13.46938776 13.7755102  14.08163265 14.3877551
#  14.69387755 15.        ]

arr = numpy.linspace(0,15,16) # it break(divided) linspace in 16 different parts , and thats why it become float vlaue
print(arr)
#[ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15.]

#####             arange()

arr = numpy.arange(15)  ## same as range() method
print(arr)
#[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14]

##   logspace()   --> spaceing(gap) between two element will be dpend on log of it

# logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0)

# Return numbers spaced evenly on a log scale.
# In linear space, the sequence starts at ``base ** start``
# (`base` to the power of `start`) and ends with ``base ** stop``

arr = numpy.logspace(1,40,5)
print(arr)
# [1.00000000e+01 5.62341325e+10 3.16227766e+20 1.77827941e+30  1.00000000e+40]
    ### REMOVING e in  logspace
print('%.2f' %arr[0])
# 10.00

##              zeros()
arr=numpy.zeros(5) # Return a new array of given shape and type, filled with zeros.
print(arr)
#[0. 0. 0. 0. 0.]

###         ones()
arr=numpy.ones(5) #Return a new array of given shape and type, filled with ones.
print(arr)
#[1. 1. 1. 1. 1.]
print(arr.dtype)
#float64
arr=numpy.ones(5,int) #data-type, optional # The desired data-type for the array, e.g., `numpy.int8`.  Default is `numpy.float64`.
print(arr)
#[1 1 1 1 1]
print(arr.dtype)
#int32


# -*- coding: utf-8 -*-
"""
Linear Regression using two models:

There are few data files each of them having a set of values for two variables (say x & y) in the folder, one
pair per line in the data file. We are trying to determine if there is a linear relationship between
them.

• Regression functions are in a module called regression_functions.py.

• The two techniques used in the program are (1) Method of Least Squares that gives us a
Coefficient of Determination about the linearity of the relationship and also allows us try and fit a
line along a possible linear path (2) Pearson technique which gives us a Correlation Coefficient
about the linearity of the relationship

• The four data files are in1, in2, in3 and in4. Run the program against a data file and observe the
results

conditions:

• In order to plot the relationship of x and y, do the following:
• (1) Plot x vs y as a scatter plot (2) Plot x vs f(x) as a line plot
• Apply appropriate text in the plot for axes, title, as well as the coefficient of determination
(from Least Squares) and Pearson coefficient (from Pearson). Your plots should also
include meaningful information infer whether or not the visualization and numerical results agree with each
other.

@author: amith
"""
import regression_functions as regress
import matplotlib.pyplot as plt
import numpy as np

file1 = open('in1.txt', 'r')
r_file1 = file1.readlines()

file2 = open('in2.txt', 'r')
r_file2 = file2.readlines()

file3 = open('in3.txt', 'r')
r_file3 = file3.readlines()

file4 = open('in4.txt', 'r')
r_file4 = file4.readlines()

file_list = [r_file1, r_file2, r_file3, r_file4]

def main():

    for f in file_list:
        print ('Input File: ')
        x, y = np.loadtxt(f, delimiter=",", unpack=True, encoding="utf-8-sig")
        m, b = regress.compute_m_and_b(x, y)
        fx, residual = regress.compute_fx_residual(x, y, m, b)
        least_squares_r = regress.compute_sum_of_squared_residuals(residual)
        sum_squares = regress.compute_total_sum_of_squares(y)
        print()

        print("Data points: ", len(x))
        print("Least Squares Method")
        print("--------------------")
        print("Coefficients: m =", "%8.6f" % m, "\tb =", "%8.6f" % b)

        print("Sum of Squared Residuals: %12.6f" % least_squares_r)
        print("Total Sum of Squares: %12.6f" % sum_squares)
        coeff_of_determination = (1 - (least_squares_r/sum_squares))
        print("Coefficient of determination: %12.6f" % coeff_of_determination)
        print()
        pearson_r = regress.compute_pearson_coefficient(x, y)
        print("Pearson Method")
        print("--------------")
        print("Pearson Correlation Coefficient: %12.6f" % pearson_r)
        print("Predicted value of y (for x=80): %8.2f" % (m*80 + b))
        plt.figure()
        plt.scatter(x, y, color='red')
        plt.plot(x, fx, 'b')

    return

main()
plt.show()


import numpy as np

def power_iteration(
    input_matrix: np.ndarray,
    vector: np.ndarray,
    error_tol: float = 1e-12,
    max_iterations: int = 100,
) -> tuple[float, np.ndarray]:
    """
    Power Iteration.
    Find the largest eigenvalue and corresponding eigenvector
    of matrix input_matrix given a random vector in the same space.
    Will work so long as vector has component of largest eigenvector.
    input_matrix must be either real or Hermitian.

    Input
    input_matrix: input matrix whose largest eigenvalue we will find.
    Numpy array. np.shape(input_matrix) == (N,N).
    vector: random initial vector in same space as matrix.
    Numpy array. np.shape(vector) == (N,) or (N,1)

    Output
    largest_eigenvalue: largest eigenvalue of the matrix input_matrix.
    Float. Scalar.
    largest_eigenvector: eigenvector corresponding to largest_eigenvalue.
    Numpy array. np.shape(largest_eigenvector) == (N,) or (N,1).

    >>> import numpy as np
    >>> input_matrix = np.array([
    ... [41,  4, 20],
    ... [ 4, 26, 30],
    ... [20, 30, 50]
    ... ])
    >>> vector = np.array([41,4,20])
    >>> power_iteration(input_matrix,vector)
    (79.66086378788381, array([0.44472726, 0.46209842, 0.76725662]))
    """

    # Ensure matrix is square.
    assert np.shape(input_matrix)[0] == np.shape(input_matrix)[1]
    # Ensure proper dimensionality.
    assert np.shape(input_matrix)[0] == np.shape(vector)[0]
    # Ensure inputs are either both complex or both real
    assert np.iscomplexobj(input_matrix) == np.iscomplexobj(vector)
    is_complex = np.iscomplexobj(input_matrix)
    if is_complex:
        # Ensure complex input_matrix is Hermitian
        assert np.array_equal(input_matrix, input_matrix.conj().T)

    # Set convergence to False. Will define convergence when we exceed max_iterations
    # or when we have small changes from one iteration to next.

    convergence = False
    lamda_previous = 0
    iterations = 0
    error = 1e12

    while not convergence:
        # Multiple matrix by the vector.
        w = np.dot(input_matrix, vector)
        # Normalize the resulting output vector.
        vector = w / np.linalg.norm(w)
        # Find rayleigh quotient
        # (faster than usual b/c we know vector is normalized already)
        vectorH = vector.conj().T if is_complex else vector.T
        lamda = np.dot(vectorH, np.dot(input_matrix, vector))

        # Check convergence.
        error = np.abs(lamda - lamda_previous) / lamda
        iterations += 1

        if error <= error_tol or iterations >= max_iterations:
            convergence = True

        lamda_previous = lamda

    if is_complex:
        lamda = np.real(lamda)

    return lamda, vector

def test_power_iteration() -> None:
    """
    >>> test_power_iteration()  # self running tests
    """
    real_input_matrix = np.array([[41, 4, 20], [4, 26, 30], [20, 30, 50]])
    real_vector = np.array([41, 4, 20])
    complex_input_matrix = real_input_matrix.astype(np.complex128)
    imag_matrix = np.triu(1j * complex_input_matrix, 1)
    complex_input_matrix += imag_matrix
    complex_input_matrix += -1 * imag_matrix.T
    complex_vector = np.array([41, 4, 20]).astype(np.complex128)

    for problem_type in ["real", "complex"]:
        if problem_type == "real":
            input_matrix = real_input_matrix
            vector = real_vector
        elif problem_type == "complex":
            input_matrix = complex_input_matrix
            vector = complex_vector

        # Our implementation.
        eigen_value, eigen_vector = power_iteration(input_matrix, vector)

        # Numpy implementation.

        # Get eigenvalues and eigenvectors using built-in numpy
        # eigh (eigh used for symmetric or hermetian matrices).
        eigen_values, eigen_vectors = np.linalg.eigh(input_matrix)
        # Last eigenvalue is the maximum one.
        eigen_value_max = eigen_values[-1]
        # Last column in this matrix is eigenvector corresponding to largest eigenvalue.
        eigen_vector_max = eigen_vectors[:, -1]

        # Check our implementation and numpy gives close answers.
        assert np.abs(eigen_value - eigen_value_max) <= 1e-6
        # Take absolute values element wise of each eigenvector.
        # as they are only unique to a minus sign.
        assert np.linalg.norm(np.abs(eigen_vector) - np.abs(eigen_vector_max)) <= 1e-6

if __name__ == "__main__":
    import doctest

    doctest.testmod()
    test_power_iteration()


#For Python 3

import numpy as np
import matplotlib.pyplot as plt

N = 1000 #global variable; number of "partitions" for the interval [-2,2]

def f(x,y):
    """
    Takes in two numpy arrays that are result of meshgrid.
    Returns a numpy array with points representing the iteration number for divergence
    """
    max_iter = 100 #maximum number of interations
    c = x + 1j*y
    z = np.zeros((N,N),dtype=complex)
    r = np.zeros((N,N),dtype=int) #return
    mask = np.full((N,N), True, dtype=bool)
    for i in range(0,max_iter,1):
        z[mask] = z[mask]**2 + c[mask]  #z_i = z_i-1**2 + c
        r[mask] = i #i is the iteration number at which point escapes (diverges)
        #if point ever becomes larger than 2, the sequence will escape to infinity:
        #https://en.wikipedia.org/wiki/Mandelbrot_set#Basic_properties
        mask[np.abs(z) > 2] = False #points that diverge
    return r, mask

def plot_set(bounds,plot_binary):
    """
    Plots the Mandelbrot set with the given bounds
    INPUT:
    ::array:: bounds            #bounds of the plot
    ::boolean:: plot_binary     #whether or not to plot binary (for colour plot, send False)
    """
    x = np.linspace(bounds[0], bounds[1], N)
    y = np.linspace(bounds[2], bounds[3], N)
    #https://numpy.org/doc/stable/reference/generated/numpy.meshgrid.html
    xv, yv = np.meshgrid(x,y)
    vals, mandelbrot = f(xv, yv)
    vals = np.flip(vals,0) #flip array vertically
    mandelbrot = np.flip(mandelbrot,0)

    font = {'fontname':'Times New Roman'} #https://stackoverflow.com/a/21323217
    plt.figure(dpi=100)
    plt.title('Mandelbrot Set')
    plt.xticks(np.arange(0,N+1,N/4),np.arange(bounds[0],bounds[1]+1,(bounds[1]-bounds[0])/4)) #careful: arange works as [start, stop)
    plt.yticks(np.arange(0,N+1,N/4),np.arange(bounds[3],bounds[2]-1,(bounds[2]-bounds[3])/4))
    plt.xlabel('Re',**font)
    plt.ylabel('Im',**font)
    if plot_binary == False:
        #for colormaps see https://matplotlib.org/examples/color/colormaps_reference.html
        plt.imshow(vals, cmap='plasma_r') #_r to reverse colormap https://stackoverflow.com/a/3280732
        cbar = plt.colorbar()
        cbar.set_label('Number of Iterations for Divergence')
    else:
        plt.imshow(mandelbrot, cmap=plt.cm.gray)
    plt.show()
    return True

def plot_set_alternate(bounds):
    """
    Similar to plot_set() but instead uses matplotlib.pyplot.contourf()
    """
    x = np.linspace(bounds[0], bounds[1], N)
    y = np.linspace(bounds[2], bounds[3], N)
    #https://numpy.org/doc/stable/reference/generated/numpy.meshgrid.html
    xv, yv = np.meshgrid(x,y)
    vals, mandelbrot = f(xv, yv)

    font = {'fontname':'Times New Roman'} #https://stackoverflow.com/a/21323217
    plt.figure(dpi=100)
    plt.title('Mandelbrot Set')
    plt.contourf(xv, yv, vals, levels=100, cmap='plasma_r')
    plt.xlabel('Re',**font)
    plt.ylabel('Im',**font)
    plt.axes().set_aspect('equal')
    plt.colorbar(label='Number of Iterations for Divergence')
    plt.show()

    return True

def main():
    bounds1 = [-2,2,-2,2] #[xmin,xmax,ymin,ymax]
    bounds2 = [-2,0,-1,1]
    plot_set_alternate(bounds1)
    plot_set(bounds2, False)
    plot_set(bounds1, True)
    plot_set(bounds2, True)
    return True

if __name__ == "__main__":
    main()


import random
import matplotlib.pyplot as plt
from scipy.stats import poisson
from scipy.stats import norm

# Helper function
def Poisson_value(mu):
    r = random.uniform(0, 1)
    values = list()
    for i in range(1000):
        values.append(poisson.pmf(i,mu))
        if sum(values) > r: break
    return  len(values)-1

# Data gen
N = 10000
mu1 = [ Poisson_value(1.0)  for i in range(N)]
mu10_3 =  [ Poisson_value(10.3)  for i in range(N)]
mu102_1 = [ Poisson_value(102.1) for i in range(N)]

# Interpolation

def extract(data):
    counts = dict()
    for i in mu1:
        counts[i] = counts.get(i, 0) + 1
    data = sorted(counts.items())
    x_vals = [ v[0] for v in data ]
    y_vals = [ v[1]/N for v in data ]
    return x_vals , y_vals

### Figure 1
plot1 = plt.figure(1)
data = mu1
x , y = extract(data)
plt.hist(data, density = 1, bins = (max(x)+1), rwidth = 0.85 )

mu , std = norm.fit(data)
p = norm.pdf(range(int(mu-4*std), int(mu+4*std)),mu,std)
plt.plot(range(int(mu-4*std), int(mu+4*std)), p)

plt.xlabel("Values")
plt.ylabel("Probability")
plt.title("Poisson deviates for $\mu=1.0$")
plt.legend(["Fit", "Normalized Data"])

### Figure 2
plot2 = plt.figure(2)
data = mu10_3
x , y = extract(data)
plt.hist(data, density = 1, bins = (max(x)+1), rwidth = 0.85 )

mu , std = norm.fit(data)
p = norm.pdf(range(int(mu-4*std), int(mu+4*std)),mu,std)
plt.plot(range(int(mu-4*std), int(mu+4*std)), p)

plt.xlabel("Values")
plt.ylabel("Probability")
plt.title("Poisson deviates for $\mu=10.3$")
plt.legend(["Normal Fit", "Normalized Data"])

### Figure 3
plot3 = plt.figure(3)
data = mu102_1
x , y = extract(data)
plt.hist(data, density = 1, bins = (max(x)+1), rwidth = 0.85 )

mu , std = norm.fit(data)
p = norm.pdf(range(int(mu-4*std), int(mu+4*std)),mu,std)
plt.plot(range(int(mu-4*std), int(mu+4*std)), p)

plt.xlabel("Values")
plt.ylabel("Probability")
plt.title("Poisson deviates for $\mu=102.1$")
plt.legend(["Normal Fit", "Normalized Data"])

plt.show()


import numpy as np

class Bayes:
    @staticmethod
    def mean(X):
        return np.mean(X,axis=0)

    @staticmethod
    def variance(X):
        return np.mean((X-Bayes.mean(X))**2,axis=0)

    def gaussian(self,x,avg,var):
        return (1./np.sqrt(2*np.pi*var)) * np.exp(-0.5*((x-avg)**2)/var)

    def fit(self,X,y):
        c = len(set(y))
        self.c = c
        Xs = [X[y==i] for i in range(c)]

        #各个类别的均值、方差、所占比率
        self.avgs = [Bayes.mean(X) for X in Xs]
        self.vars = [Bayes.variance(X) for X in Xs]
        self.percs = [len(y[y==i])/len(y) for i in range(c)]

    def predict(self,x):
        if len(x.shape) == 1:
            result = np.array(self.percs)
            for i in range(self.c):
                gaus = self.gaussian(x,self.avgs[i],self.vars[i])
                for j in range(len(x)):
                    result[i] *= gaus[j]
            return np.argmax(result)
        results = np.array([self.predict(x[i]) for i in range(len(x))])
        return results

    def score(self,X,y):
        y_pred = self.predict(X)
        return np.sum(y_pred==y)/len(y)

if __name__=="__main__":
    from sklearn.datasets import load_iris
    from sklearn.model_selection import train_test_split
    iris = load_iris()
    X,y = iris["data"],iris["target"]
    X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=22)
    # print(len(X_train))
    # print(len(X_test))
    bayes = Bayes()
    bayes.fit(X_train,y_train)
    # print(bayes.avgs)
    # print(bayes.vars)
    print(bayes.score(X_test,y_test))

    from sklearn.naive_bayes import GaussianNB
    clf = GaussianNB()
    clf.fit(X_train, y_train)
    print(clf.score(X_test,y_test))


from sklearn.preprocessing import StandardScaler
import numpy as np

data = [[2,40],[4,50],[-2,60],[-4,70]]

print(f"data pre processing:\n{data}")
scaler = StandardScaler()
scaler.fit(data)

print(f'scaler.mean_ pre processing: {scaler.mean_}')
print(f'scaler.var pre processing: {scaler.var_}')

# mean normalization + feature scaling (https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html#sklearn.preprocessing.StandardScaler.transform)
# Standardize features by removing the mean and scaling to unit variance
# The standard score of a sample x is calculated as:
# z = (x - u) / s
# where u is the mean of the training samples or zero if with_mean=False,
# and s is the standard deviation of the training samples or one if with_std=False.

data_post_processed = scaler.transform(data)
print(f"data post processing:\n{data_post_processed}")
scaler.fit(data_post_processed)
print(f'scaler.mean_ post processing\n{scaler.mean_}')
print(f'scaler.var post processing: {scaler.var_}')


import numpy as np

def sigmoid(Z):

    # Sigmoid function
    # g(Z) = 1 / (1 + e^{-Z})
    # Z: shape [m,]

    # Trick to prevent possible overflow of np.exp(-Z)
    # Output will never to be exact 0
    idx = (Z < -500)
    Z[idx] = -500

    return 1.0 / (1.0 + np.exp(-Z))

class LogisticRegressor(object):

    def __init__(self, alpha, c, T = 1000, random_seed = 0, intercept = True):

        # Initialize Logistic Regression
        # alpha: learning rate.
        # c: L2 regularization strength.

        self.alpha = alpha
        self.c = c
        self.T = T
        self.random_seed = random_seed
        self.intercept = intercept

    def fit(self, X, y):

        np.random.seed(self.random_seed)

        y = y.flatten()

        if self.intercept == True:
            X = np.insert(X, 0, np.ones(X.shape[0]), axis = 1)

        # Weights initialization
        self.theta = np.random.normal(0, 0.1, X.shape[1])

        losses = list()
        losses.append(self.logistic_regression_loss(X = X, y = y, theta = self.theta, c = self.c))

        for i in range(self.T):

            self.theta = self.logistic_regression_weight_update(X = X, y = y, theta = self.theta, alpha = self.alpha, c = self.c)
            loss = self.logistic_regression_loss(X = X, y = y, theta = self.theta, c = self.c)
            losses.append(loss)

        losses = np.array(losses)

        return losses

    def logistic_regression_loss(self, X, y, theta, c):

        # Loss function for logistic regression
        # X: input feature matrix, shape [m,n].
        # y: input target value, shape [m,1].
        # c: L2 regularization strength.

        h = sigmoid(Z = X.dot(theta))

        # Trick to prevent h is exact 1 for np.log(1 - h)
        idx = (h == 1.0)
        h[idx] = 1.0 - 1e-15

        loss_mean = 1.0 / X.shape[0] * (-np.sum(y * np.log(h) + (1 - y) * np.log(1 - h))) + c * np.sum((theta ** 2))

        return loss_mean

    def logistic_regression_weight_update(self, X, y, theta, alpha, c):

        # Weight update of gradient descent for logistic regression
        # X: input feature matrix, shape [m,n].
        # y: input target value, shape [m,1].
        # alpha: learning rate.
        # c: L2 regularization strength.
        # theta: parameters for features in X, shape [n+1,1].

        # Calculate activated values
        h = sigmoid(Z = X.dot(theta))
        # Update weigths
        theta += alpha * ((1.0 / X.shape[0] * (y - h).dot(X)) - 2 * c * theta)

        return theta

    def predict(self, X, threshold = 0.5):

        # threshold: predict 1 if above threshold.

        if self.intercept == True:
            X = np.insert(X, 0, np.ones(X.shape[0]), axis = 1)

        probabilities = sigmoid(Z = np.dot(X, self.theta))

        y_predicted = (probabilities > threshold).astype(int)

        return y_predicted


#!/usr/bin/python

'''
mjtsai1974@20180606, v1.0, MLE for https://mjtsai1974.github.io/DevBlog/2018/06/06/bayesian-ml-beyes-to-practice/

http://www.astroml.org/book_figures/chapter3/fig_gaussian_distribution.html

dist = scipy.stats.norm(...)

Where ... should be filled in with the desired distribution parameters Once we have defined the distribution parameters in this way, these distribution objects have many useful methods; for example:

    dist.pmf(x) computes the Probability Mass Function at values x in the case of discrete distributions
    dist.pdf(x) computes the Probability Density Function at values x in the case of continuous distributions
    dist.rvs(N) computes N random variables distributed according to the given distribution
'''

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

'''
#----------------------------------------------------------------------
# This function adjusts matplotlib settings for a uniform feel in the textbook.
# Note that with usetex=True, fonts are rendered with LaTeX.  This may
# result in an error if LaTeX is not installed on your system.  In that case,
# you can set usetex to False.
from astroML.plotting import setup_text_plots
setup_text_plots(fontsize=8, usetex=False)
'''

# Define the given measured weights
weights = [13.9, 14.1, 17.5]
n = len(weights)

# Define the distributions to be plotted
mu = np.mean(weights)
sample_variance = np.var(weights, ddof=1)
sample_std_deviation = np.sqrt(sample_variance)

population_variance = np.var(weights, ddof=0)
population_std_deviation = np.sqrt(population_variance)

sigma_values = [sample_std_deviation, population_std_deviation]
linestyles = ['-', '--']
colours = ['red', 'blue']
x_axis = np.linspace(mu - 2 * np.max(sigma_values), mu + 2 * np.max(sigma_values), 100) #use the

# plot the distributions
fig, ax = plt.subplots(figsize=(5, 3.75))

for sigma, ls, color in zip(sigma_values, linestyles, colours):
    # create a gaussian / normal distribution
    dist = norm(mu, sigma)

    plt.plot(x_axis, dist.pdf(x_axis), ls=ls, c=color,
             label=r'$\mu=%.3f,\ \sigma=%.3f$' % (mu, sigma))

plt.xlim(mu - 2 * np.max(sigma_values), mu + 2 * np.max(sigma_values))
plt.ylim(0, 0.45)

plt.xlabel('$x$')
plt.ylabel(r'$p(x|\mu,\sigma)$')
plt.title('Gaussian Distribution')

plt.legend()
plt.show()

# MLE to ask for possible real weight with max(sample std deviation, population std deviation)
MLE_max = 0
mu_max = mu

for i in range(len(x_axis)):
    dist = norm(x_axis[i], np.max(sigma_values))

    MLE_now = 1.0

    for j in range(len(weights)):
        MLE_now = dist.pdf(weights[j]) * MLE_now

    if MLE_now > MLE_max:
        MLE_max = MLE_now
        mu_max = x_axis[i]

print('using np.max(sigma_values), the MLE for weight {0: 5.3f}'.format(mu_max))

# MLE to ask for possible real weight with min(sample std deviation, population std deviation)
MLE_max = 0
mu_max = mu

for i in range(len(x_axis)):
    dist = norm(x_axis[i], np.min(sigma_values))

    MLE_now = 1.0

    for j in range(len(weights)):
        MLE_now = dist.pdf(weights[j]) * MLE_now

    if MLE_now > MLE_max:
        MLE_max = MLE_now
        mu_max = x_axis[i]

print('using np.min(sigma_values), the MLE for weight {0: 5.3f}'.format(mu_max))


# -*- coding: utf-8 -*-
"""

Make a simple 1D gaussian profile.

"""

import numpy as np
import matplotlib.pyplot as plt

def gaussian_1D_profile(x_min, x_max, x_step, center, sigma, amplitude):
    """Function to create a 1D Gaussian distribution.

    Parameters
    ----------

    x_min, x_max, x_step: float, float, float
        Creates a sequence (1D ndarray) of points over which to compute the Gaussian
    center: float
        The center point of the gaussian profile
    sigma: float
        1/e-squared width of beam
    amplitude: float
        Amplitude at peak value

    Returns
    -------

    x,y: ndarray
        the gaussian profile amplitude values

    """

    x = np.arange(x_min, x_max,x_step)  #create spatial array
    d = 2*float(sigma)
    y = amplitude*np.e**(-2*np.power((x-center)/d, 2))

    return x,y

    # todo: learn how to do proper unit testing...heres some manual checks
    # what if center > max(X)?  still works, just get the tail end
    # what if center, sigma negative?  Since is getting squared, doesn't matter
    # what if amplitude is neg or zero? Straight line at zero
    # what if d = 0? Straight line
    # what if the ndarray goes negative?  Is ok.
    # What if the array is empty or null? should catch an error.

def plot_1d_gaussian(x,y,hold=True):
    """Plot the gaussian profile.

    Parameters
    ----------

    x: ndarray
        X axis values
    y: float
        Y axis values

    """
    plt.hold = hold
    plt.plot(x,y)
    plt.xlabel('X axis')
    plt.ylabel('Amplitude')
    plt.title('Gaussian 1D Profile')
    plt.show()

    # todo: check if the hold true works or not

if __name__ == '__main__':

    x,y = gaussian_1D_profile(-50,50,.2, 0, 10, 1)
    plot_1d_gaussian(x,y,True)


import numpy as np
def gd(x_start, step, g):
    x = x_start
    for i in range(20):
        grad = g(x)
        x -= grad * step
        print '[ Epoch {0} ] grad = {1}, x = {2}'.format(i, grad, x)
        if abs(grad) < 1e-6:
            break;
    return x

def f(x):
    return x * x - 2 * x + 1

def g(x):
    return 2 * x - 2

import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-5,7,100)
y = f(x)
plt.plot(x, y)

gd(5,0.1,g)

gd(5,100,g)

gd(5,1,g)

gd(4,1,g)

def f2(x):
    return 4 * x * x - 4 * x + 1
def g2(x):
    return 8 * x - 4
gd(5,0.25,g2)


import numpy as np

# spearman coefficient rs
def spearman(R, Q):
    """
    Calculate Spearman rank correlation coefficient between two vectors

    Parameters
    -----------
        R : ndarray
            First vector containing values
        Q : ndarray
            Second vector containing values

    Returns
    --------
        float
            Value of correlation coefficient between two vectors

    Examples
    ----------
    >>> rS = spearman(R, Q)
    """

    N = len(R)
    denominator = N*(N**2-1)
    numerator = 6*sum((R-Q)**2)
    rS = 1-(numerator/denominator)
    return rS

# weighted spearman coefficient rw
def weighted_spearman(R, Q):
    """
    Calculate Weighted Spearman rank correlation coefficient between two vectors

    Parameters
    -----------
        R : ndarray
            First vector containing values
        Q : ndarray
            Second vector containing values

    Returns
    --------
        float
            Value of correlation coefficient between two vectors

    Examples
    ---------
    >>> rW = weighted_spearman(R, Q)
    """

    N = len(R)
    denominator = N**4 + N**3 - N**2 - N
    numerator = 6 * sum((R - Q)**2 * ((N - R + 1) + (N - Q + 1)))
    rW = 1 - (numerator / denominator)
    return rW

# pearson coefficient
def pearson_coeff(R, Q):
    """
    Calculate Pearson correlation coefficient between two vectors

    Parameters
    -----------
        R : ndarray
            First vector containing values
        Q : ndarray
            Second vector containing values

    Returns
    --------
        float
            Value of correlation coefficient between two vectors

    Examples
    ----------
    >>> corr = pearson_coeff(R, Q)
    """

    numerator = np.sum((R - np.mean(R)) * (Q - np.mean(Q)))
    denominator = np.sqrt(np.sum((R - np.mean(R))**2) * np.sum((Q - np.mean(Q))**2))
    corr = numerator / denominator
    return corr


import numpy as np

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

def reLU(x):
    """
        Rectifier transfer function
    """
    return x * (x > 0)

def leakyReLU(x):
    """
        Leaky rectifier transfer function
        if x > 0, return x ; else return 0.1 * x
    """
    return x * (x > 0) + (.1 * x) * (x < 0)

def tanh(x):
    """
        Hyperbollic tan transfer function
    """
    return np.tanh(x)


from scipy.special import erf
import math

# compute erf(1) by numerically doing the integral as a 3-point quadrature:
# trapezoid (compound), Simpson's, and Gauss-Legendre
#
# erf(x) = 2/sqrt(pi) int_0^x exp(-y^2) dy
#

# analytic integral
true = erf(1)

def f(y):
    """ integrand """
    return (2.0/math.sqrt(math.pi))*math.exp(-y**2)

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

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

# integration limits
a = 0.0
b = 1.0

# we are doing 3-point quadrature for all methods.  delta is the width
# of the slab
delta = 0.5

# trapezoidal
trap = 0.5*delta*(f(a) + f(0.5*(a+b))) + 0.5*delta*(f(0.5*(a+b)) + f(b))

# Simpson's
simp = (delta/3.0)*(f(a) + 4.0*f(0.5*(a+b)) + f(b))

# Gauss-Legendre

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

z1 = -math.sqrt(3./5.)
x1 = x(z1, a, b)
w1 = 5./9.

z2 = 0
x2 = x(z2, a, b)
w2 = 8./9.

z3 = math.sqrt(3./5.)
x3 = x(z3, a, b)
w3 = 5./9.

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

print "erf(1) (exact):         ", true
print "3-point trapezoidal:    ", trap, trap-true
print "3-point Simpson's:      ", simp, simp-true
print "3-point Gauss-Legendre: ", integral, integral-true


import numpy as np
my_list = [1,2,3,4,5,6]

print(my_list)

#creating single dimension array of vector by casting python list to numPy array
npvector = np.array(my_list)

print(npvector)

my_mat = [[1,2,3],[4,5,6],[7,8,9]]

nptwodarray = np.array(my_mat)

print(nptwodarray)

print(np.arange(0,10))# python range like function to generate vector array

print(np.arange(0,10, 2))#with step

print(np.zeros(3))#generate single/vector array using zeros

print(np.zeros((3,3)))#generate 2d/matrix array using zeros or ones and passing arg as tuple

print(np.ones((3,3)))

print(np.linspace(0,5,10))

print(np.eye(3))

print(np.random.rand(5))

print(np.random.rand(3,3))

print(np.random.randn(3,3))

print(np.random.randn(3))

print(np.random.randint(0,10,3))

rangearr = np.arange(0,25)
print(rangearr)
print(rangearr.reshape((5,5)))
print(rangearr.min())
print(rangearr.max())
print(rangearr.argmax())
print(rangearr.argmin())

print("Index and Selection")
#numpy indexing and selection
indexarr = np.arange(0,11)
print(indexarr)
#indexing
print(indexarr[7])
#slicing
print(indexarr[2:4])
#slicing will change original instance as below
slice_of_arr = indexarr[0:5]
print(slice_of_arr)
slice_of_arr[:] = 0
print(slice_of_arr)
print(indexarr)
#to avoid use copy
indexarr_copy = indexarr.copy()
print(indexarr)
print(indexarr_copy)
indexarr_copy[:]=1
print(indexarr_copy)
print(indexarr)

arr_2d = np.array([[5,10,15], [20, 25, 30], [35, 40, 45]])
print(arr_2d)
print(arr_2d[1][1])
print(arr_2d[1,1])

#grabbing sub matrix from matrix
print(arr_2d[:2,1:])
print(arr_2d[:2,:2])

#boolean array using comparator operator
normal_arr = np.arange(1, 11)
print(normal_arr)
bool_arr = normal_arr > 3
print(bool_arr)

#grabbing from normal array from bool_arr
print(normal_arr[bool_arr])
print(normal_arr[normal_arr>4])

new_2d_array = np.arange(50).reshape(5,10)
print(new_2d_array)
print(new_2d_array[2:4,2:4]) #new_2d_array([from_row:to_row,from_col,to_col])

#numpy operation
print("numpy operation")

op_arr = np.arange(0,10)
print(op_arr + op_arr)
print(op_arr - op_arr)
print(op_arr * op_arr)
print(op_arr / 2)
print(op_arr / op_arr)


from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.metrics import mean_squared_error, r2_score

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

#----------------------------------------------------------------------------------------#
# Step 1: training data

X = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
Y = [0,1,2,3,6,6,8,9,13,17,19,20,21,24,25,32,34,36,39,46,47,50,61,70,74,80,87,126,139,153,156]

X = np.asarray(X)
Y = np.asarray(Y)

X = X[:,np.newaxis]
Y = Y[:,np.newaxis]

plt.scatter(X,Y)

#plt.show()

#----------------------------------------------------------------------------------------#
# Step 2: data preparation

nb_degree = 3

polynomial_features = PolynomialFeatures(degree = nb_degree)
#print(X)
X_TRANSF = polynomial_features.fit_transform(X)

#----------------------------------------------------------------------------------------#
# Step 3: define and train a model

model = LinearRegression()

model.fit(X_TRANSF, Y)

#----------------------------------------------------------------------------------------#
# Step 4: calculate bias and variance

Y_NEW = model.predict(X_TRANSF)

rmse = np.sqrt(mean_squared_error(Y,Y_NEW))
r2 = r2_score(Y,Y_NEW)

print('RMSE: ', rmse)
print('R2: ', r2)

#----------------------------------------------------------------------------------------#
# Step 5: prediction

x_new_min = 0.0
x_new_max = 50.0

X_NEW = np.linspace(x_new_min, x_new_max, 50)
X_NEW = X_NEW[:,np.newaxis]

X_NEW_TRANSF = polynomial_features.fit_transform(X_NEW)

Y_NEW = model.predict(X_NEW_TRANSF)

plt.plot(X_NEW, Y_NEW, color='coral', linewidth=3)

plt.grid()
plt.xlim(x_new_min,x_new_max)
plt.ylim(0,1000)

title = 'Degree = {}; RMSE = {}; R2 = {}'.format(nb_degree, round(rmse,2), round(r2,2))

plt.title("Polynomial Linear Regression using scikit-learn and python 3 \n " + title,
          fontsize=10)
plt.xlabel('x')
plt.ylabel('y')

plt.savefig("polynomial_linear_regression.png", bbox_inches='tight')
plt.show()


import numpy as np
from matplotlib import pyplot as plt
import sympy
from sympy.abc import x, y

XMIN = -3
XMAX = 3
RADIUS = 1.0
N = 25

def cylinder_stream_function(U=1, R=1):
    r = sympy.sqrt(x**2 + y**2)
    theta = sympy.atan2(y, x)
    return U * (r - R**2 / r) * sympy.sin(theta)

def velocity_field(psi):
    """ u, v -> give U or V vector component for position X/Y """

    u = sympy.lambdify((x, y), psi.diff(y), 'numpy')
    v = sympy.lambdify((x, y), -psi.diff(x), 'numpy')
    return u, v

def plot_streamlines(ax, u, v, xlim=(-1, 1), ylim=(-1, 1)):
    x0, x1 = xlim
    y0, y1 = ylim
    Y, X =  np.ogrid[y0:y1:25j, x0:x1:25j]
    U = u(X,Y)
    V = v(X,Y)
    ax.streamplot(X, Y, u(X, Y), v(X, Y), density=2, color='cornflowerblue')
    #ax.quiver(X,Y,u(X,Y),v(X,Y))

def compute_components(domask):
    """ Returns:

    x: 1-D array with x coordinates
    y: 1-D array with y coordinates
    u: 2-D array with x vector components
    v: 2-D array with y vector components
    """

    uf, vf = velocity_field(cylinder_stream_function(R=RADIUS))

    y, x = np.ogrid[XMIN:XMAX:N*1j, XMIN:XMAX:N*1j]

    u = uf(x,y)
    v = vf(x, y)

    xx, yy = np.mgrid[XMIN:XMAX:N*1j, XMIN:XMAX:N*1j]

    r = np.sqrt(xx**2 + yy**2)

    mask = r <= RADIUS

    if domask:
        u[mask] = 0
        v[mask] = 0

    x = x.reshape((N,))
    y = y.reshape((N,))

    return x, y, u, v

def makeplot(show=False):

    x, y, u, v = compute_components(True)

    np.savetxt('streamlines_u.txt', u)
    np.savetxt('streamlines_v.txt', v)

    if show:
        mag = np.sqrt(u**2 + v**2)

        plt.figure(1)
        plt.clf()
        plt.axes(aspect=True)#, axisbg='#444444')

        print x.shape
        plt.streamplot(x,y,u,v,color=mag,cmap='Blues',density=1.5, arrowsize=2)
        plt.colorbar().set_label("Flow speed")

        c = plt.Circle((0,0), radius=RADIUS, facecolor='#aaaacc', linewidth=0, zorder=10)
        plt.gca().add_patch(c)
        plt.xlim(-3,3)
        plt.ylim(-3,3)


from math import sin, pi
from scipy.integrate import quad, dblquad, nquad

# Quad Function:

f = lambda x: x*sin(x)  # Equation to be integrated
a = 0                   # Lower limit
b = pi/2                # Upper limit

I,_ = quad(f, a, b)     # Neglects the 2nd return which is estimated abs error

print('I,_ = quad(f, ', a,', %f)' %b, sep='')
print('I   = %f' % I, end='\n\n')

# DblQuad Function:

fn = lambda x, y: x**2 * y + x * y**2   # Equation to be integrated
ax = 1                                  # Lower limit of inner integral
bx = 2                                  # Upper limit of inner integral
ay = -1                                 # Lower limit of outer integral
by = 1                                  # Upper limit of outer integral

I,_ = dblquad(fn, ax, bx, lambda y:ay, lambda y:by)

print('I,_ = dblquad(fn, ', ax, ', ', bx, ', lambda y:', ay, \
      ', lambda y:', by, ')', sep='')
print('I   = %f' % I, end='\n\n')

# NQuad Function:

I,_ = nquad(f, [[0, pi/2]])

print('I,_ = nquad(f, [[0, pi/2]])')
print('I   = %f' % I, end='\n\n')

I,_ = nquad(fn, [[ax, bx], [ay, by]])

print('I,_ = nquad(fn, [[',ax,', ',bx,'], [',ay,', ',by,']])', sep='')
print('I   = %f' % I)

4. Numerical Integration (Quadrature)/0. Numerical Integration functions of SciPy.py


# Scientific Computing using Python
# @Bryan Dimabayao
# Partial Differential Equation - Finite Difference Methods

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import mpl_toolkits.mplot3d
import scipy.sparse as sp
import scipy.sparse.linalg
import scipy.linalg as la
import dolfin
import mshr

N = 5
u0, u1 = 1, 2
dx = 1.0 / (N + 1)

A = (np.eye(N, k=-1) - 2 * np.eye(N) + np.eye(N, k=1)) / dx**2
A
#Output of Array

x = np.linspace(0, 1, N+2)
U = np.hstack([[u0], u, [u1]])
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(x, U)
ax.plot(x[1:-1], u, 'ks')
ax.set_xlim(0, 1)
ax.set_xlabel(r"$x$", fontsize=18)
ax.set_ylabel(r"$u(x)$", fontsize=18)
# Output and Plotting of Solution to the second-order ODE boundary value problem

Finite Difference Methods - Data Visualization.py


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

# Symbolic function and derivatives
h, t = sp.symbols('h t');
h = sp.exp(3*t)*t**2;
hp = h.diff(t);
#hpp = hp.diff(t);

# Taylor expansions around point t0
t0 = 1;
h0 = h.subs(t,t0);
h1 = h0 + hp.subs({t:t0})*(t-t0);
#h2 = h0 + hp.subs(t,t0)*(t-t0) + 1/2*hpp.subs(t,t0)*(t-t0)**2;

# Direct Taylor expansion using sympy
h5s = sp.series(h, t, t0, 6).removeO();
print("Taylor 5: ", h5s);

# Convert symbolic to functions that can be evaluated
lam_h = sp.lambdify(t, h, modules=['numpy']);
lam_h1 = sp.lambdify(t, h1, modules=['numpy']);
lam_h5s = sp.lambdify(t, h5s, modules=['numpy']);

# Plots
fig, ax = plt.subplots(1,1);
t_vals = np.linspace(0.5, 1.5, 100);
ax.plot(t_vals, lam_h(t_vals), 'r');
ax.plot(t_vals, lam_h1(t_vals), 'g');
#ax.plot(t_vals, lam_h5s(t_vals), 'b');

# Symbolic plotting also probably works
#sp.plot(h, h1, (t, 0, 1.5))


import numpy as np

'''
Proof of concept: Logits and softmax probability computations
'''

def softmax(logits):

    softmax = []
    q = 0
    for i in logits:
        softmax.append(np.exp(i) / sum(np.exp(logits)))
        q += np.exp(i) / sum(np.exp(logits))

    return softmax, q

def logits_func(prob):
    return np.log(prob / (1+prob))

proba = [0.006382342879717207, 0.2564389982593307, 0.04506310418417042, 0.08901875647497302, 0.0920775142662204,
        0.04941506219220917, 0.16701976595076282, 0.06772062316943511, 0.22686383262318108]
logits = [-5.053441047668457, -1.3600854873657227, -3.098912477493286, -2.4181292057037354, -2.384345531463623,
        -3.006721019744873, -1.7888641357421875, -2.6915855407714844, -1.4826263189315796]

softmax(logits)

for i in proba:
    print(logits_func(i))

def logit2prob(logit):
    return np.exp(logit) / (np.exp(logit) + 1)

# x2 samples of > 0.5
logits = [-4.636117458343506, -4.46367883682251, -3.3428733348846436, 2.175978183746338, -4.3089518547058105,
        -4.214722633361816, -5.114277362823486, 2.573429822921753, -4.526679039001465]

for i in logits:
    print(logit2prob(i))


#=============================================================================#
#
#    File:   sieve_of_eratosthenes.py
#    Author: Jack Morgan
#    Date:   May 2021
#    Description:
#        Uses a sieve to find all of the prime numbers up to a limit
#        Three versions, each faster than the last
#
#=============================================================================#

import numpy as np
from time import time
from math import sqrt, ceil

# print the prime numbers up to limit
# first version
def sieve_of_eratosthenes_1(limit):
    possible_primes = [True for _ in range(limit)]
    possible_primes[0] = possible_primes[1] = False
    for index, isprime in enumerate(possible_primes):
        if isprime:
            yield index
            for i in range(index**2, limit, index):
                possible_primes[i] = False
    return possible_primes

#second version
def sieve_of_eratosthenes_2(limit):
    possible_primes = np.ones(limit)
    possible_primes[0:2:1] = 0
    for (i, isprime) in enumerate(possible_primes):
        if bool(isprime):
            yield i
            possible_primes[i*i:limit:i] = 0

# third version
def sieve_of_eratosthenes_3(limit):
    possible_primes = np.ones(limit, dtype=bool)
    possible_primes[0:2:1] = False
    for i in range(2, ceil(sqrt(limit))):
        possible_primes[i*i:limit:i] = False
    return np.flatnonzero(possible_primes)

def main():
    limit = 1*10**6

    start1 = time()
    print(list(sieve_of_eratosthenes_1(limit)))
    end1 = time()

    start2 = time()
    print(list(sieve_of_eratosthenes_2(limit)))
    end2 = time()

    start3 = time()
    print(sieve_of_eratosthenes_3(limit))
    end3 = time()

    print(f'time 1: {end1-start1} seconds')
    print(f'time 2: {end2-start2} seconds')
    print(f'time 3: {end3-start3} seconds')

if __name__ == "__main__":
    main()


import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets, linear_model

def plot_line(x, y, theta=None, regressor=None):
    # Plot outputs
    x_min, x_max = x[:, 0].min() - .5, x[:, 0].max() + .5
    y_min, y_max = x[:, 1].min() - .5, x[:, 1].max() + .5
    xx, yy = np.meshgrid(np.arange(x_min, x_max, .02), np.arange(y_min, y_max, .02))

    if regressor:
        Z = regressor.predict(np.c_[xx.ravel(), yy.ravel()])
    else:
        Z = pred_val(theta, np.c_[xx.ravel(), yy.ravel()])
    # Put the result into a color plot
    Z = Z.reshape(xx.shape)
    plt.figure(1)
    plt.pcolormesh(xx, yy, Z, cmap=plt.cm.Paired)

    # Plot also the training points
    plt.scatter(x[:, 0], x[:, 1], c=y, edgecolors='k', cmap=plt.cm.Paired)
    plt.xlabel('Sepal Length')
    plt.ylabel('Sepal Width')

    plt.xlim(xx.min(), xx.max())
    plt.ylim(yy.min(), yy.max())
    plt.xticks(())
    plt.yticks(())

    plt.show()

# prediction values
def pred_val(theta, X, hard=True):
    # normalize
    X = (X - np.mean(X, axis=0)) / np.std(X, axis=0)
    pred_prob = logistic_val_func(theta, X)
    pred_value = np.where(pred_prob > 0.5, 1, 0)
    if hard:
        return pred_value
    else:
        return pred_prob

def logistic_grad_func(theta, x, y):
    # compute gradient
    grad = np.dot((logistic_val_func(theta, x) - y).T, np.c_[np.ones(x.shape[0]), x])
    grad = grad / x.shape[0]

    return grad

def sigmoid(x):
    return 1. / (1. + np.exp(-x))

def logistic_val_func(theta, x):
    # forwarding
    return sigmoid(np.dot(np.c_[np.ones(x.shape[0]), x], theta.T))

def logistic_cost_func(theta, x, y):
    # compute cost (loss)
    y_hat = logistic_val_func(theta, x)
    cost = np.sum(y * np.log(y_hat)) + np.sum((1 - y) * np.log(1-y_hat))
    cost *= 1.0 / x.shape[0]
    return -cost

def logistic_grad_desc(theta, X_train, Y_train, lr=0.03, max_iter=500, converge_change=.00001):

    cost_iter = []
    cost = logistic_cost_func(theta, X_train, Y_train)
    cost_iter.append([0, cost])
    cost_change = 1
    i = 1

    while cost_change > converge_change and i < max_iter:
        pre_cost = cost
        # compute gradient
        grad = logistic_grad_func(theta, X_train, Y_train)
        theta -= lr * grad
        cost = logistic_cost_func(theta, X_train, Y_train)
        cost_iter.append([i, cost])
        cost_change = abs(cost - pre_cost)
        i += 1

    return theta, cost_iter

def logistic_regression():
    # load dataset
    dataset = datasets.load_iris()
    # Select only 2 dims
    X = dataset.data[0:100, 0:2]
    Y = dataset.target[:100, None]

    # split dataset into training and testing
    idx_trn = range(30)
    idx_trn.extend(range(50, 80))
    idx_tst = range(30,50)
    idx_tst.extend(range(80, 100))

    X_train = X[idx_trn]
    X_test = X[idx_tst]

    Y_train = Y[idx_trn]
    Y_test = Y[idx_tst]

    # Linear regression
    theta = np.random.rand(1, X_train.shape[1]+1)
    fitted_theta, cost_iter = logistic_grad_desc(theta, X_train, Y_train, lr=0.05, max_iter=50000)

    print('Coefficients: {}'.format(fitted_theta[0, :-1]))
    print('Intercept: {}'.format(fitted_theta[0, -2]))
    print('Accuracy: {}'.format(np.sum((pred_val(fitted_theta, X_test) == Y_test)) * 1.0 / X_test.shape[0]))

    # Plot Training
    # plot_line(X_train, Y_train, fitted_theta)
    # Plot Testing
    plot_line(X_test, Y_test, theta=fitted_theta)

def sklearn_logistic_regression():
    # load dataset
    dataset = datasets.load_iris()
    # Select only 2 dims
    X = dataset.data[0:100, 0:2]
    Y = dataset.target[:100, None]

    # split dataset into training and testing
    idx_trn = range(30)
    idx_trn.extend(range(50, 80))
    idx_tst = range(30,50)
    idx_tst.extend(range(80, 100))

    X_train = X[idx_trn]
    X_test = X[idx_tst]

    Y_train = Y[idx_trn]
    Y_test = Y[idx_tst]

    # Logistic regression
    regressor = linear_model.LogisticRegression()
    regressor.fit(X_train, np.ravel(Y_train))
    print('Coefficients: {}'.format(regressor.coef_))
    print('Intercept: {}'.format(regressor.intercept_))
    print('Accuracy:{}'.format(np.sum((regressor.predict(X_test) == np.ravel(Y_test)))*1.0/X_test.shape[0]))

    plot_line(X_test, Y_test, regressor=regressor)

def main():
    print('Class 1: Linear Regression Example')
    logistic_regression()

    print ('')

    print('sklearn Linear Regression Example')
    sklearn_logistic_regression()

if __name__ == "__main__":
    main()


import numpy as np
from numpy import exp
from numpy import polyfit
from numpy import log
import matplotlib.pyplot as plt

RImageDistance,RObjectDistance,Magnification,ObjectDistance = np.loadtxt(r"2021.11.25 Lenses - Computing/lenses-experiment-a.csv",delimiter=",",skiprows=1,unpack=True)
font = {'fontname':'CMU Serif'}                                                                             # Assign font parameters
fontAxesTicks = {'size':7}

    ## 1/s against 1/s'
polyfitA,cov_polyfitA = np.polyfit(RObjectDistance,RImageDistance,1,cov=True)
plt.xlabel("Object Distance¯¹ / m¯¹", **font)                                                                        # Label axes, add titles and error bars
plt.ylabel("Image Distance¯¹ / m¯¹", **font)
plt.xticks(**font, **fontAxesTicks)
plt.yticks(**font, **fontAxesTicks)
plt.title("Experiment A: 1/s against 1/s'", **font)
plt.plot(RObjectDistance,RImageDistance,'x')
plt.plot(RObjectDistance, (polyfitA[0]*RObjectDistance+polyfitA[1]))
plt.show()
print(polyfitA)

polyfitB,cov_polyfitB = np.polyfit(RImageDistance,RObjectDistance,1,cov=True)
plt.xlabel("Image Distance¯¹ / m¯¹", **font)                                                                        # Label axes, add titles and error bars
plt.ylabel("Object Distance¯¹ / m¯¹", **font)
plt.xticks(**font, **fontAxesTicks)
plt.yticks(**font, **fontAxesTicks)
plt.title("Experiment A: 1/s against 1/s'", **font)
plt.plot(RImageDistance,RObjectDistance,'x')
plt.plot(RImageDistance, (polyfitB[0]*RImageDistance+polyfitB[1]))
plt.show()
print(polyfitB)

    ## M against s
#polyfitB,cov_polyfitB = np.polyfit(b,h,1,cov=True)
plt.xlabel("Object Distance / m", **font)                                                                        # Label axes, add titles and error bars
plt.ylabel("Magnification / no units", **font)
plt.xticks(**font, **fontAxesTicks)
plt.yticks(**font, **fontAxesTicks)
plt.title("Experiment A: M against s'", **font)
#plt.errorbar(f,e, yerr=((1/(f+0.1))-(1/(f-0.1))),xerr=(1/(e+0.1)-1/(e-0.1)),ls='',mew=1.5,ms=3,capsize=3)                         # Plots uncertainties in points
plt.plot(ObjectDistance,Magnification,'x')
#plt.plot(f, (polyfitA[0]*f+polyfitA[1]))
plt.show()

''' plt.plot(1/objectDistance, 1/imageDistance,'x')
polyfitA,cov_polyfitA = np.polyfit(1/objectDistance,1/imageDistance,2,cov=True)
#plt.plot(1/objectDistance, (polyfitA[0]*(1/objectDistance)**2+polyfitA[1]*(1/objectDistance)+polyfitA))
plt.xlabel("Time (t) / s", **font)                                                                          # Label axes, add titles and error bars
plt.ylabel("Natural Log of Voltage (ln V) / V", **font)
plt.xticks(**font, **fontAxesTicks)
plt.yticks(**font, **fontAxesTicks)
#plt.errorbar(distanceDS, grayValueDS,yerr=0,xerr=0,ls='',mew=1.5,ms=3,capsize=3)
plt.title("Small Capacitor, Discharging (Linear)", **font)
plt.show() '''


from scipy.integrate import odeint
class SIS:

	sets = ['S', 'I', 'N']
	params = ['beta', 'gamma']
	equations = {
		'S' : lambda S,I,N,_S,_I,_N,beta,gamma: f' -({beta} * {S} * {_I}) / ({_N}) + {gamma} * {I}',
		'I' : lambda S,I,N,_S,_I,_N,beta,gamma: f' ({beta} * {S} * {_I}) / ({_N}) - {gamma} * {I}',
		'N' : lambda S,I,N,_S,_I,_N,beta,gamma: f' 0',
	}

	@staticmethod
	def deriv(y, t, params):
		S, I, N = y
		beta, gamma = params
		dSdt = -(beta * S * I) / (N) + gamma * I
		dIdt = (beta * S * I) / (N) - gamma * I
		dNdt = 0
		return dSdt, dIdt, dNdt

	@staticmethod
	def solve(y, t, params):
		return odeint(SIS.deriv, y, t, args=(params,))


import numpy as np
import random

def inference (w,b,x):
    pred_y=w*x+b
    return pred_y

def gradient (pred_y,gt_y,x):
    dw=(pred_y-gt_y)*x
    db=pred_y-gt_y
    return  dw, db

def theta_step_update (batch_x_list, batch_gt_y_list, w, b, lr):
    avg_dw=0
    avg_db=0
    batch_size=len(batch_x_list)

    for i in range (batch_size):
        pred_y=inference(w,b,batch_x_list[i])
        dw,db=gradient(pred_y,batch_gt_y_list[i],batch_x_list[i])
        avg_dw+= dw
        avg_db+= db
    avg_dw/=batch_size
    avg_db/=batch_size

    #update simultanously
    w=w-lr*avg_dw
    b=b-lr*avg_db

    return w,b

def loss_function (batch_x_list, batch_gt_y_list, w, b):
    batch_size=len(batch_x_list)
    sum_loss=0
    for i in range (batch_size):
        single_loss=(w*batch_x_list[i]+b-batch_gt_y_list[i])**2
        sum_loss+=single_loss
    J=sum_loss/2*batch_size
    return J

def train(x_list, gt_y_list, batch_size,lr, maxIrr):
    #initial setup: pick up a starting point for (w,b);
    w=0
    b=0
    total_size=len(x_list)

    # randomly choose batch size of samples from the whole data
    # throw the batch into the iteration as training data for each round
    for i in range (maxIrr):
        batch_idx=np.random.choice(total_size,batch_size)
        batch_x_list=[x_list[j] for j in batch_idx]
        batch_gt_y_list=[gt_y_list[j] for j in batch_idx]
        w,b=theta_step_update(batch_x_list,batch_gt_y_list,w,b,lr)
        J=loss_function(batch_x_list,batch_gt_y_list,w,b)
        print('w:{0}, b:{1}'.format(w, b))
        print('loss: {0}'.format(J))
    return w,b,J

def generate_data(num_samples):
    w=random.randint(0,10)+random.random()
    b=random.randint(0,5)+random.random()
    x_list=[]
    gt_y_list=[]
    for i in range (num_samples):
        x = random.randint(0, 100) * random.random()
        y=w*x+b+random.random()* random.randint(-1, 1)
        x_list.append(x)
        gt_y_list.append(y)
    return w,b,x_list,gt_y_list

def run(num_samples, batch_size,lr,maxIrr):
    w0,b0,x_list,gt_y_list=generate_data(num_samples)
    w,b,J=train(x_list, gt_y_list, batch_size,lr, maxIrr)
    print ('original w: {0}, b:{1}'.format(w0,b0))
    print ('estimated w: {0}, b:{1}'.format(w,b))
    print ('final loss J: {0}'.format(J))

if __name__=='__main__':
    num_samples=100
    batch_size=50
    lr=0.001
    maxIrr=10000
    run(num_samples, batch_size,lr,maxIrr)


import numpy
import random
import time

def integral_function(x):
    return(1/(numpy.cos(x) + 2))
    # result: https://www.wolframalpha.com/input/?i=integrate+1%2F(cos(x)+%2B+2)+from+0+to+6

def monte_carlo(xmin, xmax, ymin, ymax, N):
    whole_area = (xmax - xmin) * (ymax - ymin)
    points = 0

    time_start = time.time()

    for i in range(N):
        x = xmin + (xmax - xmin) * random.random()
        y = ymin + (ymax - ymin) * random.random()

        if integral_function(x) > 0 and y > 0 and y <= integral_function(x):
            points += 1

    time_stop = time.time()
    total_time = time_stop - time_start
    result = whole_area * points / N

    return {'result': result, 'time': total_time, 'N': N}

# define limits
xmin = 0
xmax = 6
ymin = 0
x = numpy.linspace(xmin, xmax, 1000)
ymax = max(integral_function(x)) + 0.5 * max(integral_function(x))
Nmin = 100
Nmax = 10000

while Nmin <= Nmax:
    calc = monte_carlo(xmin, xmax, ymin, ymax, Nmin)
    print("Result: ", calc['result'], "Total time:", calc['time'], "N = ", calc['N'])
    Nmin = Nmin * 10


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 28 14:21:06 2019

@author: alankar
"""

import numpy as np
import matplotlib.pyplot as plt

def derivative(func,x,*args): #function to find the derivative of the polynomial
    h = 1e-4
    derivative = (func(x + h,*args) - func(x-h,*args)) / (2*h)
    return derivative

def NR(func,x0,tol,*args): #Newton Raphson
    x_new = 0
    x_old = x0
    while(np.abs(x_new-x_old)>=tol):
        x_new = x_old - func(x_old,*args)/derivative(func,x_old,*args)
        x_old = x_new
    return x_new

def f(x):
    return 924*x**6-2772*x**5+3150*x**4-1680*x**3+420*x**2-42*x+1

x = np.linspace(0,1,500)
plt.plot(x,f(x))
plt.xlabel(r'$x$',size=18)
plt.ylabel(r'$f(x)=924x^6-2772x^5+3150x^4-1680x^3+420x^2-42x+1$',size=18)
plt.grid()
#plt.savefig('poly.png')
plt.show()

print ('Roots are ')
x0 = [0.03,0.17,0.38,0.62,0.83,0.97]
for i in range(len(x0)):
    print( '%.10f'%NR(f,x0[i],1.e-10))

"""
Output

Roots are
0.0335761962
0.1693944272
0.3806901845
0.6193098155
0.8306055728
0.9664238038
"""


import numpy as np
import time
import pandas as pd

def main():
    # initi conditions---------------------------------------------------------
    A=2
    B=0.01
    t0=0.0
    t_end=5
    #--------------------------------------------------------------------------

    # Analytic solution
    analytic = lambda t_ini, y_ini, t, a, b: 1/(b/a+(1/y_ini-b/a)*np.exp(-a*(t-t_ini)))
    #--------------------------------------------------------------------------
    # ODE
    f = lambda y: A*y-B*y*y
    #--------------------------------------------------------------------------
    # initial valuse
    y0_list = np.array([8, 10, 12])
    #y0_list = np.array([100, 190, 250])
    #--------------------------------------------------------------------------

    timesteps = np.array([0.05, 0.025, 0.0125, 0.00625, 0.003125])

    # maps of 4th order for different time steps (A=2, B=0.01)
    # M(0,:) is map for dt=0.05     (N=100)
    # M(1,:) is map for dt=0.025    (N=200)
    # M(2,:) is map for dt=0.0125   (N=400)
    # M(3,:) is map for dt=0.00625  (N=800)
    # M(4,:) is map for dt=0.003125 (N=1600)

    Maps = np.array([[-9.74718510761581e-11,2.82830795154941e-7,-0.00057683855758959,1.1047522448889,0.0164019262867156],
                    [-1.379332373516e-11,6.75987803436825e-8,-0.00026920890283235,1.05124251835198,0.00113151812515],
                    [-1.83493448551926e-12,1.63316814751669e-8,-0.00012976106224663,1.0253132530535,7.43225401875509e-5],
                    [-2.36633829318494e-13,3.99916101441112e-9,-6.36821468173527e-5,1.01257833218163,4.76237954022738e-6],
                    [-3.00445936310731e-14,9.88470260129351e-10,-3.15443221011727e-5,1.00626956445964,3.0138672729979e-7]
                    ])

    #--------------------------------------------------------------------------
    # resulting table
    # result(:, 0) is N
    # result(:, 1) is err_RK4
    # result(:, 2) is err_TM4
    # result(:, 3) is time_RK4
    # result(:, 4) is time_TM4
    # result(:, 5) is time_ratio = time_RK4/time_TM4
    result = np.zeros((len(timesteps), 6))

    for k, dt in enumerate(timesteps):  # for each time stemp dt
        M = Maps[k, :]                 # get TM for this dt
        N = int((t_end-t0)/dt)
        t = np.arange(t0, t_end, dt)

        result[k, 0] = N

        for y0 in y0_list: # for each y0
            # analytic solution------------------------------------------------
            y_sol = analytic(t0, y0, t, A, B)
            #------------------------------------------------------------------

            # RK4 integration--------------------------------------------------
            y_rk4 = np.zeros(N)

            y_rk4[0]=y0
            tic = time.time()
            for i in range(N-1):
                y = y_rk4[i]
                k1 = f(y)
                k2 = f(y+dt*k1/2)
                k3 = f(y+dt*k2/2)
                k4 = f(y+dt*k3)
                y_rk4[i+1] = y + dt*(k1+2*k2+2*k3+k4)/6

            elapsed_time = time.time()-tic
            result[k, 3] += elapsed_time # time_RK4
            #------------------------------------------------------------------

            # Mapping----------------------------------------------------------
            y_map = np.zeros(N)
            y_map[0] = y0
            tic = time.time()
            for i in range(N-1):
                y=y_map[i]
                y2 = y*y
                y_map[i+1] = (y2*(M[0]*y2 + M[2]) +
                            y *(M[1]*y2 + M[3]) +
                            M[4])

            elapsed_time = time.time()-tic
            result[k, 4] += elapsed_time # time_RK4
            #------------------------------------------------------------------
            result[k, 1] += np.abs(y_rk4 - y_sol).max() # err_RK4
            result[k, 2] += np.abs(y_map - y_sol).max() # err_TM4

    result[:, 1:] /= len(y0_list) # get average results
    result[:, 5] = result[:, 3]/result[:, 4] # get time_ratio

    result = pd.DataFrame(data=result[:,1:], index=result[:,0], columns=np.array(['err_RK4', 'err_TM4', 'time_RK4', 'time_TM4', 'time_ratio']))
    return result

if __name__ == "__main__":
    print(main())


# Create by Packetsss
# Personal use is allowed
# Commercial use is prohibited

from timeit import default_timer as timer
import numpy as np

"""
How many possible ways a traveller can travel through a N x M grid?

1x1: [0]
1 way

1x2: [0, 0]
1 way

2x2: [0, 0]
     [0, 0]
2 ways

2x3: [0, 0, 0] == 2 + 1
     [0, 0, 0]
3 ways

3x3: [0, 0, 0]    [0, 0, 0]   [0, 0]
     [0, 0, 0] == [0, 0, 0] + [0, 0] == 2 + 1 + 2 + 1
     [0, 0, 0]                [0, 0]

6 ways

3x4: [0, 0, 0, 0]    [0, 0, 0]   [0, 0, 0, 0]
     [0, 0, 0, 0] == [0, 0, 0] + [0, 0, 0, 0] == 6 + 3 + 1
     [0, 0, 0, 0]    [0, 0, 0]

"""

def grid_traveller(n, m):
    if n == 0 or m == 0:
        return 0
    elif n < 2 and m < 2:
        return min(n, m)
    else:
        return grid_traveller(n - 1, m) + grid_traveller(n, m - 1)

start = timer()
print(grid_traveller(13, 10))
end = timer()
print(end - start)
# Slow naive recursive solution

### Memoized
d = {}
def grid_traveller_topdown(n, m):
    key = f"{n}{m}"
    if n == 0 or m == 0:
        return 0
    elif n < 2 and m < 2:
        return min(n, m)
    elif key in d:
        return d[key]
    else:
        d[key] = grid_traveller_topdown(n - 1, m) + grid_traveller_topdown(n, m - 1)
        return d[key]

start = timer()
print(grid_traveller_topdown(13, 100))
end = timer()
print(end - start)

### Tabulation
def grid_traveller_bottom_up(n, m):
    if n == 0 or m == 0:
        return 0

    lst = np.zeros((n + 1, m + 1))
    lst[1:, 1] = 1
    lst[1, 1:] = 1

    for i in range(2, n + 1):
        for j in range(2, m + 1):
            lst[i, j] = lst[i - 1, j] + lst[i, j - 1]
    return int(lst[-1, -1])

start = timer()
print(grid_traveller_bottom_up(13, 100))
end = timer()
print(end - start)
# 2x faster

# best to use 0 for counting problems
def grid_traveller_bottom_up_1(n, m):
    table = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
    # correct way to create a 2d array

    table[1][1] = 1

    # add the current value of i to it's right and bottom
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            cur = table[i][j]
            if i < m:
                table[i + 1][j] += cur
            if j < n:
                table[i][j + 1] += cur

    return table[m][n]

start = timer()
print(grid_traveller_bottom_up_1(13, 100))
end = timer()
print(end - start)

Python Tutorial Dynamic Programming/2_Grid_Traveller.py


from os.path import join
import os
import scipy.io as sio
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
import numpy as np
from utils import normalize_features

file = "ex7data1.mat"
current_dir = os.path.abspath(".")
data_dir = join(current_dir, 'data')
file_name = join(data_dir,file)
mat_dict = sio.loadmat(file_name)
print("mat_dict.keys() : ",mat_dict.keys())
X = mat_dict["X"]
m = X.shape[0]

# remove mean and feature scaling is recommended by Andrew Ng
X_normalized = normalize_features(X)

# m = x1.size
sigma = (1/m)*np.dot(X_normalized.T,X_normalized) # nxn (n is 2 : number of features)

def plot(_X,title):
    x1 = _X[:,0]
    x2 = _X[:,1]
    plt.plot(x1,x2,'o')
    plt.title(title)
    plt.xlabel('x1')
    plt.ylabel('x2')
    plt.grid()
    plt.show()

def svd():
    u, s, vh = np.linalg.svd(sigma)
    print(f"u : {u}")
    print(f"s : {s}")
    print(f"vh : {vh}")
    variance_retained_1 = 100*s[0]/s.sum()
    print(f"% variance retained by using 1 approximated feature : {variance_retained_1}")

# def learn():
    # pca = PCA(n_components=1)
    # pca.fit(X)
    # print(pca)
    # Z = pca.transform(X)
    # print(Z.shape)
    # plt.plot(Z,'o')
    # plt.show()

plot(X,'dataset before pre processing')
plot(X_normalized,'dataset after pre processing')
svd()
# learn()


# -*- coding: utf-8 -*-

import numpy as np, tensorflow as tf, seaborn as sns, arviz as az, tensorflow_probability as tfp
tf.config.optimizer.set_jit(True)
tfd, tfb = tfp.distributions, tfp.bijectors

def snsdistplot(data):
	g = sns.displot(data, bins = "sqrt", kde = True)
	g.fig.set_figwidth(8)
	g.fig.set_figheight(6)
	return g

data = np.loadtxt("data/mixture_data.csv")
snsdistplot(data)

var_name = ["prob", "centers", "sigmas"]

@tfd.JointDistributionCoroutineAutoBatched
def mdl_batch():
	prob = yield tfd.Uniform(low = 0., high = 1., name = var_name[0])
	centers = yield tfd.Normal(loc = [120., 190.], scale = [10.]*2, name = var_name[1])
	sigmas = yield tfd.Uniform(low = [0.]*2, high = [100.]*2, name = var_name[2])
	categories = tfd.Categorical(probs = [prob, 1. - prob]) # assignments to a group
	values = tfd.Normal(loc = centers, scale = sigmas) # group
	mixture = tfd.MixtureSameFamily(mixture_distribution = categories, components_distribution = values)
	yield tfd.Sample(mixture, sample_shape = len(data), name = "obs")

# a helper function in McMC chain
def trace_fn(current_state, kernel_results):
	mdr = kernel_results.inner_results.inner_results
	return mdr.target_log_prob, mdr.leapfrogs_taken, mdr.has_divergence, mdr.energy, mdr.log_accept_ratio

@tf.function(autograph = False, experimental_compile = True) # speed up a lot the McMC sampling
def run_mcmc( # pass numeric arguments as Tensors whenever possible
	init_state, unconstraining_bijectors,
	num_steps = 50000, burnin = 10000,
	num_leapfrog_steps = 3, step_size = .5
):
	kernel0 = tfp.mcmc.NoUTurnSampler(
		target_log_prob_fn = lambda *args: mdl_batch.log_prob(obs=data, *args),
		step_size = step_size
	)
	kernel1 = tfp.mcmc.TransformedTransitionKernel(
		inner_kernel= kernel0,
		bijector = unconstraining_bijectors
	)
	kernel2 = tfp.mcmc.DualAveragingStepSizeAdaptation( # pkr = previous kernel results
		inner_kernel = kernel1,
		num_adaptation_steps = int(0.8*burnin),
		step_size_setter_fn = lambda pkr, new_step_size: pkr._replace(inner_results = pkr.inner_results._replace(step_size=new_step_size)),
		step_size_getter_fn = lambda pkr: pkr.inner_results.step_size,
		log_accept_prob_getter_fn = lambda pkr: pkr.inner_results.log_accept_ratio
	)
	# tf.get_logger().setLevel("ERROR") # multiple chains
	return tfp.mcmc.sample_chain( # ATTENTION: 2 values to unpack
		num_results = num_steps,
		num_burnin_steps = burnin,
		current_state = init_state,
		kernel = kernel2,
		trace_fn = trace_fn
	)

nchain = 4
init_state = [mdl_batch.sample(nchain)._asdict()[_] for _ in var_name]
unconstraining_bijectors = [tfb.Identity()]*len(var_name)
samples, sampler_stat = run_mcmc(init_state, unconstraining_bijectors)

#%% using the pymc3 naming convention, with log_likelihood instead of lp so that ArviZ can compute loo and waic
sample_stats_name = ['log_likelihood', 'tree_size', 'diverging', 'energy', 'mean_tree_accept']

sample_stats = {k: v.numpy().T for k, v in zip(sample_stats_name, sampler_stat)}
posterior = {k:np.swapaxes(v.numpy(), 1, 0) for k, v in zip(var_name, samples)}
az_trace = az.from_dict(posterior = posterior, sample_stats = sample_stats)

snsdistplot(posterior["prob"])
snsdistplot(posterior["centers"][:, 0])

# put the data into a tensor
datatf = tf.constant(data, dtype = tf.float32)[:, tf.newaxis]

# This produces a cluster per MCMC chain
rv_clusters_1 = tfd.Normal(posterior["centers"][:, 0], posterior["sigmas"][:, 0])
rv_clusters_2 = tfd.Normal(posterior["centers"][:, 1], posterior["sigmas"][:, 1])

# Compute the un-normalized log probabilities for each cluster
cluster_1_log_prob = rv_clusters_1.log_prob(datatf) + tf.math.log(posterior["prob"])
cluster_2_log_prob = rv_clusters_2.log_prob(datatf) + tf.math.log(1. - posterior["prob"])

# Bayes rule to compute the assignment probability: P(cluster = 1 | data) ∝ P(data | cluster = 1) P(cluster = 1)
log_p_assign_1 = cluster_1_log_prob - tf.math.reduce_logsumexp(tf.stack([cluster_1_log_prob, cluster_2_log_prob], axis=-1), -1)

# Average across the MCMC chain
log_p_assign_1bis = tf.math.reduce_logsumexp(log_p_assign_1, -1) - tf.math.log(tf.cast(log_p_assign_1.shape[-1], tf.float32))

p_assign_1 = tf.exp(log_p_assign_1bis)
p_assign = tf.stack([p_assign_1, 1 - p_assign_1], axis=-1)

assign_trace = log_p_assign_1bis.numpy()[np.argsort(data)]
plt.scatter(data[np.argsort(data)], assign_trace, cmap = "RdBu",c = (1 - assign_trace), s = 50)
plt.title("Probability of data point belonging to cluster 0")
plt.ylabel("probability")
plt.xlabel("value of data point")


import numpy as np

# Helper functions
def _predict(theta_0, theta_1, x):
    return theta_1 * x + theta_0       # good old line equation from high school when we were all young and happy

def compute_mse(theta_0, theta_1, data):
    """
    Calcula o erro quadratico medio
    :param theta_0: float - intercepto da reta
    :param theta_1: float -inclinacao da reta
    :param data: np.array - matriz com o conjunto de dados, x na coluna 0 e y na coluna 1
    :return: float - o erro quadratico medio
    """
    n = len(data)

    predicted = [_predict(theta_0, theta_1, element[0]) for element in data]

    square_error = lambda x, y: (x - y)**2
    squared_errors = [square_error(predicted[i], data[i][1]) for i in range(n)]

    mse = sum(squared_errors) / n

    return mse

def step_gradient(theta_0, theta_1, data, alpha):
    """
    Executa uma atualização por descida do gradiente  e retorna os valores atualizados de theta_0 e theta_1.
    :param theta_0: float - intercepto da reta
    :param theta_1: float -inclinacao da reta
    :param data: np.array - matriz com o conjunto de dados, x na coluna 0 e y na coluna 1
    :param alpha: float - taxa de aprendizado (a.k.a. tamanho do passo)
    :return: float,float - os novos valores de theta_0 e theta_1, respectivamente
    """
    n = len(data)

    predicted = [_predict(theta_0, theta_1, element[0]) for element in data]

    simple_error = lambda x, y: x - y
    errors = [simple_error(predicted[i], data[i][1]) for i in range(n)]

    # Both expressions below can be checked on page 14 of the second set of slides on week 7 ("Otimizacao Continua.pdf")
    df_d0 = (2 * sum(errors)) / n
    df_d1 = (2 * sum([errors[i] * data[i][0] for i in range(n)])) / n

    new_theta_0 = theta_0 - alpha*df_d0
    new_theta_1 = theta_1 - alpha*df_d1

    return (new_theta_0 , new_theta_1)

def fit(data, theta_0, theta_1, alpha, num_iterations):
    """
    Para cada época/iteração, executa uma atualização por descida de
    gradiente e registra os valores atualizados de theta_0 e theta_1.
    Ao final, retorna duas listas, uma com os theta_0 e outra com os theta_1
    obtidos ao longo da execução (o último valor das listas deve
    corresponder à última época/iteração).

    :param data: np.array - matriz com o conjunto de dados, x na coluna 0 e y na coluna 1
    :param theta_0: float - intercepto da reta
    :param theta_1: float -inclinacao da reta
    :param alpha: float - taxa de aprendizado (a.k.a. tamanho do passo)
    :param num_iterations: int - numero de épocas/iterações para executar a descida de gradiente
    :return: list,list - uma lista com os theta_0 e outra com os theta_1 obtidos ao longo da execução
    """
    current_iteration = 1
    all_theta_zeroes = []
    all_theta_ones = []

    while current_iteration <= num_iterations:
        (cur_theta_zero, cur_theta_one) = step_gradient(theta_0, theta_1, data, alpha)

        all_theta_zeroes.append(cur_theta_zero)
        all_theta_ones.append(cur_theta_one)

        theta_0 = cur_theta_zero
        theta_1 = cur_theta_one

        current_iteration += 1

    return (all_theta_zeroes, all_theta_ones)


"""

Reference -> https://medium.com/data-science-everywhere/machine-learning-series-day-5-aeaf0baa103e
"""
import numpy as np

print(np.__version__)

"""
- A NumPy array is simply a collection of the same data typed values.
- NumPy arrays can take two forms,
  - vectors: Vectors are strictly one dimensional
  - matrices: Matrices are multi-dimensional.
"""
# %%
# create NumPy array from List

np_array = np.array([0,1,2,3,4,5])
print(type(np_array))
print(np_array)

# %%
# Vectorized Operations in NumPy
print(np_array + 2)
print(np_array * 4)
print(np_array / 2)
print(np_array // 2)

# %%
# Creation of array of zeroes/ones
np.zeros((2,2))
np.ones((2,2))

# %%
# Merging of two arrays
arr1 = np.matrix([1,2,3])
arr2 = np.matrix([4,5,6])
print('Horizontal Append:', np.hstack((arr1, arr2)))
print('Vertical Append:', np.vstack((arr1, arr2)))

# %%
# Creating 2 dimensional array from Python list
list1 = [[1,2,3], [4,5,6], [7,8,9]]
arr2d = np.array(list1)
arr2d

# %%
# Creating an array of a particular type
arr2df = np.array(list1, dtype='int') # dtype='float'
arr2df

arr2df.astype('int').astype('str') # astype( ) of NumPy allows us to convert the data type of an array from one type to other.

# %%
list_conv = arr2df.tolist()
print(type(list_conv))

## %% finding the dimension
print('Shape: ', arr2df.shape)
# dtype
print('Datatype: ', arr2df.dtype)
# size
print('Size: ', arr2df.size)
# ndim
print('Num Dimensions: ', arr2df.ndim)

# %%
# Creating a boolean matrix on applying a conditional expression
list3 = [[1, 2, 3, 4],[3, 4, 5, 9], [3, 6, 7, 8]]
arr3 = np.array(list3, dtype='float')
arr3

# %%
boolean_matrix = arr3 > 5
boolean_matrix

# %%
# Reversing an array
arr3[::-1, ]

# %%
#  Inserting nan and inf
arr3[2,1] = np.nan # not a number
arr3[1,2] = np.inf # infinite
arr3

# %%
# Replace nan and inf with -1,
missing_values = np.isnan(arr3) | np.isinf(arr3)
missing_values # <- Returns array of booleans
arr3[missing_values] = -1
arr3

# %%
# Max, min and mean calculations
arr3.mean()
arr3.max()
arr3.min()

# %%
# Row wise and column wise min
print('Column-wise minimum: ', np.amin(arr3, axis=0))
print('Row-wise minimum: ', np.amin(arr3, axis=1))

# %%
# Assigning a portion of an array to other
arr3
arr3a = arr3[:2,:2]
arr3a[:1, :1] = 24 # 24 will be reflected in the parent array too
arr3a
arr3

# %%
#Assign portion of arr3 to arr3_cpy using copy()
arr3
arr3_cpy = arr3[:2,:2].copy()
arr3_cpy[:1, :1] = 1 # 24 will not be reflected in the parent array too
print("Parent aray:",arr3)
arr3_cpy

# %%
# Reshaping arrays
"""
reshape( ) function allows us to change the shape of an array from one form to other.
Note: The reshape() can convert only when rows and columns together must be equal to the number of elements."""
# Reshape a 3x4 array to 2x6 array, here array had 12 elements, hence can be converted to shape (2,6)

arr3.reshape(2,6)

# %%
# Flatten arr3 to a 1d array
arr3.flatten()

# %%
# Changing the flattened array does not change parent
test1 = arr3.flatten()
test1[0] = 1 # changing b1 does not affect arr2

# %%
# Changing the raveled array changes the parent also.
test2 = arr3.ravel()
test2[0] = 0 # changing b2 changes arr2 also

# %%
# Random numbers generation
np.random.rand(3,3)  #Prints random numbers between 0 and 1 in a matrix of order 3x3
np.random.random()
np.random.randint(0, 10, size=[2,2]) # Prints a random number between 0 and 10 in a (2,2) matrix

# %%
# Create random integers of size 10 between [0,10)
np.random.seed(100)
arr_rand = np.random.randint(0, 5, size=10)
arr_rand

# %%
# Unique elements and their count
uniq, count = np.unique(arr_rand, return_counts=True)
uniq
count

# %%
# Pick 15 items from a given list, with equal probability
list4 = np.random.choice(['n','u','m','p','y'], size=15)
uniq1, count1 = np.unique(list4, return_counts=True)
print('Unique items : ', uniq1)
print('Counts : ', count1)

# %%


"""
Linear System (Polynomial Interpolation)
"""

import numpy as np

def swap_rows(Z, a, b):
    """
    Swap two rows (a, b) from Z matrix (np.array)

    Parameters
    ----------
        Z : np.array
            matrix
        a : int
            index row from Z
        b : int
            index row from Z
    """
    temp = np.copy(Z[a])
    Z[a] = Z[b]
    Z[b] = temp

def partial_pivoting(Z, row):
    """
    Partial pivoting of Z matrix, starting at row param

    Parameters
    ----------
        Z : np.array
            matrix
        row : int
            index row from Z

    Returns
    -------
        pivot : int
            pivot is the max value from Z(row:,row)
    """
    pivot_row = np.argmax(np.abs(Z[row:, row])) + row
    swap_rows(Z, row, pivot_row)
    pivot = Z[row, row]
    return pivot

def solve_sys(X, Y):
    """
    Solve a linear system using Gauss Elimination

    Parameters
    ----------
        X : list
            list of x values
        Y : list
            list of y values

    Returns
    -------
        list
            returns the roots of linear system (X, Y)
    """
    Z = np.copy(X)
    Z = np.hstack([Z, np.transpose(np.array([Y]))])

    for j in range(Z.shape[0] - 1):
        pivot = partial_pivoting(Z, j)
        for i in range(j + 1, Z.shape[0]):
            if Z[i, j] != 0 :
                m = pivot / Z[i, j]
                Z[i, j:] = Z[j, j:] - (m * Z[i, j:])

    A = np.zeros((X.shape[0], 1))
    for k in range(Z.shape[0] - 1, -1, -1):
        A[k] = (Z[k, Z.shape[1]-1] - (Z[k, Z.shape[1]-2:k:-1] @ A[A.shape[0]:k:-1])) / Z[k, k]

    return np.ndarray.tolist(np.transpose(A))[0]

def vandermond(X):
    """
    Create a vandermond matrix(nxn) by x values

    Parameters
    ----------
        X : list
            list of x values

    Returns
    -------
        np.array
            vandermond matrix
    """
    n = len(X)
    V = np.zeros((n, n))

    for i in range(n):
        V[i, :] = [X[i]**k for k in range(n)]

    return V

def linsys(X, Y):
    """
    Polynomial Interpolation using Gauss Elimination

    Parameters
    ----------
        X : list
            list of X values
        Y : list
            list of Y values

    Returns
    -------
        function
            function of polynomial interpolation (using linear system)
    """
    V = vandermond(X)
    A = solve_sys(V, Y)

    def f(x):
       return sum([a*(x**p) for p, a in enumerate(A)])

    return f


import numpy as np
import scipy.io
import matplotlib.pyplot as plt
import seaborn as sns

from featureNormalize import feature_normalize
from PCA_algo import pca
from projectData import project_data
from recoverData import recover_data

# In this exercise, we'll use principal component analysis (PCA) to perform dimensionality reduction.
########### Implement PCA on 2D dataset ####################
print(f"Plotting data example 1")
data1 = scipy.io.loadmat("data/ex7data1.mat")
sns.scatterplot(data1["X"][:, 0], data1["X"][:, 1])
plt.show()

input("Pause program, Press enter to continue")

# Implement PCA (Reduce from 2D to 1D -> k=1)
# (1st compute the covariance matrix of dataset. 2nd use svd function to compute eigenvectors U1, U2,...
# Un which are corresponding to principal component (main component) of variation (thành phần) dataset)
X_norm, mu, std = feature_normalize(data1["X"])
U, S = pca(X_norm)

# Visualize the dimensional reduction data resulted by PCA
# Visualize original data
print(f"\nVisualize dimensional reduction data")
data1 = scipy.io.loadmat("data/ex7data1.mat")
ax = sns.scatterplot(data1["X"][:, 0], data1["X"][:, 1])
# Compute & visualize compressed data (Z)
p1 = mu  # (1, 2)
p2 = mu + 1.5 * S[0] * U[:, 0].T  # (1, 2)
ax.plot((p1[0], p2[0]), (p1[1], p2[1]), "k")

p1 = mu
p2 = mu + 1.5 * S[1] * U[:, 1].T
ax.plot([p1[0], p2[0]], [p1[1], p2[1]], 'k')
plt.title('Computed eigenvectors of the dataset')
plt.show()
input("Pause program, Press enter to continue")

############ Dimensionality reduction with PCA ##############
print(f"\nReduce dimensionality of data from n-dim to K-dim")
# Checking correctness of reduction
K = 1
Z = project_data(X_norm, U, K)  # (m, K)
print(f"Projection of the 1st example: {Z[0]}")
print(f"This value should be 1.481274")

# Reconstructing compressed data approximately to original data
print(f"\nReconstruct compressed data to approximately original data")
X_rec = recover_data(Z, U, K)
print(f"Approximation of 1st example: {X_rec[0, 0]}, {X_rec[0, 1]}")
print(f"The result should be -1.047419 -1.047419")

# Visualize the projection
ax = sns.scatterplot(X_norm[:, 0], X_norm[:, 1], s=50)
ax = sns.scatterplot(X_rec[:, 0], X_rec[:, 1], s=50, color="r")
for i in range(X_norm.shape[0]):
    p1 = X_norm[i, :]
    p2 = X_rec[i, :]
    plt.plot([p1[0], p2[0]], [p1[1], p2[1]], "k--")
plt.title("Normalized and projected data after applying PCA")
plt.show()
input("Pause program, Press enter to continue")

################## Face image dataset ######################
# Loading faces data
faces_data = scipy.io.loadmat("data/ex7faces.mat")
# Visualize the first 100 pic of faces
print("\nVisualize the first 100 pictures of faces")
rows = 7
cols = 7
count = 0
fig = plt.figure(figsize=(5, 5))
for row in range(rows):
    for col in range(cols):
        ax = fig.add_subplot(rows, cols, count+1)
        ax.imshow(faces_data["X"][count].reshape(32, 32).T, cmap="gray")
        ax.axis("off")
        count += 1
plt.show()
input("Pause program, Press enter to continue")

# Normalize data X & compute svd() function
X_norm, mu, std = feature_normalize(faces_data["X"])  # X_norm: (5000, 1024) (5000 pic)
U, S = pca(X_norm)

# Apply PCA to data with K = 100
K = 100
Z = project_data(X_norm, U, K)  # (m, K)
# Visualize the first 100 dimensional reduction pic of face
print("\nDrawing 1st 100 pic of face with dimensional reduction to K = 100")
rows = 7
cols = 7
count = 0
fig = plt.figure(figsize=(5, 5))
for row in range(rows):
    for col in range(cols):
        ax = fig.add_subplot(rows, cols, count+1)
        ax.imshow(Z[count, :].reshape(10, 10).T, cmap="gray")
        ax.axis("off")
        count += 1
plt.show()
input("Pause program, Press enter to continue")

# Reconstructing from compressed image to original image
X_rec = recover_data(Z, U, K)
print("\nPlot the reconstructed image from compressed image (From 10*10 to 32*32)")
rows = 7
cols = 7
count = 0
fig = plt.figure(figsize=(5, 5))
for row in range(rows):
    for col in range(cols):
        ax = fig.add_subplot(rows, cols, count+1)
        ax.imshow(X_rec[count, :].reshape(32, 32).T, cmap="gray")
        ax.axis("off")
        count += 1
plt.show()


"""
golden_section_algorithm.py

Returns the reduced uncertainty interval containing the minimizer of the function
func - anonimous function
interval0 - initial uncertainty interval
N_iter - number of iterations
"""

import math
import numpy as np

def golden_section_algorithm_calc_N_iter(interval0, uncertainty_range_desired):

    N_iter = math.ceil(math.log(uncertainty_range_desired / (interval0[1] - interval0[0]), 0.618));

    return N_iter;

def golden_section_algorithm(func, interval0, N_iter):

    rho = (3 - np.sqrt(5)) / 2;
    left_limit = interval0[0];
    right_limit = interval0[1];

    smaller = 'a';
    a = left_limit + (1 - rho) * (right_limit - left_limit);
    f_at_a = func(a);

    for iter_no in range(N_iter):
        if (smaller == 'a'):
            c = a;
            f_at_c = f_at_a;
            a = left_limit + rho * (right_limit - left_limit);
            f_at_a = func(a);
        else:
            a = c;
            f_at_a = f_at_c;
            c = left_limit + (1 - rho) * (right_limit - left_limit);
            f_at_c = func(c);
        if (f_at_a < f_at_c):
            right_limit = c;
            smaller = 'a';
        else:
            left_limit = a;
            smaller = 'c';

    interval = (left_limit, right_limit);
    return interval;


from matplotlib.patches import Polygon
import matplotlib.pyplot as plt
import numpy as np

# points at 2D
def plot_2D_points(points, polyg=False):
    fig, ax = plt.subplots()
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    ax.xaxis.set_ticks_position('bottom')
    ax.spines['bottom'].set_position(('data',0)) # set position of x spine to x=0
    ax.yaxis.set_ticks_position('left')
    ax.spines['left'].set_position(('data',0))   # set position of y spine to y=0

    for point in points:
        plt.scatter(point[0], point[1], color="g")
        plt.text(point[0]+0.2, point[1]+0.2, f'({point[0]},{point[1]})' , fontsize=11)

    if polyg == False:
        plt.show()

# draw triangle
def plot_triangle(points):
    plot_2D_points(points, polyg=True)

    triangle_points = np.array(points)
    triangle_plot = plt.Polygon(triangle_points, color='g')
    plt.gca().add_patch(triangle_plot)

    plt.show()

# calculate the area o a triangle
def calc_triangle_area(x0, y0, x1, y1, x2, y2):
    return abs((x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1))/2)

# check if point (0,0) is inside the triangle
def check_origin_in(x0, y0, x1, y1, x2, y2):
    # calculate triangle areas for:
    triangle_area1 = calc_triangle_area(x0, y0, x1, y1, 0, 0) # Point0, Point1, (0.0)
    triangle_area2 = calc_triangle_area(x0, y0, 0, 0, x2, y2) # Point0,(0.0), Point2
    triangle_area3 = calc_triangle_area(0, 0, x1, y1, x2, y2) # (0,0), Point1, Point2
    triangle_area = calc_triangle_area(x0, y0, x1, y1, x2, y2)

    if(triangle_area1 + triangle_area2 + triangle_area3 == triangle_area):
        print('The interior of the triangle contains the origin (0, 0)')
    else:
        print('The interior of the triangle does not contain the origin (0, 0)')

#check if 3 points form a triangle
def check_for_triangle(x0, y0, x1, y1, x2, y2):
    # area of triangle
    # if area is 0, the points are in the same straight line
    triangle_area = calc_triangle_area(x0, y0, x1, y1, x2, y2)

    if (triangle_area != 0):
        return True
    else:
        return False

if __name__ == "__main__":

    # read 3 points from user
    print("Give 3 points.")
    points = list(tuple(map(int,input('Give a point: ').split())) for r in range(3))

    #check if these points form a triangle
    if check_for_triangle(points[0][0], points[0][1],
                        points[1][0], points[1][1],
                        points[2][0], points[2][1]):
        print ('These points form a triangle')
        check_origin_in(points[0][0], points[0][1],
                        points[1][0], points[1][1],
                        points[2][0], points[2][1])
        plot_triangle(points)
    else:
        print ('These points don\'t form a triangle')
        plot_2D_points(points)


# import modules
import numpy as np

'''
# Description.
Given a 2x1 vector, this function obtains the angle of the azimuth from
x-axis in a counter clockwise sense.
Coordiante system is with x in the abscisas and y in the ordinates  (i.e.
x horizontal pointing to the right and y vertical pointing upwards).

# Input(s).
Array that representing a bi-dimensional vector (vector).

# Output(s).
Angle in radians representing the azimut of the vector (angleRad).

Example: giving next array
vector = np.array([3,-5]), is obtined  5.2528 radians
---
angleRad = azimuthangle(vector)
'''
def azimuthangle(vector):
    if vector[0] == 0:
        if vector[1] >= 0:
            angleRad = np.pi/2
        else:
            angleRad = 3*np.pi/2
    else:
        basicAngleRad = np.arctan(np.abs(vector[1])/np.abs(vector[0]))
        if vector[0] >= 0:
            if vector[1] >= 0: #case 1
                angleRad = basicAngleRad
            elif vector[1] < 0: #case 4
                angleRad = 2*np.pi-basicAngleRad
        elif vector[0] < 0:
            if vector[1] >= 0: #case 2
                angleRad = np.pi-basicAngleRad
            elif vector[1] < 0: #case 3
                angleRad = np.pi+basicAngleRad
        else:
            print("Error: bad number")

    return angleRad
'''
BSD 2 license.

Copyright (c) 2016, Universidad Nacional de Colombia, Ludger O.
   Suarez-Burgoa and Exneyder Andrés Montoya Araque.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''


"""
The purpose of this code is to explore the use of relaxation and over-
relaxation method on computing non-linear equations i.e. f(x) = x.
"""
import numpy as np
import matplotlib.pyplot as plt

#Part a
#Text Exercise 6.10 a
#we can modify the number of loops to acheive different levels of accuracy
#in our case we achieved 10^-6 by setting the number of loops to 15
xa=1.0 #starting guess for x
numOfLoops = 15
for k in range(numOfLoops):
    xa = 1 - np.exp(-2*xa) #given equation

print("part a answer")
print("value of x with {} iterations:".format(numOfLoops), xa)
print("value of 1 - exp(-2*x) with {} iterations:".format(numOfLoops), 1 - np.exp(-2*xa))

#Text Exercise 6.10 b
#similar as above, we first reset the variables and instead of a constant c
#we generated a range of values from 0 to 300 with a stepsize of 0.01
x=1.0 #Starting guess for value of x
numOfLoops = 15
c = np.arange(0, 3, 0.01) #different values for c
for k in range(numOfLoops):
    x = 1 - np.exp(-c*x)

# plotting the results
fig, graph = plt.subplots()
graph.plot(c, x)
graph.set(xlabel="c", ylabel="x",
       title="Solutions of x for a range of c=(0, 3, 0.01) (Q3a)")
graph.grid()
fig.savefig("q3_A.png")
plt.show()

#Part b
#Text Exercise 6.11 b
def F(c):
    """
    This function uses the similar method as above and find the iterations
    when it approaches the convergence.
    """
    sigdig = 10 ** -6 #Define the accuracy (number of significant digits) we want the solution to be accurate to
    iterations = 1 #Starting value for iterations
    def f(x):
        return 1 - np.exp(-c*x)
    # Define our error function given in textbook
    # We need this so that when this value gets below the sigdigs we want it cuts off the iteration count
    def error(x1, x2):
        return (x1-x2)/(1 - 1/(c*np.exp(-c * x1)))

    x1 = 1.0 # starting value
    x2 = f(x1)
    #We need a condition so that when the error is greater than the value we want
    #It keeps running more iterations
    while(abs(error(x1, x2)) > sigdig):
        #This adds another Iteration
        x1, x2 = x2, f(x2)
        #This increases the iteration count tally
        iterations += 1
    print('The minimum number of iterations for an accuracy of 10**-6 = ', iterations)
    print("value of x:", x2)
    print("value of 1 - np.exp(-c*x)  is:", 1 - np.exp(-2*x2))

#Text Exercise 6.11 c
def F_over(c, w):
    """
    This function uses the over-relaxation method to increases the rate of
    convergence by artifically increasing the gradient of f(x)
    """
    sigdig = 10 ** -6
    iterations = 1
    def f(x):
        return 1 - np.exp(-c*x)

    def derivf(x):#This is the derivative of our function which we need for the over relax method
        return c * np.exp(-c*x)

    def error(x1, x2):# Error function for overrelaxation from text
        return (x1 - x2)/(1 - 1/((1 + w)*derivf(x1) - w))

    x1 = 1.0  # starting value
    x2 = (1 + w) * f(x1) - w * x1
    while abs(error(x1, x2)) > sigdig:
        #when the error is above the desired value, we do another iterations as before
        x1, x2 = x2, (1 + w) * f(x2) - w * x2
        #We then add 1 to the iteration count
        iterations += 1
    print('When we set omega to be ', w,'the minimum number of iterations for an accuracy of 10**-6 is ', iterations)
    print("value of x:", x2)
    print("value of 1 - exp(-2*x):", 1 - np.exp(-2*x2))

print()
print("part b answer")
F(2)
print()
F_over(2, 0.5)

#Part c
#reset the variables to desired accuracy and values
sigfig = 10 ** -6
a = 1
b = 2
def f(x, y):
    """
    the derived equation from 6.12(b)
    """
    return y*(a+x**2)

def g(x, y):
    """
    the derived equation from 6.12(b)
    """
    return b/(a+x**2)

def F(x,y):
    """
    the rewritten equation from 6.12(c)
    """
    return np.sqrt(b/y-a)

def G(x,y):
    """
    the rewritten equation from 6.12(c)
    """
    return x/(a+x**2)

def solution(f, g):
    """
    This function uses the similar method as above and find the iterations
    when it approaches the convergence.
    """
    iterations = 1
    def delta(x1, x2):
        return (x1 - x2) / x1
    x1 = 0.5
    y1 = 0.5
    x2 = f(x1, y1)
    y2 = g(x1, y1)
    #While the errors of x or y are higher than the desired value we need to do more iterations
    while abs(delta(x1, x2)) > sigfig and abs(delta(y1, y2)) > sigfig:
        #This allows our method to "Fail gracefully" as required
        if iterations > 1000:
            return 'error'

        x1, x2, y1, y2 = x2, f(x2, y2), y2, g(x2, y2)
        iterations += 1
    print('The number of iterations = ', iterations, 'the solution for x ~', x2, 'the solution for y ~', y2)
    return [ x2, y2 ]

print()
print("part c answer")
print(solution(F,G))


# We use the process of normalization to modify the values in the feature vector so that we can measure them on a common scale.
# In machine learning, we use many different forms of normalization.
# Some of the most common forms of normalization aim to modify the values so that they sum up to 1 . L1 normalization ,
# which refers to Least A bsolute Deviations , works by making sure that the sum of absolute values is 1 in each row. L2 normalization ,
# which refers to least squares, works by making sure that the sum of squares is 1 .
# In general, L1 normalization technique is considered more robust than L2 normalization technique.
# L1 normalization technique is robust because it is resistant to outliers in the data.
# A lot of times, data tends to contain outliers and we cannot do anything about it.
# We want to use techniques that can safely and effectively ignore them during the calculations.
# If we are solving a problem where outliers are important, then maybe L2 normalization becomes a better choice.

import numpy as np
from sklearn import preprocessing

input_data = np.array(
    [[5.1, -2.9, 3.3],
    [-1.2, 7.8, -6.1],
    [3.9, 0.4, 2.1],
    [7.3, -9.9, -4.5]]
)

# Normalize data
data_normalized_l1 = preprocessing.normalize(input_data, norm='l1')
data_normalized_l2 = preprocessing.normalize(input_data, norm='l2')
print("\nL1 normalized data:\n", data_normalized_l1)
print("\nL2 normalized data:\n", data_normalized_l2)