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

# (a)
n_1 = 50
n_2 = 50
x_1 = 40
x_2 = 30
p_hat_1 = x_1 / n_1
p_hat_2 = x_2 / n_2
tau_hat = p_hat_1 - p_hat_2
tau_se_hat = np.sqrt(
    p_hat_1 * (1 - p_hat_1) / n_1 + p_hat_2 * (1 - p_hat_2) / n_2
)
alpha = 0.1
z_alpha = stats.norm.ppf(1 - alpha / 2)
ci = (tau_hat - z_alpha * tau_se_hat, tau_hat + z_alpha * tau_se_hat)
print(f"MLE for tau is {tau_hat:.4}.")
print(f"Standard error for tau is {tau_se_hat:.4}.")
print(f"90% CI for tau is [{ci[0]:.4}, {ci[1]:.4}].")
print()

# (b)
sims = 5_000
rng = np.random.default_rng(42)
x_1_draws = rng.binomial(n_1, p_hat_1, size=sims)
x_2_draws = rng.binomial(n_2, p_hat_2, size=sims)
tau_draws = x_1_draws / n_1 - x_2_draws / n_2
bootstrap_ci = (
    np.quantile(tau_draws, alpha / 2),
    np.quantile(tau_draws, 1 - alpha / 2),
)
print(
    "90% parametric bootstrap CI for tau is",
    f"[{bootstrap_ci[0]:.4}, {bootstrap_ci[1]:.4}].",
)
print()

# (c)
taus = np.arange(-n_2, n_1 + 1)
p_1_posterior_draws = rng.beta(x_1 + 1, n_1 - x_1 + 1, size=sims)
p_2_posterior_draws = rng.beta(x_2 + 1, n_2 - x_2 + 1, size=sims)
tau_posterior_draws = p_1_posterior_draws - p_2_posterior_draws
tau_posterior_mean = tau_posterior_draws.mean()
posterior_ci = (
    np.quantile(tau_posterior_draws, alpha / 2),
    np.quantile(tau_posterior_draws, 1 - alpha / 2),
)
print(f"The posterior mean for tau is {tau_posterior_mean:.4}.")
print(
    "90% posterior CI for tau is",
    f"[{posterior_ci[0]:.4}, {posterior_ci[1]:.4}].",
)
print()

# (d)
psi_hat = np.log((p_hat_1 / (1 - p_hat_1)) / (p_hat_2 / (1 - p_hat_2)))
psi_se_hat = np.sqrt(
    1 / (n_1 * (p_hat_1 - p_hat_1 ** 2)) + 1 / (n_2 * (p_hat_2 ** 2 - p_hat_2))
)
psi_ci = (psi_hat - z_alpha * psi_se_hat, psi_hat + z_alpha * psi_se_hat)
print(f"MLE for psi is {psi_hat:.4}.")
print(f"Standard error for psi is {psi_se_hat:.4}.")
print(f"90% CI for psi is [{psi_ci[0]:.4}, {psi_ci[1]:.4}].")
print()

# (e)
psi_posterior_draws = np.log(
    (p_1_posterior_draws / (1 - p_1_posterior_draws))
    / (p_2_posterior_draws / (1 - p_2_posterior_draws))
)
psi_posterior_mean = psi_posterior_draws.mean()
psi_posterior_ci = (
    np.quantile(psi_posterior_draws, alpha / 2),
    np.quantile(psi_posterior_draws, 1 - alpha / 2),
)
print(f"The posterior mean for psi is {psi_posterior_mean:.4}.")
print(
    "90% posterior CI for psi is",
    f"[{psi_posterior_ci[0]:.4}, {psi_posterior_ci[1]:.4}].",
)


import numpy as np
import scipy.linalg as la

def constructor_matrix(M):
  """
  Building matrix
  """
  return np.matrix(M).transpose()

def minimum_squares(X, Y):
  """
  That function shows least squares of the values
  """
  media_X = np.mean(X)
  media_Y = np.mean(Y)
  erro_x = X-media_X
  erro_y = Y-media_Y
  soma_erro_xy = np.sum(erro_x*erro_y)
  erro_x_quadratico = (X-media_X)**2.0
  soma_erro_x_quadratico = np.sum(erro_x_quadratico)
  m = soma_erro_xy / soma_erro_x_quadratico
  c = media_Y - m*media_X
  reta = m*X+c

  return {
    'media_X': media_X,
    'media_Y': media_Y,
    'erro_x': erro_x,
    'erro_y': erro_y,
    'soma_erro_xy': soma_erro_xy,
    'erro_x_quadratico': erro_x_quadratico,
    'soma_erro_x_quadratico': soma_erro_x_quadratico,
    'm': m,
    'c': c,
    'reta': reta
  }

def plu(A):
  """
  This function shows PLU
  (permutation matrices, lower triangular and upper triangular)
  """
  (P, L, U) = la.lu(A)
  return {
    'P': P,
    'L': L,
    'U': U
  }

def autovalores_autovetores(A):
  """
  That function uses eigenvalues and eigenvectors
  to build the espectral decomposition
  """
  autovalores, autovetores = np.linalg.eig(A)
  return {
    'autovalores': autovalores,
    'autovetores': autovetores
  }

def espectral(autovetores, matrizDiagonal):
  """
  Espectral Decomposition
  """
  return np.matmul(np.matmul(autovetores,matrizDiagonal),np.linalg.inv(autovetores))

def pvd(A):
  """
  That function return the singular values decomposition
  """
  (U,s,V) = np.linalg.svd(A)
  return {
    'U': U,
    's': s,
    'V': V
  }

def back_substitution(A, x, n):
  """
  That function shows back substitution values of a matrix
  """
  b = np.dot(A, x)
  xcomp = np.zeros(n)

  for i in range(n-1, -1, -1):
      tmp = b[i]
      for j in range(n-1, i, -1):
          tmp -= xcomp[j]*A[i,j]

      xcomp[i] = tmp/A[i,i]

  return xcomp


"""
64-point Radix 2 DIF FFT implementation
by zeeshan0309

input here is the sampled signal of the CT function
{3.Sin(16pi.t)+24.Sin(2pi.t)+8.Sin(6pi.t)}
"""

from matplotlib import pyplot as plt
import math
from math import sqrt
import numpy as np

pi = math.pi
def sine(num):
    return math.sin(num)

def cosine(num):
    return math.cos(num)

#twiddle factors W_64 from 0 to 31 (only 32 Twiddle factors required for 64-point DFT)
twiddle = []
N = 64
x = [i for i in range(0,64)]

for i in range(0, 32):
    t_element = complex(cosine(2*pi*i/64), sine(2*pi*i/64))
    twiddle.append(t_element)

#generating random noise using numpy
noise = 3*np.random.randn(N)

#sampling {3.Sin(16pi.t)+24.Sin(2pi.t)+8.Sin(6pi.t)} at fs = 64Hz
# at t = {0, 1/64, 2/64, 3/64, ..., 63/64}
inputSignal = []

for i in range(0, 64):
    s_element = 3*sine(16*pi*i/64)+24*sine(2*pi*i/64)+8*sine(6*pi*i/64)
    inputSignal.append(s_element)

#adding Noise to sample
for i in range(0, N):
    inputSignal[i] += noise[i]

#function for evaluating Even indices term
#def evenAddTerms()
def evenAddTerms(arr, N):
    evenListOut = []
    temp_e_arr = [0]*int(N/2)
    temp_e_arr = arr
    for i in range(0, int(N/2)):
        even_element = temp_e_arr[i]+temp_e_arr[i+int(N/2)]
        evenListOut.append(even_element)
    return evenListOut

#function for evaluating Odd indices term
#def oddSubTerms()
def oddSubTerms(arr, N, twiddle):
    oddListOut = []
    temp_o_arr = [0]*int(N/2)
    temp_o_arr = arr
    for i in range(0, int(N/2)):
        odd_element = (temp_o_arr[i]-temp_o_arr[i+int(N/2)])*twiddle[int((64*i)/N)]
        oddListOut.append(odd_element)
    return oddListOut

#lists for output of each stage (no of stages = log(64) = 6)
stage1 = [0 for i in range(0, 64)]
stage2 = [0+0j]*64
stage3 = [0+0j]*64
stage4 = [0+0j]*64
stage5 = [0+0j]*64
stage6 = [0+0j]*64

stage_list = [inputSignal, stage1, stage2, stage3, stage4, stage5, stage6]

#calculation of all stages done in this loop
for n in range(1, 7, 1):
    step = int(N/(2**(n-1)))
    int_step = int(N/(2**n))
    index_list = [i for i in range(0, N+1, step)]
    for i in range(0, 2**(n-1)):
        stage_list[n][index_list[i]:index_list[i]+int_step] =  evenAddTerms(stage_list[n-1][index_list[i]:index_list[i+1]], int(N/(2**(n-1))))
        stage_list[n][index_list[i]+int_step:index_list[i+1]] = oddSubTerms(stage_list[n-1][index_list[i]:index_list[i+1]], int(N/(2**(n-1))), twiddle)

    print(stage_list[n])
    print("_________________________")

#converting the output to "Magnitude Spectrum"
outputSignal = []
for i in range(len(stage6)):
    temp = sqrt((stage6[i].real)**2+(stage6[i].imag)**2)
    outputSignal.append(temp)

#optional
plt.plot(x, outputSignal)
plt.show()


'''
Using the Shooting method to solve
y" = -3y
with the boundary conditions y(0) = 7 and y(2*pi) = 0
and we know the exact solution
'''

# importing stuff
import numpy as np
from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt

x = np.linspace(0,2*np.pi, 100)
y_exact = 7 * np.cos(np.sqrt(3) * x) - 7 * np.cos(2 * np.pi * np.sqrt(3) ) / np.sin(2 * np.pi * np.sqrt(3) )* np.sin(np.sqrt(3)*x)

# code our second order ODE to two first order ODE

def equations(x,y):
    yprime = np.zeros(2)

    yprime[0] = y[1]
    yprime[1] = -3* y[0]

    return yprime

'''
We will use an iteration scheme to adjust the
values of the initial conditions such that we
match the boundary conditions. What type of
iteration scheme to use is up to you. I will
define high and low bounds and set our natural
guess As the meaning of those two points. I will
then adjust the bounds depending on whether we
overshoot or undershoot our boundary. The exact
way to adjust the bounds is problem dependent.
'''

tol = 1e-6
max_iters = 100
low = -10
high = 10
count = 0

while count <= max_iters:
    count = count + 1
    xspan = (x[0], x[-1])

    #  Use the midpoint between high and low as our guess
    yprime0 = np.mean([low, high])

    #  Set the initial condition vector to be passed into the solver
    y0 = [7, yprime0 ]

    # Solve the system using our guess
    sol = solve_ivp(equations, xspan, y0, t_eval = x)

    #  For ease of use, extract the function values from the solution object.
    y_num = sol.y[0, :]

    #  Check to see if we within our desire tolerance
    if np.abs(y_num[-1]) <= tol:
        break

    #  Adjust our bounds if we are not within tolerance
    if y_num[-1] < 0:
        high = yprime0
    else:
        low = yprime0

    #print(count, y_num[-1])

#  Plot the solution and compare it to the analytical form defined above
plt.plot(x, y_exact, 'b-', label='Exact')
plt.plot(x, y_num, 'ro', label='Numeric')
plt.plot([0, 2*np.pi], [7,0], 'ro')
plt.grid(True)
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
#plt.show()
plt.savefig('shooting_1.png')


import random as rand
import math
import numpy as np
from matplotlib import pyplot as plt
from time import sleep
from sys import stdin

##### generate data for a moving object
### all the following equations are integrals/derivatives of each other
def eq_pos(x, a=-10, b=3, c=-0.2):
    return a*x + b*x**2 + c*x**3
def eq_vel(x):
    return -10 + 6*x - 0.6*x**2
def eq_acc(x):
    return 6 - 1.2*x

def calculate_max_error(x, y, eq):
    time_stamps = np.arange(x[0], x[-1], 0.001)
    m = 0

    xi = 1
    for i in time_stamps:
        while x[xi] < i and xi < len(x):
            xi += 1
        x0 = x[xi-1]
        x1 = x[xi]
        if x0 > i or x1 < i:# prevents comparing outside data set
            continue
        if x1 == 0 or i == 0: # prevents divide by 0
            continue
        slope = (y[xi] - y[xi-1])/(x1-x0)
        p = y[xi-1] + slope*(i-x0)

        m = max(m, abs(p-eq(i)))
    return m

# takes the derivative by calculating the slope between all adjacent points
# by default, calculates the first derivative (deg). Higher degrees calculated recursively
# note: |d_points_y| = |points_y| - 1
def points_derivative(points_x, points_y, deg=1):
    if deg <= 0:
        return (points_x, points_y)

    d_points_y = [] # y of derivative
    d_points_x = [] # ditto for x
    for i in range(len(points_y)-1): # compares adjacent pairs so one fewer than # points
        ## x and y values for adjacent pairs
        ax = points_x[i]
        bx = points_x[i+1]

        ay = points_y[i]
        by = points_y[i+1]

        # the slope of the adjacent point is the y value of the derivative at the x point between the pair
        slope = (by-ay)/(bx-ax)
        d_points_y.append(slope)

        d_points_x.append((ax+bx)/2)

    return points_derivative(d_points_x, d_points_y, deg-1)

# takes the integral by treating the y value between a pair of points as the slope of the integral between those two points
# the point between the x values of the same points
# note: |i_points_y| = |points_y|
def points_integral(points_x, points_y, c=0, deg=1):
    if deg <= 0:
        return (points_x, points_y)

    i_points_y = [c]
    for i in range(len(points_y)-1):
        ax = points_x[i]
        bx = points_x[i+1]
        dx = bx-ax

        slope = (points_y[i]+points_y[i+1])/2

        dy = slope*dx

        y = i_points_y[-1]+dy

        i_points_y.append(y)

    return points_integral(points_x, i_points_y, c, deg-1)

# simulates running a rangefinder by using eq_pos() to get the position values and derives the velocity and acceleration
def simulate_rangefinder(p, x):
    print("simulating rangefinder")
    ## setup plot
    p.grid(color="black", linestyle="-", linewidth=1)
    p.set_title("rangefinder simulation")

    y = eq_pos(x) # measurements taken
    add_line(p, x, y, "r", "position")

    vel_x, vel_y = points_derivative(x, y)
    add_line(p, vel_x, vel_y, "g", "velocity")
    print("velocity " + u"\u00B1" + str(calculate_max_error(vel_x, vel_y, eq_vel)))

    acc_x, acc_y = points_derivative(vel_x, vel_y)
    add_line(p, acc_x, acc_y, "b", "acceleration")
    print("acceleration " + u"\u00B1" + str(calculate_max_error(acc_x, acc_y, eq_acc)), "\n")

# simulates an accelometer using eq_acc to get the acceleration values that would be recorded and integrating to get the
#    velocity and position values
# uses known values of c from eq_vel
def simulate_accelometer(p, x):
    print("simulating accelometer")

    p.grid(color="black", linestyle="-", linewidth=1)
    p.set_title("accelometer simulation")

    acc_y = eq_acc(x) # measurements taken
    add_line(p, x, acc_y, "b", "acceleration")

    vel_x, vel_y = points_integral(x, acc_y, c=-10)
    add_line(p, vel_x, vel_y, "g", "velocity")
    print("velocity " + u"\u00B1" + str(calculate_max_error(vel_x, vel_y, eq_vel)))

    pos_x, pos_y = points_integral(x, vel_y)
    add_line(p, pos_x, pos_y, "r", "position")
    print("position " + u"\u00B1" + str(calculate_max_error(pos_x, pos_y, eq_pos)),"\n")

# draws a line from the list of floats x and y onto the plot p
def add_line(p, x, y, color, name):
    p.plot(x, y, color+".-", label=name) #################
    p.legend()

# this uses the equations for pos, vel, and acc rather than deriving/integrating one to get the other values
def calc_plot(p, x):
    p.grid(color="black", linestyle="-", linewidth=1)
    p.set_title("calculated plot")

    acc_y = eq_acc(x) # measurements taken
    add_line(p, x, acc_y, "b", "acceleration")

    vel_y = eq_vel(x)
    add_line(p, x, vel_y, "g", "velocity")

    pos_y = eq_pos(x)
    add_line(p, x, pos_y, "r", "position")

if __name__ == "__main__":
    # start, end, increment
    x = np.arange(0, 12, 0.01)
    print("number of points generated:", len(x))

    plt.figure(figsize=(9,7))
    rangefinder_plot = plt.subplot2grid((2,2),(0,0))
    accelometer_plot = plt.subplot2grid((2,2), (1,0))
    calculated_plot = plt.subplot2grid((2,2), (0,1))

    simulate_rangefinder(rangefinder_plot, x)
    simulate_accelometer(accelometer_plot, x)
    calc_plot(calculated_plot, np.arange(0, 12, 0.01))

    plt.show()


from statistics import mean
import numpy as np
import matplotlib.pyplot as plt
import random

def create_dataset(n,variance,step=2,correlation=False):
    val = 1
    ys = []
    for i in range(n):
        y = val + random.randrange(-variance,variance)
        ys.append(y)
        if correlation and correlation== "pos":
            val += step
        elif correlation and correlation=="neg":
            val -= step
    xs = [i for i in range(len(ys))]
    return np.array(xs,dtype=np.float64) , np.array(ys , dtype=np.float64)

def best_fit_slope(xs,ys):
    m = ( ((mean(xs)*mean(ys)) - mean(xs*ys)) /
        (mean(xs)*mean(xs) - mean(xs*xs) )  )
    return m

def best_intercept(slope,xs,ys):
    b = mean(ys) - m*mean(xs)
    return b

def squared_error(ys_orig,ys_line):
    return sum((ys_line-ys_orig)**2)

def coefficient_of_determination(ys_orig,ys_line):
    y_mean_line = [mean(ys_orig) for y in ys_orig]
    squared_error_regr = squared_error(ys_orig,ys_line)
    squared_error_mean = squared_error(ys_orig,y_mean_line)
    return 1 - (squared_error_regr/squared_error_mean)

xs , ys = create_dataset(40 , 20 , 2 , correlation="neg")

m = best_fit_slope(xs,ys)
b = best_intercept(m , xs, ys)

regression_line = [(m*x)+b for x in xs]

predic_x = 8
predic_y = m*predic_x + b

r_squared = coefficient_of_determination(ys , regression_line)
print(r_squared)

plt.scatter(xs , ys)
plt.scatter(predic_x,predic_y , s = 100)
plt.plot(xs,regression_line)
plt.show()


"""
Notes:
 Cosine Similarity vs Pearson Correlation Coefficient
  The two quantities represent two different physical entities.
  The cosine similarity computes the similarity between two samples, whereas the Pearson correlation
  coefficient computes the correlation between two jointly distributed random variables.
"""

from scipy.stats import linregress
from scipy.stats.stats import pearsonr

def pcc(x, y):  # pearson correlation coefficient
    """
    pcc_1 Return:
         Pearson's correlation coefficient, 2-tailed p-value

    pcc_2 Return:
        slope : slope of the regression line
        intercept : intercept of the regression line
        r-value : correlation coefficient
        p-value : two-sided p-value for a hypothesis test whose null hypothesis is that
                  the slope is zero
        stderr : Standard error of the estimate
    """

    pcc1 = pearsonr(x, y)
    pcc2 = linregress(x, y)
    return pcc1, pcc2


import numpy as np
try:
    import matplotlib.pyplot as plt
except:
    import matplotlib
    matplotlib.use('Agg')
    import matplotlib.pyplot as plt

class PolynomialRegression():
    def __init__(self, degree):
        """
        Implement polynomial regression from scratch.

        This class takes as input "degree", which is the degree of the polynomial
        used to fit the data. For example, degree = 2 would fit a polynomial of the
        form:

            ax^2 + bx + c

        Your code will be tested by comparing it with implementations inside sklearn.
        DO NOT USE THESE IMPLEMENTATIONS DIRECTLY IN YOUR CODE. You may find the
        following documentation useful:

        https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.PolynomialFeatures.html
        https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html

        Here are helpful slides:

        http://interactiveaudiolab.github.io/teaching/eecs349stuff/eecs349_linear_regression.pdf

        The internal representation of this class is up to you. Read each function
        documentation carefully to make sure the input and output matches so you can
        pass the test cases. However, do not use the functions numpy.polyfit or numpy.polval.
        You should implement the closed form solution of least squares as detailed in slide 10
        of the lecture slides linked above.

        Usage:
            import numpy as np

            x = np.random.random(100)
            y = np.random.random(100)
            learner = PolynomialRegression(degree = 1)
            learner.fit(x, y) # this should be pretty much a flat line
            predicted = learner.predict(x)

            new_data = np.random.random(100) + 10
            predicted = learner.predict(new_data)

            # confidence compares the given data with the training data
            confidence = learner.confidence(new_data)

        Args:
            degree (int): Degree of polynomial used to fit the data.
        """
        self.degree = degree
        self.confidence = None
        self.w = None  # define the weights
        self.f = None  # function
        self.X_training = None

    def fit(self, features, targets):
        """
        Fit the given data using a polynomial. The degree is given by self.degree,
        which is set in the __init__ function of this class. The goal of this
        function is fit features, a 1D numpy array, to targets, another 1D
        numpy array.

        Args:
            features (np.ndarray): 1D array containing real-valued inputs.
            targets (np.ndarray): 1D array containing real-valued targets.
        Returns:
            None (saves model and training data internally)
        """
        X = np.ones((features.size, self.degree + 1))
        X_row = X.shape[0]
        X_column = X.shape[1]

        for i in range(X_row):
            for j in range (1, X_column):
                X[i,j] = features[i]**j

        # formula for weights: (X^TX)X^ty
        X_inv = X.T
        #self.w = np.matmul(np.matmul((np.linalg.inv(np.matmul(X_inv, X))), X_inv), targets)
        self.w = np.linalg.inv(X.T @ X) @ X.T @ targets
        #self.w = ((np.linalg.inv((X.T).dot(X))).dot(X.T)).dot(targets)

        self.features_row = features.shape[0]
        self.f = np.zeros((self.features_row))
        for i in range(self.w.size):
            self.f += self.w[i] * np.sort(features)**i

        self.X_training = features  # save training data internally

    def predict(self, features):
        """
        Given features, a 1D numpy array, use the trained model to predict target
        estimates. Call this after calling fit.

        Args:
            features (np.ndarray): 1D array containing real-valued inputs.
        Returns:
            predictions (np.ndarray): Output of saved model on features.
        """
        predictions = np.zeros((features.shape[0]))

        for i in range(self.w.size):
            predictions += self.w[i] * features**i

        return predictions

    def visualize(self, features, targets, path, title, color='g'):
        """
        This function should produce a single plot containing a scatter plot of the
        features and the targets, and the polynomial fit by the model should be
        graphed on top of the points.

        DO NOT USE plt.show() IN THIS FUNCTION. Instead, use plt.savefig().

        Args:
            features (np.ndarray): 1D array containing real-valued inputs.
            targets (np.ndarray): 1D array containing real-valued targets.
        Returns:
            None (plots to the active figure)
        """

        plt.figure()
        plt.scatter(features, targets)
        plt.plot(np.sort(self.X_training), self.f)
        plt.title(title)
        plt.xlabel('x')
        plt.ylabel('y')
        plt.legend()
        plt.grid(True)
        plt.savefig(path)


'''
Created on 2013/12/29
@author: Duong Nguyen
@note: Nonnegative Matrix Factorization (NMF) with multiplicative update rules.
@version: Kullback-Leibler

V = W*H, where V, W, H >= 0. Here, ">=" means element-wise relation
V: n x m matrix
W: n x b matrix
H: b x m matrix
Minimize_over_{W,H} KL-divergence(V, W*H)

See also, http://hebb.mit.edu/people/seung/papers/nmfconverge.pdf for more details.
'''

import numpy as np
import matplotlib.pyplot as plt

def kl_distance(A, B):
    """ Compute the KL divergence between two matrices A, B.
        KL(A, B) = \sum_{i,j} (A_ij * log(A_ij / B_ij) - A_ij + B_ij)
    """
    return np.sum(A * np.log(A/B) - A + B)

def factorize(V, b, init="uniform", max_iter=100, tol=1e-8, verbose=False):
    """ Factorization with multiplicative update rules.
        @param init: specify how to initialize W, H. Default: uniformly random in [0,1)
        @param max_iter: Maximum number of iterations of updating
        @param tol: Tolerance value to check if converge

        @return: n x b matrix W, and b x m matrix H such that KL(V, W*H) is minimized.
                The values of KL-divergence at each iteration step are also returned as dists.
    """

    assert init in ("uniform", "normal"), "Unsupported initialization!"
    n, m = V.shape

    if init == "uniform":
        W, H = np.random.random((n,b)), np.random.random((b,m))
    else:
        W, H = np.random.randn(n,b), np.random.randn(b,m)

    dists = []
    for i in xrange(max_iter):
        WH = W.dot(H)

        cur_dist = kl_distance(V, WH)
        dists.append(cur_dist)

        if verbose and i % 10 == 0:
            print "%d iteration: %f" %(i, cur_dist)

        if cur_dist <= tol:
            break

        # Update H
        nu = (W.T).dot(V/(WH))
        de = np.tile(np.sum(W,0), (m,1)).T
        H = H*nu/de # element-wise update

        # Update W
        nu = (V/(W.dot(H))).dot(H.T)
        de = np.tile(np.sum(H,1), (n,1))
        W = W*nu/de # element-wise update

    return W, H, dists

def test(plot=False):
    """ Test KL-based NMF."""

    V = np.random.random((10, 9))
    W, H, dists = factorize(V, 3, init="uniform", max_iter=300, tol=1e-8, verbose=True)

    if plot:
        plt.figure()
        plt.clf()
        plt.plot(dists, "b-", lw=2)
        plt.xlabel("Iteration")
        plt.ylabel("KL divergence as cost function")
        plt.title("KL-based NMF Demo")
        plt.show()
        plt.savefig("kl_nmf_demo.png") # save figure at current working directory

    print "V =", V
    print "W * H =", W.dot(H)
    print "KL divergence =", dists[-1]

if __name__ == "__main__":
    test(plot=True)


import pandas as pd
import numpy as np

from prediction import predictions

def compute_r_squared(data, predictions):
    # Write a function that, given two input numpy arrays, 'data', and 'predictions,'
    # returns the coefficient of determination, R^2, for the model that produced
    # predictions.
    #
    # Numpy has a couple of functions -- np.mean() and np.sum() --
    # that you might find useful, but you don't have to use them.

    # YOUR CODE GOES HERE
    r_squared = 1 - np.square(data-predictions).sum()/np.square(data-np.mean(data)).sum()

    """
    Official answer:
    SST = ((data-np.mean(data))**2).sum
    SSReg = ((predictions-data)**2).sum
    r_squared = 1 - SSReg / SST
    """

    return r_squared

if __name__ == "__main__":
    input_filename = "turnstile_data_master_with_weather.csv"
    turnstile_master = pd.read_csv(input_filename)
    predicted_values = predictions(turnstile_master)
    r_squared = compute_r_squared(turnstile_master['ENTRIESn_hourly'], predicted_values)
    print r_squared


# integrantes: GABRIEL GOMEZ, EDUARDO DE LA HOZ, STEPHANIA DE LA HOZ

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.linalg as la
import sys
import mpl_toolkits.mplot3d as mpl
from numpy import genfromtxt
from collections import Counter
from sklearn.preprocessing import StandardScaler

def cleaner(df, k):
    return df[(abs(df[0]-np.mean(df[0])) <= k*np.std(df[0])) & (abs(df[1]-np.mean(df[1])) <= k*np.std(df[1])) & (abs(df[2]-np.mean(df[2])) <= k*np.std(df[2])) & (abs(df[3]-np.mean(df[3])) <= k*np.std(df[3]))]

df = pd.read_table('irisdata.txt', skiprows=9, header=None)
dfClean = df
cat = df.iloc[:, 4].values
df = df.drop(columns=4)
rawdata = np.array(df)
covRawData = np.cov(rawdata.T)
resultRaw = la.eig(covRawData)
eugenVector = resultRaw[1]
eugenValors = resultRaw[0].real

print('matriz de covarianza: ')
print(covRawData)
print('\n')
print('eugenvalores: ')
print(eugenValors)
print('\n')
print('eugenvectores: ')
print(eugenVector)

sumEugen = np.sum(eugenValors)
porEugen = eugenValors/sumEugen
porEugen = porEugen*100

x = np.arange(4)

fig, ax = plt.subplots()
lang = ['PC1', 'PC2', 'PC3', 'PC4']
ax.set_ylabel('n')
ax.set_title('nices')
ax.bar(lang, porEugen, edgecolor='black')
plt.show()

eugenPares = [(np.abs(eugenValors[i]), eugenVector[:, i])
              for i in range(len(eugenValors))]

zerros = np.zeros((4, 1))
matrix1D = np.hstack((eugenPares[0][1].reshape(4, 1), zerros.reshape(4, 1)))
matrix2D = np.hstack((eugenPares[0][1].reshape(
    4, 1), eugenPares[1][1].reshape(4, 1)))
matrix3D = np.hstack((eugenPares[0][1].reshape(
    4, 1), eugenPares[1][1].reshape(4, 1), eugenPares[2][1].reshape(4, 1)))

z = rawdata.dot(matrix3D)
lab = (0, 1, 2)
color = ('green', 'red', 'brown')
with plt.style.context('seaborn-whitegrid'):
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    for lab, color in zip(lab, color):
        ax.scatter(z[cat == lab, 0], z[cat == lab, 1],
                   z[cat == lab, 2], c=color, s=10, label=lab)
    plt.legend(loc=2)
    plt.show()

y = rawdata.dot(matrix2D)
lab2 = (0, 1, 2)
color2 = ('green', 'red', 'brown')
with plt.style.context('seaborn-whitegrid'):
    plt.figure(figsize=(6, 4))
    for lab2, color2, in zip(lab2, color2):
        plt.scatter(y[cat == lab2, 0], y[cat == lab2, 1], label=lab2, c=color2)
    plt.xlabel('componente 1')
    plt.ylabel('componente 2')
    plt.legend(loc='lower center')
    plt.tight_layout()
    plt.show()

v = rawdata.dot(matrix1D)
lab3 = (0, 1, 2)
color3 = ('green', 'red', 'brown')
with plt.style.context('seaborn-whitegrid'):
    plt.figure()
    for lab3, color3, in zip(lab3, color3):
        plt.scatter(v[cat == lab3, 0], v[cat == lab3, 1],
                    label=lab3, c=color3, s=10)
    plt.xlabel('componente 1')
    plt.ylabel('componente 2')
    plt.legend(loc='lower center')
    plt.tight_layout()
    plt.show()

k = 2
cleanDf = cleaner(dfClean, k)
catClean = cleanDf.iloc[:, 4].values
cleanDf = cleanDf.drop(columns=4)
cleanData = np.array(cleanDf)
covCleanData = np.cov(cleanData.T)
resultClean = la.eig(covCleanData)
eugenVectorClean = resultClean[1]
eugenValorsClean = resultClean[0].real
eugenParesClean = [(np.abs(eugenValorsClean[i]), eugenVectorClean[:, i])
                   for i in range(len(eugenValorsClean))]

zerros = np.zeros((4, 1))
matrix1DClean = np.hstack(
    (eugenParesClean[0][1].reshape(4, 1), zerros.reshape(4, 1)))

vClean = cleanData.dot(matrix1DClean)
lab4 = (0, 1, 2)
color4 = ('green', 'red', 'brown')
with plt.style.context('seaborn-whitegrid'):
    plt.figure(figsize=(6, 4))
    for lab4, color4, in zip(lab4, color4):
        plt.scatter(vClean[catClean == lab4, 0],
                    vClean[catClean == lab4, 1], label=lab4, c=color4, s=10)
    plt.xlabel('componente 1')
    plt.ylabel('componente 2')
    plt.legend(loc='lower center')
    plt.tight_layout()
    plt.show()
"""
respuesta de la pregunta n7.
7. What do you observe at the three plots? How many components are actually necessary?

En la grafica de 3d obsebamos que los datos se encuentran bastantes dispersos entre si,
observaamos que un grupo de datos  esta mas apartado de otros
en la grafica dos 2 esa separacion desaparece, al solo tener 2 ejes, se pierde esa separacion que se observamos en
la grafica en 3D, En el la grafica 1D Solo observamos una linea representando todos los conjuntos de datos, perdiendo
demasiada informacion util para poder diferenciar los datos.
consideramos que los componentes mas necesarios serian el pc1 y e pc2.

"""


# -*- coding: utf-8 -*-
# --------------------------------------------------------------------------------- #
# Software de Observaciones Sintéticas S.O.S.
# Line functions
#
# Marcial Becerril, @ 25 August 2020
# Latest Revision: 25 Aug 2020, 21.33 GMT
#
# For all kind of problems, requests of enhancements and bug reports, please
# write to me at:
#
# mbecerrilt92@gmail.com
# mbecerrilt@inaoep.mx
#
# --------------------------------------------------------------------------------- #

import numpy as np

def gaussian(x, A, mu, sigma):
    """
        Gaussian function
        Parameters
        ----------
        x : int/float/array
        A : float
            Amplitude
        mu : float
            Mean
        sigma : float
            Dispersion
        y0 : float
            Offset
        ----------
    """
    return A*np.exp(-((x-mu)**2)/(2*sigma**2))

def lorentzian(x, A, mu, w):
    """
        Gaussian function
        Parameters
        ----------
        x : int/float/array
        A : float
            Amplitude
        mu : float
            Mean
        w : float
            Width
        y0 : float
            Offset
        ----------
    """
    w = np.abs(w)
    return A*(w/(4*(x-mu)**2 + w**2))


'''
A robot is located at the top-left corner of a m x n grid
(marked 'Start' in the diagram below).

The robot can only move either down or right at any point
in time. The robot is trying to reach the bottom-right
corner of the grid (marked 'Finish' in the diagram below).

Now consider if some obstacles are added to the grids.
How many unique paths would there be?

An obstacle and empty space is marked as 1 and 0 respectively in the grid.

Note: m and n will be at most 100.

Example 1:

Input:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
Output: 2
Explanation:
There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right
'''
import numpy as np

class Solution(object):
    def uniquePathsWithObstacles(self, obstacleGrid):
        """
        :type obstacleGrid: List[List[int]]
        :rtype: int
        """
        n = len(obstacleGrid)
        if n == 0:
            return 0
        m = len(obstacleGrid[0])
        grid = np.array([[0 for i in range(m)] for j in range(n)])
        for i in range(m):
            if obstacleGrid[0][i] == 1:
                break
            grid[0, i] = 1
        for j in range(n):
            if obstacleGrid[j][0] == 1:
                break
            grid[j, 0] = 1
        for i in range(1, m):
            for j in range(1, n):
                if obstacleGrid[j][i] == 1:
                    grid[j, i] = 0
                else:
                    grid[j, i] = grid[j-1, i] + grid[j, i-1]
        print(grid)
        return grid[n-1, m-1]

sol = Solution()
obstacleGrid = [[0,0,0],
                [0,1,0],
                [0,0,0]
                        ]
print(sol.uniquePathsWithObstacles(obstacleGrid))


import numpy as np
import math
a = [0,1,2,3,4,5,6,7,8,9]
b = [1,3,2,5,7,8,8,9,10,12]

#Changing lists to numpy arrays
x = np.array(a)
y = np.array(b)

#Finding b0 and b1
mean_x = np.mean(x)
mean_y = np.mean(y)
SS_xy = np.sum(y*x) - 10*mean_y*mean_x
SS_xx = np.sum(x*x) - 10*mean_x*mean_x

b_1 = SS_xy / SS_xx
b_0 = mean_y - b_1*mean_x
print("\nRegression Coefficients: b0 = ",b_0," b1 = ",b_1)

#Finding SSR,SST,SSE and R squared
for i in range(10):
    y_pred = b_0 + b_1*x
SSR = 0
SSE = 0
for i in range(10):
    SSR = SSR + math.pow((y_pred[i]-mean_y),2)
    SSE = SSE + math.pow((y[i]-y_pred[i]),2)
print("\nSSR = ",SSR)
print("\nSSE = ",SSE)
SST = SSR +SSE
R_squared = SSR/SST
print("\nR squared = ",R_squared)

#Gradient decent full batch

print("\nGRADEIENT DECENT")
bb0=0
bb1=0
a=0.001
n=10
y_exp=np.zeros(n)
for j in range(10000):
    for i in range(n):
        y_exp[i]=b_0+b_1*x[i]
        bb0=bb0+a*(y[i]-y_exp[i])
        bb1=bb1+a*(y[i]-y_exp[i])*x[i]
print("\nB0=",bb0)
print("B1=",bb1)

#Gradient decent Stochastic
print("\nGRADEIENT DECENT Stochastic")
bb0=0
bb1=0
a=0.001
y_exp=np.zeros(n)
b=[0,0]
se=10
while(se>1):
    for i in range(n):
        y_exp[i]=b_0+b_1*x[i]
        bb0=bb0+a*(y[i]-y_exp[i])
        bb1=bb1+a*(y[i]-y_exp[i])*x[i]
        b[0]=bb0
        b[1]=bb1
    e=y-y_exp
    se=np.sum((e**2))*(1/n)
print("\nSquared error=",se)
print("B0=",bb0)
print("B1=",bb1)


# Bai toan: Dua vao chieu cao de du doan can nang
#   f(x) = w1.x1 + w2.x2 + w3.x3 + w0
#       w1, w2, w3: const, w0: bias
#       y ~ f(x): quan he tuyen tinh --> Linear Regression --> Toi uu: {w1, w2, w3, w0}
#       y: Gia tri thuc te
#       f(x): Gia tri du doan (predict)

# CT:   w = inverse(A). b
#   Voi:    A = Tranpose(X) . X
#           b = Tranpose(X) . y
#           w = A^-1 . b
# Trong bai nay thi:    (weight) = w_1*(height) + w_0
# Ta can tim` w_1 va w_0

import numpy as np
import matplotlib.pyplot as plt

# height (cm)
X = np.array([[147, 150, 153, 158, 163, 165, 168, 170, 173, 175, 178, 180, 183]]).T

# weight (kg)
y = np.array([[ 49, 50, 51,  54, 58, 59, 60, 62, 63, 64, 66, 67, 68]]).T

# Building Xbar
one = np.ones((X.shape[0], 1))
Xbar = np.concatenate((one, X), axis = 1)
print Xbar

# Calculating weights of the fitting line
A = np.dot(Xbar.T, Xbar)
print A
b = np.dot(Xbar.T, y)
print np.linalg.pinv(A)
w = np.dot(np.linalg.pinv(A), b)

print('w = ', w)

# Preparing the fitting line
w_0 = w[0][0]
w_1 = w[1][0]
x0 = np.linspace(145, 185, 2)
y0 = w_0 + w_1*x0

# Du doan (2 du~ lieu 155, 160 ta chua dua vao mo hinh train)
y1 = w_1*155 + w_0
y2 = w_1*160 + w_0

print( u'Predict weight of person with height 155 cm: %.2f (kg), real number: 52 (kg)'  %(y1) )
print( u'Predict weight of person with height 160 cm: %.2f (kg), real number: 56 (kg)'  %(y2) )

# Drawing the fitting line
plt.plot(X.T, y.T, 'ro')     # data
plt.plot(x0, y0)               # the fitting line
plt.axis([140, 190, 45, 75])
plt.xlabel('Height (cm)')
plt.ylabel('Weight (kg)')
plt.show()


import numpy as np
import copy
from tqdm import trange
def burgers_timestep(x:np.ndarray,y:np.ndarray,u:np.ndarray,v:np.ndarray,nt:int,dt:float=0.001,nu:float=0.1):
    """Solving burgers equation using finite difference with euler time step (1st order approximation)

    Args:
        x (np.ndarray): domain x direction
        y (np.ndarray): domain y direction
        u (np.ndarray): matrix describing x-velocity field in i,j space
        v (np.ndarray): matrix describing y-velocity field in i,j space
        nt (int): number of time advances
        dt (float): time step to use for first order approximation
        nu (float, Optional): Viscosity. Defaults to 0.1

    Returns:
        (tuple): containing

            **u_history** (np.ndarray): history for u velocity
            **v_history** (np.ndarray): history for v velocity
    """

    dx = x[0,2]-x[0,1] # We can do it this way because x and y are initialized using linspace which guarantees constant spacing
    dy = y[1,0]-y[0,0]

    u_history = list()
    v_history = list()
    u_history.append(copy.deepcopy(u)) # set equal to initial value
    v_history.append(copy.deepcopy(v))
    for n in trange(nt):
        un = u.copy()   # previous value
        vn = v.copy()
        for i in range(1,x.shape[0]-1):
            for j in range(1,y.shape[1]-1):
                # Uses backward difference in space to solve first order derivative
                # Central differencing for second order derivative
                u[i,j] = (un[i, j] -(un[i, j] * dt / dx * (un[i, j] - un[i-1, j])) -vn[i, j] * dt / dy * (un[i, j] - un[i, j-1])) + (nu*dt/(dx**2))*(un[i+1,j]-2*un[i,j]+un[i-1,j])+(nu*dt/(dx**2))*(un[i,j-1]-2*un[i,j]+un[i,j+1])
                v[i,j] = (vn[i, j] -(un[i, j] * dt / dx * (vn[i, j] - vn[i-1, j]))-vn[i, j] * dt / dy * (vn[i, j] - vn[i, j-1])) + (nu*dt/(dx**2))*(vn[i+1,j]-2*vn[i,j]+vn[i-1,j])+(nu*dt/(dx**2))*(vn[i,j-1]-2*vn[i,j]+vn[i,j+1])

        u[:,0] = 1       # At all i values when j = 0
        u[:,-1] = 1      # At all i values when j = jmax
        u[0,:] = 1       # At all j values and i = 0
        u[-1,:] = 1     # At all j values and i = imax

        v[:,0] = 1
        v[:,-1] = 1
        v[0,:] = 1
        v[-1,:] = 1

        u_history.append(copy.deepcopy(u))
        v_history.append(copy.deepcopy(v))
    return u_history, v_history


import numpy as np
from layers.activation_layer import *
from layers.gradient_check import *

def mean_square_error_loss(y_hat, y):
    """
    MSE loss, loss=mean(y_hat-y)^2
    :param y_hat: output of the network
    :param y: input labels
    :return: MSE loss
    """
    loss = np.mean((y_hat - y) ** 2)
    num_output = y.shape[1]
    d_loss = 2 * (y_hat - y) / num_output
    return loss, d_loss

def cross_entropy_loss(y_hat, y):
    """
    Cross entropy loss, loss = -sum(yi * log(y_hat))
    :param y_hat: output of the network
    :param y: input labels (one_hot)
    :return: cross entropy loss
    """
    loss = -np.sum(y * np.log(y_hat), axis=1)
    # loss = np.mean(loss, axis=0)
    d_loss = -y / y_hat
    return loss, d_loss

def softmax_loss(x, y):
    shifted_logits = x - np.max(x, axis=1, keepdims=True)
    Z = np.sum(np.exp(shifted_logits), axis=1, keepdims=True)
    log_probs = shifted_logits - np.log(Z)
    probs = np.exp(log_probs)
    N = x.shape[0]
    loss = -np.sum(log_probs[np.arange(N), y]) / N
    dx = probs.copy()
    dx[np.arange(N), y] -= 1
    dx /= N
    return loss, dx

if __name__ == '__main__':
    np.random.seed(231)
    num_classes, num_inputs = 10, 50
    x = 0.001 * np.random.randn(num_inputs, num_classes)
    y = np.random.randint(num_classes, size=num_inputs)

    dx_num = eval_numerical_gradient(lambda x: softmax_loss(x, y)[0], x, verbose=False)
    loss, dx = softmax_loss(x, y)

    # Test softmax_loss function. Loss should be 2.3 and dx error should be 1e-8
    print('\nTesting softmax_loss:')
    print('loss: ', loss)
    print('dx error: ', rel_error(dx_num, dx))


"""
This is an example showing how to use the mgd2d solver.
A 4th order accurate solution is obtained with the 5pt stencil,
by using deferred correction.

"""
import numpy as np
import time
from mgd2d import FMG,V_cycle
#analytical solution
def Uann(x,y,n):
  return np.sin(2*n*np.pi*x)*np.sin(2*n*np.pi*y)

#RHS corresponding to above
def source(x,y,n):
  return -8 * (np.pi)**2 * n**2 * np.sin(2*n*np.pi*x) * np.sin(2*n*np.pi*y)

#input

#input
#FMG is a direct solver. tolerance and iterations are not used

#nv          = 1 # nv : Number of V-cycles within FMG. nv=1 will give solution a to within discretization error.
                 # Increase this to get a higher accuracy solution (upto roundoff limit)
                 # of the discrete problem.(residual on the fine grid =round off limit)
                 # Here I am using nv=2 for the first solve and nv=6 for the second solve.

nlevels    = 7    #total number of grid levels. 1 means no multigrid, 2 means one coarse grid. etc

# Number of points is based on the number of multigrid levels as
# N=A*2**(num_levels-1) where A is an integer >=4. Smaller A is better
# This is a cell centered discretization
NX         = 4*2**(nlevels-1)
NY         = 4*2**(nlevels-1)

#the grid has one layer of ghost cells to help apply the boundary conditions
uann=np.zeros([NX+2,NY+2])#analytical solution
u   =np.zeros([NX+2,NY+2])#approximation
f   =np.zeros([NX+2,NY+2])#RHS

#for deferred correction
uxx   = np.zeros_like(u)
corr  = np.zeros_like(u)

#calcualte the RHS and exact solution
DX=1.0/NX
DY=1.0/NY

n=1 # number of waves in the solution
xc=np.linspace(0.5*DX,1-0.5*DX,NX)
yc=np.linspace(0.5*DY,1-0.5*DY,NY)
XX,YY=np.meshgrid(xc,yc,indexing='ij')

uann[1:NX+1,1:NY+1]=Uann(XX,YY,n)
f[1:NX+1,1:NY+1]=source(XX,YY,n)

print('mgd2d.py : Two Dimensional geometric multigrid solver')
print('NX:',NX,', NY:',NY,', levels: ',nlevels)
#start solving
tb=time.time()

u,res=FMG(NX,NY,nlevels,f,2)

error=np.abs(uann[1:NX+1,1:NY+1]-u[1:NX+1,1:NY+1])
print(' 2nd Order::L_inf (true error): ',np.max(np.max(error)))
print(' Elapsed time: ',time.time()-tb,' seconds')

print('Improving approximation using deferred correction')

#deferred correction
#refer Leveque, p63
Ax=1.0/DX**2
Ay=1.0/DY**2

for i in range(1,NX+1):
  for j in range(1,NY+1):
    uxx[i,j]=(u[i+1,j]+u[i-1,j] - 2*u[i,j])/DX**2

# we should be using one-sided difference formulae for values
# near the boundary. For simplicity I am just applying the
# condition known from the analytical form for these terms.

uxx[ 0,:] = -uxx[ 1,:]
uxx[-1,:] = -uxx[-2,:]
uxx[:, 0] = -uxx[:, 1]
uxx[:,-1] = -uxx[:,-2]

f[ 0,:] = -f[ 1,:]
f[-1,:] = -f[-2,:]
f[:, 0] = -f[:, 1]
f[:,-1] = -f[:,-2]

#correction term
#  del2(f)-2*uxxyy
for i in range(1,NX+1):
  for j in range(1,NY+1):
    corr[i,j]=(Ax*(f[i+1,j]+f[i-1,j])+Ay*(f[i,j+1]+f[i,j-1])-2.0*(Ax+Ay)*f[i,j])-2*(uxx[i,j+1]+uxx[i,j-1] - 2*uxx[i,j])/DY**2

#adjust the RHS to cancel the leading order terms
for i in range(1,NX+1):
  for j in range(1,NY+1):
    f[i,j]+= 1.0/12*DX**2*(corr[i,j])

##solve once again with the new RHS
u,res=FMG(NX,NY,nlevels,f,5)

tf=time.time()
error=np.abs(uann[1:NX+1,1:NY+1]-u[1:NX+1,1:NY+1])
print(' 4nd Order::L_inf (true error): ',np.max(np.max(error)))
print('Elapsed time: ',tf-tb,' seconds')


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jun 21 14:05:55 2018

@author: top40ub
"""

"""
Navigation in 3D is a non-trivial task. Due to the anisotropic definition of spherical coordinate
systems, rotations and movement along isolines or fixed points are tricky. A way to do this a bit
easier is to use an old concept from particle physics called quaternions. To be true, their
mathematical formulation exceeds those of vectors in terms of age. They are common standard
in computer vision.
"""

import numpy as np

"""
Function name : vec_to_quat()
***Description***

Transformation of 3d vectors to 4 dimensional quaternions

***I/O***
Input parameter:
	a) np.array([x,y,z])
Output:
	a) np.array([0,x,y,z])

Inline output: Raises an Error raise Exception('Error the vector is not a 3D vector [x,y,z]') if vector is not of shape (3,)
Plot output:
Save file:
"""
def vec_to_quat(vec):
    if vec.shape[0] == 3:
        quat = np.append([0], vec)
        return quat

    else:
        raise Exception('Error the vector is not a 3D vector [x,y,z]')

"""
Function name : quat_conjug()
***Description***

Calculate the conjugate quaternion of given quaternion

***I/O***
Input parameter:
	a) np.array([w,x,y,z])
Output:
	a) np.array([w,-x,-y,-z])

Inline output: Raises an Error raise Exception('Error the quaternion is not a 4D [w,x,y,z]') if quaternion is not of shape (4,)
Plot output:
Save file:
"""
def quat_conjug(quat):
    if quat.shape[0] == 4:
        w, x, y, z = quat
        quatconjung = np.array([w, -x, -y, -z])
        return quatconjung
    else:
        raise Exception('Error the quaternion is not a 4D [w,x,y,z]')

"""
Function name : vec_normal()
***Description***

Normalisation of given vector within a certain tolerance

***I/O***
Input parameter:
	a) np.array([x,y,z])

Output:
	a) np.array([x,y,z]) with x² + y² + z² = 1

Inline output: Raises an Error Exception('Error the vector is not a 3D vector [x,y,z]') if vector is not of shape (3,)
Plot output:
Save file:
"""
def vec_normal(vec, tolerance=0.00001):
    if vec.shape[0] == 3:
    	vec_len_quad = np.sum([n * n for n in vec])
    	if abs(vec_len_quad - 1.0) > tolerance:
        	vec_len = np.sqrt(vec_len_quad)
        	vec = vec/vec_len
    	return vec
    else:
        raise Exception('Error the vector is not a 3D vector [x,y,z]')

"""
Function name : quat_mult()
***Description***

This function defins how to quaternions multiplicate. The multiplication core
can be interpreted as a kind of rotation. For deeper information read the
coresponding wikipedia page or one of the plenty graphical visualition books
about computer vision like I' ve done :)

***I/O***
Input parameter:
	a) np.array([w1,x1,y1,z1]), np,array([w2,x2,y2,z2])
Output:
	a) np.array([w_mult,x_mult,y_mult,z_mult])

Inline output: Raises an error Exception('Error one quaternion is not a 4D [w,x,y,z]') if quaternion is not of shape (4,)
Plot output:
Save file:
"""
def quat_mult(quat1, quat2):
    if quat1.shape[0] == 4 and quat2.shape[0] ==4:
        w1, x1, y1, z1 = quat1
        w2, x2, y2, z2 = quat2
        w_mult = w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2
        x_mult = w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2
        y_mult = w1 * y2 + y1 * w2 + z1 * x2 - x1 * z2
        z_mult = w1 * z2 + z1 * w2 + x1 * y2 - y1 * x2
        quat_mult = np.array([w_mult, x_mult, y_mult, z_mult])
        return quat_mult
    else:
        raise Exception('Error one quaternion is not a 4D [w,x,y,z]')

"""
Function name : quat_vec_mult()
***Description***

Quaternionic multiplication between quaternion and vector. The vector
is transformed. A second quaternionc multiplication with the conjugate of given
quaternion returns the three vector compoments [1:] of the operation.

***I/O***
Input parameter:
	a) np.array([x1,y1,z1]), np,array([w2,x2,y2,z2])
Output:
	a) np.array([w_mult,x_mult,y_mult,z_mult])

Inline output: Raises an error Exception('Error the quaternion is not a 4D [w,x,y,z] or the vector is not 3D [x,y,z]') if quaternion or vector are not of shape (4,) or (3,)
Plot output:
Save file:
"""
def quat_vec_mult(vec1, quat1):
    if vec1.shape[0] == 3 and quat1.shape[0] ==4:
    	quat2 = vec_to_quat(vec1)
    	return quat_mult(quat_mult(quat1, quat2), quat_conjug(quat1))[1:]
    else:
        raise Exception('Error the quaternion is not a 4D [w,x,y,z] or the vector is not 3D [x,y,z]')

"""
Function name : axisangle_to_quat()
***Description***

Calcuation to transform a unit vector or any vector that will be normalsied
into a quaternion that elements are object to a rotation around half theta.
!Theta needs to be of type degree!

***I/O***
Input parameter:
	a) np.array([x,y,z]), np.array([theta])

Output:
	a) np.array([w_a,x_a,y_a,z_a])

Inline output: Raises an error Exception('Error the vector is not 3D [x,y,z] or the angle 1D [theta]') if vector or angle are not of shape(3,) or (1,)
Plot output:
Save file:
"""
def axisangle_to_quat(vec, theta):
    if vec.shape[0] == 3 and theta.shape[0] == 1:
        vec = vec_normal(vec)
        x, y, z = vec
        theta = theta[0]/2
        theta = np.deg2rad(theta)
        w_a = np.cos(theta)
        x_a = x * np.sin(theta)
        y_a = y * np.sin(theta)
        z_a = z * np.sin(theta)
        quat_a = np.array([w_a, x_a, y_a, z_a])
        return quat_a
    else:
        raise Exception('Error the vector is not 3D [x,y,z] or the angle 1D [theta]')

"""
Function name : quat_to_axisangle()
***Description***

The opposite function of axisangle_to_quat, it returns the axisangle the
corresponding unit vector of a given quaternion.

***I/O***
Input parameter:
	a) np.array([w,x,y,z])

Output:
	a) np.array([x_a,y_a,z_a]), np.arra([theta])

Inline output: Raises an error Exception('Error the quaternion is not a 4D [w,x,y,z]') if quaternion is not of shape (4,)
Plot output:
Save file:
"""
def quat_to_axisangle(quat):
   if quat.shape[0] == 4:
    	w, vec = quat[0], quat[1:]
    	theta = np.rad2deg(np.arccos(w) * 2.0)
    	return vec_normal(vec), theta

   else:
       raise Exception('Error the quaternion is not a 4D [w,x,y,z]')

"""
Function name :vec_angle_rot()
***Description***

Main function for the quaternionic rotation of 3D vectors:
A vector (vec) is rotated around a second vector a_unit with angle theta.
a_unit is a axisvector but mostly a basis vector of given cartesic coordinate
system. In case of a cartesic basis vector we have the rotation around
coordinate axsis.

***I/O***
Input parameter:
	a) np.array([x,y,z]), np.array([theta]),
        np.array(x2,y2,z2) with x2² + y2² + z2² = 1

Output:
	a) np.array([x1_rot,y1_rot,z1_rot])

Inline output: Raises an error Exception('Error one vector is not 3D [x,y,z] or the angle 1D [theta]') if vector or angle are not of shape (3,) or (1,)
Plot output:
Save file:
"""
def vec_angle_rot(vec,theta,a_unit):
    if vec.shape[0] == 3 and theta.shape[0] == 1 and vec.shape[0] == 3:
    	quat1 = vec_to_quat(vec)
    	quat_a = axisangle_to_quat(a_unit,theta)
    	v_rot = quat_mult(quat_mult(quat_a,quat1),quat_conjug(quat_a))[1:]
    	return v_rot
    else:
        raise Exception('Error one vector is not 3D [x,y,z] or the angle 1D [theta]')

if __name__=='__main__':
	pass


"""
.. module:: utils
    :synopsis: Provides routines of interest to different ML models.

.. moduleauthor:: Benardi Nunes <benardinunes@gmail.com>
"""

from numpy import zeros, copy, std, mean, float64, exp

# sigmoid gradient function
def g(x):
    """This function applies the sigmoid function on a given value.

    :param x: Input value or object containing value .
    :type x: obj

    :returns: Sigmoid function at value.
    :rtype: obj
    """
    return 1 / (1 + exp(-x))

# sigmoid gradient function
def g_grad(x):
    """This function calculates the sigmoid gradient at a given value.

    :param x: Input value or object containing value .
    :type x: obj

    :returns: Sigmoid gradient at value.
    :rtype: obj
    """
    return g(x) * (1 - g(x))

def gradient_descent(X, y, grad, initial_theta,
                     alpha, num_iters, _lambda=None):
    """This function performs parameter optimization via gradient descent.

    :param X: Features' dataset plus bias column.
    :type X: numpy.array

    :param y: Column vector of expected values.
    :type y: numpy.array

    :param grad: Routine that generates the partial derivatives given theta.
    :type grad: numpy.array

    :param initial_theta: Initial value for parameters to be optimized.
    :type initial_theta: numpy.array

    :param alpha: Learning rate or step size of the optimization.
    :type alpha: float

    :param num_iters: Number of times the optimization will be performed.
    :type num_iters: int

    :param _lambda: Weight of the penalty term.
    :type _lambda: float

    :returns: Optimized model parameters.
    :rtype: numpy.array
    """
    if _lambda is not None:
        theta = copy(initial_theta)

        for _ in range(num_iters):
            theta = theta - alpha * grad(theta, X, y, _lambda)

    else:
        theta = copy(initial_theta)
        for _ in range(num_iters):
            theta = theta - alpha * grad(theta, X, y)

    return theta

def numerical_grad(J, theta, err):
    """Numerically calculates the gradient of a given cost function.

    :param J: Function handle that computes cost given theta.
    :type J: function

    :param theta: Model parameters.
    :type theta: numpy.array

    :param err: distance between points where J is evaluated.
    :type err: float

    :returns: Computed numeric gradient.
    :rtype: numpy.array
    """
    num_grad = zeros(theta.shape, dtype=float64)
    perturb = zeros(theta.shape, dtype=float64)

    for i in range(len(theta)):
        perturb[i] = err
        loss1 = J(theta - perturb)
        loss2 = J(theta + perturb)
        num_grad[i] = (loss2 - loss1) / (2 * err)
        perturb[i] = 0

    return num_grad

def feature_normalize(X):
    """Performs Z score normalization in a numeric dataset.

    :param X: Features' dataset plus bias column.
    :type X: numpy.array

    :returns:
        - X_norm - Normalized features' dataset.
        - mu - Mean of each feature
        - sigma - Standard deviation of each feature.

    :rtype:
        - X_norm (:py:class: numpy.array)
        - mu (:py:class: numpy.array)
        - sigma (:py:class: numpy.array)
    """
    mu = mean(X)
    sigma = std(X)

    X_norm = (X - mu) / sigma

    return X_norm, mu, sigma


'''
06 - Boolean operators with Numpy

Before, the operational operators like < and >= worked with Numpy arrays out of the box.
Unfortunately, this is not true for the boolean operators and, or, and not.

To use these operators with Numpy, you will need np.logical_and(), np.logical_or() and np.logical_not().
Here's an example on the my_house and your_house arrays from before to give you an idea:

logical_and(your_house > 13,
            your_house < 15)

Instructions:

 - Generate boolean arrays that answer the following questions:

 - Which areas in my_house are greater than 18.5 or smaller than 10?

 - Which areas are smaller than 11 in both my_house and your_house? Make sure to wrap both commands
   in print() statement, so that you can inspect the output.
'''
# Create arrays
import numpy as np
my_house = np.array([18.0, 20.0, 10.75, 9.50])
your_house = np.array([14.0, 24.0, 14.25, 9.0])

# my_house greater than 18.5 or smaller than 10
print(np.logical_or(my_house > 18.5,
                    my_house < 10))

# Both my_house and your_house smaller than 11
print(np.logical_and(my_house < 11,
                     your_house < 11))


# Chapter 3 Decision tree learning

# Maximizing information gain - getting the most bang for the buck
''' Plot the impurity indices for the probability range [0,1] for class 1.
Note that we will also add in a scaled version of the entropy (entropy/2)
to observe that the Gini impurity is an intermediate measure  between
entropy and the classification error. '''

import matplotlib.pyplot as plt
import numpy as np

def gini(p):
    return (p) * (1 - (p)) + (1 - p) * (1 - (1-p))

def entropy(p):
    return - p*np.log2(p) - (1 - p)* np.log2((1 - p))

def error(p):
    return 1 - np.max([p, 1 - p])

x = np.arange(0.0, 1.0, 0.01)
ent = [entropy(p) if p != 0 else None for p in x]
sc_ent = [e*0.5 if e else None for e in ent]
err = [error(i) for i in x]
fig = plt.figure()
ax = plt.subplot(111)
for i, lab, ls, c, in zip([ent, sc_ent, gini(x), err], ['Entropy', 'Entropy (scaled)', 'Gini Impurity', 'Misclassification Error'],
['-', '-', '--', '-.'], ['black', 'lightgray', 'red', 'green', 'cyan']):
   line = ax.plot(x, i, label=lab, linestyle=ls, lw=2, color=c)

ax.legend(loc='upper center', bbox_to_anchor=(0.5, 1.15), ncol=3, fancybox=True, shadow=False)
ax.axhline(y=0.5, linewidth=1, color='k', linestyle='--')
ax.axhline(y=1.0, linewidth=1, color='k', linestyle='--')
plt.ylim([0, 1.1])
plt.xlabel('p(i=1)')
plt.ylabel('Impurity Index')
plt.show()

# Building a decision tree
'''
Decision trees can build complex decision boundaries by dividing the feature
space into rectangles. Using scikit-learn, we will now train a decision tree with
a maximum depth of 3 using entropy as a criterion for impurity.  Although feature
scaling may be desired for visualization purposes, note that feature scaling is
not a requirement for decision tree algorithms.
 '''
# Train a  model to classify the different flowers in our Iris dataset
from sklearn import datasets
import numpy as np

iris = datasets.load_iris()
X = iris.data[:, [2, 3]]
y = iris.target

from sklearn.cross_validation import train_test_split

# random_state : int or RandomState
# Pseudo-random number generator state used for random sampling.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt

def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):
    # setup marker generator and color map
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])
    # plot the decision surface
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
                           np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())
    # plot all samples
    X_test, y_test = X[test_idx, :], y[test_idx]
    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1], alpha=0.8, c=cmap(idx), marker=markers[idx], label=cl)

    # highlight test samples
    if test_idx:
        X_test, y_test = X[test_idx, :], y[test_idx]
        plt.scatter(X_test[:, 0], X_test[:, 1], c='', alpha=1.0, linewidth=1, marker='o', s=55, label='test set')

from sklearn.tree import DecisionTreeClassifier
tree = DecisionTreeClassifier(criterion='entropy',max_depth=3, random_state=0)
tree.fit(X_train, y_train)
X_combined = np.vstack((X_train, X_train))
y_combined = np.hstack((y_train, y_test))
plot_decision_regions(X_combined, y_combined, classifier=tree, test_idx=range(105,150))
plt.xlabe('petal length [cm]')
plt.ylabel('petal width [cm]')
plt.legend(loc='upper left')
plt.show()

'''
A nice feature in scikit-learn is that is allows us to export the decision tree as a
.dot file after training, which we can visualize using the GraphViz program.
First, we create the .dot file via scikit-learn using the export_graphviz function
from the tree submodule, as follows:
'''
from sklearn.tree import export_graphviz
export_graphviz(tree, out_file='C:\Users\Wei\Desktop/tree.dot', feature_names=['petal length', 'petal width'])

'''
After installed GraphViz on the computer, we can convert the tree.dot file into a PNG file
by executing the following command from the command line in the location where we
saved the tree.dot file:

> dot -Tpng tree.dot -o tree.png
'''

self_practice/Chapter 3 Decision Tree.py


# -*- coding: utf-8 -*-
"""
Created on Fri Apr 23 11:49:57 2021

@author: ahmed
"""

from statistics import mean
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import style

style.use('fivethirtyeight')

xs = np.array([1,2,3,4,5,6], dtype=np.float64)
ys = np.array([5,4,6,5,6,7], dtype=np.float64)

def best_fit_slope_and_intercept(xs,ys):
    m = (((mean(xs)*mean(ys)) - mean(xs*ys))/
          ((mean(xs)**2)-mean(xs**2)) )
    b = mean(ys) - m*mean(xs)
    return m,b

def squared_error(ys_orig, ys_line):
    return sum((ys_line-ys_orig)**2)

def coefficient_of_determination(ys_orig, ys_line):
    y_mean_line =[mean(ys_orig) for y in ys_orig]
    print('y_mean_line', y_mean_line)

    squared_error_regr = squared_error(ys_orig, ys_line)
    print('squared_error_regr', squared_error_regr)

    squared_error_y_mean = squared_error(ys_orig, y_mean_line)

    return 1 - (squared_error_regr / squared_error_y_mean)

m,b = best_fit_slope_and_intercept(xs,ys)
regression_line = [(m*x)+b for x in xs]

predict_x = 7
predict_y = m*predict_x + b

r_squared =coefficient_of_determination(ys, regression_line)
print(r_squared)

plt.scatter(xs,ys)
plt.scatter(predict_x,predict_y, color='r')
plt.plot(xs,regression_line)
plt.show()

Machine learning/sentdex course/Machine learning/Regression/ML8-slopecalculation.py


"""ЛР 1.5, Ларькин Владимир, М8О-303Б-18"""

import numpy as np
import fire  # CLI
import matplotlib.pyplot as plt

from utilities import parse_matrix  # парсинг матрицы из файла

def householder(a, sz, k):
    v = np.zeros(sz)
    v[k] = a[k] + np.sign(a[k]) * np.linalg.norm(a[k:])
    for i in range(k + 1, sz):
        v[i] = a[i]
    v = v[:, np.newaxis]
    H = np.eye(sz) - (2 / (v.T @ v)) * (v @ v.T)
    return H

def get_QR(A):
    sz = len(A)
    Q = np.identity(sz)
    A_i = np.copy(A)

    for i in range(sz - 1):
        col = A_i[:, i]
        H = householder(col, len(A_i), i)
        Q = Q @ H
        A_i = H @ A_i

    return Q, A_i

def get_roots(A, i):
    sz = A.shape[0]
    a11 = A[i, i]
    a12 = A[i, i + 1] if i + 1 < sz else 0
    a21 = A[i + 1, i] if i + 1 < sz else 0
    a22 = A[i + 1, i + 1] if i + 1 < sz else 0
    return np.roots((1, -a11 - a22, a11 * a22 - a12 * a21))

def finish_iter_for_complex(A, eps, i):
    Q, R = get_QR(A)
    A_next = R @ Q
    lambda1 = get_roots(A, i)
    lambda2 = get_roots(A_next, i)
    return True if abs(lambda1[0] - lambda2[0]) <= eps and abs(lambda1[1] - lambda2[1]) <= eps else False

def get_eigenvalue(A, eps, i):
    A_i = np.copy(A)
    while True:
        Q, R = get_QR(A_i)
        A_i = R @ Q
        a = np.copy(A_i)
        if np.linalg.norm(a[i + 1:, i]) <= eps:
            res = (a[i][i], False, A_i)
            break
        elif np.linalg.norm(a[i + 2:, i]) <= eps and finish_iter_for_complex(A_i, eps, i):
            res = (get_roots(A_i, i), True, A_i)
            break
    return res

def QR_method(A, eps):
    res = []
    i = 0
    A_i = np.copy(A)
    while i < A.shape[0]:
        eigenval = get_eigenvalue(A_i, eps, i)
        if eigenval[1]:
            res += [*eigenval[0]]
            i += 2
        else:
            res.append(eigenval[0])
            i += 1
        A_i = eigenval[2]
    return np.array(res), i

def main(src, test=False, eps=0.01):
    """Нахождение собственных значений матрицы методом QR-разложения

    :param src: путь к текстовому файлу с матрицей
    :param test: флаг, запускающий тестирование
    :param eps: точность вычисления
    """

    np.random.seed(42)

    # чтение файла
    with open(src, "r") as file:
        s = file.readlines()

    matrix = parse_matrix(s)

    print(f"Матрица:\n{matrix}")
    print(f"\neps={eps}\n")

    tmp, count_iter = QR_method(matrix, eps)
    print("QR_method:\n", tmp)

    print("\nnp.linalg.eig:\n", np.linalg.eig(matrix)[0])

if __name__ == "__main__":
    fire.Fire(main)


# A manufacturer purchases a part for use at both of its plantsdashone at Roseville, California, the other at Akron, Ohio.
# The part is available in limited quantities from two suppliers.

# Each supplier has 85 units available.

# The Roseville plant needs 50 units, and the Akron plant requires 85 units.

# The first supplier charges $50 per unit delivered to Roseville and $80 per unit delivered to Akron.

# Corresponding costs from the second supplier are $90 and $110.

# The manufacturer wants to order a total of 85 units from the first, less expensive supplier, with the remaining 50 units to come from the second supplier.
# If the company spends $10,800 to purchase the required number of units for the two plants, find the number of units that should be sent from each supplier to each plant.

# Write a linear system of equations.

# The number of units sent from the first supplier to Roseville is w,
# the number of units sent from the first supplier to Akron is x,
# the number of units sent from the second supplier to Roseville is y,
# and the number of units sent from the second supplier to Akron is z.

# Choose the correct answer below.

from sympy import symbols, solve

w,x,y,z = symbols( 'w,x,y,z' )

# w + y = 50
expr1 = w + y - 50

# w + x = 85
expr2 = w + x - 85

# w + x + y + z = 135
expr3 = w + x + y + z - 135

# 50*w + 80*x + 90*y + 110*z
expr4 = 50*w + 80*x + 90*y + 110*z - 10800

solve( ( expr1, expr2, expr3, expr4 ), dict = True )


import numpy as np

# Demonstrates ndarray attributes.
#
# Run from the commandline with
#
#  python arrayattributes2.py
b = np.arange(24).reshape(2, 12)
print "In: b"
print b
#Out:
#array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11],
#       [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]])

print "In: b.ndim"
print b.ndim
#Out: 2

print "In: b.size"
print b.size
#Out: 24

print "In: b.itemsize"
print b.itemsize
#Out: 8

print "In: b.nbytes"
print b.nbytes
#Out: 192

print "In: b.size * b.itemsize"
print b.size * b.itemsize
#Out: 192

print "In: b.resize(6,4)"
print b.resize(6,4)

print "In: b"
print b
#Out:
#array([[ 0,  1,  2,  3],
#       [ 4,  5,  6,  7],
#       [ 8,  9, 10, 11],
#       [12, 13, 14, 15],
#       [16, 17, 18, 19],
#       [20, 21, 22, 23]])

print "In: b.T"
print b.T
#Out:
#array([[ 0,  4,  8, 12, 16, 20],
#       [ 1,  5,  9, 13, 17, 21],
#       [ 2,  6, 10, 14, 18, 22],
#       [ 3,  7, 11, 15, 19, 23]])

print "In: b.ndim"
print b.ndim
#Out: 1

print "In: b.T"
print b.T
#Out: array([0, 1, 2, 3, 4])

print "In: b = array([1.j + 1, 2.j + 3])"
b = np.array([1.j + 1, 2.j + 3])

print "In: b"
print b
#Out: array([ 1.+1.j,  3.+2.j])

print "In: b.real"
print b.real
#Out: array([ 1.,  3.])

print "In: b.imag"
print b.imag
#Out: array([ 1.,  2.])

print "In: b.dtype"
print b.dtype
#Out: dtype('complex128')

print "In: b.dtype.str"
print b.dtype.str
#Out: '<c16'

print "In: b = arange(4).reshape(2,2)"
b = np.arange(4).reshape(2,2)

print "In: b"
print b
#Out:
#array([[0, 1],
#       [2, 3]])

print "In: f = b.flat"
f = b.flat

print "In: f"
print f
#Out: <numpy.flatiter object at 0x103013e00>

print "In: for it in f: print it"
for it in f:
   print it
#0
#1
#2
#3

print "In: b.flat[2]"
print b.flat[2]
#Out: 2

print "In: b.flat[[1,3]]"
print b.flat[[1,3]]
#Out: array([1, 3])

print "In: b"
print b
#Out:
#array([[7, 7],
#       [7, 7]])

print "In: b.flat[[1,3]] = 1"
b.flat[[1,3]] = 1

print "In: b"
print b
#Out:
#array([[7, 1],
#       [7, 1]])


''' mbinary
#########################################################################
# File : numerical_integration.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-10-02  21:14
# Description:
#########################################################################
'''

#########################################################################
# File : numerical integration.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-11  08:58
# Description:
#       numerical intergration: using Newton-Cotes integration,  and Simpson
#       数值积分, 使用 牛顿-科特斯积分, 辛普森
#########################################################################

import numpy as np
def trapezoidal(a,b,h,fs):
    '''梯形积分公式'''
    xs = [i for i in np.arange(a,b+h,h)]
    print(xs)
    ret = h*(sum(fs)-fs[0]/2 - fs[-1]/2)
    print(ret)
    return ret

def simpson(a,b,h,fs):
    '''辛普森积分公式'''
    xs = [i for i in np.arange(a,b+h,h)]
    print(xs)
    ret = h/3*(4* sum(fs[1::2])+ 2*sum(fs[2:-1:2]) + fs[0]+fs[-1])
    print(ret)
    return ret

def romberg(a,b,f,epcilon):
    '''romberg(龙贝格) 数值积分'''
    h = b-a
    lst1=[h*(f(a)+f(b))/2]
    print(lst1)
    delta = epcilon
    k=1
    while delta >= epcilon:
        h/=2
        k+=1
        lst2=[]
        lst2.append((lst1[0]+h*2*sum(f(a+(2*i-1)*h) for i in range(1,2**(k-2)+1)))/2)
        for j in range(0,k-1):
            lst2.append(lst2[j]+(lst2[j]-lst1[j])/(4**(j+1)-1))
        delta = abs(lst2[-1]-lst1[-1])
        lst1=lst2
        print(lst1)

if __name__=='__main__':
    a,b,h = 0.6,1.8,0.2
    fs=[5.7,4.6,3.5,3.7,4.9,5.2,5.5]
    trapezoidal(a,b,h,fs)
    simpson(a,b,h,fs)
    romberg(1,2,lambda x:sin(x**4),1e-4)


import numpy as np

def euclidean_distance(x):
    """Computes euclidean distance between coordinates in x

    :param x: a vecotr of values
    :type x: list or numpy arrau
    :return: scalar value of euclidean distance
    :rtype: scalar
    """
    dist = np.linalg.norm(x)
    return dist


import numpy as np

class Sigmoid():
    """
    Sigmoid activation function
    """
    def __call__(self, X: np.ndarray) -> np.ndarray:
        """
        Performs the sigmoid function on a given vector

        Parameters
        ----------
        X : array_like, shape {n_samples, n_features}
            Input vector

        Returns
        -------
        array_like, shape {n_samples, n_features}
            Input vector transformed
        """
        return 1 / (1 + np.exp(-X))

class Softmax():
    """
    Softmax activation function
    """
    def __call__(self, scores: np.ndarray) -> np.ndarray:
        """
        Performs the softmax function on a given vector

        Parameters
        ----------
        X : array_like, shape {n_samples, n_classes}
            Scores vector

        Returns
        -------
        array_like, shape {n_samples, n_classes}
            Scores vector transformed
        """
        exps = np.exp(scores)
        exps_sum = np.sum(exps, axis=1, keepdims=True)

        return exps / exps_sum


"""
# Execution
## $ python3 problem2.py input2.csv output2.csv
### This should generate an output file called output2.csv. There are ten cases in total, nine with the specified learning rates (and 100 iterations), and one with your own choice of learning rate (and your choice of number of iterations). After each of these ten runs, your program must print a new line to the output file, containing a comma-separated list of alpha, number_of_iterations, b_0, b_age, and b_weight in that order (see example), please do not round you your numbers. These represent the regression models that your gradient descents have computed for the given dataset.

### For the output, please follow the exact format, with no extra commas, change in upper/lower case etc. Extra unnecessary commas may make the automated script fail and result in you losing points.

### What To Submit. problem2.py, which should behave as specified above. Before you submit, the RUN button on Vocareum should help you determine whether or not your program executes correctly on the platform.

"""

# builtin modules
import os
import psutil
import requests
import sys
import math

# 3rd party modules
import pandas as pd
import numpy as np
#import plotly.graph_objects as go

# Prepare data

def get_data(source_file:str = 'input2.csv'):

# Define input and output filepaths
    input_path = os.path.join(os.getcwd(),'datasets','in', source_file)

    # Read input data
    df = pd.read_csv(input_path)

    for col in df.columns:
        df[col] = (df[col] - np.mean(df[col]))/np.std(df[col])
        #note: numpy.std returns the population standard deviation
    return df

def gradient_descent(df=df, iterations:int = 100, learning_rates:tuple = (0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10)):

    """
    X:dataframe of feature columns: age and weight
    y: dataframe of label column: height
    beta:
    learning_rate:
    iterations:
    """
    df = pd.concat([pd.Series(1, index=df.index, name='b_0'), df], axis=1)

    X = df[df.columns[0:3]].values

    y = df[df.columns[3]].to_numpy()
    #y = y[:, np.newaxis]

    m = y.shape[0]
    betas = np.zeros(X.shape[1]) #initialize betas as zeros, e.g. array([0., 0., 0.])
    betas_new =[]

    for alfa in learning_rates:
        i = 0
        while i < iterations:
            hypothesis = np.dot(X, betas)
            #hypothesis = hypothesis.reshape(hypothesis.shape[0],1)
            betas = betas - (1/m) * alfa *(X.T.dot((hypothesis - y)))
            i += 1
        betas_new.append(betas)

    return betas_new

def write_csv(filename:str='output2.csv', betas_new:list = betas_new, iterations:int = 100, learning_rates:tuple = (0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10)):
        # write the outputs csv file
        filepath = os.path.join(os.getcwd(),'datasets','out', filename)
        iter_array = np.full(len(learning_rates), iterations)
        df_iter = pd.DataFrame(iter_array)
        df_lr = pd.DataFrame(learning_rates)
        df_b = pd.DataFrame(betas_new)
        df_final = pd.concat([df_lr, df_iter, df_b], axis = 1, ignore_index = True)
        dataframe = df_final.rename(columns={0:'alpha',1:'number_of_iterations',2:'b_0', 3:'b_age',4:'b_weight'})
        dataframe.to_csv(filepath, index = False, header = False)
        return print("New Outputs file saved to: <<", filename, ">>", sep='', end='\n')

def main():
    """
    ## $ python3 problem2.py input2.csv output2.csv
    """
    #take string for input data csv file
    in_data = str(sys.argv[1])
    #take string for output data csv file
    out_data = str(sys.argv[2])

    df = get_data(in_data)
    betas_new = gradient_descent(df)
    write_csv(out_data, betas_new)

if __name__ == '__main__':
    main()


import numpy as np
import tensorflow as tf
from utils.general_utils import test_all_close

def softmax(x):
    """
    Compute the softmax function in tensorflow.

    You might find the tensorflow functions tf.exp, tf.reduce_max,
    tf.reduce_sum, tf.expand_dims useful. (Many solutions are possible, so you may
    not need to use all of these functions). Recall also that many common
    tensorflow operations are sugared (e.g. x + y does elementwise addition
    if x and y are both tensors). Make sure to implement the numerical stability
    fixes as in the previous homework!

    Args:
        x:   tf.Tensor with shape (n_samples, n_features). Note feature vectors are
                  represented by row-vectors. (For simplicity, no need to handle 1-d
                  input as in the previous homework)
    Returns:
        out: tf.Tensor with shape (n_sample, n_features). You need to construct this
                  tensor in this problem.
    """

    ### YOUR CODE HERE
    out = tf.exp(x - tf.reduce_max(x, axis=1, keep_dims=True))/tf.reduce_sum(tf.exp(x - tf.reduce_max(x, axis=1, keep_dims=True)), axis=1, keep_dims=True)
    ### END YOUR CODE

    return out

def cross_entropy_loss(y, yhat):
    """
    Compute the cross entropy loss in tensorflow.
    The loss should be summed over the current minibatch.

    y is a one-hot tensor of shape (n_samples, n_classes) and yhat is a tensor
    of shape (n_samples, n_classes). y should be of dtype tf.int32, and yhat should
    be of dtype tf.float32.

    The functions tf.to_float, tf.reduce_sum, and tf.log might prove useful. (Many
    solutions are possible, so you may not need to use all of these functions).

    Note: You are NOT allowed to use the tensorflow built-in cross-entropy
                functions.

    Args:
        y:    tf.Tensor with shape (n_samples, n_classes). One-hot encoded.
        yhat: tf.Tensorwith shape (n_sample, n_classes). Each row encodes a
                    probability distribution and should sum to 1.
    Returns:
        out:  tf.Tensor with shape (1,) (Scalar output). You need to construct this
                    tensor in the problem.
    """

    ### YOUR CODE HERE
    out = -tf.reduce_sum(tf.to_float(y)*tf.log(yhat))
    ### END YOUR CODE

    return out

def test_softmax_basic():
    """
    Some simple tests of softmax to get you started.
    Warning: these are not exhaustive.
    """

    test1 = softmax(tf.constant(np.array([[1001, 1002], [3, 4]]), dtype=tf.float32))
    with tf.Session() as sess:
            test1 = sess.run(test1)
    test_all_close("Softmax test 1", test1, np.array([[0.26894142, 0.73105858],
                                                      [0.26894142, 0.73105858]]))

    test2 = softmax(tf.constant(np.array([[-1001, -1002]]), dtype=tf.float32))
    with tf.Session() as sess:
            test2 = sess.run(test2)
    test_all_close("Softmax test 2", test2, np.array([[0.73105858, 0.26894142]]))

    print "Basic (non-exhaustive) softmax tests pass\n"

def test_cross_entropy_loss_basic():
    """
    Some simple tests of cross_entropy_loss to get you started.
    Warning: these are not exhaustive.
    """
    y = np.array([[0, 1], [1, 0], [1, 0]])
    yhat = np.array([[.5, .5], [.5, .5], [.5, .5]])

    test1 = cross_entropy_loss(tf.constant(y, dtype=tf.int32), tf.constant(yhat, dtype=tf.float32))
    with tf.Session() as sess:
        test1 = sess.run(test1)
    expected = -3 * np.log(.5)
    test_all_close("Cross-entropy test 1", test1, expected)

    print "Basic (non-exhaustive) cross-entropy tests pass"

if __name__ == "__main__":
    test_softmax_basic()
    test_cross_entropy_loss_basic()


# Exercise 4.3.1
# Mortality rates in the middle ages

from scipy import optimize
from math import log
from math import exp

# Ages at time of death (given in lecture notes)
ages = [47, 67, 38, 45, 48, 48, 51, 76, 32, 43, 42, 26, 25, 40, 53, 64, 49, 42,
        57, 30, 1, 1, 6, 9, 12, 14, 18]

# Model ansatz
# mu(x) = Probability to die between age x and x+1,
#         conditional on being alive at age x.
def mu(x, a, b, c):
    return(exp(a + b * x + c * x ** 2))

# Negative log-likelihood
# Probability of dying at age x is the product of the probabilities of not dying
# during years before x, and the probability of dying between age x and x+1.
def negll(abc, ages):
    a, b, c = abc
    ll = 0
    for age in ages:
        for x in range(age):
            # not dying before age of death
            ll += log(1 - mu(x, a, b, c))
        # dying at age of death
        ll += a + b * age + c * age ** 2  # same as log(mu(x, a, b, c))
    return(-ll)

# Solving for three parameters in model ansatz
# Initial values are the solution given in lecture notes
print(optimize.minimize(negll, (-4.36, 1.01e-2, 4.08e-4), args=(ages,)))
# This gives [a, b, c] = [-4.48664309e+00, 1.52875034e-02, 3.38010681e-04],
# different from the given solution.


import numpy as cp

class Softmax():

    '''
    The softmax function is a generalization of the logistic function to multiple dimensions.
    It is used in multinomial logistic regression and is often used as the last activation
    function of a neural network to normalize the output of a network to a probability
    distribution over predicted output classes.

    The softmax function takes as input a vector z of K real numbers, and normalizes it into
    a probability distribution consisting of K probabilities proportional to the exponentials
    of the input numbers.

    The Softmax function is defined as follows:

        softmax(x) =  ___exp(xi)____ where exp is exponential function
                           ∑ exp(x)

    Parameters
    ----------
    x : cp.array
        Array of ouputs of deeplearning layer.

    Returns
    -------
    cp.array
        Array after Softmax function applied .

    '''

    def __call__(self, x: cp.array) -> cp.array:

        e_x = cp.exp(x)
        return e_x / cp.sum(e_x, axis=-1, keepdims=True)

    def gradient(self, x: cp.array) -> cp.array:
        '''

        Parameters
        ----------
        x : cp.array
             Array of ouputs of deeplearning layer..

        Returns
        -------
        cp.array
            Array after derivatives of Softmax applied .

        '''

        p = self.__call__(x)
        return p * (1 - p)

tutorial/7. Deep Learning/Activation Function/Softmax.py


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

"""
Some notations:
    d = number of features including W_0
    n = number of observations

"""

def prepare_X(X:np.ndarray, degree:int = 1)-> np.ndarray:
    '''
    Expands X as per degrees and appends a column of ones in the begining
    Input:
        X: (n*1) Input matrix
        degress: expanding X to number of degrees
    Returns:
        X_new : (n * d) matrix
    '''
    assert X.ndim == 2

    n = X.shape[0]

    X_new = X.copy()

    if degree>1:
        for d in range(2,degree+1):
            X_new = np.hstack((X_new, X**d))

    # append column of ones'
    X_new = np.hstack((np.ones([n,1]), X_new))

    return X_new

def normaliz_data(X):
    '''
    Z- normalized data and array of means and sds to normalize validation data
    Input:
        X: (n*d) matrix
    Returns:
        X_norm : n*d , z-normalized data
        mean = np array of means of all columns
        std = np array of std of all columns
    '''
    mean = X.mean(axis=0)
    std = X.std(axis=0)
    mean[0] = 0 # the first columns is column of ones.
    std[0] = 1 # the first columns is column of ones.

    X_norm = (X - mean)/ std

    return X_norm, mean, std

def w_closedForm(X,y):
    '''
    Finds the optimal w using closed form solution

    Input:
        X = 2D array, N*(D+1) data matrix
        y = 1D array, N lenghth vector of y values
    Output:
        w = 1D array, (D+1) lengthe vector
    '''

    w = np.dot(np.linalg.pinv(X),y)

    return w

def give_squared_loss_grad(X, y, w, overPred_penalty=1, underPred_penalty=1):
    '''
    Gives squared loss and grandient given X, w and other parameters
    Input:
        X = 2D array; n*d input matrix
        y = 1D array; (n,) output array
        w = 1D array; (), weights array
        overPred_penalty = [-Inf, Inf] penulty for over prediction
        underPred_penalty = [-Inf, Inf] penulty for under prediction
    Returns:
        loss: float = squared loss
        grad: (d*1) array of gradients
    '''

    n = X.shape[0]

    # errors
    e = np.dot(X,w) - y

    # Penalty for Over/ Under Prediction
    penulty_vect = (e>0.).astype(float)
    penulty_vect[penulty_vect==1] = overPred_penalty
    penulty_vect[penulty_vect==0] = underPred_penalty

    # Asymmetric Loss
    asym_e = np.multiply(penulty_vect, e)

    # Normalised Squared Loss
    loss = np.dot(np.transpose(asym_e), asym_e) /(2*n)

    # Gradient
    grad = (np.dot(X.T, asym_e)) / n

    return loss, grad

def GradDescent_LinReg(X, y, overPred_penalty=1, underPred_penalty=1, lr=0.1 , maxIt = 10000, verbose=False):

    '''
    Finds the optimal w using Gradient Descent method
    Input:
        X = 2D array; n*d input matrix
        y = 1D array; (n,) output array
        w = 1D array; (), weights array
        overPred_penalty = [-Inf, Inf] penulty for over prediction
        underPred_penalty = [-Inf, Inf] penulty for under prediction
        lr = learing rate
        maxIt = Maximum Iterations
    Returns:
        w  = (d*1) array of weights
    '''
    n,d = X.shape

    if verbose:
        itr_data = []

    # initialize W randomly
    w = np.random.rand(d,1)

    for i in range(maxIt):
        loss, grad = give_squared_loss_grad(X, y, w, overPred_penalty, underPred_penalty)

        if verbose:
            itr_data.append(loss[0][0])
        w = w - (lr*grad)

    if verbose:
        return itr_data, w

    return w

def find_best_model_plot_results(X_train, y_train, X_val, y_val,
                            method:str, overPred_penalty=1, underPred_penalty=1, lr=0.1 , maxIt = 10000 ):

    # checking for degrees till 5
    degrees = [i for i in range(1,6)]

    # storing the best model

    min_loss = np.Inf
    best_model = {}
    all_model = {}

    # for plotting
    fig = matplotlib.pyplot.gcf()
    fig.set_size_inches(11, 7)
    plt.plot(X_train, y_train, 'k.')

    x_axis_data = np.linspace(min(X_train)-0.1, max(X_train)+-.1, num=100)

    # below loop: for each polynomial degree finds the w*, finds the val loss and plots the fitted curve
    for d in degrees:
        X = prepare_X(X_train, degree=d)
        X_norm, X_mean, X_std = normaliz_data(X)
        if method == 'ClosedForm':
            w = w_closedForm(X_norm, y_train)
        if method == "GradientDescent":
            w = GradDescent_LinReg(X_norm, y_train, overPred_penalty, underPred_penalty, lr, maxIt)
        train_loss = give_squared_loss_grad(X_norm, y_train, w)[0]

        # for validation loss
        X_val_prep = prepare_X(X_val, degree=d)
        X_val_norm = (X_val_prep - X_mean) / X_std
        val_loss = give_squared_loss_grad(X_val_norm, y_val, w)[0]

        all_model['degree:'+str(d)] = {'train_loss':train_loss, 'val_loss':val_loss, 'w':w}

        if val_loss < min_loss:
            min_loss = val_loss
            best_model['degree'] = d
            best_model['w'] = w
            best_model['train_loss'] = train_loss
            best_model['val_loss'] = val_loss

            if method == "GradientDescent":
                best_model['OverPred Penalty'] = overPred_penalty
                best_model['UnderPred Penalty'] = underPred_penalty
                best_model['learning_rate'] = lr
                best_model['maxIt'] : maxIt

        # to plot the line
        X_graph = ((prepare_X(x_axis_data, degree=d))-X_mean) / X_std

        y_axis_data = np.dot(X_graph,w)

        color = {1:'b', 2:'g', 3:'r', 4:'y', 5:'c'}[d]
        plt.plot(x_axis_data, y_axis_data, color, label = "deg:"+str(d))

    plt.legend()

    return best_model


#inverse an matrix
import numpy as np
A = np.mat("2 4 6;4 2 6;10 -4 18")
print "A\n", A
inverse = np.linalg.inv(A)
print "inverse of A\n", inverse
print "Check\n", A * inverse
print "Error\n", A * inverse - np.eye(3)

#solve linear system with numpy
import numpy as np
A = np.mat("1 -2 1;0 2 -8;-4 5 9")
print "A\n", A
b = np.array([0, 8, -9])
print "b\n", b
x = np.linalg.solve(A, b)
print "Solution", x
print "Check\n", np.dot(A , x)

#find eigenvalue and eigenvectors
import numpy as np
A = np.mat("3 -2;1 0")
print "A\n", A
print "Eigenvalues", np.linalg.eigvals(A)
eigenvalues, eigenvectors = np.linalg.eig(A)
print "First tuple of eig", eigenvalues
print "Second tuple of eig\n", eigenvectors
for i in range(len(eigenvalues)):
    print "Left", np.dot(A, eigenvectors[:,i])
    print "Right", eigenvalues[i] * eigenvectors[:,i]
    print


import numpy as np
import matplotlib.pyplot as plt

class PolyFit:
    def __init__(self, degree=1):
        self.degree = degree
        self.betas = np.ones(degree+1)

    def fit(self, x, y):
        """
        Entradas:
        x : array unidimensional de valores de x.
        y : array unidimensiondal de valores de y.

        Este codigo resuelve el siguiente sistema de ecuaciones
        S * beta = Y, beta = S^{-1} * Y,
        donde S es una matriz que tiene como vectotes a columnas de potencias de X.
        """
        m = self.degree
    # matriz que guarda los vectores columna de potencias de x
        S = np.zeros([len(x), m+1])
        for i in range(m+1):
            S[:,i] = x**i

    # Calculo la inversa de S.
        S_inv = np.linalg.pinv(S)

    # calculo beta
        self.betas = np.dot(S_inv, y)

    def predict(self, x):
        """
        Entradas:
        x : array de entrada.

        Salida:
        y : array de salida
        """
        y = np.zeros(len(x))
        for i in range(len(self.betas)):
            y +=  self.betas[i] * x**i
        return y

    def score(self, x, y):
        """
        Calcula el root mean squared error

        Entradas:
        x : array de entrada de valores de x.
        y : array unidimensiondal de valores de y.
        """
        y_predict  = self.predict(x)
        return np.sqrt(np.mean((y_predict - y)**2))

# cargo los datos para manipular
data = np.loadtxt("numeros_20.txt")

# divido en training y test
x_train = data[:10,0]
x_test = data[10:,0]
y_train = data[:10,1]
y_test = data[10:,1]

# distintos valores de m para probar
m_values = [0,1,3,9]

plt.figure()

for i,m in enumerate(m_values):
    modelo = PolyFit(degree=m)
    modelo.fit(x_train, y_train)

    plt.subplot(2,2,i+1)
    #grafica del modelo
    x_model = np.linspace(x_train.min(), x_train.max(), 100)
    plt.plot(x_model, modelo.predict(x_model))
    #grafica de los puntos
    plt.scatter(x_train, y_train)
    plt.xlabel("X")
    plt.ylabel("Y")
    plt.title("M={}".format(m))

plt.subplots_adjust(hspace=0.5)
plt.savefig("polinomios.png", bbox_inches='tight')

#segunda figura con los errores
error_train = []
error_test = []

for m in range(10):
    modelo = PolyFit(degree=m)
    modelo.fit(x_train, y_train)
    error_train.append(modelo.score(x_train, y_train))
    error_test.append(modelo.score(x_test, y_test))

plt.figure()
plt.plot(np.array(range(10)), error_train, label='training')
plt.plot(np.array(range(10)), error_test, label='test')
plt.semilogy()
plt.legend()
plt.xlabel("M")
plt.ylabel("$E_{RMS}$")
plt.savefig("train_test_error.png")


''' mbinary
#########################################################################
# File : iteration.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-10-02  21:14
# Description:
#########################################################################
'''

import sympy
import numpy as np
from math import sqrt

def newton(y:sympy.core,x0:float,epsilon:float=0.00001,maxtime:int=50) ->(list,list):
    '''
        newton 's iteration method for finding a zeropoint of a func
        y is the func, x0 is the init x val: int float epsilon is the accurrency
    '''
    if epsilon <0:epsilon = -epsilon
    ct =0
    t =  y.free_symbols
    varsymbol = 'x' if len(t)==0 else t.pop()
    x0= float(x0)
    y_diff = y.diff()
    li = [x0]
    vals = []
    while 1:
        val = y.subs(varsymbol,x0)
        vals.append(val)
        x = x0- val/y_diff.subs(varsymbol,x0)
        li.append(x)
        ct+=1
        if ct>maxtime:
            print("after iteration for {} times, I still havn't reach the accurrency.\
                    Maybe this function havsn't zeropoint\n".format(ct))
            return li ,val
        if abs(x-x0)<epsilon:return li,vals
        x0 = x

def secant(y:sympy.core,x0:float,x1:float,epsilon:float =0.00001,maxtime:int=50) ->(list,list):
    '''
        弦截法, 使用newton 差商计算,每次只需计算一次f(x)
        secant method for finding a zeropoint of a func
        y is the func , x0 is the init x val,     epsilon is the accurrency
    '''
    if epsilon <0:epsilon = -epsilon
    ct =0
    x0,x1 = float(x0),float(x1)
    li = [x0,x1]
    t =  y.free_symbols
    varsymbol = 'x' if len(t)==0 else t.pop()
    last = y.subs(varsymbol,x0)
    vals = [last]
    while 1:
        cur = y.subs(varsymbol,x1)
        vals.append(cur)
        x = x1-cur*(x1-x0)/(cur-last)
        x0 ,x1= x1,x
        last = cur
        li.append(x)
        ct+=1
        if ct>maxtime:
            print("after iteration for {} times, I still havn't reach the accurrency.\
                    Maybe this function havsn't zeropoint\n".format(ct))
            return li,vals
        if abs(x0-x1)<epsilon:return li,vals
        x0 = x

def solveNonlinearEquations(funcs:[sympy.core],init_dic:dict,epsilon:float=0.001,maxtime:int=50)->dict:
    '''solve  nonlinear equations:'''
    li = list(init_dic.keys())
    delta = {i:0 for i in li}
    ct = 0
    while 1:
        ys = np.array([f.subs(init_dic) for f in funcs],dtype = 'float')
        mat = np.matrix([[i.diff(x).subs(init_dic) for x in li] for i in funcs ],dtype = 'float')
        delt = np.linalg.solve(mat,-ys)
        for i,j in enumerate(delt):
            init_dic[li[i]] +=j
            delta[li[i]] = j
        if ct>maxtime:
            print("after iteration for {} times, I still havn't reach the accurrency.\
                    Maybe this function havsn't zeropoint\n".format(ct))
            return init_dic
        if sqrt(sum(i**2 for i in delta.values()))<epsilon:return init_dic

if __name__ =='__main__':
    x,y,z = sympy.symbols('x y z')

    res,res2= newton(x**5-9,2,0.01)
    print(res,res2)

    res,res2 = secant (x**3-3*x-2,1,3,1e-3)
    print(res,res2)

    funcs=[x**2+y**2-1,x**3-y]
    init = {x:0.8,y:0.6}
    res_dic = solveNonlinearEquations(funcs,init,0.001)
    print(res_dic)


import numpy as np

from numericalmethods.exceptions import InadequateArgsCombination

def newton_horner(x, x_points: np.ndarray, y_points: np.ndarray = None, coeffs: np.ndarray = None) -> np.ndarray:
    """ Evaluates the polynomial returned by Horner's algorithm.

    The user must give `y_points` or `coeffs`. If `coeffs` is not given this method will compute them with `x_points` and `y_points`.

    Args:
        x(float): The point where to evaluate the polynomial.
        x(np.ndarray): `x` coordinates of the points.
        y(np.ndarray): `y` coordinates of the points. Defaults to None.
        coeffs(np.ndarray): coefficients of the polynomial. Defaults to None.

    Raises:
        InadequateArgsCombination: If the combination  of arguments is not valid.
        ValueError: If `x` and `y` are not of the same length.

    Returns:
        float: the polynomial evaluated at x.

    """
    if y_points is None and coeffs is None:
        raise InadequateArgsCombination('Cannot evaluate Newton\'s polynomial with the combination of arguments given. Check the valid combinations.')

    if y_points is not None:
        if len(x_points) != len(y_points):
            raise ValueError('`x_points` and `y_points` must be the same length.')

    coeffs_ = coeffs if coeffs is not None else horner_algorithm(x_points, y_points)

    N = len(x_points) - 1
    polynom = coeffs_[N]

    for k in range(1, N+1):
        polynom = coeffs_[N-k] + (x - x_points[N-k])*polynom

    return polynom

def horner_algorithm(x: np.ndarray, y: np.ndarray) -> np.ndarray:
    """ Computes Newton interpolation polynomial by Horner's algorithm for some given coordinates.

    `x` and `y` must have the same length.

    Args:
        x(np.ndarray): x coordinates of the points.
        y(np.ndarray): y coordinates of the points.

    Raises:
        ValueError: If `x` and `y` are not of the same length.

    Returns:
        np.ndarray: Polynomial coefficients of the Newton interpolation.

    """
    if len(x) != len(y):
        raise ValueError('x and y must be the same length.')

    LEN = len(y)
    matrix = np.zeros((LEN, LEN))

    for j in range(LEN):
        if j == 0:
            matrix[:, 1] = y

        for i in range(LEN-j):
            matrix[i, j] = (matrix[i+1, j] - matrix[i, j]) / (x[i+1] - x[i])

    return matrix[0]


import numpy as np
import math

def f(mu, sigma2, x):
    return 1/np.sqrt(2 * np.pi * sigma2) * np.exp(-0.5 * np.square(x-mu) / sigma2)

print(f(10., 4., 8.))
print(f(10., 4., 10.)) # f(x) is max when mu and x are same, maximizing the gaussian


#!/usr/bin/env python3
import math
import copy
from decimal import *
from itertools import product
import numpy as np

# CHANGEME:
TP=150
TN=300
FP=50
FN=0

tot = TP+TN+FP+FN

print(f"N={tot}")

probtab = np.array([[TN/tot,FN/tot],[FP/tot,TP/tot]]).astype(Decimal)

print("The marginal probabilities of all the values of 𝑋")

row_labels = ["N", "A"];
px = np.sum(probtab, axis=0)
py = np.sum(probtab, axis=1)
print("     N    A     P(y)")
for row_label, row in zip(row_labels, probtab):
  print('%s  [%s]' % (row_label, ' '.join('%04s' % i for i in row)), end=" ")
  print(f"- {np.sum(row, axis=0):.2f}")

print("p(x) " + ' '.join(f"{i:.2f}" for i in px))

print("- " * 10)

# sum of all columns and rows must be one
assert sum(px) == 1
assert sum(py) == 1

print("Entropy of the input")
print("𝐻(𝑋)=−∑𝑃(𝑥)log2𝑃(𝑥)")
hx = -sum([i * math.log2(i) for i in px])
print("-(", end="")
for i in px:
  print(f"{i:.3f}*log2({i:.3f})", end=" + ")
print(f") = {hx:.3f}")
print("- " * 10)

print("The joint probabilities:")
print("P(X|Y)=𝑃(𝑥,𝑦)/𝑃(𝑦)")
for k, i in zip(py, probtab):
  for j in i:
    if j:
      print(f"({j}/{k:.3f})={(j/k):.2f}")
print("- " * 10)

print("The conditional entropy 𝐻(𝑋|𝑌)")
print("𝐻(𝑋|𝑌)=−∑y∑x𝑃(𝑥,𝑦)log2𝑃(𝑥|𝑦)")
hxy = 0
print("-(", end="")
for k, i in zip(py, probtab):
  for j in i:
    if j:
      hxy += (j * math.log2(j / k))
      print(f"{j}*log2({(j/k):.2f})", end=" + ")
hxy = -hxy
print(f") = {hxy:.3f} ")
print("- " * 10)

print("The intrusion detection capability:")
print("C_I_D=(𝐻(𝑋)−𝐻(𝑋|𝑌)) / 𝐻(𝑋)")
cid = ((hx - hxy)/hx)
print(f"({hx:.3f} - {hxy:.3f})/{hx:.3f} = {cid:.3f}")

print("\n##### Abstract IDS models ####\n")
px_ol = copy.copy(px)
probtab = np.array([[TN/tot,0],[FP/tot,FN/tot],[0,TP/tot]]).astype(Decimal)
print("The marginal probabilities of all the values of 𝑋")
row_labels = ["N", "U", "A"];
px = np.sum(probtab, axis=0)
pz = np.sum(probtab, axis=1)
print("     N    A     P(z)")
for row_label, row in zip(row_labels, probtab):
  print('%s  [%s]' % (row_label, ' '.join('%04s' % i for i in row)), end=" ")
  print(f"- {np.sum(row, axis=0):.2f}")

print("p(x) " + ' '.join(f"{i:.2f}" for i in px))
print("- " * 10)

# sum of all columns and rows must be one
assert sum(px) == 1
assert sum(pz) == 1

if set(px_ol) == set(px):
  print("Entropy of the input is still the same as above")
  print(f"recall, H(𝑋)=−∑𝑃(𝑥)log2𝑃(𝑥) = {hx:.3f}")
  print("- " * 10)
else:
  print("Entropy of the input")
  print("𝐻(𝑋)=−∑𝑃(𝑥)log2𝑃(𝑥)")
  hx = -sum([i * math.log2(i) for i in px])
  print("-(", end="")
  for i in px:
    print(f"{i:.3f}*log2({i:.3f})", end=" + ")
  print(f") = {hx:.3f}")
  print("- " * 10)

print("The joint probabilities:")
print("𝑃(𝑥,𝑦)/𝑃(𝑦)=P(X|Y)")
for k, i in zip(pz, probtab):
  for j in i:
    if j:
      print(f"({j}/{k:.3f})={(j/k):.2f}")
print("- " * 10)

print("The conditional entropy 𝐻(𝑋|𝑌)")
print("𝐻(𝑋|𝑌)=−∑y∑x𝑃(𝑥,𝑦)log2𝑃(𝑥|𝑦)")
hxy = 0
print("-(", end="")
for k, i in zip(pz, probtab):
  for j in i:
    if j:
      hxy += (j * math.log2(j / k))
      print(f"{j}*log2({(j/k):.2f})", end=" + ")
hxy = -hxy
print(f") = {hxy:.3f} ")
print("- " * 10)

print("The feature representation capability:")
print("C_r=(𝐻(𝑋)−𝐻(𝑋|𝑌)) / 𝐻(𝑋)")

cr = ((hx - hxy)/hx)
print(f"({hx:.3f} - {hxy:.3f})/{hx:.3f} = {cr:.3f}")

print("- " * 10)

print("The classification information loss:")
print(f"L_c = C_r - C_I_D = {cr:.3f} - {cid:.3f} = {(cr-cid):.3f}")