from typing import Callable
import numpy as np
from scipy import stats

def chi_square(result_distribution:np.ndarray, expected_distribution:np.ndarray) -> float:
    # https://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test
    assert(len(result_distribution)==len(expected_distribution))
    not_zero = np.where(expected_distribution != 0)[0]
    return stats.chisquare(result_distribution[not_zero], expected_distribution[not_zero]).statistic

def kullback_leibler_divergence(result_distribution:np.ndarray, expected_distribution:np.ndarray) -> float:
    # https://en.wikipedia.org/wiki/Kullback%E2%80%93Leibler_divergence
    assert(len(result_distribution)==len(expected_distribution))
    return stats.entropy(result_distribution, expected_distribution)

def bhattacharyya_difference(dist_1:np.ndarray, dist_2:np.ndarray) -> float:
    # https://en.wikipedia.org/wiki/Bhattacharyya_distance
    assert(len(dist_1)==len(dist_2))
    bc = np.sum(np.sqrt(dist_1*dist_2))
    if bc == 0:
        return np.inf
    return - np.log(bc)

def fidelity(dist_1:np.ndarray, dist_2:np.ndarray) -> float:
    return np.power(np.sum(np.sqrt(dist_1*dist_2)), 2)

def metric_diff(result_dist_1:np.ndarray, result_dist_2:np.ndarray, expected_dist:np.ndarray, metric:Callable[[np.ndarray, np.ndarray], float]) -> float:
    m_1 = metric(result_dist_1, expected_dist)
    m_2 = metric(result_dist_2, expected_dist)
    return m_1 - m_2

def same_max(result_dist:np.ndarray, expected_dist:np.ndarray) -> bool:
    return np.argmax(result_dist) == np.argmax(expected_dist)

def same_order(result_dist:np.ndarray, expected_dist:np.ndarray) -> bool:
    return (np.argsort(result_dist) == np.argsort(expected_dist)).all()

if __name__ == "__main__":
    a = np.array([0,0,1,0])
    b = np.array([0,1,0,0])
    c = np.array([1,1,1,1])/4

    print("chi_square")
    print(chi_square(a, b))
    print(chi_square(a, c))
    print("kullback_leibler_divergence")
    print(kullback_leibler_divergence(a, b))
    print(kullback_leibler_divergence(a, c))
    print("bhattacharyya_difference")
    print(bhattacharyya_difference(a, b))
    print(bhattacharyya_difference(a, c))


import numpy as np

def mean_squared_error(estimates, targets):
    """
    Mean squared error measures the average of the square of the errors (the
    average squared difference between the estimated values and what is
    estimated. The formula is:

    MSE = (1 / n) * sum_{i=1}^{n} (Y_i - Yhat_i)^2

    Args:
        estimates(np.ndarray): the estimated values (should be the same shape as targets)
        targets(np.ndarray): the ground truth values

    Returns:
        MSE(int): mean squared error calculated by above equation
    """

    MSE_matrix = []
    n = targets.shape[0]
    for i in range(n):
        MSE_matrix.append(np.linalg.norm(estimates[i] - targets[i])**2)
    MSE = sum(MSE_matrix)/n
    return MSE


import numpy as np

#1)input:directed graph and parameter beta
beta = 0.9
dic = np.loadtxt("web-Google.txt",dtype='int')
dic_1 = dic[:,0]
dic_2 = dic[:,1]
from_nodes = np.sort(dic_1)
node_ind = np.argsort(dic_1)
to_nodes = dic_2[node_ind]
dic_sorted = np.transpose(np.vstack([from_nodes, to_nodes]))

all_nodes = np.sort(dic_sorted, axis=None)
fdn, f_counts = np.unique(from_nodes,return_counts=True)
aln = np.unique(all_nodes)
array_l=len(aln)
r_old = np.ones((array_l),dtype=float)/array_l
epson = 1

#2)output :pagerank
while epson>0.0001:
	dic_count = 0
	for i in range(len(fdn)):
            print 'i =', i
	    r_new = (1-beta)*np.ones((array_l),dtype=float)/array_l
	    f_ind = np.argwhere(aln==fdn[i])
	    add = r_old[f_ind]/f_counts[i]
	    for j in range(f_counts[i]):
                print 'j = ', j
		to_ind = np.argwhere(aln==to_nodes[dic_count])
		r_new[to_ind]+=beta*add
		dic_count+=1
        diff_r = r_new - r_old
        epson = np.dot(np.transpose(diff_r),diff_r)/np.dot(np.transpose(r_old),r_old)
        r_old = r_new
        print 'epson=', epson

indice = np.argsort(r_new)

sorted_scores = np.sort(r_new)
sorted_nodes = aln[indice]
for i in range(array_l):
   index = -i-1
   print sorted_nodes[index], sorted_scores[index]


# -*- coding: utf-8 -*-
"""
Created on Wed Sep 27 20:02:04 2017

@author: USER
"""
import math
from scipy.stats import norm

def blscall(S,L,T,r,sigma):
    d1 = (math.log(S/L)+(r+0.5*sigma*sigma)*T)/(sigma*math.sqrt(T))
    d2 = d1- sigma*math.sqrt(T)
    return S*norm.cdf(d1)-L*math.exp(-r*T)*norm.cdf(d2)

def Bisection2(left,right,S,L,T,r,call,error):
    center = (left+right)/2
    if((right-left)/2<error):
        return center
    if((blscall(S,L,T,r,left)-call)*(blscall(S,L,T,r,center)-call)<0):
        return Bisection2(left,center,S,L,T,r,call,error)
    else:
        return Bisection2(center,right,S,L,T,r,call,error)

def Newton2(initsigma,S,L,T,r,call,iteration):
    sigma = initsigma
    for i in range(iteration):
        fx = blscall(S,L,T,r,sigma)-call
        fx2 = (blscall(S,L,T,r,sigma+0.00000001)-blscall(S,L,T,r,sigma-0.00000001))/0.00000002;
        sigma = sigma - fx/fx2
    return sigma

S = 10326.68
L = 10300.0
T = 21.0/365
r = 0.01065
sigma = 0.10508

print(blscall(S,L,T,r,sigma))
sigma = Bisection2(0.0000001,1,S,L,T,r,121.0,0.000000001)
print(sigma)
print(blscall(S,L,T,r,sigma))
print(Newton2(0.5,S,L,T,r,121.0,10))


import scipy.optimize

# Objective Function: 50x_1 + 80x_2
# Constraint 1: 5x_1 + 2x_2 <= 20
# Constraint 2: -10x_1 + -12x_2 <= -90

result = scipy.optimize.linprog(
    [50, 80],  # Cost function: 50x_1 + 80x_2
    A_ub=[[5, 2], [-10, -12]],  # Coefficients for inequalities
    b_ub=[20, -90],  # Constraints for inequalities: 20 and -90
)

if result.success:
    print(f"X1: {round(result.x[0], 2)} hours")
    print(f"X2: {round(result.x[1], 2)} hours")
else:
    print("No solution")

HarvardX/CS50's Intro to AI with Python/Part1/src3/production/production.py


import numpy as np

def Rx(theta):
    return np.array([[1, 0, 0 , 0],
                    [0, np.cos(theta),-np.sin(theta), 0],
                    [0, np.sin(theta), np.cos(theta), 0],
                    [0,            0,              0,  1]])

def Rz(theta):
    return np.array([[ np.cos(theta), -np.sin(theta), 0 , 0 ],
                    [ np.sin(theta), np.cos(theta) , 0 , 0],
                    [ 0           , 0            , 1 , 0],
                     [0            ,0          ,0     ,1]])

def Tz(z):
    return np.array([[1,0,0,0],
                    [0,1,0,0,],
                    [0,0,1,z],
                    [0,0,0,1]])

def Tx(x):
    return np.array([[1,0,0,x],
                    [0,1,0,0],
                    [0,0,1,0],
                    [0,0,0,1]])

def Amat(theta,d,a,alpha):
    return Rz(theta) @ Tz(d) @ Tx(a) @ Rx(alpha)

def Tmat(dh):
    T = np.eye(4)
    if dh.size < 5:
        T = Amat(dh[0], dh[1], dh[2], dh[3])
    else:
        num_frame, _ = np.shape(dh)
        for k in range(num_frame):
                T = T @ Amat(dh[k,0], dh[k,1], dh[k,2], dh[k,3])

    return T


import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from mpl_toolkits.mplot3d import Axes3D

def rossler(x, y, z, a, b, c):
    """ Rössler System of Ordinary Differential Equations """
    dx = - y - z
    dy = x + a*y
    dz = b + z*(x - c)

    return dx, dy, dz

def solver(x, y, z, t, a, b, c):
    """ Euler's Method to solve the ODEs associated with the Rössler Attractor """
    for i in range(len(t)-1):
        # calculate derivatives
        dx, dy, dz = rossler(x[i], y[i], z[i], a, b, c)

        x[i + 1] = x[i] + (dx * (t[i+1]-t[i]))
        y[i + 1] = y[i] + (dy * (t[i+1]-t[i]))
        z[i + 1] = z[i] + (dz * (t[i+1]-t[i]))

def plot_rossler(x_1, y_1, z_1, t, x_2, y_2, z_2):
    fig = plt.figure(figsize=(14, 7))
    fig.set_facecolor('#E8E6E6')

    ax1 = fig.add_subplot(1, 2, 1, projection='3d')
    line, = ax1.plot([], [], [], color='b', linewidth=0.5, label='$(x_1, y_1, z_1): IC = (0.1, 0., 0.1)$')
    line2, = ax1.plot([], [], [], color='r', linewidth=0.5, label='$(x_2, y_2, z_2): IC = (0.1001, 0., 0.1001)$')

    point, = ax1.plot([], [], [], marker='o', color='b', markersize=4)
    point2, = ax1.plot([], [], [], marker='o', color='r', markersize=4)

    ax1.set_facecolor('#E8E6E6')
    ax1.xaxis.set_pane_color((1.0, 1.0, 1.0, 1.0))
    ax1.yaxis.set_pane_color((1.0, 1.0, 1.0, 1.0))
    ax1.zaxis.set_pane_color((1.0, 1.0, 1.0, 1.0))

    # set point-of-view: specified by (altitude degrees, azimuth degree)
    ax1.view_init(elev=23, azim=-131)

    # set limits
    ax1.set_xlim(-10, 15)
    ax1.set_ylim(-15, 10)
    ax1.set_zlim(0, 25)

    # set axis labels
    ax1.set_xlabel('X', fontsize=12)
    ax1.set_ylabel('Y', fontsize=12)
    ax1.set_zlabel('Z', fontsize=12)

    # remove tick labels
    ax1.set_yticklabels([])
    ax1.set_xticklabels([])
    ax1.set_zticklabels([])

    # legend
    ax1.legend(loc=(0.2, -0.08), fancybox=True, facecolor='white', edgecolor='black', frameon=True)

    # set title
    ax1.set_title('Phase Space: Trajectories', fontsize=14)

    # plot x_1 and x_2 values against time
    ax2 = fig.add_subplot(2, 2, 2)
    line3, = ax2.plot([], [], 'b-', linewidth=0.8)
    line4, = ax2.plot([], [], 'r-', linewidth=0.8)

    point3, = ax2.plot([], [], marker='o', color='b', markersize=4)
    point4, = ax2.plot([], [], marker='o', color='r', markersize=4)

    ax2.set_xlim(t[0], t[len(t)-1])
    ax2.set_ylim(-10, 12.5)
    ax2.set_ylabel('x(t)', fontsize=12)
    ax2.set_title('$Solutions: x_1 (Blue), x_2 (Red)$', fontsize=14)

    # plot difference (x2-x1)
    difference = np.absolute(x_2 - x_1)
    ax3 = fig.add_subplot(2, 2, 4)
    line5, = ax3.plot([], [], 'g-', linewidth=0.8)

    point5, = ax3.plot([], [], marker='o', color='g', markersize=4)

    ax3.set_xlim(t[0], t[len(t)-1])
    ax3.set_ylim(-0.5, 8)
    ax3.set_ylabel('$|x_2 - x_1|$', fontsize=12)
    ax3.set_xlabel('time (s)', fontsize=12)
    ax3.set_title('$Difference: |x_2 - x_1|$', fontsize=14)

    plt.subplots_adjust(left=0.125, bottom=0.1, right=0.9, top=0.9, wspace=0.2, hspace=0.35)

    def update(i):
        i = 250*i
        if i >= 300000:
            i = 300000-1

        xq_1 = x_1[0:i]
        yq_1 = y_1[0:i]
        zq_1 = z_1[0:i]

        xq_2 = x_2[0:i]
        yq_2 = y_2[0:i]
        zq_2 = z_2[0:i]

        tq = t[0:i]

        line.set_data(xq_1, yq_1)
        line.set_3d_properties(zq_1)
        point.set_data(x_1[i], y_1[i])
        point.set_3d_properties(z_1[i])

        line2.set_data(xq_2, yq_2)
        line2.set_3d_properties(zq_2)
        point2.set_data(x_2[i], y_2[i])
        point2.set_3d_properties(z_2[i])

        line3.set_data(tq, xq_1)
        point3.set_data(t[i], x_1[i])

        line4.set_data(tq, xq_2)
        point4.set_data(t[i], x_2[i])

        line5.set_data(tq, difference[0:i])
        point5.set_data(t[i], difference[i])

        return line, line2, line3, line4, line5, point, point2, point3, point4, point5

    # instantiate the animator
    ani = FuncAnimation(fig, update, frames=np.size(x_1), interval=0, blit=True)

    plt.show()

    # save as mp4. This requires mplayer or ffmpeg to be installed
    # anim.save('RosslerAttractor.mp4', fps=15, extra_args=['-vcodec', 'libx264'])

def main():
    # parameters
    a = 0.2
    b = 0.2
    c = 5.7

    # time interval and the step size
    t = np.arange(0, 300, 0.001)

    # vectors for the solutions
    x_1 = np.zeros((len(t)))
    y_1 = np.zeros((len(t)))
    z_1 = np.zeros((len(t)))

    x_2 = np.zeros((len(t)))
    y_2 = np.zeros((len(t)))
    z_2 = np.zeros((len(t)))

    # initial conditions
    x_1[0], y_1[0], z_1[0] = (0.1, 0., 0.1)
    x_2[0], y_2[0], z_2[0] = (0.1001, 0., 0.1001)

    solver(x_1, y_1, z_1, t, a, b, c)
    solver(x_2, y_2, z_2, t, a, b, c)

    plot_rossler(x_1, y_1, z_1, t, x_2, y_2, z_2)

if __name__ == "__main__":
    main()


import logging

import numpy as np
from scipy.special import gamma

class AnalyticalGammaToGumbel:
    """
    Compute relevant quantities related to the Gumbel distribution arising from the
    maximum over an ensemble of iid Gamma-distributed random variables (which includes
    the chi-squared distribution as a special case).
    """

    def __init__(self, dofs=None, shape=None, scale=None, rate=None):
        """
        The single-variable probability distribution can either be described as a
        chi-squared distribution with `dofs` degrees of freedom,
        a Gamma distribution with shape and scale parameters (`shape`, `scale`),
        or a Gamma distribution with shape and rate parameters (`shape`, `rate`).

        A chi-squared distribution with `dofs` degrees of freedom corresponds to a
        Gamma distribution with `shape=dofs/2` and `scale=2`, `rate=1/2`.

        Parameters
        ----------
        dofs: float, optional
            Degrees of freedom of the underlying chi-squared distribution.
            Authomatically implies `shape=dofs/2` and `scale=2`.
            This parameter is incompatible with `shape`, `scale`, and `rate`.
        shape: float, optional
            Shape parameter of the underlying Gamma distribution.
            This parameter must be given jointly with `scale` or `rate`
            and is incompatible with `dofs`.
        scale: float, optional
            Scale parameter of the underlying gamma distribution
            (inverse of the rate parameter).
            This parameter must be given jointly with `shape` and is
            incompatible with `dofs` or `rate`.
        rate: float, optional
            Rate parameter of the underlying gamma distribution
            (inverse of the scale parameter).
            This parameter must be given jointly with `shape` and is
            incompatible with `dofs` or `scale`.
        """

        # Check the validity of the input
        if dofs:
            if shape:
                raise ValueError("Only one out of dofs and shape can be given")
            shape = dofs / 2
            scale = 2.
        elif shape:
            if not (bool(scale) ^ bool(rate)):
                raise ValueError("Only one out of scale and rate can be given")
            elif rate:
                scale = 1 / rate
        else:
            raise ValueError("Invalid input parameters: "
                    "Please enter dofs, (scale, shape) or (scale, rate)")

        self._set_shape_scale(shape=shape, scale=scale)

    def _set_shape_scale(self, shape, scale):
        self.shape = shape
        self.scale = scale

    def get_gumbel_loc_scale(self, n, improved=True):
        """
        Compute the theoretical estimation of the location and scale parameters of the
        Gumbel distribution resulting from maximizing over a batch of `n` independent
        random variables following the distribution specified by this class.

        We provide two implementations of said parameters, selected by
        switching the `improved` flag.

        If improved is falsy, location and scale parameters are taken from table 3.4.4
        in "Modelling Extremal Events for Insurance and Finance", P. Embrechts,
        C. Klüppelberg, T. Mikosch (1997) https://doi.org/10.1007/978-3-642-33483-2.

        If improved is truthy (recommended), location and scale parameters are taken
        from Eqs. (32) and (33) in  Gasull, López-Salcedo, and Utzet, TEST 24, 714–733
        (2015) https://doi.org/10.1007/s11749-015-0431-9 .

        The improved option returns better estimates for n < 1e6 (and possibly beyond).

        Parameters
        ----------
        n: int
            Number of random variables within the batch being maximized.
        improved: bool
            If True (recommended), apply the improved loc and scale parameters. See
            the main docstring for details.

        Returns
        -------+
        loc: float
            Location parameter of the resulting Gumbel distribution.
        scale: float
            Scale parameter of the resulting Gumbel distribution.
        """

        logn = np.log(n)
        gamma_shape = gamma(self.shape)

        if improved:
            logn_gamma = np.log(n / gamma_shape)
            shape_m1 = self.shape - 1
            Bn = logn_gamma + shape_m1 * np.log(shape_m1)
            logBn = np.log(Bn)

            loc = self.scale * (
                logn_gamma
                + shape_m1 * logBn
                + (shape_m1 * shape_m1 * (logBn - np.log(shape_m1)) + shape_m1) / Bn
            )
            scale = (self.scale * loc * (self.scale * shape_m1 + loc)) / (
                loc * loc - self.scale * self.scale * shape_m1 * (self.shape - 2)
            )

        else:
            loc = self.scale * (
                logn + (self.shape - 1) * np.log(logn) + np.log(gamma_shape)
            )
            scale = self.scale

        return loc, scale

    def get_gumbel_mean_std(self, n, improved=True):
        """
        Compute the theoretical estimation of the mean and standard deviation parameters
        of the Gumbel distribution resulting from maximizing over a batch of `n` independent
        random variables following the distribution specified by this class.

        These results computed from the `loc` and `scale` parameters returned by
        `self.gumbel_mean_std`. See the docstring therein for a further explanation of the
        parameters.

        Parameters
        ----------
        n: int
            Number of random variables within the batch being maximized.
        improved: bool
            If True (recommended), apply the improved loc and scale parameters. See
            the main docstring for details.

        Returns
        -------
        mean: float
            Mean of the Gumbel distribution, computed as `loc + euler_gamma * scale`,
            where `euler_gamma=0.5772...` represents the Euler-Mascheroni constant
            (sequence A001620 in the OEIS).
        std: float
            Standard deviation of the Gumbel distribution,
            computed as `pi/sqrt(6) * scale`.
        """
        loc, scale = self.get_gumbel_loc_scale(n=n, improved=improved)
        mean = loc + np.euler_gamma * scale
        std = np.pi / np.sqrt(6) * scale
        return mean, std


'''Compute decibels dB(x) = 10.*log10(|x|).'''

import numpy as np
# convert X to decibels
def dB(X,floor=None):
  if (floor != None):
    return 10.*np.log10(np.maximum(floor, np.abs(X)))
  else:
    return 10.*np.log10(np.abs(X))


# https://github.com/pymc-devs/resources/blob/master/Rethinking/Chp_02.ipynb

#%matplotlib inline
import pymc3 as pm
import numpy as np
import scipy.stats as stats
import matplotlib.pyplot as plt

#%config InlineBackend.figure_format = 'retina'
plt.style.use(['seaborn-colorblind', 'seaborn-darkgrid'])

ways = np.array([0, 3, 8, 9, 0])
ways / ways.sum()

stats.binom.pmf(6, n=9, p=0.5)

def posterior_grid_approx(grid_points=5, success=6, tosses=9):
    """
    """
    # define grid
    p_grid = np.linspace(0, 1, grid_points)

    # define prior
    prior = np.repeat(5, grid_points)  # uniform
    #prior = (p_grid >= 0.5).astype(int)  # truncated
    #prior = np.exp(- 5 * abs(p_grid - 0.5))  # double exp

    # compute likelihood at each point in the grid
    likelihood = stats.binom.pmf(success, tosses, p_grid)

    # compute product of likelihood and prior
    unstd_posterior = likelihood * prior

    # standardize the posterior, so it sums to 1
    posterior = unstd_posterior / unstd_posterior.sum()
    return p_grid, posterior

points = 20
w, n = 6, 9
p_grid, posterior = posterior_grid_approx(points, w, n)
plt.figure()
plt.plot(p_grid, posterior, 'o-', label='success = {}\ntosses = {}'.format(w, n))
plt.xlabel('probability of water', fontsize=14)
plt.ylabel('posterior probability', fontsize=14)
plt.title('{} points'.format(points))
plt.legend(loc=0);
plt.show()

data = np.repeat((0, 1), (3, 6))
with pm.Model() as normal_aproximation:
    p = pm.Uniform('p', 0, 1)
    w = pm.Binomial('w', n=len(data), p=p, observed=data.sum())
    mean_q = pm.find_MAP()
    std_q = ((1/pm.find_hessian(mean_q, vars=[p]))**0.5)[0]
mean_q['p'], std_q

norm = stats.norm(mean_q, std_q)
prob = .89
z = stats.norm.ppf([(1-prob)/2, (1+prob)/2])
pi = mean_q['p'] + std_q * z
pi

# analytical calculation
w, n = 6, 9
x = np.linspace(0, 1, 100)
plt.figure()
plt.plot(x, stats.beta.pdf(x , w+1, n-w+1),
         label='True posterior')

# quadratic approximation
plt.plot(x, stats.norm.pdf(x, mean_q['p'], std_q),
         label='Quadratic approximation')
plt.legend(loc=0, fontsize=13)

plt.title('n = {}'.format(n), fontsize=14)
plt.xlabel('Proportion water', fontsize=14)
plt.ylabel('Density', fontsize=14);
plt.show()


import numpy as np
import kmeans
import common
import naive_em
import em

X = np.loadtxt("toy_data.txt")

########## Begin: kMeans vs EM (and BIC) #############
K = [1, 2, 3, 4]    # Clusters to try
seeds = [0, 1, 2, 3, 4]     # Seeds to try

# Costs for diff. seeds
costs_kMeans = [0, 0, 0, 0, 0]
costs_EM = [0, 0, 0, 0, 0]

# Best seed for cluster based on lowest costs
best_seed_kMeans = [0, 0, 0, 0]
best_seed_EM = [0, 0, 0, 0]

# Mixtures for best seeds
mixtures_kMeans = [0, 0, 0, 0, 0]
mixtures_EM = [0, 0, 0, 0, 0]

# Posterior probs. for best seeds
posts_kMeans = [0, 0, 0, 0, 0]
posts_EM = [0, 0, 0, 0, 0]

# BIC score of cluster
bic = [0., 0., 0., 0.]

for k in range(len(K)):
    for i in range(len(seeds)):

        # Run kMeans
        mixtures_kMeans[i], posts_kMeans[i], costs_kMeans[i] = \
        kmeans.run(X, *common.init(X, K[k], seeds[i]))

        # Run Naive EM
        mixtures_EM[i], posts_EM[i], costs_EM[i] = \
        naive_em.run(X, *common.init(X, K[k], seeds[i]))

    # Print lowest cost
    print("=============== Clusters:", k+1, "======================")
    print("Lowest cost using kMeans is:", np.min(costs_kMeans))
    print("Highest log likelihood using EM is:", np.max(costs_EM))

    # Save best seed for plotting
    best_seed_kMeans[k] = np.argmin(costs_kMeans)
    best_seed_EM[k] = np.argmax(costs_EM)

    # Plot kMeans and EM results
    common.plot(X,
                mixtures_kMeans[best_seed_kMeans[k]],
                posts_kMeans[best_seed_kMeans[k]],
                title="kMeans")

    common.plot(X,
                mixtures_EM[best_seed_EM[k]],
                posts_EM[best_seed_EM[k]],
                title="EM")

    #BIC score for EM
    bic[k] = common.bic(X, mixtures_EM[best_seed_EM[k]], np.max(costs_EM))

# Print the best K based on BIC
print("================= BIC ====================")
print("Best K is:", np.argmax(bic)+1)
print("BIC for the best K is:", np.max(bic))

########## End: kMeans vs EM (and BIC) #############


# ToDo: Properly document this module
"""This module contains functions used by other modules in the pterasoftware package.

"""
import logging

import numpy as np
from numba import njit, prange

def cosspace(
    minimum,
    maximum,
    n_points=50,
    endpoint=True,
):
    """This function is used to create a array containing a specified number of
    values between a specified minimum and maximum value that are spaced via a cosine
    function.

    Citation:
        Adapted from:         geometry.cosspace in AeroSandbox
        Author:               Peter Sharpe
        Date of Retrieval:    04/28/2020

    :param minimum: float
        This is the minimum value of the range of numbers you would like spaced.
    :param maximum: float
        This is the maximum value of the range of numbers you would like spaced.
    :param n_points: int, optional
        This is the number of points to space. The default is 50.
    :param endpoint: bool, optional
        This sets whether or not the maximum value will be included in the output.
        The default is True.
    :return cosine_spaced_points: 1D array
        This is a 1D array of the points, ranging from the minimum to the maximum
        value (inclusive), spaced via a cosine function.
    """
    # Find the mean and the amplitude of the cosine function.
    mean = (maximum + minimum) / 2
    amp = (maximum - minimum) / 2

    # Space the points by applying cosine to the linspace function. Then return the
    # points.
    cosine_spaced_points = mean + amp * np.cos(
        np.linspace(np.pi, 0, n_points, endpoint=endpoint)
    )
    return cosine_spaced_points

def reflect_over_xz_plane(input_vector):
    """This function is used to flip a the y coordinate of a coordinate vector.

    Citation:
        Adapted from:         geometry.reflect_over_xz_plane in AeroSandbox
        Author:               Peter Sharpe
        Date of Retrieval:    04/28/2020

    :param input_vector: array
        This can either be a 1D array of three items, a M x 3 2D array, or a M x
        N x 3 3D array. N and
        represent arbitrary numbers of rows or columns.
    :return output vector: array
        This is a array with each vertex's y variable flipped.
    """
    # Initialize the output vector.
    output_vector = input_vector

    # Find the shape of the input vector.
    shape = np.shape(output_vector)

    # Characterize the input vector.
    if len(shape) == 1 and shape[0] == 3:
        # The input vector is a 1D array of 3 items. Flip the vertex's y variable.
        output_vector = output_vector * np.array([1, -1, 1])
    elif len(shape) == 2 and shape[1] == 3:
        # The input vector is a 2D array of shape M x 3. Where M is some arbitrary
        # number of rows. Flip each
        # vertex's y variable.
        output_vector = output_vector * np.array([1, -1, 1])
    elif len(shape) == 3 and shape[2] == 3:  # 3D MxNx3 vector
        # The input vector is a 3D array of shape M x N x 3. Where M is some
        # arbitrary number of rows, and N is
        # some arbitrary number of columns. Flip each vertex's y variable.
        output_vector = output_vector * np.array([1, -1, 1])
    else:
        # The input vector is an unacceptable shape. Throw an error.
        raise Exception("Invalid input for reflect_over_xz_plane.")

    # Return the output vector.
    return output_vector

def angle_axis_rotation_matrix(angle, axis, axis_already_normalized=False):
    """This function is used to find the rotation matrix for a given axis and angle.

    Citation:
        Adapted from:         geometry.angle_axis_rotation_matrix in AeroSandbox
        Author:               Peter Sharpe
        Date of Retrieval:    04/28/2020

    For more information on the math behind this method, see:
    https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle

    :param angle: float or 1D array of 3 angles
        This is the angle. Provide it in radians.
    :param axis: 1D array of 3 elements.
        This is the axis.
    :param axis_already_normalized: bool, optional
        Set this as True if the axis given is already normalized, which will skip
        internal normalization and speed up the method. If not, set as False. The
        default is False.
    :return rotation matrix: array
        This is the rotation matrix. If the given angle is a scalar, this will be a 3
        x 3 array. If the given angle is a vector, this will be a 3 x 3 x N array.
    """
    # Normalize the axis is it is not already normalized.
    if not axis_already_normalized:
        axis = axis / np.linalg.norm(axis)

    # Define constants to use when calculating the rotation matrix.
    sin_theta = np.sin(angle)
    cos_theta = np.cos(angle)
    u_x = axis[0]
    u_y = axis[1]
    u_z = axis[2]

    # Calculate the rotation matrix.
    rotation_matrix = np.array(
        [
            [
                cos_theta + u_x ** 2 * (1 - cos_theta),
                u_x * u_y * (1 - cos_theta) - u_z * sin_theta,
                u_x * u_z * (1 - cos_theta) + u_y * sin_theta,
            ],
            [
                u_y * u_x * (1 - cos_theta) + u_z * sin_theta,
                cos_theta + u_y ** 2 * (1 - cos_theta),
                u_y * u_z * (1 - cos_theta) - u_x * sin_theta,
            ],
            [
                u_z * u_x * (1 - cos_theta) - u_y * sin_theta,
                u_z * u_y * (1 - cos_theta) + u_x * sin_theta,
                cos_theta + u_z ** 2 * (1 - cos_theta),
            ],
        ]
    )

    # Return the rotation matrix.
    return rotation_matrix

@njit(cache=True)
def numba_centroid_of_quadrilateral(
    front_left_vertex, front_right_vertex, back_left_vertex, back_right_vertex
):
    """This function is used to find the centroid of a quadrilateral. It has been
    optimized for JIT compilation using Numba.

    :param front_left_vertex: 1D array of floats
        This is an array containing the x, y, and z components of the front left
        vertex of the quadrilateral.
    :param front_right_vertex: 1D array of floats
        This is an array containing the x, y, and z components of the front right
        vertex of the quadrilateral.
    :param back_left_vertex: 1D array of floats
        This is an array containing the x, y, and z components of the back left
        vertex of the quadrilateral.
    :param back_right_vertex: 1D array of floats
        This is an array containing the x, y, and z components of the back right
        vertex of the quadrilateral.
    :return: 1D array of floats
        This is an array containing the x, y, and z components of the centroid of the
        quadrilateral.
    """
    x_average = (
        front_left_vertex[0]
        + front_right_vertex[0]
        + back_left_vertex[0]
        + back_right_vertex[0]
    ) / 4
    y_average = (
        front_left_vertex[1]
        + front_right_vertex[1]
        + back_left_vertex[1]
        + back_right_vertex[1]
    ) / 4
    z_average = (
        front_left_vertex[2]
        + front_right_vertex[2]
        + back_left_vertex[2]
        + back_right_vertex[2]
    ) / 4

    return np.array([x_average, y_average, z_average])

def calculate_streamlines(solver, num_steps=25, delta_time=0.02):
    """Calculates the location of the streamlines coming off the back of the wings.

    This method is vectorized to increase performance.

    :param solver: Solver
        This is the solver object for which to calculate the streamlines.
    :param num_steps: int, optional
        This is the integer number of points along each streamline (not including the
        initial points). It can be increased for higher fidelity visuals. The default
        value is 25.
    :param delta_time: float, optional
        This is the time in seconds between each time current_step It can be
        decreased for higher fidelity visuals or to make the streamlines shorter.
        It's default value is 0.02 seconds.
    :return: None
    """
    # Initialize a array to hold this solver's matrix of streamline points.
    solver.streamline_points = np.expand_dims(solver.seed_points, axis=0)

    # Iterate through the streamline steps.
    for step in range(num_steps):
        # Get the last row of streamline points.
        last_row_streamline_points = solver.streamline_points[-1, :, :]

        # Add the freestream velocity to the induced velocity to get the total
        # velocity at each of the last row of streamline points.
        total_velocities = solver.calculate_solution_velocity(
            points=last_row_streamline_points
        )

        # Interpolate the positions on a new row of streamline points.
        new_row_streamline_points = (
            last_row_streamline_points + total_velocities * delta_time
        )

        # Stack the new row of streamline points to the bottom of the matrix of
        # streamline points.
        solver.streamline_points = np.vstack(
            (
                solver.streamline_points,
                np.expand_dims(new_row_streamline_points, axis=0),
            )
        )

def convert_logging_level_name_to_value(name):
    """This function takes in a string that represents the the logging level and
    returns the integer that can be used to set the logger to this level.

    :param name: str
        This is the string representation of the logging level. The options are
        "Debug", "Info", "Warning", "Error", and "Critical".
    :return: int
        This is the integer value that can used to set the appropriate logging level.
    """
    logging_levels = {
        "Debug": logging.DEBUG,
        "Info": logging.INFO,
        "Warning": logging.WARNING,
        "Error": logging.ERROR,
        "Critical": logging.CRITICAL,
    }
    try:
        return logging_levels[name]
    except KeyError:
        raise Exception("The name of the logging level provided is not a valid option.")

# ToDo: Update this function's documentation.
def process_steady_solver_forces(
    steady_solver, near_field_forces_geometry_axes, near_field_moments_geometry_axes
):
    """

    :param steady_solver:
    :param near_field_forces_geometry_axes:
    :param near_field_moments_geometry_axes:
    :return:
    """
    # Initialize a variable to hold the global panel position.
    global_panel_position = 0

    # Iterate through this solver's panels.
    for panel in steady_solver.panels:
        # Update the force and moment on this panel.
        panel.near_field_force_geometry_axes = near_field_forces_geometry_axes[
            global_panel_position, :
        ]
        panel.near_field_moment_geometry_axes = near_field_moments_geometry_axes[
            global_panel_position, :
        ]

        # Update the pressure on this panel.
        panel.update_pressure()

        # Increment the global panel position.
        global_panel_position += 1

    # Sum up the near field forces and moments on every panel to find the total
    # force and moment on the geometry.
    total_near_field_force_geometry_axes = np.sum(
        near_field_forces_geometry_axes, axis=0
    )
    total_near_field_moment_geometry_axes = np.sum(
        near_field_moments_geometry_axes, axis=0
    )

    # Find the total near field force in wind axes from the rotation matrix and
    # the total near field force in geometry axes.
    steady_solver.airplane.total_near_field_force_wind_axes = (
        np.transpose(
            steady_solver.operating_point.calculate_rotation_matrix_wind_axes_to_geometry_axes()
        )
        @ total_near_field_force_geometry_axes
    )

    # Find the total near field moment in wind axes from the rotation matrix and
    # the total near field moment in geometry axes.
    steady_solver.airplane.total_near_field_moment_wind_axes = (
        np.transpose(
            steady_solver.operating_point.calculate_rotation_matrix_wind_axes_to_geometry_axes()
        )
        @ total_near_field_moment_geometry_axes
    )

    # Calculate the current_airplane's induced drag coefficient
    induced_drag_coefficient = (
        -steady_solver.airplane.total_near_field_force_wind_axes[0]
        / steady_solver.operating_point.calculate_dynamic_pressure()
        / steady_solver.airplane.s_ref
    )

    # Calculate the current_airplane's side force coefficient.
    side_force_coefficient = (
        steady_solver.airplane.total_near_field_force_wind_axes[1]
        / steady_solver.operating_point.calculate_dynamic_pressure()
        / steady_solver.airplane.s_ref
    )

    # Calculate the current_airplane's lift coefficient.
    lift_coefficient = (
        -steady_solver.airplane.total_near_field_force_wind_axes[2]
        / steady_solver.operating_point.calculate_dynamic_pressure()
        / steady_solver.airplane.s_ref
    )

    # Calculate the current_airplane's rolling moment coefficient.
    rolling_moment_coefficient = (
        steady_solver.airplane.total_near_field_moment_wind_axes[0]
        / steady_solver.operating_point.calculate_dynamic_pressure()
        / steady_solver.airplane.s_ref
        / steady_solver.airplane.b_ref
    )

    # Calculate the current_airplane's pitching moment coefficient.
    pitching_moment_coefficient = (
        steady_solver.airplane.total_near_field_moment_wind_axes[1]
        / steady_solver.operating_point.calculate_dynamic_pressure()
        / steady_solver.airplane.s_ref
        / steady_solver.airplane.c_ref
    )

    # Calculate the current_airplane's yawing moment coefficient.
    yawing_moment_coefficient = (
        steady_solver.airplane.total_near_field_moment_wind_axes[2]
        / steady_solver.operating_point.calculate_dynamic_pressure()
        / steady_solver.airplane.s_ref
        / steady_solver.airplane.b_ref
    )

    steady_solver.airplane.total_near_field_force_coefficients_wind_axes = np.array(
        [induced_drag_coefficient, side_force_coefficient, lift_coefficient]
    )
    steady_solver.airplane.total_near_field_moment_coefficients_wind_axes = np.array(
        [
            rolling_moment_coefficient,
            pitching_moment_coefficient,
            yawing_moment_coefficient,
        ]
    )

# ToDo: Update this function's documentation.
def update_ring_vortex_solvers_panel_attributes(solver, global_panel_position, panel):
    """

    :param solver:
    :param global_panel_position:
    :param panel:
    :return:
    """
    # Update the solver's list of attributes with this panel's attributes.
    solver.panels[global_panel_position] = panel
    solver.panel_normal_directions[global_panel_position, :] = panel.normal_direction
    solver.panel_areas[global_panel_position] = panel.area
    solver.panel_centers[global_panel_position] = panel.center
    solver.panel_collocation_points[global_panel_position, :] = panel.collocation_point
    solver.panel_back_right_vortex_vertices[
        global_panel_position, :
    ] = panel.ring_vortex.right_leg.origin
    solver.panel_front_right_vortex_vertices[
        global_panel_position, :
    ] = panel.ring_vortex.right_leg.termination
    solver.panel_front_left_vortex_vertices[
        global_panel_position, :
    ] = panel.ring_vortex.left_leg.origin
    solver.panel_back_left_vortex_vertices[
        global_panel_position, :
    ] = panel.ring_vortex.left_leg.termination
    solver.panel_right_vortex_centers[
        global_panel_position, :
    ] = panel.ring_vortex.right_leg.center
    solver.panel_right_vortex_vectors[
        global_panel_position, :
    ] = panel.ring_vortex.right_leg.vector
    solver.panel_front_vortex_centers[
        global_panel_position, :
    ] = panel.ring_vortex.front_leg.center
    solver.panel_front_vortex_vectors[
        global_panel_position, :
    ] = panel.ring_vortex.front_leg.vector
    solver.panel_left_vortex_centers[
        global_panel_position, :
    ] = panel.ring_vortex.left_leg.center
    solver.panel_left_vortex_vectors[
        global_panel_position, :
    ] = panel.ring_vortex.left_leg.vector
    solver.panel_back_vortex_centers[
        global_panel_position, :
    ] = panel.ring_vortex.back_leg.center
    solver.panel_back_vortex_vectors[
        global_panel_position, :
    ] = panel.ring_vortex.back_leg.vector
    solver.panel_is_trailing_edge[global_panel_position] = panel.is_trailing_edge
    solver.panel_is_leading_edge[global_panel_position] = panel.is_leading_edge
    solver.panel_is_right_edge[global_panel_position] = panel.is_right_edge
    solver.panel_is_left_edge[global_panel_position] = panel.is_left_edge

    # Check if this panel is on the trailing edge.
    if panel.is_trailing_edge:
        # If it is, calculate it's streamline seed point and add it to
        # the solver's array of seed points.
        solver.seed_points = np.vstack(
            (
                solver.seed_points,
                panel.back_left_vertex
                + 0.5 * (panel.back_right_vertex - panel.back_left_vertex),
            )
        )

def calculate_steady_freestream_wing_influences(steady_solver):
    """This method finds the vector of freestream-wing influence coefficients
    associated with this problem.

    :return: None
    """
    # Take the batch dot product of the freestream velocity with each panel's
    # normal direction. This is now the problem's 1D array of freestream-wing
    # influence coefficients.
    steady_solver.freestream_wing_influences = np.einsum(
        "ij,j->i",
        steady_solver.panel_normal_directions,
        steady_solver.freestream_velocity,
    )

@njit(parallel=True, cache=True, fastmath=True)
def numba_1d_explicit_cross(vectors_1, vectors_2):
    """This function takes in two arrays, each of which contain N vectors of 3
    components. The function then calculates and returns the cross product of the two
    vectors at each position.

    Note: This function has been optimized for JIT compilation and parallel
    computation using Numba.

    Citation: Some or all of the following code was written by Jérôme Richard as a
    response to a question on Stack Overflow. The original response is here:
    https://stackoverflow.com/a/66757029/13240504.

    :param vectors_1: array of floats of size (N x 3)
        This is the first array of N vectors.
    :param vectors_2: array of floats of size (N x 3)
        This is the second array of N vectors.
    :return crosses: array of floats of size (N x 3)
        This is the cross product of the two inputted vectors at each of the N
        positions.
    """
    crosses = np.zeros(vectors_1.shape)
    for i in prange(crosses.shape[0]):
        crosses[i, 0] = (
            vectors_1[i, 1] * vectors_2[i, 2] - vectors_1[i, 2] * vectors_2[i, 1]
        )
        crosses[i, 1] = (
            vectors_1[i, 2] * vectors_2[i, 0] - vectors_1[i, 0] * vectors_2[i, 2]
        )
        crosses[i, 2] = (
            vectors_1[i, 0] * vectors_2[i, 1] - vectors_1[i, 1] * vectors_2[i, 0]
        )
    return crosses


#!/usr/bin/env python

from mpi4py import MPI
import numpy

# Function to calcualte pi that each MPI rank will use
def compute_pi(samples):
    count = 0
    for x, y in samples:
        if x**2 + y**2 <= 1:
            count += 1
    pi = 4*float(count)/len(samples)
    return pi

# Set up our MPI environment
comm = MPI.COMM_WORLD
nprocs = comm.Get_size()
myrank = comm.Get_rank()

# Processor 0 generates random samples that each processor will use
if myrank == 0:
    N = 10000000 // nprocs
    samples = numpy.random.random((nprocs, N, 2))
else:
    samples = None

# Distribute the samples amongst all processors wiht MPI_Scatter
samples = comm.scatter(samples, root=0)

# Each processors calculates their value of pi (we'll take the average)
mypi = compute_pi(samples) / nprocs

# MPI_Reduce collects all individual
pi = comm.reduce(mypi, op=MPI.SUM, root=0)

if myrank == 0:
    error = abs(pi - numpy.pi)
    print("pi is approximately %.16f, error is %.16f" % (pi, error))


import numpy                as np

class Configuration:

    def __init__(self):

        # Problem setting (in canonical form)
        # self.constraint = [
        #     # [coefficient_1, coefficient_2, ... , constant_value]
        #     [ 4,     1,     22],
        #     [ 2,    -1,      8],
        #     [ 1,     2,     10]
        # ]
        # self.object = [-1, -2, 12]   # [coefficient_1, coefficient_2, ... , constant_value]

        self.constraint = [
            # [coefficient_1, coefficient_2, ... , constant_value]
            [ 5,    -2,     11],
            [ 4,     2,     28],
            [-3,     3,      6]
        ]
        self.object = [-4, -5, 4]   # [coefficient_1, coefficient_2, ... , constant_value]

class Simplex:

    def __init__(self, cnf):

        self.cnf    = cnf

        # Make dictionary (= Basis form expression)
        stack       = np.vstack((self.cnf.constraint, self.cnf.object))
        slack       = np.eye(stack.shape[0])
        self.prob   = np.insert(stack, [-1], slack, axis=1)

        print("Initial Dictionary:")
        print(self.prob)

    def run(self):
        count = 0
        while any(self.prob[-1] < 0):   # while having space to be optimized
            # Title
            count += 1
            print("\n<Operation " + str(count) + ">")

            # Decide colmun ID with Dantzig's selection method
            col_id = self.prob[-1].argmin()

            # Decide row ID
            cand = self.prob[:,-1]/self.prob[:,col_id]
            cand[cand<0] = np.inf
            row_id = cand.argmin()

            # Calculate a variable to be assigned
            pivot_row = self.prob[row_id] / self.prob[row_id,col_id]

            # Assign
            for i in range(self.prob.shape[0]):
                if i == row_id:
                    self.prob[i] = pivot_row
                else:
                    self.prob[i] = self.prob[i] - (pivot_row * self.prob[i,col_id])

            # Show temporary result
            print(" Dictionary:")
            print(self.prob)

            # Avoid infinity loop
            if count > 100:
                print("\n Failed")
                break

        # Show final result
        if not count > 100:
            print("\n <Final result> \n Objective value = " + str(self.prob[-1,-1]) + "\n")

# run
if __name__ == '__main__':

    cnf = Configuration()

    print("\n\t\t[ Simplex Method ]\n")
    slx = Simplex(cnf)
    slx.run()


######################################################################
#
# Functions to calculate integration points and weights for Gaussian
# quadrature
#
# x,w = gaussxw(N) returns integration points x and integration
#           weights w such that sum_i w[i]*f(x[i]) is the Nth-order
#           Gaussian approximation to the integral int_{-1}^1 f(x) dx
# x,w = gaussxwab(N,a,b) returns integration points and weights
#           mapped to the interval [a,b], so that sum_i w[i]*f(x[i])
#           is the Nth-order Gaussian approximation to the integral
#           int_a^b f(x) dx
#
# This code finds the zeros of the nth Legendre polynomial using
# Newton's method, starting from the approximation given in Abramowitz
# and Stegun 22.16.6.  The Legendre polynomial itself is evaluated
# using the recurrence relation given in Abramowitz and Stegun
# 22.7.10.  The function has been checked against other sources for
# values of N up to 1000.  It is compatible with version 2 and version
# 3 of Python.
#
# Written by Mark Newman <mejn@umich.edu>, June 4, 2011
# You may use, share, or modify this file freely
#
######################################################################

from numpy import ones, copy, cos, tan, pi, linspace

def gaussxw(N):
    # Initial approximation to roots of the Legendre polynomial
    a = linspace(3, 4 * N - 1, N) / (4 * N + 2)
    x = cos(pi * a + 1 / (8 * N * N * tan(a)))

    # Find roots using Newton's method
    epsilon = 1e-15
    delta = 1.0
    while delta > epsilon:
        p0 = ones(N, float)
        p1 = copy(x)
        for k in range(1, N):
            p0, p1 = p1, ((2 * k + 1) * x * p1 - k * p0) / (k + 1)
        dp = (N + 1) * (p0 - x * p1) / (1 - x * x)
        dx = p1 / dp
        x -= dx
        delta = max(abs(dx))

    # Calculate the weights
    w = 2 * (N + 1) * (N + 1) / (N * N * (1 - x * x) * dp * dp)

    return x, w

def gaussxwab(N, a, b):
    x, w = gaussxw(N)
    return 0.5 * (b - a) * x + 0.5 * (b + a), 0.5 * (b - a) * w


# integrate an elliptical orbit with adaptive timestep 4th-order Runge-Kutta

import numpy
import pylab
import math
from orbit_adaptive import *

# circular orbit
o = orbit(1, 0.95)  # a, e

# period
P = o.keplerPeriod()

err = 1.e-7
histRK4 = o.intRK4(0.0005, err, P)

print "number of steps = ", len(histRK4.t)-1

# plot the orbit
pylab.plot(histRK4.x, histRK4.y, label="4th order RK", color="b")
#pylab.scatter(histRK4.x, histRK4.y, marker="x", color="b")

# mark the Sun
pylab.scatter([0],[0],s=250,marker=(20,1),color="k")
pylab.scatter([0],[0],s=200,marker=(20,1),color="y")

pylab.xlim(-1.5,1.5)
pylab.ylim(-2.5,0.5)

ax = pylab.gca()
ax.set_aspect("equal", "datalim")

pylab.savefig("orbit-rk4-adaptive.png")

# plot the energy
pylab.clf()

E = histRK4.energy()
pylab.plot(histRK4.t, E/E[0])

pylab.ylabel(r"$E(t)/E_0$")
pylab.xlabel(r"t")

ax = pylab.gca()
ax.ticklabel_format(useOffset=False)

pylab.savefig("energy-rk4-adaptive.png")

# plot the timesteps
pylab.clf()

dt = histRK4.t[1:-1] - histRK4.t[0:-2]
tmid = 0.5*(histRK4.t[1:-1] + histRK4.t[0:-2])
pylab.scatter(tmid, dt)

ax = pylab.gca()
ax.set_yscale('log')

pylab.ylabel(r"$\tau$")
pylab.xlabel(r"t")

pylab.ylim(1.e-5,1.e-1)

pylab.savefig("dt-rk4-adaptive.png")


import numpy as np
import matplotlib.pyplot as plt

from matplotlib import animation, rc
from IPython.display import HTML

class uTriangular():
    """
      documentation
    """
    def __init__(self, x_pts, num_terms=20, c_wave=1., L=1.):
        self.x_pts = x_pts
        self.num_terms = num_terms
        self.c = c_wave
        self.L = L

    def B_coeff(self, n):
        """Fourier coefficient for the nth term in the expansion, which is only
            non-zero if n is odd, or n = 2*m + 1.
        """
        if n % 2 == 1:   # n is odd
            m = (n - 1)/2
            return (-1)**m * 8. / (n * np.pi)**2
        else:  # n is even
            return 0.

    def k(self, n):
        """Wave number for n
        """
        return n * np.pi / self.L

    def u_wave(self, t):
        """Returns the wave from the sum of Fourier components.
        """
        y_pts = np.zeros(len(self.x_pts))  # define y_pts as the same size as x_pts
        for n in np.arange(0, self.num_terms):
            y_pts += self.B_coeff(n) * np.sin(self.k(n) * self.x_pts) \
                      * np.cos(self.k(n) * self.c * t)
        return y_pts

L = 1.
num_n = 40
c_wave = 1
omega_1 = np.pi * c_wave / L
tau = 2.*np.pi / omega_1

# Set up the array of x points (whatever looks good)
x_min = 0.
x_max = L
delta_x = 0.01
x_pts = np.arange(x_min, x_max, delta_x)

u_triangular_1 = uTriangular(x_pts, num_n, c_wave, L)
u_triangular_2 = uTriangular(x_pts, num_n/8, c_wave, L)

# Make a figure showing the initial wave.
t_now = 0.

fig = plt.figure(figsize=(6,4), num='Standing wave')
ax = fig.add_subplot(1,1,1)
ax.set_xlim(x_min, x_max)
gap = 0.1
ax.set_ylim(-1. - gap, 1. + gap)
ax.set_xlabel(r'$x$')
ax.set_ylabel(r'$u(x, t=0)$')
ax.set_title(rf'$t = {t_now:.1f}$')

line, = ax.plot(x_pts,
                u_triangular_1.u_wave(t_now),
                color='blue', lw=2)
line2, = ax.plot(x_pts,
                u_triangular_2.u_wave(t_now),
                color='red', lw=2)

fig.tight_layout()

t_array = tau * np.arange(0., 1.125, .125)

fig_array = plt.figure(figsize=(12,12), num='Standing wave')

for i, t_now in enumerate(t_array):
    ax_array = fig_array.add_subplot(3, 3, i+1)
    ax_array.set_xlim(x_min, x_max)
    gap = 0.1
    ax_array.set_ylim(-1. - gap, 1. + gap)
    ax_array.set_xlabel(r'$x$')
    ax_array.set_ylabel(r'$u(x, t)$')
    ax_array.set_title(rf'$t = {t_now/tau:.3f}\tau$')

    ax_array.plot(x_pts,
                  u_Triangular(x_pts, t_now, num_n, c_wave, L),
                  color='blue', lw=2)

fig_array.tight_layout()
fig_array.savefig('Taylor_Problem_16p14.png',
                   bbox_inches='tight')

# Set up the t mesh for the animation.  The maximum value of t shown in
#  the movie will be t_min + delta_t * frame_number
t_min = 0.   # You can make this negative to see what happens before t=0!
t_max = 2.*tau
delta_t = t_max / 100.
t_pts = np.arange(t_min, t_max + delta_t, delta_t)

u_triangular_1 = uTriangular(x_pts, num_n, c_wave, L)
u_triangular_2 = uTriangular(x_pts, num_n/8., c_wave, L)

fig_anim = plt.figure(figsize=(6,3), num='Triangular wave')
ax_anim = fig_anim.add_subplot(1,1,1)
ax_anim.set_xlim(x_min, x_max)
gap = 0.1
ax_anim.set_ylim(-1. - gap, 1. + gap)

# By assigning the first return from plot to line_anim, we can later change
#  the values in the line.
line_anim, = ax_anim.plot(x_pts,
                          u_Triangular(x_pts, t_min, num_n, c_wave, L),
                          color='blue', lw=2)

fig_anim.tight_layout()

def animate_wave(i):
    """This is the function called by FuncAnimation to create each frame,
        numbered by i.  So each i corresponds to a point in the t_pts
        array, with index i.
    """
    t = t_pts[i]
    y_pts = u_triangular(x_pts, t, num_n, c_wave, L)

    line_anim.set_data(x_pts, y_pts)  # overwrite line_anim with new points
    return (line_anim,)   # this is needed for blit=True to work

frame_interval = 80.  # time between frames
frame_number = 101    # number of frames to include (index of t_pts)
anim = animation.FuncAnimation(fig_anim,
                               animate_wave,
                               init_func=None,
                               frames=frame_number,
                               interval=frame_interval,
                               blit=True,
                               repeat=False)

HTML(anim.to_jshtml())


"""
@file orthogonal.py
@description solutions to linear algebra textbook 6.2
@author Hiukong Dan
@version 1.0 May 26, 2021
"""
#!/bin/python
from sympy import Matrix
import numpy as np
import random

def problem35():
    A = np.array([[-6,-3,6,1],[-1,2,1,-6],[3,6,3,-2],[6,-3,6,-1],[2,-1,2,3],[-3,6,3,2],[-2,-1,2,-3],[1,2,1,6]])
    for x in range(0, A.shape[1]-1):
        for y in range(x+1, A.shape[1]):
            print(Matrix(np.dot(A.T[x], A.T[y])))

def problem36():
    A = np.array([[-6,-3,6,1],[-1,2,1,-6],[3,6,3,-2],[6,-3,6,-1],[2,-1,2,3],[-3,6,3,2],[-2,-1,2,-3],[1,2,1,6]])
    U = np.array([A.T[x] / np.linalg.norm(A.T[x]) for x in range(A.shape[1])]).T
    # (a)
    # print("U^T * U", np.matmul(U.T, U))
    # print("U * U^T", np.matmul(U, U.T))

    # (b)
    y = np.array([random.random() * 18 - 9 for x in range(8)])
    print("y", y)

    p = np.matmul(U, np.matmul(U.T, y))
    print("p", p)

    z = y - p
    print("z", z)

    print("dot(z, p)", np.dot(z, p))

    # (c)
    for x in range(U.shape[1]):
        print(np.dot(U.T[x], z))

if __name__ == "__main__":
    problem36();


import numpy as np
from Graphs import *

def primeFactors(n):
    if n == 1:
        return 0
    factors = 0
    d = 2
    while(n > 1):
        while(n % d == 0):
            factors += 1
            n //= d
        d = d + 1
        if(d*d > n):
            if(n > 1):
                factors += 1
            break
    return factors

def HaaseDivisibility(L,title=None,H=None,sc=.4,ptsz=.05,
                  drawConnections=True):

    L = sorted(L)

    numfacts = [primeFactors(i) for i in L]
    m = max(numfacts)
    lvls = [list() for i in range(m+1)]

    for i in L:
        n = primeFactors(i)
        lvls[n].append(i)

    G = Graph(rdef=ptsz,tscaledef=5)
    fig,ax = makeCanvas([-.4,1.4],[-.1,sc*len(lvls)],[12,12])

    y = 0
    ## We'll use these to store some information about the previous level
    XYold = []
    XYnew = []
    XYout = []
    for f in lvls:
        ## The XY positions of the previous level are now old
        ## We also reset the XY positions for this level to be blank so we can
        ## start fillign them in.
        XYold = XYnew
        XYnew = []
        ## Place the text on top of a circle. If the point is a factor of the
        ## subgraph make it salmon colored. Otherwise light blue.
        ## Also take note of the current position.
        x = np.linspace(0,1,len(f))
        if len(f) == 1:
            x = [.5]
        for l in range(len(f)):

            if H != None and H % f[l] == 0:
                G.addNode([x[l],y],text=f[l],col='#FF91A4')
            else:
                G.addNode([x[l],y],text=f[l])
            XYnew.append((f[l],x[l],y))
            XYout.append((x[l],y))

        ## Check if any of the current numbers are divisible by the ones in the
        ## level before. If they are draw a connecting line.
        ## Then also check if both numbers are factors of the subgraph. If they
        ## are then make the line red, otherwise make it gray. Gray lines are
        ## drawn beneath the red lines and are slightly thinner.
        if drawConnections == True:
            for val,xpos,ypos in XYnew:
                for valOLD,xposOLD,yposOLD in XYold:
                    if val % valOLD == 0:
                        if H != None and H % val == 0 and H % valOLD == 0:
                            connect([xpos,ypos],[xposOLD,yposOLD],width=2,col='red')
                        else:
                            connect([xpos,ypos],[xposOLD,yposOLD],width=2)

        y += sc
    G.QuickDraw(fig,ax)
    G.drawText(fig,ax)
    if title != None:
        plt.savefig(title,dpi=100)
    print(lvls)
    #print(XYout)
    return XYout

HaaseDivisibility([1,2,3,4,5,6,9,10,12,15,18,20,30,60],H=18,ptsz=.1)


import numpy as np

def medstddev(data, mask=None, medi=False, axis=0):
    """Compute the stddev with respect to the median.

    This is rather than the standard method of using the mean.

    Parameters:
    -----------
    data:   ndarray
        An array from which to caculate the median standard deviation.
    mask:   1D ndarray
        Mask indicating the good values (ones) and bad values (zeros).
        Same shape as data.
    medi:   boolean, optional
        If True return a tuple with (stddev, median) of data.
    axis:   int
        The axis along wich the median std deviation is calculated.

    Notes:
    ------
    MEANSTDDEV calculates the median, subtracts it from each value of
    X, then uses this residual to calculate the standard deviation.

    The numerically-stable method for calculating the variance from
    moment.pro doesn't work for the median standard deviation.  It
    only works for the mean, because by definition the residuals from
    the mean add to zero.

    Example:
    --------
    >>> import medstdev as m
    >>> a  = np.array([1,3,4,5,6,7,7])
    >>> std, med = m.medstddev(a, medi=True)
    >>> print(median(a))
    5.0
    >>> print(med)
    5.0
    >>> print(std)
    2.2360679775

    >>> # use masks
    >>> a    = np.array([1,3,4,5,6,7,7])
    >>> mask = np.array([1,1,1,0,0,0,0])
    >>> std, med = m.medstddev(a, mask, medi=True)
    >>> print(std)
    1.58113883008
    >>> print(med)
    3.0

    >>> # automatically mask invalid values
    >>> a = np.array([np.nan, 1, 4, np.inf, 6])
    >>> std, med = m.medstddev(a, medi=True)
    >>> print(std, med)
    (2.5495097567963922, 4.0)

    >>> # critical cases:
    >>> # only one value, return std = 0.0
    >>> a    = np.array([1, 4, 6])
    >>> mask = np.array([0, 0, 1])
    >>> std, med = m.medstddev(a, mask, medi=True)
    >>> print(std, med)
    (0.0, 6.0)

    >>> # no good values, return std = nan, med = nan
    >>> mask[-1] = 0
    >>> std, med = m.medstddev(a, mask, medi=True)
    >>> print(std, med)
    (nan, nan)

    Modification history:
    ---------------------
    2005-01-18  statia
        Written by Statia Luszcz.
    2005-01-19  statia
        Updated variance calculation according to algorithm in moment.pro,
        added medi keyword.
    2005-01-20  Joe Harrington, Cornell, jh@oobleck.astro.cornell.edu
        Header update.  Removed algorithm from moment.pro because it
        doesn't work for the median.  Added /double.
    2010-11-05  patricio  pcubillos@fulbrightmail.org
        Converted to python, documented.
    2022-04-11  Taylor James Bell
        Efficiently using numpy axes
    """
    # mask invalid values:
    data = np.ma.masked_invalid(data)
    if mask is not None:
        data = np.ma.masked_where(~mask.astype(bool), data)
    # number of good values:
    ngood = np.sum(~np.ma.getmaskarray(data), axis=axis)

    # calculate median of good values:
    median = np.ma.median(data, axis=axis)
    # residuals is data - median, masked values don't count:
    residuals = data - median
    # calculate standar deviation:
    std = np.array(np.ma.sqrt(np.ma.sum(residuals**2.0) / (ngood - 1.0)))

    # Convert masked arrays to just arrays
    std = np.array(std)
    median = np.array(median)
    if std.shape == ():
        # If just a single value, make sure using a shaped array
        std = std.reshape(-1)
        median = median.reshape(-1)

    # critical case fixes:
    if np.any(ngood == 0):
        std[np.where(ngood == 0)[0]] = np.nan
        median[np.where(ngood == 0)[0]] = np.nan
    if np.any(ngood == 1):
        std[np.where(ngood == 1)[0]] = 0.

    if len(std) == 1:
        std = std[0]
        median = median[0]

    # return statement:
    if medi:
        return (std, median)
    return std


#!/usr/bin/python2
import sympy as sp
import os
import subprocess
from implementations import *
from matplotlib import pyplot as plt
from sympy import Point2D

def getFunction():
    while True:
        string = ''
        try:
            string = raw_input("Type in the f(t,y) function: ")  # get expression as string
            expr = sp.sympify(string)  # turn string expression into Sympy expression
            break
        except:
            print "Please try again, invalid input: ", string
    return expr

def getPoint(k):
    if k is None:  # in case the user doesn't want to specify which point they're getting
        k = ''
    while True:
        try:
            t = input("Type in t{0}: ".format(k))  # get k-th t as a number
            break
        except:
            print "Please try again, invalid input"

    while True:
        try:
            y = input("Type in y{0}: ".format(k))  # get k-th y as a number
            break
        except:
            print "Please try again, invalid input"

    return t, y

def getNandH():
    h = input("Type in the step h: ")  # gets h as number
    n = input("Type in the number of iterations n: ")  # gets h as number

    return h, n

"""
    Gets order of Adams-Moulton and Adams-Bashforth methods
"""
def getOrder():

        order = 1
        while True:
                try:
                    order = int(input("\nPlease input the degree of the method: "))
                    if order > 0:
                        break
                    else:
                        print "Degree must be greater than 0."
                except:
                    print "Please try again, invalid input."
        return order

def plot(mts, mys, labels, title):
    """
        mts = Array of arrays of t coordinates
        mys = Array of arrays of y coordinates
        labels = labels for each function. (i.e. points mts[0], mys[0] have the label labels[0])
        title = plot titlte
    """
    for i in range(len(mts)):
        plt.plot(mts[i], mys[i], label=labels[i])

    plt.xlabel('t')
    plt.ylabel('y(t)')
    plt.title(title)

    plt.ticklabel_format(style='plain')              # disables scientific notation
    plt.legend(loc='best')                          # puts legend in the best place
    plt.show()

def runSimpleMethod(method, name):
    f = getFunction()

    t, y = getPoint(0)

    h, n = getNandH()

    ts, ys = method(f, t, y, h, n)

    plot([ts], [ys], [''], name)

    print "\nHave a great day!"

    return ts, ys

def runAllEulers():

    f = getFunction()

    t, y = getPoint(0)

    h, n = getNandH()

    ts1, ys1 = eulers.simple_euler(f, t, y, h, n)
    ts2, ys2 = eulers.improved_euler(f, t, y, h, n)
    ts3, ys3 = eulers.inverse_euler(f, t, y, h, n)

    #plot config
    plt.plot(ts1, ys1, label='Simple Euler')
    plt.plot(ts2, ys2, label='Improved Euler')
    plt.plot(ts3, ys3, label='Inverse Euler')
    plt.xlabel('t')
    plt.ylabel('y')
    plt.title("All Euler Methods")

    plt.legend(loc='best')
    plt.ticklabel_format(style='plain')              # disables scientific notation
    plt.show()

    print "\nHave a great day!"

    return

def runAdamsBash(order):
    name = "Adams-Bashforth Method"
    f = getFunction()

    p = []
    for i in range(order):
        p.insert(0,Point2D(getPoint(i)))

    h, n = getNandH()

    points, ts, ys = adams_bashforth.method(f, p, h, n, order)

    plot([ts], [ys], [''], name)

    return ts, ys

def runAdamsMoulton(order):
    name = "Adams-Moulton Method"
    f = getFunction()
    p = []

    print '\nObs: Adams-Moulton of order k needs only k-1 points\n'

    if order == 1: order = 2                #makes sure at least one point is asked for
    for i in range(order - 1):
        p.insert(0,Point2D(getPoint(i)))

    h, n = getNandH()

    points, ts, ys = adams_moulton.method(f, p, h, n, order)

    plot([ts], [ys], [''], name)

    return ts, ys

def runAllMethods(order):
    f = getFunction()

    t, y = getPoint(0)

    h, n = getNandH()

    p = []          # array of points for adams methods

    ts1, ys1 = eulers.simple_euler(f, t, y, h, n)
    ts2, ys2 = eulers.improved_euler(f, t, y, h, n)
    ts3, ys3 = eulers.inverse_euler(f, t, y, h, n)
    ts4, ys4 = runge.method(f, t, y, h, n)

    if order == 1: order = 2                # makes sure at least one point is put into the p array
    for i in range(order):
        p.insert(0,Point2D(ts4[i], ys4[i])) # takes point generated from runge kutta method
        n = n - 1

    points, ts5, ys5 = adams_bashforth.method(f, p, h, n + 1, order)
    # p = []      #reset p
    # for i in range(order):
    #     p.insert(0,Point2D(ts4[i], ys4[i])) # takes point generated from runge kutta method
    p.pop()                                 # adams moulton takes order - 1 points to run
    points, ts6, ys6 = adams_moulton.method(f, p, h, n + 1, order)

    # 'points' is not necessary...

    #plot config
    plot(
        [ts1, ts2, ts3, ts4, ts5, ts6],
        [ys1, ys2, ys3, ys4, ys5, ys6],
        ['Simple Euler', 'Improved Euler', 'Inverse Euler', 'Runge-Kutta', 'Adams-Bashforth', 'Adams-Moulton'],
        'All Single Step methods'
        )

def allAdamsMoulton():
    mts = []
    mys = []
    pts = []
    p = []

    f = getFunction()

    t, y = getPoint(0)

    h, n = getNandH()

    ts, ys = runge.method(f, t, y, h, 7)
    p.insert(0,Point2D(ts[0], ys[0])) # takes point generated from runge kutta method
    for i in range(6):
        o = i + 1
        if i - 1 > 0: p.insert(0,Point2D(ts[i], ys[i])) # takes point generated from runge kutta method
        if i == 1:
            i = i -1
        pts, ts5, ys5 = adams_moulton.method(f, p, h, n-i, o)
        plot([ts5], [ys5], [''], 'Adams-Moulton of order {}'.format(o))
        os.system('clear')
        mts.append(ts5)
        mys.append(ys5)

    plot(
        mts,
        mys,
        ['1st Order', '2nd Order','3rd Order','4th Order','5th Order','6th Order'],
        'Adams-Moulton Methods (1-6)'
        )


#---------------------------------------------------------------------
# File Name   : HypothesisTesting2.py
# Author      : Kunal K.
# Description : Implementing hypothesis test methods
# Date:       : 9 Nov. 2020
# Version     : V1.0
# Ref No      : DS_Code_P_K07
#---------------------------------------------------------------------

import pandas as pd
# import numpy as np
import scipy
from scipy import stats
import statsmodels.stats.descriptivestats as sd
# import plotly.plotly as py
# import plotly.graph_objs as go
# from plotly.tools import FigureFactory as FF

############## 1 Sample Sign Test(Student_Scores) ################
# import statsmodels.stats.descriptivestats as sd
data=pd.read_excel("Marks-1sample sign test.xlsx")
data
#############Normality test###############
print(stats.shapiro(data.Marks))

###################1 Sample Sign Test #############
sd.sign_test(data.Marks,mu0=82)
help(sd.sign_test)

############### Mann-Whitney test(Vehicles with and without addictive) ############
data=pd.read_excel("Hyothesis Testing\Mann_whitney.xlsx")
data
data.columns="Without_additive","With_additive"
#############Normality test###############
print(stats.shapiro(data.Without_additive))
print(stats.shapiro(data.With_additive))

############## Mann-Whitney test #############
# import statsmodels.stats.descriptivestats as sd
scipy.stats.mannwhitneyu(data.Without_additive, data.With_additive)

############2 sample T Test(Marketing Strategy) ##################
#############Normality test###############
#promotion=pd.read_excel("C:\Datasets_BA\Hypothesis\Hypothesis Testing_R&Python_codes\Promotion.xlsx")

promotion=pd.read_excel("E:/Day Wise/Day 08 Hypothesis Testing/Data/Promotion.xlsx")
promotion
promotion.columns = "Credit","Promotion.Type","InterestRateWaiver","StandardPromotion"
##########Normality Test ############

print(promotion.columns)
print(scipy.stats.anderson(promotion.InterestRateWaiver,dist = 'norm'))
#15%, 10%, 5%, 2.5%, 1%
print(scipy.stats.anderson(promotion.StandardPromotion,dist = 'norm'))
help(stats.shapiro)

######## 2 Sample T test ################
scipy.stats.ttest_ind(promotion.InterestRateWaiver,promotion.StandardPromotion,nan_policy='omit')
help(scipy.stats.ttest_ind)

############# One - Way Anova###################

cof=pd.read_excel("ContractRenewal_Data(unstacked).xlsx")
cof
cof.columns="SupplierA","SupplierB","SupplierC"

scipy.stats.levene(cof.SupplierA, cof.SupplierB,cof.SupplierC)
help(scipy.stats.levene)

stats.f_oneway(cof.SupplierA , cof.SupplierB , cof.SupplierC)

################Chi-Square Test ################

Bahaman=pd.read_excel("Hypothesis Testing/Data/Bahaman.xlsx")
Bahaman

count=pd.crosstab(Bahaman["Defective"],Bahaman["Country"])
count
Chisquares_results=scipy.stats.chi2_contingency(count)
help(scipy.stats.chi2_contingency)
Chisquares_results
Chi_square=[['','Test Statistic','p-value'],['Sample Data',Chisquares_results[0],Chisquares_results[1]]]
#chisample_results=FF.create_table(Chi_square,index=True)
#chisample_results

import numpy,import scipy,from scipy,import statsmodels


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

# In[4]:

#Antono Muniz      22.119.001-0
#Atividade 3

# In[5]:

#ex 2

#Sabe-se que 60% dos indivíduos submetidos a um tratamento médico sobrevivem.
#Se 20 indivíduos foram submetidos ao tratamento, determine, aplicando a
#distribuição binomial, a probabilidade de no máximo dois sobreviverem.

# In[6]:

from scipy.stats import binom
t = binom.pmf(2, 20, 6/10) + binom.pmf(1, 20, 6/10) + binom.pmf(0, 20, 6/10)
print(t)

# In[7]:

#ex 3
#O número de mortes por afogamento em fins de semana, numa cidade praiana,
#é de 2 a cada grupo de 50000 habitantes em média.

# In[8]:

#a - Qual a probabilidade de que em um grupo de 200000 habitantes ocorram 5 afogamentos?

# In[9]:

from scipy.stats import binom
binom.pmf(5,200000,2/50000)

# In[10]:

#b - Qual a probabilidade de que em um grupo de 125000 habitantes ocorram pelo menos 3 afogamentos?

# In[11]:

from scipy.stats import binom
print(1 - (binom.pmf(2,125000,2/50000) + binom.pmf(1,125000,2/50000) + binom.pmf(0,125000,2/50000) ) )

# In[15]:

#ex 4
#Uma empresa de eletrônicos considerou que o tempo de vida de suas baterias de celular
#segue uma distribuição normal com média de 120 minutos e variância de 100 minutos.

#media = 120
#var = 100
#desvio padrão é a raiz quadrada da variância = 10

# In[16]:

#a - Qual é a probabilidade aproximada de uma bateria durar menos que 100 minutos?

# In[17]:

from scipy.stats import norm
#P(x < 100)
norm.cdf(100,120,10)

# In[18]:

#b - Qual é a probabilidade de uma bateria durar 115 e 130 minutos?

# In[19]:

#P(115 < x < 130)
norm.cdf(130,120,10) - norm.cdf(115,120,10)


"""Functions utilities.

Some functions for implementation.

"""
import numpy as np

# Generic #
def G(x, y, s):
    """Gaussian kernel.

    .. math::
        G(x, y) = \exp(-(x^2 + y^2) / s)

    Parameters
    ----------
    x : float or array_like
        x value.
    y : float or array_like
        y value.
    s : float
        Gaussian shape parameter.

    Returns
    -------
    float or array_like
        Gaussian function
    """
    return np.exp(-(x ** 2 + y ** 2) / s)

# PDE FUNCTIONS #
def K(u, kap, eps):
    """Compute diffusion function

    .. math::
        K(u) = \kappa \, (1 + \varepsilon u)^3 + 1

    Parameters
    ----------
    u : array_like
        Temperature variable.
    kap : float
        Diffusion parameter.
    eps : float
        Inverse of activation energy.

    Returns
    -------
    array_like
        Evaluation of K function.
    """
    return kap * (1 + eps * u) ** 3 + 1

def Ku(u, kap, eps):
    """Derivative of K with respect to u.

    .. math:
        \dfrac{\partial K}{\partial u} = K_{u} = 3\,\varepsilon \kappa\, (1 + \varepsilon\, u)^2
    Parameters
    ----------
    u : array_like
        Temperature variable.
    kap : float
        Diffusion parameter.
    eps : float
        Inverse of activation energy.

    Returns
    -------
    array_like
        Ku evaluation.
    """
    return 3 * eps * kap * (1 + eps * u) ** 2

def f(u, b, eps, alp, s):
    """Temperature-fuel reaction function.

    Parameters
    ----------
    u : array_like
        Temperature value.
    b : array_like
        Fuel value.
    eps : float
        Inverse of activation energy parameter.
    alp : float
        Natural convection parameter.
    s : function or lambda
        Step function.

    Returns
    -------
    array_like
        Reaction function.
    """
    return s(u) * b * np.exp(u / (1 + eps * u)) - alp * u

def g(u, b, eps, q, s):
    """RHS of fuel PDE.

    Parameters
    ----------
    u : array_like
        Temperature value
    b : array_like
        Fuel value.
    eps : float
        Inverse of activation energy parameter.
    q : float
        Reaction heat parameter.
    s : function or lambda
        Step function.

    Returns
    -------
    array_like
        Fuel RHS PDE.
    """
    return -s(u) * (eps / q) * b * np.exp(u / (1 + eps * u))

def H(u, upc):
    """2D heaviside funcion

    Parameters
    ----------
    u : array_like
        Temperature value
    upc : float
        Phase change threshold.

    Returns
    -------
    array_like
        Heaviside function evaluation.
    """
    S = np.zeros_like(u)
    S[u >= upc] = 1.0
    return S

def sigmoid(u, k=.5):
    """Sigmoid function.

    Parameters
    ----------
    u : array_like
        Temperature value.
    k : float, optional
        Slope constant factor, by default .5

    Returns
    -------
    array_like
        Sigmoid evaluation.
    """
    return 1 / (1 + np.exp(-k * scale(u))) #0.5 * (1 + np.tanh(k * self.scale(u)))

def scale(u, a=-10, b=10):
    """Scale function.

    Parameters
    ----------
    u : array_like
        Temperature value.
    a : int, optional
        Minimum value, by default -10
    b : int, optional
        Maximum value, by default 10

    Returns
    -------
    array_like
        Scaled value of u.
    """
    return (b - a) * (u - np.min(u)) / (np.max(u) - np.min(u)) + a


# Importing important libraries
import numpy as np

# A function which will find the line between two points.
# @4_data_exploration.ipynb
# @ Intercept And Slope
def get_line_equation(p1, p2):
    """
    Solve the system of equations:
    y1 = m*x1 + b
    y2 = m*x2 + b

    This translates to:
    m = (y2 - y1) / (x2 - x1)
    b = y1 - m*x1

    Input:
    p1: first point [x1, y1]
    p2: second point [x2, y2]

    returns: slope, intercept
    """
    m = (p2[1] - p1[1]) / (p2[0] - p1[0]) # Slope
    b = p1[1] - m * p1[0] # Intercept
    return  m, b

# Removing the outliers
def remove_outliers(data, col):
      for x in col:
        q75,q25 = np.percentile(data.loc[:,x],[75,25])
        intr_qr = q75-q25

        max = q75+(1.5*intr_qr)
        min = q25-(1.5*intr_qr)

        data.loc[data[x] < min,x] = np.nan
        data.loc[data[x] > max,x] = np.nan


# -*- coding: utf-8 -*-
# @Time    : 7/29/2018 10:08 PM
# @Author  : DonaldY

# 1. 定义数据集
x = [4, 8, 12, 25, 32, 43, 58, 63, 69, 79]
y = [20, 33, 50, 56, 42, 31, 33, 46, 65, 75]

# 2. 实现 n 次多项式拟合
import numpy as np
from scipy.optimize import leastsq
from matplotlib import pyplot as plt

# 根据公式，定义 n 次多项式函数
def fit_func(p, x):
    f = np.poly1d(p)
    return f(x)

# 残差函数（观测值与拟合值之间的差距）
def err_func(p, x, y):
    ret = fit_func(p, x) - y
    return ret

# n 次多项式拟合
def n_poly(n):
    p_init = np.random.randn(n) # 生成 n 个随机数
    parameters = leastsq(err_func, p_init, args=(np.array(x), np.array(y)))
    return parameters[0]

n_poly(3)

# 3. 绘制出 4，5，6，7, 8, 9 次多项式的拟合图像
# 绘制拟合图像时需要的临时点
x_temp = np.linspace(0, 80, 10000)

# 绘制子图
fig, axes = plt.subplots(2, 3, figsize=(15,10))

axes[0,0].plot(x_temp, fit_func(n_poly(4), x_temp), 'r')
axes[0,0].scatter(x, y)
axes[0,0].set_title("m = 4")

axes[0,1].plot(x_temp, fit_func(n_poly(5), x_temp), 'r')
axes[0,1].scatter(x, y)
axes[0,1].set_title("m = 5")

axes[0,2].plot(x_temp, fit_func(n_poly(6), x_temp), 'r')
axes[0,2].scatter(x, y)
axes[0,2].set_title("m = 6")

axes[1,0].plot(x_temp, fit_func(n_poly(7), x_temp), 'r')
axes[1,0].scatter(x, y)
axes[1,0].set_title("m = 7")

axes[1,1].plot(x_temp, fit_func(n_poly(8), x_temp), 'r')
axes[1,1].scatter(x, y)
axes[1,1].set_title("m = 8")

axes[1,2].plot(x_temp, fit_func(n_poly(9), x_temp), 'r')
axes[1,2].scatter(x, y)
axes[1,2].set_title("m = 9")


# Copyright (c) 2020 Max Planck Gesellschaft

'''
File in order to compute an optimal LQR controller
x[k] = [theta , thetaDot]
'''

import numpy as np
import scipy.linalg

# Discrete-time LQR
def dlqr(A, B, Q, R):
    """Solve the discrete time lqr controller.

    x[k+1] = A x[k] + B u[k]

    cost = sum x[k].T*Q*x[k] + u[k].T*R*u[k]
    """
    # ref Bertsekas, p.151

    # first, try to solve the ricatti equation
    X = np.matrix(scipy.linalg.solve_discrete_are(A, B, Q, R))

    # compute the LQR gain
    K = np.matrix(scipy.linalg.inv(B.T * X * B + R) * (B.T * X * A))

    eigVals, eigVecs = scipy.linalg.eig(A - B * K)

    return K

# Define Params:
g = 10.0
m = 1.0
l = 1.0
dt = 0.05

A = np.matrix([[1,dt],[dt*(3*g)/(2*l),1]])
B = np.matrix([[0],[dt*(3)/(m*l**2)]])

Q = np.diag([1,0.1])
R = np.diag([0.1])

# Calculate Gain Matrix:
K = dlqr(A,B,Q,R)

print ("Gain Matrix is:")
print (K)

# PREVIOUSLY USED LQR Matrix: <-> SO FAR ALREADY CONSISTENT WITH ENV (1.0,0.1,0.001)
#Q = np.diag([10,1])
#R = 0.01
#K = [[19.80210901  6.03515527]]


import numpy as np
# Teta is features vector : teta_0,teta_1,....,teta_n . Teta is column vector (n+1)x1 (n+1 is the number of features)

# X is a matrix [X0,X1,X2,....,Xn]. each X0,X1,X2,....,Xn is a column vector mX1 where m is number of data set points. thus X is m*n. Notice that X0 is always 1

# X*Teta is : teta0*X0 + teta1*X1 + ….. +teta_n*Xn .i.e. X*Teta is a column vector mX1

# for example suppose we have 3 features i.e. teta0,teta1,teta2
Teta = np.array([2,3,-0.5])
print("Teta : ",Teta)
m=10
# for example suppose we have 10 data set points
X0 = np.ones(m)
print("X0 : ",X0)

X1 = np.arange(0,m,1)
print("X1 : ",X1)

X2 = np.arange(20,m+20,1)
print("X2 : ",X2)

X = np.vstack((X0,X1,X2)).T
print("X.shape : ",X.shape)

# both solutions works
print(np.dot(X,Teta))
print(np.matmul(X,Teta))


# The content of this module is taken from a Datacamp courses
# Statistical Thinking in Python I and II by Justin Bois

import numpy as np

def ecdf(data):
    """Compute ECDF for a one-dimensional array of measurements."""
    # Number of data points: n
    n = len(data)

    # x-data for the ECDF: x
    x = np.sort(data)

    # y-data for the ECDF: y
    y = np.arange(1, n + 1) / n

    return x, y

def bootstrap_replicate_1d(data, func):
    """Generate bootstrap replicate of 1D data."""
    bs_sample = np.random.choice(data, len(data))
    return func(bs_sample)

def draw_bs_reps(data, func, size=1):
    """Draw bootstrap replicates."""

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

    # Generate replicates
    for i in range(size):
        bs_replicates[i] = bootstrap_replicate_1d(data, func)

    return bs_replicates

def draw_bs_reps_ind(data, func, size=1):
    """Draw bootstrap replicates, resampling indices"""

    # Set up array of indices
    inds = np.arange(len(data))

    # Initialize replicates
    bs_reps = np.empty(size)

    # Generate replicates
    for i in range(size):
        bs_inds = np.random.choice(inds, size=len(data))
        bs_data = data[bs_inds]
        bs_reps[i] = func(bs_data)
    return bs_reps

def draw_bs_pairs_linreg(x, y, size=1):
    """Perform pairs bootstrap for linear regression."""

    # Set up array of indices to sample from: inds
    inds = np.arange(len(x))

    # Initialize replicates: bs_slope_reps, bs_intercept_reps
    bs_slope_reps = np.empty(size)
    bs_intercept_reps = np.empty(size)

    # Generate replicates
    for i in range(size):
        bs_inds = np.random.choice(inds, size=len(x))
        bs_x, bs_y = x[bs_inds], y[bs_inds]
        bs_slope_reps[i], bs_intercept_reps[i] = np.polyfit(bs_x, bs_y, 1)

    return bs_slope_reps, bs_intercept_reps

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

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

    # Permute the concatenated array: permuted_data
    permuted_data = np.random.permutation(data)

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

    return perm_sample_1, perm_sample_2

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

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

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

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

    return perm_replicates


# coding: utf-8

# In[1]:

#imported packages
import numpy as np
import time
from matplotlib import pyplot as plt
import seaborn as sns
get_ipython().magic(u'matplotlib inline')

# In[2]:

#created a deta set with "years" as X and "salary" as y
#there is a linear relationship between X and y

years = np.arange(0,40,0.5)
np.random.seed(0)
salary = 45000+np.sqrt(years)*16789 +np.random.normal(2000,10000,len(years))

# In[17]:

y=np.array(salary)

X_original= np.array(years)

#Created a ones vector
ones = np.ones((X_original.shape[0],1))

#converted X_original to a nX2 matrix, n is the number samples, and the first column of X_original is 1
#add ones to the first vector/column in X_original
X = np.reshape(X_original, (X_original.shape[0],1))
X = np.concatenate((ones,X),axis=1)

print(X.shape)
print(X[0:3, :])
print(X_original.shape)

# In[ ]:

#In the above cell, I gave X_original since in Vectorized_update_theta function,
#under gradient[1] multiplication------error(theta,X,y) is in order of 80*1. So, X_original has dimension of 80*1
#Whereas X has dimension of 80*2 which would result in error for the above function and the optimum never gets executed.

##This is the most important step in vectorization assignment.

# In[24]:

# error = y_i - y_hat_i
def error(theta, X, y):
    return y - (X.dot(theta))  #np.dot() multiplication

# SSE (sum squared error)
def vectorized_calculate_SSE(theta):

    return sum(error(theta, X, y)**2 )

def vectorized_update_theta(theta, gamma):
    gradient=[0,0]

    gradient=[0,0]
    gradient[0] = -2*sum(error(theta, X, y) )
    gradient[1] = -2*sum(error(theta, X, y)*X_original) #multiplication of matrices with same dimensions [80*1]

    return  [theta[0]-gamma*gradient[0], theta[1]-gamma*gradient[1]]

def vectorized_adaptive_optimum(theta, gamma, t, precision):
    #infinite loop if no "return" is executed
    while True:
        #decrease gamma in every iteration
        gamma *=t

        #store SSE
        old_SSE = vectorized_calculate_SSE(theta)

        #update theta for a small number of time
        for i in range(10):
            temp_theta =vectorized_update_theta(theta, gamma)

        #get the new SSE
        new_SSE = vectorized_calculate_SSE(temp_theta)

        # if SSE is thrinking, go to the next iteration and try a smaller gamma
        if new_SSE > old_SSE:
            continue

        # if SEE does converge
        else:
            # try a large iteration to see if gamma can be found
            for i in range(100000):

                #update theta and calculate new SSE
                theta =vectorized_update_theta(theta, gamma)
                new_SSE = vectorized_calculate_SSE(theta)

                #if the update is within the prcision
                if abs(old_SSE - new_SSE) < precision:

                    #print out the result and return to the function call
                    print("found minimum cost:", new_SSE)
                    print("the optimum theta:", theta)
                    print("the learning rate is:", gamma)
                    return theta

# In[29]:

#initiate theta
init_theta=[1,1]

#start from a large learning rate
gamma = 1

#the decrease rate of gamma
t=0.9

#the precision for stopping the search. 1 unit is a $1
precision =1

#print out the time used for computing
start_time = time.time()

#call the vectorized function

theta = vectorized_adaptive_optimum(init_theta,gamma,t,precision)
print("the calculation takes ", time.time()-start_time, " seconds.")

# In[38]:

#plot the prediction line

plt.title("Experience vs. Salary")
plt.xlabel('Years of Experience (Years)')
plt.ylabel('Salary ($)')
plt.grid(True)
plt.xlim(0,40)
plt.ylim(45000,180000)
plt.scatter(years, salary)

y_hat = X.dot(theta)  #y_hat is the linear regression line with respect to years
plt.plot(years,y_hat, color='red')

# In[ ]:

#Thus, the above cell fulfills the assignment.


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

# ### Principal component analysis (PCA)
#
# * PCA is used to decompose a multivariate dataset in a set of successive orthogonal components that explain a maximum amount of the variance. In scikit-learn, PCA is implemented as a transformer object that learns `n`  components in its fit method, and can be used on new data to project it on these components.
#
# PCA centers but does not scale the input data for each feature before applying the SVD. The optional parameter whiten=True makes it possible to project the data onto the singular space while scaling each component to unit variance. This is often useful if the models down-stream make strong assumptions on the isotropy of the signal: this is for example the case for Support Vector Machines with the RBF kernel and the K-Means clustering algorithm.
#
#     Below is an example of the iris dataset, which is comprised of 4 features, projected on the 2 dimensions that explain most variance:

# In[2]:

get_ipython().system('pip install numpy')
get_ipython().system('pip install pandas ')
get_ipython().system('pip install matplotlib ')
get_ipython().system('pip install scikit-learn')

# In[3]:

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

from sklearn import datasets
from sklearn.decomposition import PCA
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

# In[5]:

iris = datasets.load_iris()

# In[6]:

iris.keys()

# In[7]:

X = iris.data
y = iris.target

# In[8]:

target_names = iris.target_names

# In[9]:

X.shape # 150 rows and 4 columns

# In[10]:

pca = PCA(n_components=2) # 150 rows and 2 columns

# In[11]:

X_r = pca.fit_transform(X)
X_r.shape

# In[23]:

lda = LinearDiscriminantAnalysis(n_components=2)
X_r2 = lda.fit(X,y).transform(X)

# In[14]:

# Percentage of variance explained for each components
print('explained variance ratio (first two components): %s'
      % str(pca.explained_variance_ratio_))

# In[24]:

plt.figure()
colors = ['navy', 'turquoise', 'darkorange']
lw = 2

for color, i, target_name in zip(colors, [0, 1, 2], target_names):
    plt.scatter(X_r[y == i, 0], X_r[y == i, 1], color=color, alpha=.8, lw=lw,
                label=target_name)
plt.legend(loc='best', shadow=False, scatterpoints=1)
plt.title('PCA of IRIS dataset')

plt.figure()
for color, i, target_name in zip(colors, [0, 1, 2], target_names):
    plt.scatter(X_r2[y == i, 0], X_r2[y == i, 1], alpha=.8, color=color,
                label=target_name)
plt.legend(loc='best', shadow=False, scatterpoints=1)
plt.title('LDA of IRIS dataset')

plt.show()

# In[ ]:

Clustring/Dimensionality reduction/PCA for IRIS Dataset.py


from scipy.stats import t, norm
import pandas as pd
import numpy as np

def compute_ci(r=None, nx=None, ny=None, confidence=.95):
    """Compute Parametric confidence intervals around correlation coefficient.
    See : https://online.stat.psu.edu/stat505/lesson/6/6.3

    This is done by applying Fisher's r to z transform
    z = .5[ln((1+r)/(1-r))] = arctanh(r)

    The Standard error is 1/sqrt(N-3) where N is sample size

    The critical value for normal distribution for a corresponding confidence
    level is calculated from stats.norm.ppf((1 - alpha)/2) for two tailed test

    The lower and upper condidence intervals in z space are calculated with the formula
    z ± critical value*error

    The confidence interval is then converted back to r space

    :param stat : correlation coefficient
    :param nx : length of vector x
    :param ny :length of vector y
    :param confidence : Confidence level (0.95 = 95%)

    :returns : array containing confidence interval
    """

    assert r is not None and nx is not None
    assert isinstance(confidence, float)
    assert 0 < confidence < 1

    z = np.arctanh(r) # Fisher Transform  from r to z
    se = 1 / np.sqrt(nx - 3) # Standard error = 1/sqrt(N-3) where N is sample size
    crit = np.abs(norm.ppf((1 - confidence) / 2)) # Z-critical value
    ci_z = np.array([z - crit * se, z + crit * se]) # CI = point estimator ± critical value*error
    ci = np.tanh(ci_z)  # Back Transform to r-space

    return ci

def partial_corr(data=None, x=None, y=None, z=None, method="pearson"):
    """ Calculate Partial correlation which is the degree of association between
    x and y after removing effect of z. This is done by calculating correlation
    coefficient between the residuals of two linear regressions :
    x\sim z, y\sim z
    See : 1 https://en.wikipedia.org/wiki/Partial_correlation
          2 https://onlinelibrary.wiley.com/doi/pdf/10.1111/j.1467-842X.2004.00360.x?casa_token=p_D3joHC8C0AAAAA:qigIZHVfcVi8vsz1j2t7uQYOorrYaF3Tm4lpQOUzqG_J9gJgtFerOyliKBnQPVG187nJxbA-wcbXU3QcOw
          3 https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4681537/
          4 http://parker.ad.siu.edu/Olive/slch6.pdf
    :param data : pandas dataframe
    :param x : Column name in data
    :param y : Column name in data
    :param z : string or list
    :param method : string denoting the correlation type - "pearson" or "spearman"

    : returns: a python dictionary with keys as
        n: Sample size
        r: Partial correlation coefficient
        CI95: 95% parametric confidence intervals
        p-val: p-value
    """

    assert data.shape[0] > 2 # Check for atleast 3 samples
    assert x != z # x and z should be distinct
    assert y != z # y and z should be distinct
    assert x != y # x and y should be distinct
    if isinstance(z, list):
        assert x not in z # x and z should be distinct
        assert y not in z # y and z should be distinct

    combined_variables = [x,y] # Combine all variables - x, y and z
    for var in z:
        combined_variables.append(var)
    data = data[combined_variables].dropna() #Drop missing values
    n = data.shape[0] # Number of samples after dropping missing values
    k = data.shape[1] - 2 # Number of covariates
    assert n > 2

    if method == "spearman":
        V = data.rank(na_option='keep').cov() # Change data to rank for spearman correlation
    else:
        V = data.astype(float).cov() # Computing Covariance Matrix
    Vi = np.linalg.pinv(V, hermitian=True)   # Computing Inverse Covariance Matrix
    Vi_diag = Vi.diagonal()  # Storing variance
    D = np.diag(np.sqrt(1 / Vi_diag)) # Storing Standard Deviations from diagonal of inverse covariance matrix
    pcor = -1 * (D @ Vi @ D)
    r = pcor[0,1]

    if np.isnan(r):
        return {'n': n, 'r': np.nan, 'CI95%': np.nan, 'p-val': np.nan}

    # Finding p-value using student T test
    dof = n - k - 2  # Degree of freedom for multivariate analysis
    tval = r * np.sqrt(dof / (1 - r**2)) # Test statistic
    pval = 2 * t.sf(np.abs(tval), dof) # Calculate p-value corresponding to the test statistic and degree of freedom

    ci = compute_ci(r=r, nx=(n - k), ny=(n - k)) #Finding Confidence Interval
    ci=np.round(ci, 3)
    stats = {
        'n': n,
        'r': r,
        'CI95%': [ci],
        'p-val': pval.round(5),
    }
    return stats


"""
G R A D I E N T - E N H A N C E D   N E U R A L   N E T W O R K S  (G E N N)

Author: Steven H. Berguin <steven.berguin@gtri.gatech.edu>

This package is distributed under New BSD license.
"""

import numpy as np

class Activation(object):
    def __init__(self, **kwargs):
        for name, value in kwargs.items():
            setattr(self, name, value)

    def evaluate(self, z):
        """
        Evaluate activation function

        :param z: a scalar or numpy array of any size
        :return: activation value at z
        """
        pass

    def first_derivative(self, z):
        """
        Evaluate gradient of activation function

        :param z: a scalar or numpy array of any size
        :return: gradient at z
        """
        pass

    def second_derivative(self, z):
        """
        Evaluate second derivative of activation function

        :param z: a scalar or numpy array of any size
        :return: second derivative at z
        """
        pass

class Sigmoid(Activation):
    def evaluate(self, z):
        a = 1.0 / (1.0 + np.exp(-z))
        return a

    def first_derivative(self, z):
        a = self.evaluate(z)
        da = a * (1.0 - a)
        return da

    def second_derivative(self, z):
        a = self.evaluate(z)
        da = self.first_derivative(z)
        dda = da * (1 - 2 * a)
        return dda

class Tanh(Activation):
    def evaluate(self, z):
        numerator = np.exp(z) - np.exp(-z)
        denominator = np.exp(z) + np.exp(-z)
        a = np.divide(numerator, denominator)
        return a

    def first_derivative(self, z):
        a = self.evaluate(z)
        da = 1 - np.square(a)
        return da

    def second_derivative(self, z):
        a = self.evaluate(z)
        da = self.first_derivative(z)
        dda = -2 * a * da
        return dda

class Linear(Activation):
    def evaluate(self, z):
        return z

    def first_derivative(self, z):
        return np.ones(z.shape)

    def second_derivative(self, z):
        return np.zeros(z.shape)

def plot_activations():  # pragma: no cover
    import matplotlib.pyplot as plt

    x = np.linspace(-10, 10, 100)
    activations = {"tanh": Tanh(), "sigmoid": Sigmoid()}
    for name, activation in activations.items():
        plt.plot(x, activation.evaluate(x))
        plt.title(name)
        plt.show()

if __name__ == "__main__":  # pragma: no cover
    plot_activations()


import sys
import numpy as np
from timeit import default_timer as timer

def norm(v, x):
    n = v.shape[1]  # Número de colunas do vetor (k + 1).
    maximum_numerator = 0
    maximum_denominator = 0

    for i in range(n):
        # Colhendo a maior diferença modular entre os elementos dos vetores (k +1) e k.
        if abs(v[0, i] - x[0, i]) > maximum_numerator:
            maximum_numerator = abs(v[0, i] - x[0, i])

        # Colhendo o maior elemento do vetor (k + 1).
        if abs(v[0, i]) > maximum_denominator:
            maximum_denominator = abs(v[0, i])

    return maximum_numerator / maximum_denominator

def gauss_seidel_method(A, b, e, max_interactions):
    start = timer()
    print("Matrix A:")
    print(A)

    print("\nVector b:")
    print(b)

    n = b.shape[1]  # Número de colunas do vetor b.

    # Inicialmente, os vetores (k + 1) e k e a matriz C terão apenas zeros.
    v = np.zeros((1, n))
    x = np.zeros((1, n))
    C = np.zeros((n, n))

    g = b.copy()  # O vetor g assume os mesmos elementos do vetor b.

    for i in range(n):  # Gerando a matriz C e o vetor g.
        for j in range(n):
            if i != j:
                C[i, j] = ((-1) * A[i, j]) / A[i, i]

        g[0, i] = g[0, i] / A[i, i]

    k = 1

    print("\nMatrix C:")
    print(C)

    print("\nVector g:")
    print(g)

    while k <= max_interactions:
        for i in range(n):  # Atualizando o vetor (k + 1).
            partial_sum = 0

            for j in range(n):
                partial_sum += C[i, j] * v[0, j]

            v[0, i] = partial_sum + g[0, i]

        if norm(v, x) < e:  # Checando se a precisão foi atingida por meio da norma.
            print("\nSolution found:")
            print(v)

            end = timer()
            print("\nRuntime: %.6e seconds in %d interactions." % ((end - start), k))
            return v

        x = v.copy()
        k += 1

    # Corrigindo o número de interações quando a precisão não é atingida durante o while.
    if k == max_interactions + 1:
        k -= 1

    end = timer()
    print("\nRuntime: %.6e seconds in %d interactions." % ((end - start), k))
    return v

gauss_seidel_method(A = np.array(np.mat(sys.argv[1]), dtype = float),
                    b = np.array(np.mat(sys.argv[2]), dtype = float),
                    e = float(sys.argv[3]),
                    max_interactions = 50)