# -*- coding: utf-8 -*-
"""
Created on Wed Sep 23 11:20:19 2020

@author: Ruben Andre Barreiro
"""

# Import NumPy Python's Library
import numpy as np

# Import Matplotlib Python's Library
import matplotlib.pyplot as plt

# Load the Matrix with the Polynomial Data
mat = np.loadtxt('../files/polydata.csv',delimiter=';')

# Set the X values, from the Polynomial Data
x = mat[:,0]

# Set the Y values, from the Polynomial Data
y = mat[:,1]

# Set the Coefficients, of Degree 3
coefs_3 = np.polyfit(x,y,3)

# Set the Coefficients, of Degree 15
coefs_15 = np.polyfit(x,y,15)

# Set the Pixels, for the Linear Space
pxs = np.linspace(0,max(x),100)

# Fit a 3rd Degree Polynomial function
poly_3 = np.polyval(coefs_3,pxs)

# Fit a 15th Degree Polynomial function
poly_15 = np.polyval(coefs_15,pxs)

# Create a Figure for Plotting
plt.figure(figsize=(12, 8))

# Plot the points of the Polynomial data
plt.plot(x,y,'or')

# Plot the Fitted 3rd Degree Polynomial Function
plt.plot(pxs,poly_3,'-')

# Plot the Fitted 15th Degree Polynomial Function
plt.plot(pxs,poly_15,'-')

# Set the Axis for the Plotting Chart
plt.axis([0,max(x),-1.5,1.5])

# Set the Title for the Plotting Chart
#plt.title('Degree: 3')
#plt.title('Degree: 15')
plt.title('Degree: 3 and 15')

# Save a figure for the Plotting of the Polynomial data points
# NOTE: This needs to be done always after the plot function
#       and before the close function
#plt.savefig('../files/imgs/1.6-exercise-2-coef-3.png')
#plt.savefig('../files/imgs/1.6-exercise-2-coef-15.png')
plt.savefig('../files/imgs/1.6-exercise-2-coefs-3-and-15.png')

# Close the Figure for Plotting
plt.close()

# Print the Coefficients of the 3rd Degree Polynomial Function
print('\n')
print('The Coefficients of the 3rd Degree Polynomial Function:')
print(coefs_3)

# Print the Coefficients of the 15th Degree Polynomial Function
print('\n')
print('The Coefficients of the 15th Degree Polynomial Function:')
print(coefs_15)

# Exercise 1.6.1:
# Q: What is the hypothesis class you are using in each case
#    (degree 3 and degree 15)?
# A: Degree 3: A polynomial curve of degree 3
#    Degree 15: A polynomial curve of degree 15

# Exercise 1.6.2:
# Q: What is the corresponding model for each hypothesis class?
# A: Degree 3: y = θ_{1}x^{3} + θ_{2}x^{2} + θ_{3}x + θ_{4}
#    Degree 15: y = θ_{1}x^{15} + θ_{2}x^{14} + θ_{3}x^{13} + θ_{4}x^{12} +
#                 + θ_{5}x^{11} + θ_{6}x^{10} + θ_{7}x^{9} + θ_{8}x^{8} +
#                 + θ_{9}x^{7} + θ_{10}x^{6} + θ_{11}x^{5} + θ_{12}x^{4} +
#                 + θ_{13}x^{3} + θ_{14}x^{2} + θ_{15}x + θ_{16}

# Exercise 1.6.3:
# Q: What is the hypothesis in each case?
# A: Degree 3:  [ θ_{1} = 0.12831139 ; θ_{2} = -1.24583487 ;
#                 θ_{3} = 3.01638739 ; θ_{4} = -1.10432872 ]
#    Degree 15: [ θ_{1} = -1.16565156e-03 ; θ_{2} = 5.94797587e-02 ;
#                 θ_{3} = -1.39485584e+00 ; θ_{4} = 1.99433035e+01 ;
#                 θ_{5} = -1.94455094e+02 ; θ_{6} = 1.36991372e+03 ;
#                 θ_{7} = -7.20494944e+03 ; θ_{8} = 2.88096907e+04 ;
#                 θ_{9} = -8.82893589e+04 ; θ_{10} = 2.07259302e+05 ;
#                 θ_{11} = -3.69289141e+05 ; θ_{12} = 4.89713241e+05 ;
#                 θ_{13} = -4.66923307e+05 ; θ_{14} = 3.01463118e+05 ;
#                 θ_{15} = -1.17541384e+05 ; θ_{16} = 2.08092837e+04 ]

# Exercise 1.6.4:
# Q: How was each hypothesis chosen?
# A: Instantiating the parameters' vector (theta), representing the vector of
#    all theta_{1}; ... ; theta_{n} parameters.
#    The probability of the data given the hypothesis is
#    the likelihood of the hypothesis.
#    The best hypothesis is the one with the best (or maximum) likelihood
#    However, in some cases, increasing too much the degree of
#    a Polynomial Curve, can lead to not a good prediction of future values,
#    because the range of Polynomial Curve is very stricted to the data used
#    So, a good idea is to separate the global set in two subsets:
#    1) Training Set: The subset for training the Model;
#    2) Test Set: The subset for test the Model and predict the future values;


## 3. Bikesharing distribution ##

import pandas
bikes = pandas.read_csv("bike_rental_day.csv")
prob_over_5000 = bikes[bikes["cnt"] > 5000].shape[0] / bikes.shape[0]

## 4. Computing the distribution ##

import math

# Each item in this list represents one k, starting from 0 and going up to and including 30.
outcome_counts = list(range(31))
def find_probability(N, k, p, q):
    # Find the probability of any single combination.
    term_1 = p ** k
    term_2 = q ** (N-k)
    combo_prob = term_1 * term_2

    # Find the number of combinations.
    numerator = math.factorial(N)
    denominator = math.factorial(k) * math.factorial(N - k)
    combo_count = numerator / denominator

    return combo_prob * combo_count

outcome_probs = [find_probability(30, i, .39, .61) for i in outcome_counts]

## 5. Plotting the distribution ##

import matplotlib.pyplot as plt

# The most likely number of days is between 10 and 15.
plt.bar(outcome_counts, outcome_probs)
plt.show()

## 6. Simplifying the computation ##

import scipy
from scipy import linspace
from scipy.stats import binom

# Create a range of numbers from 0 to 30, with 31 elements (each number has one entry).
outcome_counts = linspace(0,30,31)
dist = binom.pmf(outcome_counts,30,0.39)
plt.bar(outcome_counts, dist)
plt.show()

## 8. Computing the mean of a probability distribution ##

dist_mean = None
dist_mean = 30 * .39

## 9. Computing the standard deviation ##

dist_stdev = None
dist_stdev = (30*0.39*0.61)** (1/2)

## 10. A different plot ##

# Enter your answer here.
import scipy
from scipy import linspace
from scipy.stats import binom
outcome_counts = linspace(0,10,11)
dist = binom.pmf(outcome_counts,10,0.39)
plt.bar(outcome_counts,dist)
plt.show()
outcome_counts = linspace(0,100,101)
dist = binom.pmf(outcome_counts,100,0.39)
plt.bar(outcome_counts,dist)
plt.show()

## 11. The normal distribution ##

# Create a range of numbers from 0 to 100, with 101 elements (each number has one entry).
outcome_counts = scipy.linspace(0,100,101)

# Create a probability mass function along the outcome_counts.
outcome_probs = binom.pmf(outcome_counts,100,0.39)

# Plot a line, not a bar chart.
plt.plot(outcome_counts, outcome_probs)
plt.show()

## 12. Cumulative density function ##

outcome_counts = linspace(0,30,31)
outcome_probs = binom.cdf(outcome_counts,30,0.39)
plt.plot(outcome_counts, outcome_probs)
plt.show()

## 14. Faster way to calculate likelihood ##

left_16 = None
right_16 = None

left_16 = binom.cdf(16,30,0.39)
right_16 = 1 - left_16

Probability Statistics Intermediate/Probability distributions-135.py


import numpy as np

class linearSys:
    def __init__(self, A, b):
        self.A = A
        self.b = b
        self.n = A.shape[0]
        self.L = np.eye(self.n)
        self.U = np.eye(self.n)
        self.x = np.zeros([self.n, 1])
        self.y = np.zeros([self.n, 1])

    def LU_Decompose(self):
        if self.A[0, 0] != 0:
            self.L[0, 0] = self.A[0, 0]
            self.U[0, 1:] = self.A[0, 1:] / self.L[0, 0]
            self.L[1:, 0] = self.A[1:, 0] / self.U[0, 0]
            for i in range(1, self.n - 1):
                self.L[i, i] = self.A[i, i] - np.dot(self.L[i, 0:i], self.U[0:i, i])
                if self.L[i, i] != 0:
                    self.U[i, i+1:] = (self.A[i, i+1:] - np.dot(self.L[i, 0:i], self.U[0:i, i+1:])) / self.L[i, i]
                    self.L[i+1:, i] = (self.A[i+1:, i] - np.dot(self.L[i+1:, 0:i], self.U[0:i, i])) / self.U[i, i]
                else:
                    return 'Factorization impossible at l{0}{0}'.format(i+1)

            self.L[-1, -1] = self.A[-1, -1] - np.dot(self.L[-1, 0:-1], self.U[0:-1, -1])
            if self.L[-1, -1] == 0:
                print('A is singular')

            self.y[0] = self.b[0] / self.L[0, 0]
            for i in range(1, self.n):
                self.y[i, 0] = (self.b[i] - np.dot(self.L[i, 0:i], self.y[0:i, 0])) / self.L[i, i]

            self.x[-1] = self.y[-1] / self.U[-1, -1]
            for i in range(self.n - 2, -1, -1):
                self.x[i, 0] = (self.y[i, 0] - np.dot(self.U[i, i+1:], self.x[i+1:, 0])) / self.U[i, i]

            return self.x, self.L, self.U
        else:
            return 'Factorization impossible at a11'

    def LLt_Decompose(self):
        self.L[0, 0] = np.sqrt(self.A[0, 0])
        self.L[1:, 0] = self.A[1:, 0] / self.L[0, 0]
        for i in range(1, self.n - 1):
            self.L[i, i] = np.sqrt(self.A[i, i] - np.sum(self.L[i, 0:i] ** 2))
            self.L[i+1:, i] = (self.A[i+1:, i] - np.sum(self.L[i+1:, 0:i] * self.L[i, 0:i], axis=1)) / self.L[i, i]
        self.L[-1, -1] = np.sqrt(self.A[-1, -1] - np.sum(self.L[-1, 0:-1] ** 2))
        self.y[0] = self.b[0] / self.L[0, 0]
        for i in range(1, self.n):
            self.y[i, 0] = (self.b[i] - np.dot(self.L[i, 0:i], self.y[0:i, 0])) / self.L[i, i]

        self.x[-1] = self.y[-1] / self.L[-1, -1]
        for i in range(self.n - 2, -1, -1):
            self.x[i, 0] = (self.y[i, 0] - np.dot(self.L[i+1:, i], self.x[i+1:, 0])) / self.L[i, i]

        return self.x

def array2latex(arr):
    s = ''
    for k in range(len(arr)):
        row = arr[k]
        if k < len(arr) - 1:
            s += ' & '.join(map(str, row)) + ' \\\\\n'
        else:
            s += ' & '.join(map(str, row))
    return s

if __name__ == '__main__':
    # A = np.array([[1,1,0,3], [2,1,-1,1], [3,-1,-1,2], [-1,2,3,-1]])
    # b = np.array([1, 1, -3, 4])
    A = np.array([[1,1,0,3], [2,1,-1,1], [3,-1,-1,2], [-1,2,3,-1]])
    b = np.array([8, 7, 14, -7])
    sol = linearSys(A, b)
    try:
        # x, L, U = sol.LU_Decompose()
        x, L, U = sol.LLt_Decompose()
        print('Solution:', x.T)
        print('L=\n', array2latex(L))
        print('U=\n', array2latex(U))
    except ValueError:
        print(sol.LU_Decompose())


from typing import Optional

import numpy as np

from mygrad import Tensor
from mygrad.operation_base import Operation
from mygrad.typing import ArrayLike, Real

__all__ = ["selu"]

_ALPHA = 1.6732632423543772848170429916717
_SCALE = 1.0507009873554804934193349852946

class SELU(Operation):
    """Returns the scaled exponential linear activation (SELU) elementwise along x. The SELU is
    given by  λɑ(exp(x) - 1) for x < 0 and λx for x ≥ 0.

    Notes
    -----
    The SELU activation was proposed in the paper
        Self-Normalizing Neural Networks
        Günter Klambauer, Thomas Unterthiner, Andreas Mayr, Sepp Hochreiter
    at https://arxiv.org/abs/1706.02515
    """

    def __call__(self, x):
        """
        Parameters
        ----------
        x : mygrad.Tensor
            Input data.

        Returns
        -------
        numpy.ndarray
            The SELU function applied to `x` elementwise.
        """
        self.variables = (x,)

        x = x.data
        self.exp = _ALPHA * (np.exp(x) - 1)
        return _SCALE * np.where(x < 0, self.exp, x)

    def backward_var(self, grad, index, **kwargs):
        x = self.variables[index]
        return grad * _SCALE * np.where(x.data < 0, self.exp + _ALPHA, 1)

def selu(x: ArrayLike, *, constant: Optional[bool] = None) -> Tensor:
    """Returns the scaled exponential linear activation (SELU) elementwise along x.

    The SELU is given by  λɑ(exp(x) - 1) for x < 0 and λx for x ≥ 0.

    Parameters
    ----------
    x : ArrayLike
        Input data.

    constant : Optional[bool]
        If ``True``, the returned tensor is a constant (it
        does not back-propagate a gradient)

    Returns
    -------
    mygrad.Tensor
        The SELU function applied to `x` elementwise.

    References
    ----------
    .. [1] Günter Klambauer, Thomas Unterthiner, Andreas Mayr, Sepp Hochreiter
       Self-Normalizing Neural Networks
       https://arxiv.org/abs/1706.02515

    Examples
    --------
    >>> import mygrad as mg
    >>> from mygrad.nnet.activations import selu
    >>> x = mg.arange(-5, 6)
    >>> x
    Tensor([-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5])
    >>> y = selu(x, alpha=0.1); y
    Tensor([-1.74625336, -1.72589863, -1.67056873, -1.52016647, -1.11133074,
         0.        ,  1.05070099,  2.10140197,  3.15210296,  4.20280395,
         5.25350494])

    .. plot::

       >>> import mygrad as mg
       >>> from mygrad.nnet.activations import selu
       >>> import matplotlib.pyplot as plt
       >>> x = mg.linspace(-2, 2, 100)
       >>> y = selu(x)
       >>> plt.title("selu(x)")
       >>> y.backward()
       >>> plt.plot(x, x.grad, label="df/dx")
       >>> plt.plot(x, y, label="f(x)")
       >>> plt.legend()
       >>> plt.grid()
       >>> plt.show()
    """
    return Tensor._op(SELU, x, constant=constant)


import numpy as np
import ast
import json
def jacobi(A, b, x, norm, tol, iteMax):
    A = ast.literal_eval(A)
    b = ast.literal_eval(b)
    x = ast.literal_eval(x)
    result = {}
    iters = []
    D = np.diag(np.diag(A))
    L = (-1 * np.tril(A))+D
    U = (-1 * np.triu(A))+D
    if(0 in np.diag(A)): return {"status" : "diagonal has 0", "error" : True}
    ite = 0
    #Change here for Jacobi, Sor and Gauss seidel
    T = np.dot(np.linalg.inv(D), (L+U))
    C = np.dot(np.linalg.inv(D),b)
    #End changes
    spectRad = np.max(np.absolute(np.linalg.eigvals(T)))
    if(spectRad > 1): return {"status" : "spectral radious > 1", "error" : True}
    #Saving into result dict
    result['tmatrix'] = json.dumps(T.tolist())
    result['cmatrix'] = json.dumps(C.tolist())
    result['spectrad'] = spectRad

    iters.append({ "iter" : ite, "E" : "n/a", "x" : x})
    #End savings
    while(norm > tol and ite < iteMax):
        xold = x
        x = np.dot(T,xold)+C
        norm = np.linalg.norm(xold-x)
        ite += 1
        #Saving into iters
        iters.append({ "iter" : ite,  "E" : float(norm),  "x" : x.tolist()})
        #End saving
    result['iters'] = iters
    result['error'] = False
    return result


import numpy as np
import settings as globalv

def centerData(data):
	print('\nCentering data...')
	mean_vector = np.mean(data, axis = 1).reshape(data.shape[0], 1)
	centered_data = data - mean_vector

	if (globalv.print_results):
		print('Mean vector: \n', mean_vector)
		print('Centered data: \n', centered_data)
	return centered_data, mean_vector

def correlationMatrix(centered_data):
	print('\nComputing correlation matrix...')
	D = globalv.D
	N = globalv.N

	correlation_matrix = np.zeros((D, D))
	for i in range(N):
		correlation_matrix += (centered_data[:,i].reshape(D,1)).dot(centered_data[:,i].reshape(D,1).T)
	correlation_matrix = correlation_matrix/N

	if (globalv.print_results):
		print(correlation_matrix)

	return correlation_matrix

def eigenDecomposition(corr):
	print('\nEigendecomposition of correlation matrix...')
	D = globalv.D
	N = globalv.N

	eigvals, eigvecs = np.linalg.eig(corr)

	for i in range(len(eigvals)):
		eigv = eigvecs[:,i].reshape(1,D).T
		np.testing.assert_array_almost_equal(corr.dot(eigv), eigvals[i] * eigv, decimal=6, err_msg='', verbose=True)

	if (globalv.print_results):
		print('Eigenvalues: \n', eigvals)
		print('Eigenvectors: \n', eigvecs)

	return eigvals, eigvecs

def readUserNumComponents(msg):
	D = globalv.D
	N = globalv.N

	# numComponents = raw_input(msg)
	numComponents = 4
	# try:
		# Try to convert the user input to an integer
	    # numComponents = int(numComponents)
		# if numComponents > D or numComponents < 0:
		# 	print 'Invalid number of components'
		# 	sys.exit(-3)
	# except ValueError:
	# 	Catch the exception if the input was not a number
		# numComponents = 1
	# print 'Using %d components' %numComponents
	return numComponents

def computeProjectionMatrix(eigvals, eigvecs, r):
	print('\nComputing the projection matrix...')
	D = globalv.D
	N = globalv.N

	# List of (eigenvalue, eigenvector) tuples
	eig_pairs = [(np.abs(eigvals[i]), eigvecs[:,i]) for i in range(len(eigvals))]

	# Sort the (eigenvalue, eigenvector) tuples from high to low (reverse=True)
	eig_pairs.sort(key=lambda tup: tup[0], reverse=True)

	# Projection matrix
	proj_matrix = np.zeros((D,r))
	for i in range(r):
		proj_matrix[:,i] = eig_pairs[i][1].reshape(1, D)

	if (globalv.print_results):
		print('Projection matrix: \n', proj_matrix)

	return proj_matrix

def computePrincipalComponents(centered_data, proj_matrix):
	print('\nComputing principal components...')
	p = (proj_matrix.T).dot(centered_data)

	if (globalv.print_results):
		print('Principal components: \n', p)

	return p

def reconstructData(princ_comps, proj_matrix, mean_vector):
	print('\nReconstructing the data...')
	reconstructed_data = (proj_matrix).dot(princ_comps) + mean_vector

	if (globalv.print_results):
		print('Reconstructed data: \n', reconstructed_data)

	return reconstructed_data

def computeRecError(data, reconstructed_data):
	print('\nComputing reconstruction error...')
	D = globalv.D
	N = globalv.N

	error = data - reconstructed_data
	error_var = 0
	for i in range(N):
		error_var += np.linalg.norm(error[:, i])**2
	error_var = error_var/N

	if (globalv.print_results):
		print('Error: \n', error)
	print('Error variance: ', error_var)

	return error


import numpy as np
import matplotlib.pyplot as plt

def cities_on_circle(r: float, n_cities: int):
    pi = np.pi
    xy = np.zeros((n_cities, 2))
    x = np.linspace(0, 2 * pi, n_cities + 1)
    x = x[0:n_cities]

    xy[:, 0] = np.cos(x) * r
    xy[:, 1] = np.sin(x) * r
    return xy

def cities_on_line(n_cities: int) -> np.ndarray:
    xy = np.zeros((n_cities, 2))
    xy[:, 0] = np.linspace(0, 1, n_cities)
    return xy

def cities_random(n_cities: int) -> np.ndarray:
    xy = np.random.rand(n_cities, 2)
    return xy

def gen_distance_lookup(xy: np.ndarray) -> dict:
    dist = {}
    for idx1 in range(xy.shape[0]):
        x1 = xy[idx1][0]
        y1 = xy[idx1][1]
        dist[idx1] = {}
        for idx2 in range(xy.shape[0]):
            x2 = xy[idx2][0]
            y2 = xy[idx2][1]
            d = np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
            dist[idx1][idx2] = d
    return dist

class CityFactory:
    @staticmethod
    def custom(xy: np.ndarray) -> dict:
        dist = gen_distance_lookup(xy)
        cities = {'xy': xy, 'dist': dist}
        return cities

    @staticmethod
    def line(n_cities: int) -> dict:
        xy = cities_on_line(n_cities)
        dist = gen_distance_lookup(xy)
        cities = {'xy': xy, 'dist': dist}
        return cities

    @staticmethod
    def circle(r: float, n_cities: int) -> dict:
        xy = cities_on_circle(r=r, n_cities=n_cities)
        dist = gen_distance_lookup(xy)
        cities = {'xy': xy, 'dist': dist}
        return cities

    @staticmethod
    def random(n_cities: int, seed=0) -> dict:
        np.random.seed(seed)
        xy = cities_random(n_cities)
        dist = gen_distance_lookup(xy)
        cities = {'xy': xy, 'dist': dist}
        return cities

def get_cities_labels(n_cities) -> list:
    """generate labels to differentiate cities on the plot"""
    city_labels = ['{0}'.format(i) for i in range(n_cities)]
    return city_labels

def plot_cities(xy, route_labels=None, show_labels=False):
    colors = (0, 0, 0)
    area = 10
    plt.scatter(xy[:, 0], xy[:, 1], s=area, c=colors, alpha=0.5)
    plt.title('Cities')

    if show_labels:
        for label, x, y in zip(route_labels, xy[:, 0], xy[:, 1]):
            plt.annotate(
                label,
                xy=(x, y), xytext=(-20, 20),
                textcoords='offset points', ha='right', va='bottom',
                bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5),
                arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0'))
    plt.xlabel('x')
    plt.ylabel('y')
    plt.show()


import numpy as np
import matplotlib.pyplot as plt

def least_square_algorithm(t, y, n):
    """ Least square algorithm

    Args:
        t: list/ndarray, the list of points
        y: list/ndarray, the list of function value
        n: int, the order of the fitting curve

    Returns:
        c: ndarray, the cofficients of the fitting curve
    """
    # the number of the points
    leng = len(t)
    # the cofficient matrix
    A = np.ones(leng)
    for i in range(n):
        A = np.c_[A, t**(i+1)]
    # the solution of the normal equations
    c = np.linalg.solve(A.T.dot(A), A.T.dot(y))

    return c

def calculate_square_error(y, func):
    """ Calculate the square error

    Args:
        y: ndarray, the list of prediction value
        func: ndarray, the list of original value

    Returns:
        sq_err: double, the square error
    """
    return np.sum(np.square(y - func))

def draw_curve(x, y, func, file_name):
    """ Draw the fitting curve

    Args:
        x: ndarray, the data of independent variable
        y: ndarray, the original value
        func: ndarray, the prediction function
        file_name: string, the name of the saved figure file

    """
    fig = plt.figure(figsize=(6, 6))
    plt.plot(x, y, 'ro', label='data set')
    t = np.arange(x[0], x[-1], 0.1)
    plt.plot(t, func(t), 'g-', label='fitting curve')
    plt.title('Least Square Algorithm')
    plt.legend()
    plt.savefig(file_name)

def linear_fitting():
    """ Fitting experiment 1

    """
    # data
    x = np.array([1, 2, 3, 4, 5])
    y = np.array([4, 4.5, 6, 8, 8.5])
    # get the cofficients
    a, b = least_square_algorithm(x, y, 1)
    # define the fitting curve using the cofficients
    f = lambda x: a + b * x
    # get the square error
    print(f"The linear fitting's square error is {calculate_square_error(f(x), y)}")
    # visualization
    draw_curve(x, y, f, 'linear_fitting.png')

def non_linear_fitting():
    """ two order polinomial fitting

    """
    # data
    x = np.array([2, 3, 4, 7, 8, 10, 11, 14, 16, 18, 19])
    y = np.array([106.42, 108.2, 109.5, 110, 109.93, 110.49, 110.59, 110.6, 110.76, 111, 111.2])
    # get the cofficients
    a, b, c = least_square_algorithm(x, y, 2)
    # define the fitting curve
    f = lambda x: a + b * x + c * x**2
    # get the square error
    print(f"The 2-order polinomial fitting's square error is {calculate_square_error(f(x), y)}")
    # visualization
    draw_curve(x, y, f, 'polinomial_fitting.png')

    """ exponential fitting

    """
    # data preprocessing
    t = 1 / x
    z = np.log(y)
    # get the cofficients
    a0, b0 = least_square_algorithm(t, z, 1)
    a1, b1 = np.exp(a0), b0
    # define the fitting curve
    g = lambda x: a1 * np.exp(b1 / x)
    print(f"The exponential fitting's square error is {calculate_square_error(g(x), y)}")
    # visualization
    draw_curve(x, y, g, 'exponential_fitting.png')

if __name__ == '__main__':
    linear_fitting()
    non_linear_fitting()


#!/usr/bin/env python
"""Module providing functionality surrounding gaussian function.
"""
SVN_REVISION = '$LastChangedRevision: 16541 $'

import sys
import numpy

def gaussian2(size, sigma):
    """Returns a normalized circularly symmetric 2D gauss kernel array

    f(x,y) = A.e^{-(x^2/2*sigma^2 + y^2/2*sigma^2)} where

    A = 1/(2*pi*sigma^2)

    as define by Wolfram Mathworld
    http://mathworld.wolfram.com/GaussianFunction.html
    """
    A = 1/(2.0*numpy.pi*sigma**2)
    x, y = numpy.mgrid[-size//2 + 1:size//2 + 1, -size//2 + 1:size//2 + 1]
    g = A*numpy.exp(-((x**2/(2.0*sigma**2))+(y**2/(2.0*sigma**2))))
    return g

def fspecial_gauss(size, sigma):
    """Function to mimic the 'fspecial' gaussian MATLAB function
    """
    x, y = numpy.mgrid[-size//2 + 1:size//2 + 1, -size//2 + 1:size//2 + 1]
    g = numpy.exp(-((x**2 + y**2)/(2.0*sigma**2)))
    return g/g.sum()

def main():
    """Show simple use cases for functionality provided by this module."""
    from mpl_toolkits.mplot3d.axes3d import Axes3D
    import pylab
    argv = sys.argv
    if len(argv) != 3:
        print >>sys.stderr, 'usage: python -m pim.sp.gauss size sigma'
        sys.exit(2)
    size = int(argv[1])
    sigma = float(argv[2])
    x, y = numpy.mgrid[-size//2 + 1:size//2 + 1, -size//2 + 1:size//2 + 1]

    fig = pylab.figure()
    fig.suptitle('Some 2-D Gauss Functions')
    ax = fig.add_subplot(2, 1, 1, projection='3d')
    ax.plot_surface(x, y, fspecial_gauss(size, sigma), rstride=1, cstride=1,
                    linewidth=0, antialiased=False, cmap=pylab.jet())
    ax = fig.add_subplot(2, 1, 2, projection='3d')
    ax.plot_surface(x, y, gaussian2(size, sigma), rstride=1, cstride=1,
                    linewidth=0, antialiased=False, cmap=pylab.jet())
    pylab.show()
    return 0

if __name__ == '__main__':
    sys.exit(main())


# Project Euler Problem 5 Solution
#
# Problem statement:
# 2520 is the smallest number that can be divided by each of
# the numbers from 1 to 10 without any remainder.
# What is the smallest positive number that is evenly divisible
# by all of the numbers from 1 to 20?
#
# Solution description:
# This script is a brute-force solution of the above problem,
# followed by a faster solution exploiting prime number factorization.
#
# Author: Daniel Schuette, Philipp Schuette
# Date: 2019/02/09
# License: MIT (see ../LICENSE.md)
import time

import numpy as np

def evenly_divisible(limit):
    """
    Doc string
    """
    current_num = limit  # represents the currently tested number
    divisible = True  # whether `current_num' is still divisible

    while True:
        for divisor in range(1, limit+1):
            if not (current_num % divisor) == 0:
                divisible = False
                break  # break out of for loop

        if not divisible:
            current_num += limit
            divisible = True
        else:
            return current_num

def check_prime(x):
    """
    checks, whether or not x is a prime number
    """
    prime = True
    for i in range(2, x):
        if (x % i) == 0:
            prime = False
            break
    return prime

def prime_list(n):
    """
    outputs a list of all prime numbers between 1 and n > 1
    """
    prime_list = []
    for i in range(2, n + 1):
        if check_prime(i):
            prime_list.append(i)
    return prime_list

def lcm(n):
    """
    outputs the least common multiple for the numbers from 1 to 20
    """
    primes = prime_list(n)
    lcm = 1
    for p in primes:
        e_p = 1
        while pow(p, e_p + 1) <= n:
            e_p += 1
        lcm *= pow(p, e_p)
    return lcm

if __name__ == "__main__":
    # calculate the solution with the 'slow' variant
    start1 = time.time()
    solution1 = evenly_divisible(20)
    end1 = time.time()
    # calculate the solution with the 'fast' variant
    start2 = time.time()
    solution2 = lcm(30)
    end2 = time.time()

    # print both solutions
    print("slow solution expired: {}s, solution: {}".format(
        np.round(end1 - start1, 5), solution1))
    print("fast solution expired: {}s, solution {}". format(
        np.round(end2 - start2, 5), solution2))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Oct  7 10:11:19 2019

@author: amandaash
"""

import numpy as np
import scipy.optimize as opt
import matplotlib.pyplot as plt

E_b = np.arange(0,10,0.001)
f_Eb = (((10-E_b)**(0.5))*np.tan((10-E_b)**(0.5))) - E_b**(0.5)

plt.plot(E_b, f_Eb)
plt.ylim(-10,10)
plt.grid()
plt.axvline(x = 8.592785275230653, color = 'k', linestyle = 'dashed')
#plt.yscale('log')
plt.savefig('binding_func_10_even.pdf')
plt.show()

def binding_energy(Eb):
    f = (((10-Eb)**(0.5))*np.tan((10-Eb)**(0.5))) - Eb**(0.5)
    return f

E_b_bisect = opt.bisect(binding_energy,8,9.5)

E_b_newton = opt.newton(binding_energy, 8.5)

E_b_brents = opt.brentq(binding_energy, 8.5, 9.5)

print('root even function: bisection method = {0}, precision = {1}'.format(E_b_bisect, binding_energy(E_b_bisect)))
print('root even function: Newton method = {0}, precision = {1}'.format(E_b_newton, binding_energy(E_b_newton)))
print('root even function: brents method = {0}, precision = {1}'.format(E_b_brents, binding_energy(E_b_brents)))
def binding_energy_beta(Eb):
    f = (np.sqrt(Eb)*(np.tan(np.sqrt(10-Eb))**-1))-np.sqrt(10-Eb)
    return(f)

energies = np.arange(0,10,0.001)
fE = binding_energy_beta(energies)

plt.plot(energies, fE)
plt.ylim(-20,10)
plt.axvline(x = 8.592785275230653, color = 'k', linestyle = 'dashed')
plt.grid()
plt.savefig('binding_func_10_odd.pdf')
plt.show()

Eb_bisect_beta = opt.bisect(binding_energy_beta,8,9.5)
print("root odd function: bisection method = {0}".format(Eb_bisect_beta))
E_b_newton_beta = opt.newton(binding_energy_beta, 8.5)
print("root odd function: Newton method = {0}".format(E_b_newton_beta))

def binding_energy_gamma(E, A):
    f = (((A-E)**(0.5))*np.tan((A-E)**(0.5))) - E**(0.5)
    return f

energy_gamma1 = np.arange(0,10,0.001)
energy_gamma2 = np.arange(0,20,0.001)
energy_gamma3 = np.arange(0,30,0.001)

plt.plot(energy_gamma1, binding_energy_gamma(energy_gamma1, 10))
plt.ylim(-10,10)
plt.grid()
plt.show()
plt.title('Binding energy = 20')
plt.plot(energy_gamma2, binding_energy_gamma(energy_gamma2, 20))
plt.ylim(-20,20)
plt.grid()
plt.savefig('binding_func_20_even.pdf')
plt.show()
def binding_energy_gamma20(E):
    f = (((20-E)**(0.5))*np.tan((20-E)**(0.5))) - E**(0.5)
    return f
Eb_bisect_gamma20_root1 = opt.bisect(binding_energy_gamma20,5,7.5)
Eb_bisect_gamma20_root2 = opt.bisect(binding_energy_gamma20,17.7,19)

print(Eb_bisect_gamma20_root1, binding_energy_gamma20(Eb_bisect_gamma20_root1))
print(Eb_bisect_gamma20_root2, binding_energy_gamma20(Eb_bisect_gamma20_root2))
plt.title('Binding energy = 30')
plt.plot(energy_gamma3, binding_energy_gamma(energy_gamma3, 30))
plt.ylim(-30,30)
plt.grid()
plt.savefig('binding_func_30_even.pdf')
plt.show()
def binding_energy_gamma30(E):
    f = (((30-E)**(0.5))*np.tan((30-E)**(0.5))) - E**(0.5)
    return f
Eb_bisect_gamma30_root1 = opt.bisect(binding_energy_gamma30,14,16)
Eb_bisect_gamma30_root2 = opt.bisect(binding_energy_gamma30,28,29.5)

print(Eb_bisect_gamma30_root1, binding_energy_gamma30(Eb_bisect_gamma30_root1))
print(Eb_bisect_gamma30_root2, binding_energy_gamma30(Eb_bisect_gamma30_root2))


from helper import load_times, str_time_to_num_time

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

# Load in 5k times and VDOT scores
df = load_times()
df = df[['VDOT', '5k']]
df['5k Time'] = df['5k'].apply(lambda x: str_time_to_num_time(x))

# Create a plot of 5k times against VDOT
df.plot(y='VDOT',
        x='5k Time',
        kind='scatter',
        grid=True,
        title='5k Times Against VDOT')
plt.xticks(ticks=[900, 1200, 1500, 1800],
           labels=['15:00', '20:00', '25:00', '30:00'])
plt.savefig('../generated-notes/5k-models/regular-plot.png')

####################
# We will create a linear regression model and plot results

# Plot a linear regression
model = LinearRegression().fit(df[['5k Time']], df['VDOT'])
print(model.coef_)
print(model.intercept_)
print(model.score(df[['5k Time']], df['VDOT']))

# Get presumed VDOTs from model
plot_space = np.linspace(700, 1900, num=50)
vdots = model.intercept_ + (plot_space * model.coef_[0])

# Plot true, and model predictions
df.plot(y='VDOT',
        x='5k Time',
        kind='scatter',
        grid=True,
        title='5k Times Against VDOT (with Linear Regression Model)')
plt.xticks(ticks=[900, 1200, 1500, 1800],
           labels=['15:00', '20:00', '25:00', '30:00'])
plt.plot(plot_space, vdots)
plt.savefig('../generated-notes/5k-models/linear-plot.png')

####################
# We will create multiple regression models and plot results

# Create multiple regression models
df['5k_1'] = df['5k Time']
df['5k_2'] = df['5k_1'] * df['5k_1']
df['5k_3'] = df['5k_2'] * df['5k_1']
df['5k_4'] = df['5k_3'] * df['5k_1']
model_1 = LinearRegression().fit(df[['5k_1']], df['VDOT'])
model_2 = LinearRegression().fit(df[['5k_1', '5k_2']], df['VDOT'])
model_3 = LinearRegression().fit(df[['5k_1', '5k_2', '5k_3']], df['VDOT'])
model_4 = LinearRegression().fit(df[['5k_1', '5k_2', '5k_3', '5k_4']], df['VDOT'])

# Get model predictions
plot_space = np.linspace(700, 1900, num=50)
vdots_1 = model_1.intercept_ + (plot_space * model_1.coef_[0])
vdots_2 = model_2.intercept_ + (plot_space * model_2.coef_[0]) + ((plot_space**2)*model_2.coef_[1])
vdots_3 = model_3.intercept_ + (plot_space * model_3.coef_[0]) + ((plot_space**2)*model_3.coef_[1]) + ((plot_space**3)*model_3.coef_[2])
vdots_4 = model_4.intercept_ + (plot_space * model_4.coef_[0]) + ((plot_space**2)*model_4.coef_[1]) + ((plot_space**3)*model_4.coef_[2]) + ((plot_space**4)*model_4.coef_[3])

# Plot true, and model predictions
df.plot(y='VDOT',
        x='5k Time',
        kind='scatter',
        grid=True,
        title='5k Times Against VDOT (with Multiple Regression Models)')
plt.xticks(ticks=[900, 1200, 1500, 1800],
           labels=['15:00', '20:00', '25:00', '30:00'])
plt.plot(plot_space, vdots_1, label='Power 1')
plt.plot(plot_space, vdots_2, label='Power 2')
plt.plot(plot_space, vdots_3, label='Power 3')
plt.plot(plot_space, vdots_4, label='Power 4')
plt.legend()
plt.savefig('../generated-notes/5k-models/multi-plot.png')

# Output scores for each model
print()
print('Model 1:', model_1.score(df[['5k_1']], df['VDOT']))
print('Model 2:', model_2.score(df[['5k_1', '5k_2']], df['VDOT']))
print('Model 3:', model_3.score(df[['5k_1', '5k_2', '5k_3']], df['VDOT']))
print('Model 4:', model_4.score(df[['5k_1', '5k_2', '5k_3', '5k_4']], df['VDOT']))

# Print coefs and intercept for model 4
print()
print('Model 4')
print('Coefs:    ', model_4.coef_)
print('Intercept:', model_4.intercept_)

####################
# These are helper functions created from the power 4 model

def fivek_time_to_vdot(time):
    c = 320.21840994212795
    m = [-5.85338453e-01,4.99386989e-04,-2.05665011e-07,3.29250289e-11]

    secs = str_time_to_num_time(time)
    vdot = c + (secs*m[0]) + ((secs**2)*m[1]) + ((secs**3)*m[2]) + ((secs**4)*m[3])
    return vdot

print()
print('20:00 to ', fivek_time_to_vdot('20:00'))
print('22:00 to ', fivek_time_to_vdot('22:00'))
print('24:00 to ', fivek_time_to_vdot('24:00'))
print('26:00 to ', fivek_time_to_vdot('26:00'))


import numpy as np
import pymc3
from scipy.stats import binom, beta

#3M1
grid = np.linspace(0.0, 1.0, 1000)
prior = np.ones(1000)

likelihood = binom.pmf(8, 15, p=grid)

posterior = likelihood * prior
posterior /= np.sum(posterior)

#3M2
np.random.seed(100)
samples = np.random.choice(grid, size=10000, replace=True, p=posterior)

print('2')
print(pymc3.stats.hpd(samples, 0.9))

#3M3
dummyData = binom.rvs(15, samples, size=samples.shape[0])
print('\n3')
print(np.mean(dummyData == 8))

#3M4
dummyData = binom.rvs(9, samples, size=samples.shape[0])
print('\n4')
print(np.mean(dummyData == 6))

#3M5
prior[grid < 0.5] = 0

posterior = likelihood * prior
posterior /= np.sum(posterior)

samples = np.random.choice(grid, size=10000, replace=True, p=posterior)
print('\n5')
print(pymc3.stats.hpd(samples, 0.9))

dummyData = binom.rvs(15, samples, size=samples.shape[0])
print(np.mean(dummyData == 8))

dummyData = binom.rvs(9, samples, size=samples.shape[0])
print(np.mean(dummyData == 6))

#3M6

N = 2500
s = int(np.round(8 * N / 15))
likelihood = binom.pmf(s, N, p=grid)

posterior = likelihood * prior
posterior /= np.sum(posterior)

samples = np.random.choice(grid, size=10000, replace=True, p=posterior)

interval = pymc3.stats.hpd(samples, 0.99)
print('\n6')
print('%d: %f' % (N, interval[1] - interval[0]))


from pylab import *
from scipy.integrate import quad;
from scipy.interpolate import interp1d

close('all')

# PDF of the standard normal distribution.
p = lambda t : exp(-t**2/2.0)/sqrt(2*pi);
# CDF of the standard normal distribution.
F = lambda x : (quad(p,-inf,x))[0];

# Take discrete points (x,F(x))
Ns = 40;
x = linspace(-7,7,Ns);
y = zeros(Ns)
for i in xrange(Ns):
	y[i] = F(x[i]);

plot(x,y,'r*')

# Interpolate F
Fint = interp1d(x,y);

plot(x,Fint(x),'g--')
legend(['(x,F(x))','Interpolation'],loc=0);

figure()

Finv = interp1d(y,x);
plot(x,Finv(Fint(x)),'b--',x,x,'r*-')
legend(['Finv(Fint(x))','y=x'],loc=0)

# Now let's sample from F!

# First, we need N samples from U[0,1]
N = 1e+6;
u = rand(N)

# Now, we need to calculate Finv(u), which will
# gives us the samples we want.
x = Finv(u);

print "Mean of samples : ", mean(x)
print "Variance of samples :", var(x)

# Let's make a histogram of what we got.

figure()
hist(x,normed=True)

# We need to compare with samples from the Standard Normal distribution.
un = randn(N);
hist(un,normed=True,color='red',alpha=0.6)

legend(['Samples with our method','"Real" samples'],loc=0)

show()


# coding: utf-8

# ## Exercises
#
# This will be a notebook for you to work through the exercises during the workshop. Feel free to work on these at whatever pace you feel works for you, but I encourage you to work together! Edit the title of this notebook with your name because I will ask you to upload your final notebook to our shared github repository at the end of this workshop.
#
# Feel free to google the documentation for numpy, matplotlib, etc.
#
# Don't forget to start by importing any libraries you need.

# In[2]:

# import your libraries here
import numpy as np
import pylab as plt

# ### Day 1
#
# #### Exercise 1
#
#    A. Create an array with 10 evenly spaced values in logspace ranging from 0.1 to 10,000.
#
#    B. Print the following values: The first value in the array, the final value in the array, and the range of 5th-8th values.
#
#    C. Append the numbers 10,001 and 10,002 (as floats) to the array. Make sure you define this!
#
#    D. Divide your new array by 2.
#
#    E. Reshape your array to be 3 x 4.
#
#    F. Multiply your array by itself.
#
#    G.  Print out the number of dimensions and the maximum value.

# In[5]:

# your solution here

print('A')
log_arr = np.logspace(-1, 4, 10)
print(log_arr)
print()

print('B')
print(log_arr[0], log_arr[-1], log_arr[4:8])

print()

print('C')
x = np.array([10001. , 10002. ])

new_log_arr = np.append(log_arr, x)
print(new_log_arr)
print()

print('D')
divide_by_2 = new_log_arr/2
print(divide_by_2)
print()

print('E')
reshaped_arr = divide_by_2.reshape((3,4))

print(reshaped_arr)
print()

print('F')
mult = reshaped_arr * reshaped_arr
print(mult)
print()

print('G')
print(mult.ndim, np.amax(mult))

# ### Day 2

# #### Exercise 1
#
#    A. Create an array containing the values 4, 0, 6, 5, 11, 14, 12, 14, 5, 16.
#    B. Create a 10x2 array of zeros.
#    C. Write a for loop that checks if each of the numbers in the first array squared is less than 100. If the statement is true, change that row of your zeros array to equal the number and its square. Hint: you can change the value of an array by stating "zerosarray[i] = [a number, a number squared]".
#    D. Print out the final version of your zeros array.
#
# Hint: should you loop over the elements of the array or the indices of the array?

# In[7]:

# your solutions here

#making my array
arr = np.array([4, 0, 6, 5, 11, 14, 12, 14, 5, 16])

#making my 10X2 array of zeros
zero_arr = np.zeros((10,2))

#going through the loop and finding the square values < 100
for i, val in enumerate(arr):

    if val**2 < 100:
        zero_arr[i] = [val, val**2]

print(zero_arr)

# #### Exercise 2
#
#    A. Write a function that takes an array of numbers and spits out the Gaussian distribution. Yes, there is a function for this in Python, but it's good to do this from scratch! This is the equation:
#
# $$ f(x) = \frac{1}{\sigma \sqrt{2\pi}} \exp{\frac{-(x - \mu)^2}{2\sigma^2}} $$
#
#     (Pi is built into numpy, so call it as np.pi.)
#
#    B. Call the function a few different times for different values of mu and sigma, between -10 < x < 10.
#
#    C. Plot each version, making sure they are differentiated with different colors and/or linestyles and include a legend. Btw, here's a list of the customizations available in matplotlib:
#
#     https://matplotlib.org/3.1.0/api/_as_gen/matplotlib.pyplot.plot.html
#
#     https://matplotlib.org/gallery/color/named_colors.html
#
#    D. Save your figure.
#
# If you have multiple lines with plt.plot(), Python will plot all of them together, unless you write plt.show() after each one. I want these all on one plot.

# In[24]:

# your solutions here
def Gauss(x, mu, sigma):
    '''
    This function calculates the Guassian distribution given x, mu, sigma

    Parameters
    -------------
    x: the range of x values you are interested in finding the Gaussian distribution
    mu: the average of the given distribution
    sigma: the standard deviation of the distribution

    Output:
    Gaussian distribution given the x, mu, and sigma you passed in

    '''
    #making a prefactor variable
    prefactor = 1/(sigma* np.sqrt(2*np.pi))
    #making the exponential part into its own variable
    exp = np.exp(-(x-mu)**2/(2*sigma**2))

    #returning the Gaussian
    return prefactor * exp

#making my x array
x = np.linspace(-10, 10, 500)

y1 = Gauss(x, 1, 1)
y2 = Gauss(x, 3, .5)
y3 = Gauss(x, -2, 4)
y4 = Gauss(x, 1.2, .3)
y5 = Gauss(x, -3.2, 2)

plt.figure(figsize = (14, 8))
plt.title('Gaussian Function', fontsize = 16)
plt.xlabel('x values', fontsize = 16)
plt.ylabel('y-values of Gaussian', fontsize = 16)

#yaxis goes from 0 to 1 since it sproperly normalized by the prefactor
plt.axis([x[0], x[-1], 0, 1])
plt.plot(x, y1, 'r-', label = r'$\mu$ = 1, $\sigma$ = 1')
plt.plot(x, y2, 'b--', label = r'$\mu$ = 3, $\sigma$ = .5')
plt.plot(x, y3, 'k*', label = r'$\mu$ = -2, $\sigma$ = 4')
plt.plot(x, y4, 'gs', label = r'$\mu$ = 1.2, $\sigma$ = 8')
plt.plot(x, y5, 'yo', label = r'$\mu$ = -3.2, $\sigma$ = 6.75')
plt.legend(loc = 'best')
plt.savefig('Gaussian_Plots.pdf')
plt.show()

# ### Day 3
#
# #### Exercise 1
#
# There is a file in this directory called "histogram_exercise.dat" which consists of of randomly generated samples from a Gaussian distribution with an unknown $\mu$ and $\sigma$. Using what you've learned about fitting data, load up this file using np.genfromtxt, fit a Gaussian curve to the data and plot both the curve and the histogram of the data. As always, label everything, play with the colors, and choose a judicious bin size.
#
# Hint: if you attempt to call a function from a library or package that hasn't been imported, you will get an error.

# In[5]:

from scipy.stats import norm

# In[6]:

# your solution here
gauss_data = np.loadtxt('histogram_exercise.dat')

# In[8]:

mu, sigma = norm.fit(gauss_data)

x = np.linspace(np.min(gauss_data), np.max(gauss_data), 1000)

gauss = norm.pdf(x, mu, sigma)

# In[21]:

plt.figure(figsize =(12, 12))
plt.title('Gauss and Gaussian Fit')
plt.plot(x, gauss, 'k', linewidth = 2, label= 'Gauss Fit')
plt.hist(gauss_data, color= 'yellow', normed=True, hatch='//', label='Gaussian Data')
plt.legend(loc='best')
plt.show()

# #### Exercise 2
#
# Create a 1D interpolation along these arrays. Plot both the data (as points) and the interpolation (as a dotted line). Also plot the value of the interpolated function at x=325. What does the function look like to you?

# In[22]:

from scipy.interpolate import interp1d

# In[24]:

x = np.array([0., 50., 100., 150., 200., 250., 300., 350., 400., 450., 500])
y = np.array([0., 7.071, 10., 12.247, 14.142, 15.811, 17.321, 18.708, 20., 21.213, 22.361])

# solution here

f = interp1d(x, y)

# In[34]:

xnew = np.linspace(0, 500, 1000)
plt.figure(figsize = (10,10))
plt.plot(x, y, 'ko', label = 'Data')
plt.plot(xnew, f(xnew), 'r--', label = 'Interpolation')
plt.plot(325, f(325), 'b*', label = 'x = 325', markersize = 15)
plt.legend(loc = 'best', frameon=False)
plt.show()

# In[1]:

from astropy import constants as const
import numpy as np
import matplotlib.pyplot as plt
from astropy.io import fits
import aplpy

# ### Day 4
#
# #### Exercise 1
#
# Let's practice some more plotting skills, now incorporating units.
#
# A. Write a function that takes an array of frequencies and spits out the Planck distribution. That's this equation:
#
# $$ B(\nu, T) = \frac{2h\nu^3/c^2}{e^{\frac{h\nu}{k_B T}} - 1} $$
#
# This requires you to use the Planck constant, the Boltzmann constant, and the speed of light from astropy. Make sure they are all in cgs.
#
# B. Plot your function in log-log space for T = 25, 50, and 300 K. The most sensible frequency range is about 10^5 to 10^15 Hz. Hint: if your units are correct, your peak values of B(T) should be on the order of 10^-10. Make sure everything is labelled.

# In[4]:

h = const.h.cgs
k = const.k_B.cgs
c = const.c.cgs.value
print(h)
print(k)
print(c)

# In[8]:

h = const.h.cgs.value
k = const.k_B.cgs.value
c = const.c.cgs.value

# solution here
def blackbody(nu, T):

    numerator = (2 * h * nu**3)/c**2
    denom = np.exp((h * nu)/(k * T)) - 1

    return numerator/denom

nu = np.linspace(1e5, 1e15, 1e5)
T = [25, 50, 300]

plt.figure(figsize = (10,10))
plt.xlabel('Frequency [Hz]', fontsize = 16)
plt.ylabel('Specific Intensity', fontsize = 16)
plt.title('Planck Distribution', fontsize = 16)

for i in T:
    plt.loglog(nu, blackbody(nu, i), label = str(i) + ' K')

plt.legend(loc='best', fontsize = 14, frameon=False)
plt.show()

# #### Exercise 2
#
# Let's put everything together now! Here's a link to the full documentation for FITSFigure, which will tell you all of the customizable options: http://aplpy.readthedocs.io/en/stable/api/aplpy.FITSFigure.html. Let's create a nice plot of M51 with a background optical image and X-ray contours overplotted.
#
# The data came from here if you're interested: http://chandra.harvard.edu/photo/openFITS/multiwavelength_data.html
#
# A. Using astropy, open the X-RAY data (m51_xray.fits). Flatten the data array and find its standard deviation, and call it sigma.
#
# B. Using aplpy, plot a colorscale image of the OPTICAL data. Choose a colormap that is visually appealing (list of them here: https://matplotlib.org/2.0.2/examples/color/colormaps_reference.html). Show the colorbar.
#
# C. Plot the X-ray data as contours above the optical image. Make the contours spring green with 80% opacity and dotted lines. Make the levels go from 2$\sigma$ to 10$\sigma$ in steps of 2$\sigma$. (It might be easier to define the levels array before show_contours, and set levels=levels.)

# In[20]:

# solution here
data = fits.getdata('m51_xray.fits')

flat_data = data.flatten()

sigma = np.std(flat_data)

# In[35]:

galaxy = aplpy.FITSFigure('m51_optical_B.fits')
galaxy.show_colorscale(cmap='cubehelix')
galaxy.show_colorbar()

plt.show()

# In[21]:

2*sigma

# In[29]:

levels = np.linspace(2*sigma, 10*sigma, num = 5)
levels[1]-levels[0]

# In[36]:

levels = np.linspace(2*sigma, 10*sigma, num = ((8*sigma)/(2*sigma)))

galaxy = aplpy.FITSFigure('m51_optical_B.fits')
galaxy.show_colorscale(cmap='cubehelix')
galaxy.show_contour('m51_xray.fits', linestyle= 'dotted', colors = 'springgreen', alpha = .8, levels = levels)
#galaxy.show_colorbar()

plt.show()


import numpy as np
from numpy import array
from numpy import mean
from numpy.linalg import eig

C_1 = array([[1, 2], [2, 3], [3, 3], [4, 5], [5, 5]])
C_2 = array([[1, 0], [2, 1], [3, 1], [3, 2], [5, 3], [6, 5]])
print("We have the data:")
print("Class C1:\n", C_1)
print("Class C1:\n", C_2)
M_1 = mean(C_1.T, axis=1)
M_2 = mean(C_2.T, axis=1)
print("Step1: Let's compute the mean for each class:")
print("Mean of class C1: mu1 = \n", M_1)
print("Mean of class C2: mu2 = \n", M_2)
S_1 = (len(C_1) - 1) * np.cov(C_1.T)
S_2 = (len(C_2) - 1) * np.cov(C_2.T)
print("Step2: Let's compute the scatter matrices for each class:")
print("Scatter matrix of class C1: S1 = \n", S_1)
print("Scatter matrix of class C2: S2 = \n", S_2)
S_W = S_1 + S_2
print("Step3: Within the class scatter S_W = S_1 + S_2")
print("S_W = \n", S_W)
S_W_I = np.linalg.inv(S_W)
print("Step4: Let's compute the inverse of S_W")
print("S_W_I = \n", S_W_I)
V = np.matmul(S_W_I, (M_1 - M_2))
print("Step5: The optimal line direction v = S_W_I(mu1-mu2)")
print("v = \n", V)


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

########
#Name: Conner Carnahan
#ID: 1614309
#Email: carna104@mail.chapman.edu
#Class: PHYS220
#Date: Oct 16, 2018
########

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

@np.vectorize
def Sn(T,t,n):
    """Sn(float T,float t,int n): Returns a value computed by a sum of sin functions in accordance with the Fourier series expansion of sign(x)"""
    if (abs(t) > T/2):
        print("t should be within the range -T/2, T/2")
        pass
    K = np.arange(1,n+1)
    K = np.divide(4,np.pi*(2*K-1))
    SinPeriods = np.divide(2*np.pi*(2*np.arange(1,n+1)-1),T)
    value = np.sum(K*np.sin(SinPeriods*t))
    return value

@np.vectorize
def f(T,t):
    """f(float T, float t): Returns a value that is the sign of the value inputed
       if t < 0 sign(t) = -1
       if t > 0 sign(t) = 1
       if t = 0 sign(t) = 0"""
    if (abs(t) > T/2):
        print("t should be between T/2")
        pass
    return np.sign(t)

def Snarray(T,n,K = 300):
    """Snarray(T float, n int, K = 300 int): returns numpy array, Generates an array of values for K values of t in [-T/2,T/2] of the summed sines which approximate sign(x)"""
    Time = np.linspace(-T/2,T/2,K)
    return Sn(T,Time,n)

def farray(T,K = 300):
    """farray(T float, K = 300 int): returns numpy array of values evaluated by sign(x) for equally spaced K values of x in [-T/2,T/2]"""
    Time = np.linspace(-T/2,T/2,K)
    return f(T,Time)

def timespace(T,K = 300):
    """timespace(T float, K = 300 int), returns numpy array of K equally spaced values in [-T/2,T/2]"""
    return np.linspace(-T/2,T/2,K)

### DO NOT USE (OUT OF ORDER)
def buildallplots(alpha):
    """DON'T DO IT ONLY A PROTOTYPE
    args: alpha (float),
       returns null
       This is a helper function that takes in a float, alpha,
       and generates a sequence of partial Fourier Sums that approximate the sign function"""
    T = alpha*2*np.pi
    F1Array = ss.Snarray(T,1)
    F3Array = ss.Snarray(T,3)
    F5Array = ss.Snarray(T,5)
    F10Array = ss.Snarray(T,10)
    F30Array = ss.Snarray(T,30)
    F100Array = ss.Snarray(T,100)
    FuncArray = ss.farray(T)
    Time = ss.timespace(T)
###


from numpy.linalg import norm
from math import sin, cos, asin, acos, atan2, pi, degrees

class Finesse:
    @staticmethod
    def forward_pack(lengths, angles):
        """
        Computes the forward kinematics for the legs of DOG.
        :param lengths: An array of lengths (l1, l2).
        :param angles: An array of angles (theta1, theta2, theta3).
        :return: (x3, y3, z3)
        """

        l1, l2 = lengths
        theta1, theta2, theta3 = angles

        x1, y1, z1 = 0, 0, 0

        x2 = -l1 * sin(theta1) * cos(theta2)
        y2 = l1 * sin(theta2)
        z2 = -l1 * cos(theta1) * cos(theta2)

        x3 = x2 - l2 * cos(theta1) * sin(theta3) - l2 * cos(theta2) * cos(theta3) * sin(theta1)
        y3 = y2 + l2 * cos(theta3) * sin(theta2)
        z3 = z2 + l2 * sin(theta1) * sin(theta3) - l2 * cos(theta1) * cos(theta2) * cos(theta3)

        return x3, y3, z3

    @staticmethod
    def inverse_pack(lengths, target, a2=False, a3=False, deg=True):
        """
        Computes the inverse kinematics for the legs of DOG and Alpha
        For the back legs of Alpha, pass 0 for y.
        :param lengths: An array of lengths (l1, l2).
        :param target: The coordinate of the target (x, y, z).
        :param a2: Returns an alternate solution for theta2.
        :param a3: Returns an alternate solution for theta3.
        :param deg: Return the result in degrees if True and radians otherwise.
        :return: (theta1, theta2, theta3)
        """

        if lengths is None or target is None:
            raise ValueError

        l1, l2 = lengths
        x, y, z = target
        dist = norm(target)

        if dist > sum(lengths):
            raise ValueError

        # theta3 *= -1
        # Returns [0, 180]. +/- expands solution to [-180, 180].
        theta3 = (l1 ** 2 + l2 ** 2 - dist ** 2) / (2 * l1 * l2)
        theta3 = round(theta3, 13)
        theta3 = acos(theta3) - pi
        if a3:
            theta3 *= -1

        # theta2 = (pi - theta2)
        # Returns [-90, 90]. (pi - theta2) expands solution to [-180, 180].
        theta2 = y / (l1 + l2 * cos(theta3))
        theta2 = round(theta2, 13)
        theta2 = asin(theta2)
        if a2:
            theta2 = pi - theta2

        # theta1 -= 2 * pi
        # Sometimes (theta1 - 2 * pi). Doesn't matter. Either is cool.
        theta1 = atan2(z, -x) + atan2((l1 + l2 * cos(theta3)) * cos(theta2), l2 * sin(theta3))

        if deg:
            return degrees(theta1), degrees(theta2), degrees(theta3)
        else:
            return theta1, theta2, theta3


'''
    Recursive multiplication algorithms.
'''

import pandas as pd
import numpy as np
import timeit

def pad_inputs_(x, y):
    '''Left 0-pad inputs to have equal number of digits.'''
    if len(x) > len(y):
        y = '0' * (len(x) - len(y)) + y
    elif len(y) > len(x):
        x = '0' * (len(y) - len(x)) + x
    return x, y

def split_input_(s):
    '''Splits input digits in half.'''
    split_point = len(s) // 2
    return s[:split_point], s[split_point:]

def rec_int_mult_(x, y):
    '''Multiply two integers using a recrusive approach.'''
    # Pad inputs to be the same length
    x, y = pad_inputs_(x, y)

    # Check for base case
    n = len(x)
    if n == 1:
        return int(x) * int(y)

    # Split inputs
    a, b = split_input_(x)
    c, d = split_input_(y)

    # Recursively compute pair products
    ac = rec_int_mult_(a, c)
    ad = rec_int_mult_(a, d)
    bc = rec_int_mult_(b, c)
    bd = rec_int_mult_(b, d)

    # Combine results
    if n % 2 == 1: # Handle odd-length strings
        n += 1
    return ac*10**(n) + (ad + bc)*10**(n//2) + bd

def rec_int_mult(x, y):
    '''Multiply two integers using a recursive approach.

    Parameters
    ----------
    x : int
        The left operand for integer multiplication.
    y : int
        The right operand for integer multiplication.
    Returns
    -------
    int
        The result of multiplying x and y.

    Based off pseudocode from Algorithms Illuminated Part 1.
    '''
    # This is a wrapper to cast the inputs to strings for the first call
    x = str(x)
    y = str(y)
    return rec_int_mult_(x, y)

def karatsuba_(x, y):
    '''Multiply two integers using Karatsuba multiplication.'''
    # Pad inputs to be the same length
    x, y = pad_inputs_(x, y)

    # Check for base case
    n = len(x)
    if n == 1:
        return int(x) * int(y)

    # Split inputs
    a, b = split_input_(x)
    c, d = split_input_(y)

    # Compute p and q
    p = str(int(a) + int(b))
    q = str(int(c) + int(d))

    # Recursively compute pair products
    ac = karatsuba_(a, c)
    bd = karatsuba_(b, d)
    pq = karatsuba_(p, q)

    # Combine results
    adbc = pq - ac - bd
    if n % 2 == 1: # Handle odd-length strings
        n += 1
    return ac*10**(n) + (adbc)*10**(n//2) + bd

def karatsuba(x, y):
    '''Multiply two integers using Karatsuba multiplication.

    Parameters
    ----------
    x : int
        The left operand for integer multiplication.
    y : int
        The right operand for integer multiplication.
    Returns
    -------
    int
        The result of multiplying x and y.

    Based off pseudocode from Algorithms Illuminated Part 1.
    '''
    # This is a wrapper to cast the inputs to strings for the first call
    x = str(x)
    y = str(y)
    return karatsuba_(x, y)

def built_in_multiply(x, y):
    '''Applies the built-in multiplication operator '''
    return x * y

def get_random_input(n):
    '''Returns random integer with specified number of digits.'''
    return int(''.join([str(digit) for digit in np.random.randint(0,10,n)]))

def get_setup(algorithm_name, n):
    s = f"from __main__ import {algorithm_name}; import numpy as np;"
    s += f"x = int(''.join([str(digit) for digit in np.random.randint(0,10,{n})]));"
    s += f"y = int(''.join([str(digit) for digit in np.random.randint(0,10,{n})]));"
    return s

if __name__ == '__main__':
    # First, correctness tests involving varying length combinations
    algorithms = {'rec_int_mult': rec_int_mult, 'karatsuba': karatsuba}
    digit_range = (1,20) # Range of number of digits to test
    for algorithm_name, algorithm in algorithms.items():
        print(f'\nRunning correctness tests for {algorithm_name} with number of digits from {digit_range[0]} to {digit_range[1]}...')
        num_tested = 0
        num_passed = 0
        failed_inputs = []
        # Tests all permutations of digit ranges with built-in operator as reference
        for x_digits in range(min_digits, max_digits):
            for y_digits in range(min_digits, max_digits):
                x, y = get_random_input(x_digits), get_random_input(y_digits)
                result = algorithm(x, y)
                if result == x * y:
                    num_passed += 1
                else:
                    failed_inputs.append((x, y))
                num_tested += 1
        print(f'Results: {num_passed} passed out of {num_tested} tests.')
        if num_tested > num_passed:
            print(f'Failed input sets:')
            for inputs in failed_inputs:
                print(inputs)

    # Second, timing tests for various input sizes
    algorithms['built_in_multiply'] = built_in_multiply
    results = pd.DataFrame(data={'n':[40, 80, 160, 320]})
    for algorithm_name, algorithm in algorithms.items():
        print(f'\nRunning timing tests for {algorithm_name}...')
        temp_results = []
        for n in results['n'].values:
            n = int(n)
            temp_results.append(np.round(timeit.timeit(f'{algorithm_name}(x, y)', setup=get_setup(algorithm_name, n), number=1), 4))
        results[algorithm_name] = temp_results
    print('Timing tests complete.')
    print(results.head(results.shape[0]))


# Load modules
from __future__ import print_function
import os
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt

# read the data from into a pandas.DataFrame
wisc_emp = pd.read_csv("datasets/wisconsin-employment-time-series.csv")

# Let's find out the shape of the DataFrame
print("Shape of the DataFrame:", wisc_emp.shape)

# Let's see first 10 rows of it
wisc_emp.head()

# plot the wisconsin employment dataset
wisc_emp.plot()

# Capture seasonality component
def initialize_T(x, seasonLength):
    total = 0.0
    for i in range(seasonLength):
        total += float(x[i + seasonLength] - x[i]) / seasonLength
    return total

initialize_T(wisc_emp["Employment"], 12)

# Initialize seasonal trend
def initialize_seasonalilty(x, seasonLength):
    seasons = {}
    seasonsMean = []
    num_season = int(len(x) / seasonLength)
    # Compute season average
    for i in range(num_season):
        seasonsMean.append(
            sum(x[seasonLength * i : seasonLength * i + seasonLength])
            / float(seasonLength)
        )

    # compute season intial values
    for i in range(seasonLength):
        tot = 0.0
        for j in range(num_season):
            tot += x[seasonLength * j + i] - seasonsMean[j]
        seasons[i] = tot / num_season
    return seasons

initialize_seasonalilty(wisc_emp["Employment"], 12)

# Triple Exponential Smoothing Forecast
def triple_exp_smoothing(x, seasonLength, alpha, beta, gamma, h):
    yhat = []
    S = initialize_seasonalilty(x, seasonLength)
    for i in range(len(x) + h):
        if i == 0:
            F = x[0]
            T = initialize_T(x, seasonLength)
            yhat.append(x[0])
            continue
        if i >= len(x):
            m = i - len(x) + 1
            yhat.append((F + m * T) + S[i % seasonLength])
        else:
            obsval = x[i]
            F_last, F = (
                F,
                alpha * (obsval - S[i % seasonLength]) + (1 - alpha) * (F + T),
            )
            T = beta * (F - F_last) + (1 - beta) * T
            S[i % seasonLength] = (
                gamma * (obsval - F) + (1 - gamma) * S[i % seasonLength]
            )
            yhat.append(F + T + S[i % seasonLength])
    return yhat

# Triple exponential smoothing
wisc_emp["TES"] = triple_exp_smoothing(wisc_emp["Employment"], 12, 0.4, 0.6, 0.2, 0)

### Plot Single Exponential Smoothing forecasted value
fig = plt.figure(figsize=(5.5, 5.5))
ax = fig.add_subplot(2, 1, 1)
wisc_emp["Employment"].plot(ax=ax)
ax.set_title("Beer Production")
ax = fig.add_subplot(2, 1, 2)
wisc_emp["TES"].plot(ax=ax, color="r")
ax.set_title("Triple Smoothing Forecast")
plt.savefig("plots/ch2/B07887_03_14.png", format="png", dpi=300)

time series regression/autocorelation, mov avg etc/tripleExponentialSmoothing.py


# find the inverse of a matrix using Gaussian elimination

import numpy

def inverse(AInput):
    """ return the inverse of AInput """

    A = AInput.copy()

    N = len(A[:,0])

    # A is square, with each dimension of length N
    if not (A.shape[0] == A.shape[1]):
        print "ERROR: A should be square"
        return None

    # create an identity matrix
    I = numpy.identity(N)

    # allocation for the inverse
    Ainv = numpy.zeros((N,N), dtype=A.dtype)

    # find the scale factors for each row -- this is used when pivoting
    scales = numpy.max(numpy.abs(A), 1)

    # keep track of the number of times we swapped rows
    numRowSwap = 0

    # we are essentially doing Gaussian elimination, but with A Ainv = I
    # each column of I represents a separate righthand side to an Ax = b
    # linear system

    # main loop over rows
    for k in range(N):

        # find the pivot row based on the size of column k -- only consider
        # the rows beyond the current row
        rowMax = numpy.argmax(A[k:, k]/scales[k:])
        if (k > 0): rowMax += k  # we sliced A from k:, correct for total rows

        # swap the row with the largest scaled element in the current column
        # with the current row (pivot) -- do this with b too!
        if not rowMax == k:
            A[[k, rowMax],:] = A[[rowMax, k],:]
            I[[k, rowMax],:] = I[[rowMax, k],:]
            numRowSwap += 1

        # do the forward-elimination for all rows below the current
        for i in range(k+1, N):
            coeff = A[i,k]/A[k,k]

            for j in range(k+1, N):
                A[i,j] += -A[k,j]*coeff

            A[i,k] = 0.0
            I[i,:] += -coeff*I[k,:]

    # back-substitution -- once for each column in the I matrix

    for c in range(N):

        # last solution is easy
        Ainv[N-1,c] = I[N-1,c]/A[N-1,N-1]

        for i in reversed(range(N-1)):
            sum = I[i,c]
            for j in range(i+1,N):
                sum += -A[i,j]*Ainv[j,c]
            Ainv[i,c] = sum/A[i,i]

    # determinant
    det = numpy.prod(numpy.diagonal(A))*(-1.0)**numRowSwap

    return Ainv

# output: numpy.savetxt("test.out", a, fmt="%5.2f", delimiter="  ")
# convert -font Courier-New-Regular -pointsize 20 text:test.out test.png

A = numpy.array([ [4, 3, 4, 10], [2, -7, 3, 0], [-2, 11, 1, 3], [3, -4, 0, 2] ], dtype=numpy.float64)
Ainv = inverse(A)
print "A . Ainv = \n", numpy.dot(A, Ainv)
print" Ainv = \n", Ainv

print " "

A = numpy.array([ [0, 1, 1], [1, 1, 0], [1, 0, 1] ], dtype=numpy.float64)
Ainv = inverse(A)
print "A . Ainv = \n", numpy.dot(A, Ainv)

print " "

A = numpy.array([ [0, 0, 0, 4],
                  [0, 0, 3, 0],
                  [5, 6, 7, 8],
                  [0, 4, 3, 2] ], dtype=numpy.float64)
Ainv = inverse(A)
print "A . Ainv = \n", numpy.dot(A, Ainv)


# Code by Desh Iyer

# ----------------------------------------------------------------

# PROBLEM STATEMENT

# Observe the dataset: https://www.kaggle.com/subhashinimariappan/numerical-dataset Compute all the statistical measures learnt till the last class: central tendency, dispersion, covariance, correlation, eq of a straight line for all comb. where r>0.6

# ----------------------------------------------------------------

# SOLUTION

# Import libs
import pandas as pd
import numpy as np
from scipy.stats import pearsonr

# Read data from csv file given
df = pd.read_csv(r'C:\Users\Volt\Code\B.Tech-CSE-Y2\applied-statistics\lab\experiment-7\phpB0xrNj.csv')

# Print the dataset
print("\nGiven Data Set")
print(df)

# Give user input
column = input("\nEnter column name to proceed: ")
new_data = df[column]

# Calculating details
Mean = new_data.mean()
Mode = new_data.mode()
Median = new_data.median()
sd = np.std(new_data)
var = np.var(new_data)

# Printing relevant details
print("\nDetails for the column: " + column)

print("\nMeasures of Central Tendency")

print("Calculated Mean of the selected column:", Mean)
print("Calculated Mode of the selected column:", Mode)
print("Calculated Median of the selected column:", Median)

print("\nMeasures of Dispersion")

print("Calculated Standard Deviation of the selected column:", sd)
print("Calculated variance of the selected column: ", var)

# Taking input for second col and printing relevant details
column2 = input("\nEnter the name of another column for finding covariance :")

y = df[column2]

print("\nCovariance matrix for columns: " + column + " and " + column2 + " :")
print(np.cov(new_data,y))

corr, _ = pearsonr(new_data,y)

print("Correlation for columns: " + column + " and " + column2 + " :")
print(corr)


"""
3D version of approx2D.py.
Numerical integration only.
"""
import sympy as sym
import numpy as np
import scipy.integrate

def least_squares(f, psi, Omega):
    """
    Given a function f(x,y,z) on a rectangular domain
    Omega=[[xmin,xmax],[ymin,ymax],[zmin,zmax]],
    return the best approximation to f in the space V
    spanned by the functions in the list psi.
    f and psi are symbolic (sympy) expressions, but will
    be converted to numeric functions for faster integration.
    """
    N = len(psi) - 1
    A = np.zeros((N+1, N+1))
    b = np.zeros(N+1)
    x, y, z = sym.symbols('x y z')
    f = sym.lambdify([x, y, z], f, modules='numpy')
    psi_sym = psi[:]  # take a copy, needed for forming u later
    psi = [sym.lambdify([x, y, z], psi[i]) for i in range(len(psi))]

    print('...evaluating matrix...')
    for i in range(N+1):
        for j in range(i, N+1):
            print(('(%d,%d)' % (i, j)))

            integrand = lambda x, y, z: psi[i](x,y,z)*psi[j](x,y,z)
            I, err = scipy.integrate.nquad(
                integrand,
                [[Omega[0][0], Omega[0][1]],
                 [Omega[1][0], Omega[1][1]],
                 [Omega[2][0], Omega[2][1]]])
            A[i,j] = A[j,i] = I
        integrand = lambda x, y, z: psi[i](x,y,z)*f(x,y,z)
        I, err = scipy.integrate.nquad(
            integrand,
            [[Omega[0][0], Omega[0][1]],
             [Omega[1][0], Omega[1][1]],
             [Omega[2][0], Omega[2][1]]])
        b[i] = I
    print()
    c = np.linalg.solve(A, b)
    if N <= 10:
        print(('A:\n', A, '\nb:\n', b))
        print(('coeff:', c))
    u = sum(c[i]*psi_sym[i] for i in range(len(psi_sym)))
    print(('approximation:', u))
    return u, c

def sine_basis(Nx, Ny, Nz):
    """
    Compute basis sin((p+1)*pi*x)*sin((q+1)*pi*y)*sin((r+1)*pi*z),
    p=0,...,Nx, q=0,...,Ny, r=0,...,Nz.
    """
    x, y, z = sym.symbols('x y z')
    psi = []
    for r in range(0, Nz+1):
        for q in range(0, Ny+1):
            for p in range(0, Nx+1):
                s = sym.sin((p+1)*sym.pi*x)*\
                    sym.sin((q+1)*sym.pi*y)*sym.sin((r+1)*sym.pi*z)
                psi.append(s)
    return psi

def test_least_squares():
    # Use sine functions
    x, y, z = sym.symbols('x y z')
    N = 1  # (N+1)**3 = 8 basis functions
    psi = sine_basis(N, N, N)
    f_coeff = [0]*len(psi)
    f_coeff[3] = 2
    f_coeff[4] = 3
    f = sum(f_coeff[i]*psi[i] for i in range(len(psi)))
    # Check that u exactly reproduces f
    u, c = least_squares(f, psi, Omega=[[0,1], [0,1], [0,1]])
    diff = np.abs(np.array(c) - np.array(f_coeff)).max()
    print(('diff:', diff))
    tol = 1E-15
    assert diff < tol

if __name__ == '__main__':
    import time
    t0 = time.clock()
    test_least_squares()


import numpy as np;

ar=np.array([1,2,3])

ar=np.array([(1,2,3),(3,4,5)],dtype=float)
# print(ar)

ar = np.array([(1, 2, 3), (3, 4, 5),(6,7,8)], dtype=float)

# print(ar)

#Creating Zero
print(np.zeros((2,3)))

print(np.ones((3,3),dtype=np.int16))

print(np.arange(2,10,2))

print(np.linspace(1,10,10))

print(ar.T) #Transpose

arT=ar.T

#Dot mul
print(ar.dot(arT))

""" Determinant of upper triangle or diagnal matrix is product of diagnal element """

a = np.array([(2, 3, 4), (0, 2, 5), (0, 0, 2)])
# a
# array([[2, 3, 4],
#        [0, 2, 5],
#        [0, 0, 2]])
print(np.linalg.det(a))
# 7.999999999999998

""" Determinant of row exhanged matrix will change the sign """

a=np.array([(2, 3, 4), (0, 0, 2), (0, 2, 5)])
print(np.linalg.det(a))
# - 7.999999999999998

""" Determinant of identiy matrix is 1 """
a = np.array([(1,0,0), (0, 1, 0), (0, 0,1)])
print(np.linalg.det(a))
# 1


import numpy as np
import matplotlib.pyplot as plt

plt.style.use('ggplot')

########## Função degrau
def step():
    z = np.arange(-5, 5, .001)
    step_fn = np.vectorize(lambda z: 1.0 if z >= 0.0 else 0.0)
    step = step_fn(z)
    return z, step, "Função degrau"

def step_d():
    z = np.arange(-5, 5, .02)
    return z, [0]*len(z), "Derivada da função degrau"

########## Função logística
def logistic():
    z = np.arange(-10, 10, .1)
    sigma_fn = np.vectorize(lambda z: 1/(1+np.exp(-z)))
    sigma = sigma_fn(z)
    return z, sigma, "Função logística"

def logistic_d():
    z = np.arange(-10, 10, .1)
    sigma_fn = np.vectorize(lambda z: np.exp(-z)/((np.exp(-z) + 1)**2))
    sigma = sigma_fn(z)
    return z, sigma, "Derivada da função logística"

########## Função ReLU
def relu():
    z = np.arange(-2, 2, .01)
    zero = np.zeros(len(z))
    y = np.max([zero, z], axis=0)
    return z, y, "Função ReLU"

def relu_d():
    z = np.arange(-2, 2, .01)
    y = [1 if x > 0 else 0 for x in z]
    return z, y, "Derivada da função ReLU"

########## Função LeakyReLU
def lrelu(alpha=.2):
    z = np.arange(-2, 2, .01)
    y = [x if x > 0 else alpha*x for x in z]
    return z, y, "Função LeakyReLU (α = 0.2)"

def lrelu_d(alpha=.2):
    z = np.arange(-2, 2, .01)
    y = [1 if x > 0 else alpha for x in z]
    return z, y, "Derivada da função LeakyReLU (α = 0.2)"

########## Função tangente hiperbólica
def tanh():
    z = np.arange(-5, 5, .1)
    t = np.tanh(z)
    return z, t, "Função tangente hiperbólica"

def tanh_d():
    z = np.arange(-5, 5, .1)
    # sech(z) = 1 / cosh(z)
    t = 1/np.cosh(z)
    return z, t, "Derivada da função tangente hiperbólica"

########## Função tangente hiperbólica
def mish():
    z = np.arange(-5, 5, .1)
    t = z * np.tanh(np.log(1 + np.exp(z)))
    return z, t, "Função Mish"

def mish_d():
    z = np.arange(-5, 5, .1)
    t = ((2*np.exp(z)*z*(1+np.exp(z)))/((1+np.exp(z))**2+1)) - \
            (2*np.exp(z)*z*((1+np.exp(z))**2 - 1)*(1+np.exp(z)))/((1+np.exp(z))**2 + 1)**2 + \
                ((1+np.exp(z))**2 - 1)/((1+np.exp(z))**2 + 1)
    return z, t, "Derivada da função Mish"

########## Função APL
def apl_func(x,a,b):
    return max(0, x) + sum([a[i]*max(0, -x + b[i]) for i in range(len(a))])

def apl(a=[.2], b=[0]):
    z = np.arange(-5, 5, .01)
    t = [apl_func(x,a,b) for x in z]
    return z, t, "Função APL (a = " + a + "; b = " + b + ")"

def apl_d_a02_b0():
    z = np.arange(-5, 5, .01)
    t = [1 if x > 0 else -0.2 for x in z]
    return z, t, "Derivada da função APL (a = 0.2; b = 0)"

########## Função SHReLU
def shrelu(tau=0.2):
    z = np.arange(-5, 5, .01)
    t = [0.5*(x + np.sqrt(x**2 + tau**2)) for x in z]
    return z, t, "Função SHReLU (τ = %.2f)" % (tau)

def shrelu_d(tau=0.2):
    z = np.arange(-5, 5, .01)
    t = [0.5*((x/(np.sqrt(x**2 + tau**2))) + 1) for x in z]
    return z, t, "Derivada da função SHReLU (τ = %.2f)" % (tau)

########## Função BHSA
def h1_bhsa(l, tau, z):
    return np.sqrt( (l**2) * (z + (1/(2*l)))**2 + tau**2)

def h2_bhsa(l, tau, z):
    return np.sqrt( (l**2) * (z - (1/(2*l)))**2 + tau**2)

def bhsa(l=1, tau=0, z = None):
    # h1 = torch.sqrt( ((self.l**2) * (x + (1/(2*self.l)))**2) + self.t1**2 )
    # h2 = torch.sqrt( ((self.l**2) * (x - (1/(2*self.l)))**2) + self.t2**2 )
    if z is None: z = np.arange(-5, 5, .01)
    t = h1_bhsa(l, tau, z) - h2_bhsa(l, tau, z)
    return z, t, "Função BHSA (λ = %.2f; τ = %.2f)" % (l, tau)

def bhsa_d(l=1, tau=0):
    z = np.arange(-5, 5, .01)
    t = (l * (1 - 2 * l * z))/np.sqrt(4 * tau**2 + (1 - 2 * l * z)**2) + (l * (1 + 2 * l * z))/np.sqrt(4 * tau**2 + (1 + 2 * l * z)**2)
    return z, t, "Derivada da função BHSA (λ = %.2f; τ = %.2f)" % (l, tau)

########## Função BHAA
def bhaa(l=1, tau1=0, tau2=0):
    z = np.arange(-5, 5, .01)
    t = np.sqrt((l**2) * (z+(1/(2*l)))**2 + (tau1**2)) - np.sqrt((l**2) * (z-(1/(2*l)))**2 + (tau2**2))
    return z, t, "Função BHAA (λ = %.2f; τ1 = %.2f; τ2 = %.2f)" % (l, tau1, tau2)

def bhaa_d(l=1, tau1=0, tau2=0):
    z = np.arange(-5, 5, .01)
    t = (l * (1 - 2 * l * z))/np.sqrt((1 - 2 * l * z)**2 + 4 * tau2**2) + (l * (2 * l * z + 1))/np.sqrt((2 * l * z + 1)**2 + 4 * tau1**2)
    return z, t, "Derivada da função BHAA (λ = %.2f; τ1 = %.2f; τ2 = %.2f)" % (l, tau1, tau2)

def bhata(l=1,tau1=0,tau2=0):
    z, t, _ = bhaa(l, tau1, tau2)
    t[t > 1] = 1
    t[t < -1] = -1
    return z, t, "Função BHAA truncada (λ = %.2f; τ1 = %.2f; τ2 = %.2f)" % (l, tau1, tau2)

def func_bh_derivative_equal_to_zero(tau1, tau2, l):
    return [(tau1 - tau2)/(2*l*(tau1 + tau2)), (tau1 + tau2)/(2*l*(tau1 - tau2))]

def raw_func_bh_derivative(x, tau1, tau2, l):
    return (l * (1 - 2 * l * x))/np.sqrt(4 * tau2**2 + (1 - 2 * l * x)**2) + (l * (1 + 2 * l * x))/np.sqrt(4 * tau1**2 + (1 + 2 * l * x)**2)

def raw_func_bh(x, tau1, tau2, l):
    return (np.sqrt((l**2) * (x+(1/(2*l)))**2 + (tau1**2)) - np.sqrt((l**2) * (x-(1/(2*l)))**2 + (tau2**2)))

def bhana(l=1,tau1=0,tau2=0):
    z = np.arange(-5, 5, .001)
    result = raw_func_bh(z, tau1, tau2, l)
    func_points_edge_value = func_bh_derivative_equal_to_zero(tau1, tau2, l)
    func_points_edge_value = max(func_points_edge_value) if abs(tau1) > abs(tau2) else min(func_points_edge_value)
    func_edge_value = raw_func_bh(func_points_edge_value, tau1, tau2, l)

    if(abs(tau1) > abs(tau2)):
        result = (result - (-1))/(func_edge_value + 0.001 - (-1))
    elif(abs(tau2) > abs(tau1)):
        result = (result - func_edge_value)/(1 + 0.001 - func_edge_value)

    result = (result - 0.5) * 2

    return z, result, "Função BHANA (λ = %.2f; τ1 = %.2f; τ2 = %.2f)" % (l, tau1, tau2)

########## Função MiDA
def raw_softmax(x):
    return np.log(1 + np.exp(x))

def mida(l=1, tau=1):
    z = np.arange(-5, 5, .01)
    t = z * bhsa(l,tau,raw_softmax(z))[1]
    return z, t, "Função MiDA (λ = %.2f; τ = %.2f)" % (l, tau)

def mida_d(l=1, tau=1):
    z = np.arange(-5, 5, .01)
    delta = (l*np.exp(z)*z)/(2*(1+np.exp(z)))
    t = bhsa(l, tau, raw_softmax(z))[1] + delta * (((1 + 2*l*raw_softmax(z))/h1_bhsa(l, tau, raw_softmax(z))) + ((1-2*l*raw_softmax(z))/(h2_bhsa(l, tau, raw_softmax(z)))))
    return z, t, "Derivada da função MiDA (λ = %.2f; τ = %.2f)" % (l, tau)

#############################################################
def conf(ax, xlim=2, ylim=None, offsetx=0, offsety=0):
    if ylim is None: ylim = xlim
    ax.set_ylim([-ylim + offsety, ylim + offsety])
    ax.set_xlim([-xlim + offsetx, xlim + offsetx])
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.grid(True)
    ax.legend()

#############################################################
def step_and_derivative():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    data, data_d = [step(), step_d()]
    ax.plot(data[0], data[1], label=data[2])
    ax.plot(data_d[0], data_d[1], ls='dashed', lw=1, label=data_d[2])
    conf(ax,xlim=1,offsety=.5)
    # fig.suptitle('Funções de ativação sigmoidais tradicionais')
    plt.show()

def logistic_and_derivative():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    data, data_d = [logistic(), logistic_d()]
    ax.plot(data[0], data[1], label=data[2])
    ax.plot(data_d[0], data_d[1], ls='dashed', lw=1, label=data_d[2])
    conf(ax, xlim=4,ylim=1,offsety=.5)
    plt.show()

def tanh_and_derivative():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    data, data_d = [tanh(), tanh_d()]
    ax.plot(data[0], data[1], label=data[2])
    ax.plot(data_d[0], data_d[1], ls='dashed', lw=1, label=data_d[2])
    conf(ax,ylim=1.5,offsety=.3)
    plt.show()

def mish_and_derivative():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    data, data_d = [mish(), mish_d()]
    ax.plot(data[0], data[1], label=data[2])
    ax.plot(data_d[0], data_d[1], ls='dashed', lw=1, label=data_d[2])
    conf(ax,xlim=4,offsety=1.5)
    plt.show()

def relu_and_derivative():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    data, data_d = [relu(), relu_d()]
    ax.plot(data[0], data[1], label=data[2])
    ax.plot(data_d[0], data_d[1], ls='dashed', lw=1, label=data_d[2])
    conf(ax, offsety=1,xlim=1.5)
    plt.show()

def lrelu_and_derivative():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    data, data_d = [lrelu(), lrelu_d()]
    ax.plot(data[0], data[1], label=data[2])
    ax.plot(data_d[0], data_d[1], ls='dashed', lw=1, label=data_d[2])
    conf(ax, offsety=1,xlim=1.5)
    plt.show()

def apl_and_derivative():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    data, data_d = [apl(), apl_d_a02_b0()]
    ax.plot(data[0], data[1], label=data[2])
    ax.plot(data_d[0], data_d[1], ls='dashed', lw=1, label=data_d[2])
    conf(ax,offsety=1)
    plt.show()

def shrelu_and_derivative():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    for tau in [0.05, 0.25, 1]:
        data, data_d = [shrelu(tau), shrelu_d(tau)]
        ax.plot(data[0], data[1], label=data[2])
        ax.plot(data_d[0], data_d[1], ls='dashed', lw=1, label=data_d[2])
    conf(ax, offsety=1,xlim=1.5)
    plt.show()

def bhsa_and_derivative():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    for l, tau in [(1, 1), (.5, 1), (1, .5)]:
        data, data_d = [bhsa(l, tau), bhsa_d(l, tau)]
        ax.plot(data[0], data[1], label=data[2])
        ax.plot(data_d[0], data_d[1], ls='dashed', lw=1, label=data_d[2])
    conf(ax)
    plt.show()

def bhaa_and_derivative():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    for l, tau1, tau2 in [(1, .5, .5), (1, .5, .1), (1, .1, .5)]:
        data, data_d = [bhaa(l, tau1, tau2), bhaa_d(l, tau1, tau2)]
        ax.plot(data[0], data[1], label=data[2])
        ax.plot(data_d[0], data_d[1], ls='dashed', lw=1, label=data_d[2])
    conf(ax)
    plt.show()

def mida_and_derivative():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    for l, tau in [(1, 1), (.5, 1), (1, .5)]:
        data, data_d = [mida(l, tau), mida_d(l, tau)]
        ax.plot(data[0], data[1], label=data[2])
        ax.plot(data_d[0], data_d[1], ls='dashed', lw=1.25, label=data_d[2])
    conf(ax,xlim=3,offsety=1.5)
    plt.show()

def bhata_only():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    for l, tau1, tau2 in [(1, .5, .1), (1, .1, .5)]:
        data = bhata(l, tau1, tau2)
        ax.plot(data[0], data[1], label=data[2])
    conf(ax)
    plt.show()

def bhana_only():
    fig, (ax) = plt.subplots(1, 1, figsize=(6,6))
    for l, tau1, tau2 in [(1, .75, .1), (1, .1, .75)]:
        data = bhana(l, tau1, tau2)
        ax.plot(data[0], data[1], label=data[2])
    conf(ax)
    plt.show()

# step_and_derivative()
# logistic_and_derivative()
# tanh_and_derivative()
# mish_and_derivative()
# relu_and_derivative()
# lrelu_and_derivative()
# apl_and_derivative()
# shrelu_and_derivative()
# bhsa_and_derivative()
# bhaa_and_derivative()
# mida_and_derivative()
# bhata_only()
bhana_only()


import numpy as np

def simpson(f, a, b, n):
    """Approximates the definite integral of f from a to b by
    the composite Simpson's rule, using n subintervals.
    From http://en.wikipedia.org/wiki/Simpson's_rule

    Args:
    f   : function to integrate
    a,b : boundaries
    n   : number of subintervals

    Return: integral
    """
    h = (b - a) / n
    i = np.arange(0,n)
    s = f(a) + f(b)
    s += 4 * np.sum( f( a + i[1::2] * h ) )
    s += 2 * np.sum( f( a + i[2:-1:2] * h ) )
    sum = s * h / 3
    return sum

def trapezoid(f, a, b, n):
    """Approximates the definite integral of f from a to b by
    the composite trapezoidal rule, using n subintervals.
    From http://en.wikipedia.org/wiki/Trapezoidal_rule

    Args:
    f   : function to integrate
    a,b : boundaries
    n   : number of subintervals

    Return: integral
    """
    h = (b - a) / n
    s = f(a) + f(b)
    i = np.arange(0,n)
    s += 2 * np.sum( f(a + i[1:] * h) )
    return s * h / 2

def adaptive_trapezoid(f, a, b, acc, output=False):
    """
    Uses the adaptive trapezoidal method to compute the definite integral
    of f from a to b to desired accuracy acc.

    Args:
    f      : function to integrate
    a,b    : boundaries
    acc    : desired accurarcy
    output : prints individual steps, default is False

    Return: integral
    """
    old_s = np.inf
    h = b - a
    n = 1
    s = (f(a) + f(b)) * 0.5
    if output == True :
        print ("N = " + str(n+1) + ",  Integral = " + str( h*s ))
    while abs(h * (old_s - s*0.5)) > acc :
        old_s = s
        for i in np.arange(n) :
            s += f(a + (i + 0.5) * h)
        n *= 2.
        h *= 0.5
        if output == True :
            print ("N = " + str(n) + ",  Integral = " + str( h*s ))
    return h * s


import numpy as np

def coding_problem_32(exchange_matrix):
    """
    Suppose you are given a table of currency exchange rates, represented as a 2D array. Determine whether there is a
    possible arbitrage: that is, whether there is some sequence of trades you can make, starting with some amount A of
    any currency, so that you can end up with some amount greater than A of that currency.
    There are no transaction costs and you can trade fractional quantities.

    >>> em = [[1, 2, 3], [1./2, 1, 3./2], [1./3, 2./3, 1]]
    >>> coding_problem_32(em)
    True

    >>> em[0][2] = 2.98
    >>> coding_problem_32(em)
    False

    Note: idea is that given a single row in the currency exchange matrix, it is possible to generate the entire 2D
    array. Any difference between the given currency exchange matrix and the computed one implies the possibility of
    arbitration.

    For example, for five currencies and given the exchange rates from the first to the other 4 [b, c, d, e]:

      |  A   B   C   D   E
    --+------------------
    A |  1   b   c   d   e
    B | 1/b  1  c/b d/b e/b
    C | 1/c b/c  1  d/b e/c
    D | 1/d b/d c/d  1  e/d
    E | 1/e b/e c/e d/e  1

    Since floating point quantities are involved, we need to test for approximate equality.
    """
    em = np.array(exchange_matrix)  # ideally, we should test if the exchange_matrix is well-formed
    cem = np.vstack(tuple(em[0, :] / em[0, n] for n in range(len(em))))  # computed exchange_matrix
    return np.allclose(em, cem)

if __name__ == '__main__':

    import doctest
    doctest.testmod(verbose=True)


'''
Content under Creative Commons Attribution license CC-BY 4.0,
code under MIT license (c)2018 Sergio Rojas (srojas@usb.ve)

http://en.wikipedia.org/wiki/MIT_License
http://creativecommons.org/licenses/by/4.0/

Created on march, 2018
Last Modified on: may 15, 2018
'''

TheValues = [336.1, 346.67, 354.54, 359.9, 338.61, 348.16, 355.2, 360.,
339.32, 349.31, 355.36, 363.13, 350.56, 355.76, 342.62, 351.88,
356.85, 342.88, 351.99, 358.16, 343.44, 352.12, 358.3, 344.32,
352.47, 359.18, 345.03, 353.21, 359.56, 346.5]

TheValues.sort()
NumberOfValues = len(TheValues)

if NumberOfValues == 0:
   print(' List of values in empty ')
elif NumberOfValues == 1:
   TheMedian = TheValues[ 0 ]     # The only element in the list
elif (NumberOfValues % 2) == 1:   # Check if the number of values is odd
   temp = NumberOfValues//2
   TheMedian = TheValues[ temp ]
else:
   temp = NumberOfValues//2
   TheMedian = (TheValues[ temp ] + TheValues[ temp - 1 ])/2

print('The median = {0}'.format(TheMedian))
In [8]: import numpy as np

In [9]: np.median(TheValues)
Out[9]: 352.05500000000001


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import norm
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()

AmznData = pd.read_csv('AMZN.csv',header=0, usecols=['Date', 'Close'],parse_dates=True,index_col='Date')
print(AmznData.info())
print(AmznData.head())
print(AmznData.tail())
print(AmznData.describe())

plt.figure(figsize=(10,5))
plt.plot(AmznData)
plt.show()

AmznDataPctChange = AmznData.pct_change()

AmznLogReturns = np.log(1 + AmznDataPctChange)
print(AmznLogReturns.tail(10))

plt.figure(figsize=(10,5))
plt.plot(AmznLogReturns)
plt.show()

MeanLogReturns = np.array(AmznLogReturns.mean())

VarLogReturns = np.array(AmznLogReturns.var())

StdevLogReturns = np.array(AmznLogReturns.std())

Drift = MeanLogReturns - (0.5 * VarLogReturns)
print("Drift = ",Drift)

NumIntervals = 2518

Iterations = 20

np.random.seed(7)
SBMotion = norm.ppf(np.random.rand(NumIntervals, Iterations))

DailyReturns = np.exp(Drift + StdevLogReturns * SBMotion)

StartStockPrices = AmznData.iloc[0]

StockPrice = np.zeros_like(DailyReturns)

StockPrice[0] = StartStockPrices

for t in range(1, NumIntervals):

    StockPrice[t] = StockPrice[t - 1] * DailyReturns[t]

plt.figure(figsize=(10,5))

plt.plot(StockPrice)

AMZNTrend = np.array(AmznData.iloc[:, 0:1])

plt.plot(AMZNTrend,'k*')

plt.show()


#coding=utf-8
# 计算图像文件 '正方形面积占比计算.JPG'中粉红色区域占总正方形面积的比例

# 思路：蒙特卡洛算方法：
# 假设正方形边长为1
# 以正方形的左下角定点为直角坐标系圆点，记圆点为A（0，0）
# 正方形右下角的点为B（1，0）
# 正方形左上角的点为C（0，1）
# 正方形上面的那条边的中点为D（0.5,1）
# 记AD与BC两线的交点，即为粉红色三角形的定点为P
# 直线AD的方程式为 y = 2*x
# 直线BC的方程为   y = 1-x
# 粉红的区域的可行域为满足 y < 2*x 且 y < 1-x 且 y >0，其中x的范围为 0～1
# 正方形区域的可行域为 0<x<1;0<y<1

import numpy as np
import matplotlib.pyplot as plt

def meng_num(n):
    col_X=[]; col_y=[]
    z=np.zeros(n)
    sum=0                       # 程序刚开始的时候，没有点落入粉红色区域的可行域
    for i in range(n):
        x=np.random.rand()      # 随机生成一个值为0～1的数即记为x坐标
        y=np.random.rand()      # 随机生成一个值为0～1的数即记为y坐标
        col_X.append(x)         # 收集生成的x，留着作图用
        col_y.append(y)         # 收集生成的y，留着作图用
        if y<2*x and y < 1-x:   # 若坐标（x，y）落入粉红区域,则进行计数
            sum +=1
            z[i]=1
    area_rate=sum/len(range(n+1))   # 则粉红色区域所占正方形的概率为落入粉红色区域的点数除以总生成的随机数n
    print('当随机生成 %i 个点的时候，面积占比为： %f ' %(n,area_rate))

    #以下是可视化输出，只是把生成的点投影到区域中
    x1 = np.linspace(0, 1 / 3, 1000)
    x2 = np.linspace(1 / 3, 1, 1000)
    x3 = np.linspace(0, 1, 1000)
    y1 = 2 * x1
    y2 = 1 - x2
    y3 = 0 * x1
    plt.plot(x1, y1, x2, y2, x3, y3)
    plt.xlim(0, 1)
    plt.ylim(0, 1)
    plt.scatter(col_X,col_y,c=z,cmap='rainbow')
    plt.title('when create %i random point' %n)
    plt.show()

for n in list([10,100,1000,10000,100000]):
    meng_num(n)


import sys

import numpy as np

def bayes_theorem(P_B_A, P_A, P_B_nA):
    """An implementation of Bayes theorem.
    Evaluate the probability of event $A$ given that $B$ is true.

    Parameters
    ----------
    P_B_A : array_like
        the likelihood of event $B$ occurring given that $A$ is true.
    P_A : array_like
        the likelihood of observing $A$.
    P_B_nA : array_like
        the likelihood of observing $B$ given $A$ is false.

    Returns
    -------
    P_A_B : float
        probability of event $A$ given that $B$ is true.

    Notes
    -----
    From wikipedia:
    [Bayes Theorem](https://en.wikipedia.org/wiki/Bayes%27_theorem)
    is described as in (1.):

    1. $$P(A|B) = \frac{P(B|A)P(A)}{P(B)} $$

    Where `A` and `B` are [events](https://en.wikipedia.org/wiki/Event_(probability_theory))
    and $P(B) \\neq 0$.

    - $P(A|B)$ is a [conditional probability](https://en.wikipedia.org/wiki/Conditional_probability):
      the likelihood of event $A$ occurring _given that_ $B$ is true.
    - $P(B|A)$ is also a conditional probability: the likelihood of event $B$ occurring
      given that $A$ is true.
    - $P(A)$ and $P(B)$ are the probabilities of observing $A$ and $B$ respectively;
      they are known as the [marginal probability](https://en.wikipedia.org/wiki/Marginal_distribution).
    - $A$ and $B$ must be different events.

    However it strikes me as obfuscating to only show the denominator as $P(B)$ as it must
    be developed in order to actually evaluate this equation, as follows in (2.):

    2. $$ P(B) = P(B|A)P(A) + P(B|¬A)P(¬A) $$

    Where:
    - $P(B|¬A)$ is a conditional probability;
        the likelihood of event $B$ occurring given that $A$ is false.
    - $P(¬A)$ is the probablity of not observing $A$.

    So we need a minimum of 3 numeric inputs to run this calculation:

    1. $P(B|A)$ the likelihood
    2. $P(A)$ the normalizing constant
    3. $P(B|¬A)$

    Example
    -------
    Retrieving a Special Publication of the GeolSoc (SPGS) from my bookshelf:
    Getting a SPGS book is the test (A);
    I have 11 SPGS books on my bookshelf and a total of 44 books on that shelf
    so:

    P(A) = 11 / 44 = 0.25
    P(B|A) = 1 - P(A) = 0.75
    P(B|¬A) = 1

    >>> python bayes_theorem.py 0.75 0.25 1
    P(A|B) = 0.200

    """
    P_B_A, P_A, P_B_nA = np.array(P_B_A), np.array(P_A), np.array(P_B_nA)
    return (P_B_A * P_A) / ((P_B_A * P_A) + P_B_nA * (1 - P_A))

if __name__ == "__main__":
    try:
        P_B_A_str, P_A_str, P_B_nA_str = sys.argv[1:]
        P_B_A, P_A, P_B_nA = float(P_B_A_str), float(P_A_str), float(P_B_nA_str)
        print(f'P(A|B) = {bayes_theorem(P_B_A, P_A, P_B_nA):.3f}')
    except ValueError:
        num_vals = int((len(sys.argv) - 1) / 3)
        vals = [float(val.strip('[],')) for val in sys.argv[1:]]
        P_B_A = vals[:num_vals]
        P_A = vals[num_vals:-num_vals]
        P_B_nA = vals[-num_vals:]
        print(f'P(A|B) = {bayes_theorem(P_B_A, P_A, P_B_nA)}')


# %% codecell
# create some x and y date
from matplotlib import pyplot as plt
x_list = [-4.0, -2.0, 3.0, 4.0, 5.0, 6.0]
y_list = list()
m = 2
b = 4

for x in x_list:
    y = (m*x) + b
    y_list.append(y)

plt.plot(x_list, y_list)

# %% codecell
def lin_model_single_ele(m, x, b):
    """ Returns a single y for a given x using a line """
    return (m*x) + b

x_list = [1, 2, 3, 4, 5, 6]
y_observed = [2.11, 3.87, 6.01, 7.93, 9.99, 12.12]

y_predicted = []
m = 2
b = 4

for x in x_list:
    y = lin_model_single_ele(m, x, b)
    y_predicted.append(y)

print(y_predicted[0])
# %% codecell
def calculate_residual(y_pred, y_obs):
    """ Returns the residual of either a point or array """
    return y_pred-y_obs

residuals = []
for i in range(0, len(y_predicted)):
    residual = calculate_residual(y_predicted[i], y_observed[i])
    residuals.append(residual)

print(residuals)
# %% codecell
from statistics import mean

def calculate_ssr(y_pred, y_obs, deci=4):
    """  Calculates the Sum of Squared Residuals using the observed and predicted y"""
    res = [calculate_residual(a_i, b_i) for a_i, b_i in zip(y_pred, y_obs)]
    return round(sum([d * d for d in res]), deci)

def calculate_tss(y_obs, deci=4):
	y_mean = mean(y_obs)
	delta = [y - y_mean for y in y_obs]
	return round(sum([d * d for d in delta]), deci)

def calculate_rsquared(ssr, tss, deci=4):
	return round(1-(ssr/tss), 4)
# %% codecell
tss = calculate_tss(y_observed)
ssr = calculate_ssr(y_observed, y_predicted)
r2 = calculate_rsquared(ssr, tss)

print('SSE: %s' % ssr)
print('R^2: %s' % r2)
# %% codecell
def fit_line(x_input, y_observed, m_max=5, c_max=5, print_output=True):

	best_model = {
		'm': None,
		'c': None,
		'SSR': None,
		'R^2': None
	}
	assert len(x_input) == len(y_observed), 'Input vectors have differing lengths'

	tss = calculate_tss(y_observed)

	for m in range(1, m_max):
		for c in range(0, c_max):
			y_model = list()
			for x_i in x_input:
				y_model.append(lin_model_single_ele(m, x_i, c))

			ssr = calculate_ssr(y_observed, y_model)
			r2 = calculate_rsquared(ssr, tss)
			if print_output:
				print('#####')
				print('using: m=%s and c=%s' % (m, c))
				print('actual: %s' % y_observed)
				print('model: %s' % y_model)
				print('SSR: %s' % ssr)
				print('R^2: %s' % r2)
				print('#####')

			if best_model['SSR'] is None or best_model['SSR'] > ssr:
				best_model['m'] = m
				best_model['c'] = c
				best_model['SSR'] = ssr
				best_model['R^2'] = r2

	return best_model

# %% codecell
my_model = fit_line(x_list, y_observed, print_output=False)
print('best model: %s' % my_model)
# %% codecell
from sklearn import linear_model
import numpy as np

lm = linear_model.LinearRegression()
X = np.array(x_list).reshape(-1, 1)
Y = np.array(y_observed).reshape(-1, 1)
model = lm.fit(X, Y)
print(model.coef_)
print(model.intercept_)
print(model.score(X, Y))

# %% codecell

# %% codecell
tss = calculate_tss(y_observed)
ssr = calculate_ssr(y_observed, y_predicted)
r2 = calculate_rsquared(ssr, tss)

print('SSE: %s' % ssr)
print('R^2: %s' % r2)
# %% codecell
def fit_line(x_input, y_observed, m_max=5, c_max=5, print_output=True):

	best_model = {
		'm': None,
		'c': None,
		'SSE': None,
		'R^2': None
	}
	assert len(x_input) == len(y_observed), 'Input vectors have differing lengths'

	tss = calculate_tss(y_observed)

	for m in range(1, m_max):
		for c in range(0, c_max):
			y_model = list()
			for x_i in x_input:
				y_i = (m*x_i) + c
				y_model.append(y_i)

			ssr = calculate_ssr(y_observed, y_model)
			r2 = calculate_rsquared(ssr, tss)
			if print_output:
				print('#####')
				print('using: m=%s and c=%s' % (m, c))
				print('actual: %s' % y_observed)
				print('model: %s' % y_model)
				print('SSE: %s' % ssr)
				print('R^2: %s' % r2)
				print('#####')

			if best_model['SSE'] is None or best_model['SSE'] > ssr:
				best_model['m'] = m
				best_model['c'] = c
				best_model['SSE'] = ssr
				best_model['R^2'] = r2

	return best_model

# %% codecell
my_model = fit_line(x_list, y_observed, print_output=False)
print('best model: %s' % my_model)
# %% codecell
from sklearn import linear_model
import numpy as np

lm = linear_model.LinearRegression()
X = np.array(x).reshape(-1, 1)
Y = np.array(y).reshape(-1, 1)
model = lm.fit(X, Y)
print(lm.score(X, Y))


import sympy

##################################################################
# Function : factorize(a, n, factor_matrix)
# This function recursively divides a by n to get the largest
# multiple of n that is a divisor of a. It also checks if n is
# a prime factor because we only wanna account for prime factors
#
# In other words, repeatedly integer divides a by n, increasing
# the count of n as displayed in factor_matrix[n-1][1] by every
# time. The greatest divisor of a that is a multiple of only n
# is given by n ^ (factor_matrix[n-1][1])
#
# params : a - The number to be factored (int)
#        : n - The factor (int)
#        : factor_matrix - 2D matrix that holds the prime factors
#                          of a and the gcd of a that is a power
#                          of n.
#
# returns: nothing
#################################################################
def factorizer(a, n, factor_matrix):
    if a % n == 0 and sympy.isprime(n):  # replace with own isprime function
        factor_matrix[n-1][1] += 1
        factorizer(a//n, n, factor_matrix)
    return

##################################################################
# Function : gcd(x,y)
# Calculates the Greatest Common Divisor of x and y
#
# How the algorithm works:
# Find all the prime factors of x and y and their powers.
# GCD is set to 1 initially
# If any of x an y have common prime factors, multiply the GCD
# by the lower of the powers of the common prime factors.
#
# params : x - (int)
#        : y - (int)
#
# returns: (int) Greatest common divisor of x and y
#################################################################
def gcd(x, y):
    greatest_common_divisor = 1

########## Edge Case testing# #############
    if x == 0:
        raise ValueError("x cannot be 0")
    if y == 0:
        raise ValueError("y cannot be 0")

    if x < 0:
        x = abs(x)
    if y < 0:
        y = abs(y)

    if not isinstance(x, int):
        raise TypeError("x has to be an integer")
    if not isinstance(y, int):
        raise TypeError("y has to be an integer")

    # 1 is always a divisor of both x and y
    factor_matrix_x = [[1, 1]]     # matrix that contains the prime factors of x
    factor_matrix_y = [[1, 1]]     # matrix that contains the prime factors of y

    for i in range(2, x + 1):
        factor_matrix_x.append([i, 0])
        factorizer(x, i, factor_matrix_x)

    i = 2
    for i in range(2, y + 1):
        factor_matrix_y.append([i, 0])
        factorizer(y, i, factor_matrix_y)

    for i in range(0, len(factor_matrix_x) if len(factor_matrix_x) <= len(factor_matrix_y) else len(factor_matrix_y)):
        if factor_matrix_x[i][1] == 0 or factor_matrix_y[i][1] == 0:
            continue
        elif factor_matrix_x[i][1] <= factor_matrix_y[i][1]:
            greatest_common_divisor *= pow(factor_matrix_x[i][0], factor_matrix_x[i][1])
        else:
            greatest_common_divisor *= pow(factor_matrix_y[i][0], factor_matrix_y[i][1])

    return greatest_common_divisor


import numpy as np
from Exercise5.util import matrix_mult, transpose, matrix_vector_mult
from Exercise5.lu_decomposition import lu

def least_squares_fit(x, y, degree=10):
    """
        Computes the coefficients of the degree degree polynomial of the least squares fit.
Constant term
        first.

        Parameters
        ----------
        x : list
            The values of the independent variable.
        y : list
            The values of f(x) for every x, where x is the independent variable
        degree : int
            The degree of the polynomial model fitting the data.

        Returns
        -------
        c : list
            coefficients of interpolating polynomial
    """
    # construct A
    a = []
    for row in range(len(x)):
        a.append([])
        for column in range(degree):
            a[row].append(x[row]**column)
    # construct A^T * A
    a_transpose = transpose(a)
    a_transpose_a = matrix_mult(a_transpose, a)

    # solve (A^T * A) * x = A^T * y
    return lu(a_transpose_a, matrix_vector_mult(a_transpose, y))

def calculate_polynomial(c, x, degree=10):
    """
        Computes the value of the degree degree least squares fit polynomial.

        Parameters
        ----------
        c : list
            The coefficients of the degree degree polynomial. Constant term first.

        x : int
            The point at which the polynomial will be calculated
        degree : int
            The degree of the polynomial model that was used when fitting the data.

        Returns
        -------
        return_value : float
            The value of the interpolating polynomial at point x.
    """
    return_value = 0.0
    for i in range(degree):
        return_value += c[i] * (x ** i)
    return return_value

def custom_sin(value, d=10):
    """
        Approximates sin curve with least squares using d degree polynomial model.

        Parameters
        ----------
        value : float
            The point at which the sin will be approximated
        d : int
            The degree of the polynomial model fitting the data.

        Returns
        -------
        float
            The approximation value of the sin curve at point x.
    """
    x = [0.0, 0.65, 1.3, 1.9500000000000002, 2.6, 3.25, 3.9000000000000004, 4.55, 5.2, 2*np.pi]
    y = [0.0, 0.6051864057, 0.9635581854, 0.9289597150, 0.5155013718, -0.1081951345, -0.6877661591, -0.9868438585,
         -0.8834546557, 0]
    c = least_squares_fit(x, y, degree=d)

    value = value % (2*np.pi)
    return calculate_polynomial(c, value, degree=d)