import numpy as np

class Parabolic(object):
    def __init__(self, focal_length, depth, height):
        self.a = self.focal_length_to_x_squared_coeff(focal_length)
        self.depth = depth
        self.height = height

    def set_x_offset(self, x_offset):
        self.c = x_offset

    def prop(self, eqns):
        a = self.a
        c = self.c

        result_ms = []
        result_bs = []
        result_xs = []
        result_ys = []
        result_freqs = []
        result_colors = []

        for eq in eqns:
            m, b, old_x, old_y, freq = eq

            if m == 0:
                # The special case is super easy
                y0 = b
                x0 = a * y0 * y0 + c
            else:
                # Newton's Method
                y0 = b
                for i in xrange(1):
                    fy = a * y0 * y0 - (1.0 / m) * y0 + c + b / m
                    fydot = 2 * a * y0 - (1.0 / m)
                    y1 = y0 - fy / fydot
                    y0 = y1

                x0 = a * y0 * y0 + c

            # Okay we've found the intercept, let's reflect.
            # First step is to find the slope of the reflected line
            slope_inverse = 2 * a * y0
            if slope_inverse == 0:
                # Another special case: the parabola is perfectly vertical here
                # All we gotta do is reflect off a vertical line, which amounts
                # to flipping the sign of the slope
                final_m = -m

            else:
                M1 = 1 / slope_inverse
                M2 = m
                M3 = (M1 * M1 * M2 + 2 * M1 - M2) / (1 + 2 * M1 * M2 - M1 * M1)
                # print "slope", slope
                final_m = M3

            # Great, just plug in the slope and a know point on the line
            # To find the y intercept
            final_b = y0 - final_m * x0

            # print "Intercept:", x0,  y0
            # print "m:", final_m
            # print "b:", final_b

            result_ms.append(final_m)
            result_bs.append(final_b)
            result_xs.append(x0)
            result_ys.append(y0)
            result_freqs.append(freq)

        return np.array(zip(
            result_ms, result_bs, result_xs, result_ys, result_freqs))

    def focal_length_to_x_squared_coeff(self, focal_length):
        '''
        ax^2 = focal_length
        2ax = 1
        x = 1 / (2a)
        x^2 = 1 / 4a^2 = 1/a * 1/4a
        a * 1/a * 1/4a = focal_length
        1/4a = focal_length
        4a = 1 / focal_length
        a = 1 / (4 * focal_length)
        '''
        return 1.0 / (4 * focal_length)

    def __str__(self):
        return "Parabolic: x = {} * y * y + {} : {}".format(self.a, self.c, self.height)


import numpy as np

def calculate_tilt_angle(initial_grade_percent):
    tilt_angle = np.arctan(initial_grade_percent / 100)
    tilt_angle = np.degrees(tilt_angle)
    return tilt_angle

def calculate_pipe_upper_invert(pipe_invert_elev, tilt_angle, pipe_length):
    pipe_upper_invert = np.tan(np.radians(tilt_angle)) * pipe_length + pipe_invert_elev
    return pipe_upper_invert

def calculate_upper_liquid_level(lower_liquid_level, tilt_angle, pipe_length):
    upper_liquid_level = lower_liquid_level
    return upper_liquid_level

def calculate_tilt_angle(initial_grade_percent):
    tilt_angle = np.arctan(initial_grade_percent / 100)
    tilt_angle = np.degrees(tilt_angle)

    return tilt_angle

def calculate_pipe_upper_invert(pipe_invert_elev, tilt_angle, pipe_length):
    pipe_upper_invert = np.tan(np.radians(tilt_angle)) * pipe_length + pipe_invert_elev
    return pipe_upper_invert

def calculate_upper_liquid_level(lower_liquid_level, tilt_angle, pipe_length):
    upper_liquid_level = lower_liquid_level
    return upper_liquid_level

def calculate_total_pipe_volume(pipe_diameter, pipe_length):
    pipe_cross_sectional_area = np.pi / 4 * (pipe_diameter ** 2)
    total_volume = pipe_cross_sectional_area * pipe_length
    total_volume = round(total_volume, 2)
    return total_volume

def calculate_sloped_pipe_volume(
    pipe_diameter, tilt_angle, pipe_length, relative_lower_liquid_level
):
    if tilt_angle == 0:
        tilt_angle = 0.001  # angle of zero breaks the np.tan function, so making a close approximation
    pipe_radius = pipe_diameter / 2
    tilt_angle_radians = np.radians(tilt_angle)
    _h0 = relative_lower_liquid_level - (pipe_length * np.tan(tilt_angle_radians))

    # "normal" case, where both ends have some liquid
    if _h0 >= 0:
        _lf = pipe_length

    # upper end has no liquid - liquid does not reach end of pipe
    elif _h0 < 0:
        # lower_liquid_level = 0
        _lf = pipe_length + _h0 / np.tan(tilt_angle_radians)
        _h0 = 0
        # assert _lf < pipe_length, "Liquid fill length cannot be greater than pipe length"

    _h1 = _h0 + _lf * np.tan(tilt_angle_radians)
    full_volume = None
    # Case where pipe is (at least) partially completely full.
    if _h1 > pipe_diameter:
        _lt = (_h1 - pipe_diameter) / np.tan(tilt_angle_radians)
        full_volume = np.pi * pipe_radius ** 2 * _lt
    else:
        _lt = 0

    _pipe_length = _lf - _lt

    _k = 1 - (_h0 / pipe_radius)
    _c = _k - ((_pipe_length * np.tan(tilt_angle_radians)) / pipe_radius)

    assert -1 <= _k <= 1, "k out of range"
    assert -1 <= _c <= 1, "c out of range"

    integral0 = pipe_radius ** 3 / np.tan(tilt_angle_radians)
    integral1 = _k * np.arccos(_k)
    integral2 = (1 / 3) * (np.sqrt(1 - (_k ** 2))) * (_k ** 2 + 2)
    integral3 = _c * np.arccos(_c)
    integral4 = (1 / 3) * (np.sqrt(1 - (_c ** 2))) * (_c ** 2 + 2)
    volume = integral0 * (integral1 - integral2 - integral3 + integral4)

    if (pipe_radius == relative_lower_liquid_level) and (
        tilt_angle == 0
    ):  # Pipe is exactly half full and no slope
        volume = (pipe_length * np.pi * pipe_radius ** 2) / 2
    if full_volume is not None:
        volume = volume + full_volume

    return volume

# initial values
initial_grade_percent = 0.1  # inital grade value
maximum_grade_value = 2  # maximum grade (%) to plot
pipe_length = 50
pipe_diameter = 2
pipe_invert_start = 1  # pipe invert at pipe end
lower_liquid_level = 3  # liquid level at pipe end

relative_lower_liquid_level = np.abs(pipe_invert_start - lower_liquid_level)

no_points_to_plot = 100
no_grades = np.arange(0, maximum_grade_value, 20)
pipe_chainage = np.linspace(0, pipe_length, no_points_to_plot).tolist()
pipe_chainage = [round(elem) for elem in pipe_chainage]

tilt_angle = calculate_tilt_angle(initial_grade_percent)

test_grades = np.linspace(0, 5, 10)

for i in test_grades:
    sloped_volume = calculate_sloped_pipe_volume(
        pipe_diameter, i, pipe_length, relative_lower_liquid_level
    )
    print(sloped_volume)


from math import ceil
import numpy as np
import matplotlib.pyplot as plt

#Ut + aUx =0 gia -2<=x<=3 kai t>=0
#me a.s. U0(x) = 1-|x| gia |x|<=1, 0 diaforetika
#kai sunoriakh U(-2, t)=0. psaxnw sto t=1.6
#akrivhs lush U(x, 1.6) = U0(x-1.6) gia -2<=x-1.6, 0 diaforetika

def u0(x):
	ax = np.abs(x)
	return np.where(ax > 1, 0, 1 - ax)

alpha = 1
a = -2;  b = 3;  J = 49;  h = (b - a) / (J+1)
x = np.linspace(-2, 3, J+2)
lam = 0.8;  k = lam * h;  t = 1.6;  N = ceil(t/k)

U = u0(x);  V = np.zeros(J+2)

for n in range(N):
	for j in range(J+1):
		V[j] = 1/2*( U[j+1] + U[j-1] - lam * alpha * ( U[j+1] - U[j-1] ) )
	for j in range(J+1):
		U[j] = V[j]

plt.plot(x, u0(x-t), 'k-')#, linewidth=1.5)
plt.plot(x, U, 'b-o')
plt.ylim(-0.1, 1.1)
plt.title('$\lambda = %g \quad h = %g \quad t = %g$' % (lam, h, t))
#plt.savefig('upwind.png')
plt.show()

Ex1-oral exercise-Finite Difference-Euler's Method/Code/LaxFriedrichs.py


import numpy as np
import pylab as plt

'''
Performs the Principal Component analysis of the Matrix X
Matrix must be n * m dimensions
where n is # features
m is # examples
'''

def PCA(X, varRetained=0.95, show=False):
    # Compute Covariance Matrix Sigma
    (n, m) = X.shape
    Sigma = 1.0 / m * X * np.transpose(X)
    # Compute eigenvectors and eigenvalues of Sigma
    U, s, V = np.linalg.svd(Sigma, full_matrices=True)

    # compute the value k: number of minumum features that
    # retains the given variance
    sTot = np.sum(s)
    var_i = np.array([np.sum(s[: i + 1]) / \
                      sTot * 100.0 for i in range(n)])
    k = len(var_i[var_i < (varRetained * 100)])
    print
    '%.2f %% variance retained in %d dimensions' \
    % (var_i[k], k)

    # plot the variance plot
    if show:
        plt.plot(var_i)
        plt.xlabel('Number of Features')
        plt.ylabel(' Percentage Variance retained')
        plt.title('PCA $\% \sigma^2 $ vs # features')
        plt.show()

    # compute the reduced dimensional features by projction
    U_reduced = U[:, : k]
    Z = np.transpose(U_reduced) * X

    return Z, U_reduced

import csv as csv
import numpy as np
import Activation, logReg, optim, loadData

#################################################################
# reading from csv
print
'Loading Training Data'
csv_train = csv.reader(open('../data/train.csv', 'rb'))
header = csv_train.next()
data = [[map(int, row[1:]), [int(row[0])]] for row in csv_train]

train = loadData.Data()
train.loadList(data, numClasses=10)
train.NormalizeScale(factor=255.0)

#################################################################
# PCA of training set
print
'Performing PCA - Principal COmponent Analysis'
import npPCA

Z, U_reduced = npPCA.PCA(train.X, varRetained=0.95, show=True)


import numpy as np

from ..density import Distribution
from ..util import interpret_array

class Uniform(Distribution):

    def __init__(self, ndim, sample_range=(0, 1)):
        super().__init__(ndim, True)
        self.low = sample_range[0]
        self.high = sample_range[1]
        self.vol = np.prod(np.diff(sample_range, axis=0))

    def pdf(self, xs):
        xs = interpret_array(xs, self.ndim)
        density = (np.all(xs > self.low, axis=1) *
                   np.all(xs < self.high, axis=1) / self.vol)
        return density

    def pdf_gradient(self, xs):
        return np.zeros(xs.shape)

    def pot(self, xs):
        xs = interpret_array(xs, self.ndim)
        logpdf = -(np.all(xs > self.low, axis=1) *
                   np.all(xs < self.high, axis=1) * np.log(self.vol))
        return logpdf

    def pot_gradient(self, xs):
        return np.zeros(xs.shape)

    def rvs(self, sample_size):
        return np.random.uniform(self.low, self.high, (sample_size, self.ndim))

    def __repr__(self):
        return type(self).__name__ + "(ndim=%s, sample_range=%s)" % (
            self.ndim, (self.low, self.high))


import numpy as np
from sklearn.decomposition import TruncatedSVD

def get_weighted_average(We, x, w):
    """
    Compute the weighted average vectors
    :param We: We[i,:] is the vector for word i
    :param x: x[i, :] are the indices of the words in sentence i
    :param w: w[i, :] are the weights for the words in sentence i
    :return: emb[i, :] are the weighted average vector for sentence i
    """
    n_samples = x.shape[0]
    emb = np.zeros((n_samples, We.shape[1]))
    for i in range(n_samples):
        emb[i,:] = w[i,:].dot(We[x[i,:],:]) / np.count_nonzero(w[i,:])
    return emb

def compute_pc(X,npc=1):
    """
    Compute the principal components. DO NOT MAKE THE DATA ZERO MEAN!
    :param X: X[i,:] is a data point
    :param npc: number of principal components to remove
    :return: component_[i,:] is the i-th pc
    """
    svd = TruncatedSVD(n_components=npc, n_iter=7, random_state=0)
    svd.fit(X)
    return svd.components_

def remove_pc(X, npc=1):
    """
    Remove the projection on the principal components
    :param X: X[i,:] is a data point
    :param npc: number of principal components to remove
    :return: XX[i, :] is the data point after removing its projection
    """
    pc = compute_pc(X, npc)
    if npc==1:
        XX = X - X.dot(pc.transpose()) * pc
    else:
        XX = X - X.dot(pc.transpose()).dot(pc)
    return XX

def SIF_embedding(We, x, w, params):
    """
    Compute the scores between pairs of sentences using weighted average + removing the projection on the first principal component
    :param We: We[i,:] is the vector for word i
    :param x: x[i, :] are the indices of the words in the i-th sentence
    :param w: w[i, :] are the weights for the words in the i-th sentence
    :param params.rmpc: if >0, remove the projections of the sentence embeddings to their first principal component
    :return: emb, emb[i, :] is the embedding for sentence i
    """
    emb = get_weighted_average(We, x, w)
    if  params.rmpc > 0:
        emb = remove_pc(emb, params.rmpc)
    return emb


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

"""
Rotation matrix using the `Euler-Rodrigues formula
<http://en.wikipedia.org/wiki/Euler%E2%80%93Rodrigues_parameters>`_

Rotation using the `right hand rule
<http://en.wikipedia.org/wiki/Right_hand_rule>`_

Code downloaded from
`<http://stackoverflow.com/questions/6802577/python-rotation-of-3d-vector>`_
"""

import numpy as np
import math

def rotation_matrix_numpy(axis, theta):
    """ return the rotation matrix using numpy

    Parameters
    ----------
    axis : numpy.array([x,y,z])
    theta : rotation angle in radians
    """
    mat = np.eye(3, 3)
    axis = axis / math.sqrt(np.dot(axis, axis))
    a = math.cos(theta / 2.0)
    b, c, d = -axis * math.sin(theta / 2.0)

    return np.array(
        [
            [a * a + b * b - c * c - d * d, 2 * (b * c - a * d), 2 * (b * d + a * c)],
            [2 * (b * c + a * d), a * a + c * c - b * b - d * d, 2 * (c * d - a * b)],
            [2 * (b * d - a * c), 2 * (c * d + a * b), a * a + d * d - b * b - c * c],
        ]
    )

def rotation_matrix_weave(axis, theta, mat=None):
    """ return the rotation matrix using Weave
    (~20x faster than numpy)

    Parameters
    ----------
    axis : numpy.array([x,y,z])
    theta : rotation angle in radians
    """
    if mat == None:
        mat = np.eye(3, 3)

    support = "#include <math.h>"
    code = """
    double x = sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
    double a = cos(theta / 2.0);
    double b = -(axis[0] / x) * sin(theta / 2.0);
    double c = -(axis[1] / x) * sin(theta / 2.0);
    double d = -(axis[2] / x) * sin(theta / 2.0);

    mat[0] = a*a + b*b - c*c - d*d;
    mat[1] = 2 * (b*c - a*d);
    mat[2] = 2 * (b*d + a*c);

    mat[3*1 + 0] = 2*(b*c+a*d);
    mat[3*1 + 1] = a*a+c*c-b*b-d*d;
    mat[3*1 + 2] = 2*(c*d-a*b);

    mat[3*2 + 0] = 2*(b*d-a*c);
    mat[3*2 + 1] = 2*(c*d+a*b);
    mat[3*2 + 2] = a*a+d*d-b*b-c*c;
    """

    weave.inline(code, ["axis", "theta", "mat"], support_code=support, libraries=["m"])

    return mat

def rotate(arr, axis, theta, method="numpy"):
    """ rotate array around axis by theta with 'numpy' or 'weave'

    Arguments
    ---------
    arr : np.array([x,y,z])
    axis : np.array([x,y,z])
    theta : in radians
    method : 'numpy' or 'weave'

    Returns
    -------
    np.array([x,y,z])

    """
    if method == "numpy":
        return np.dot(rotation_matrix_numpy(axis, theta), arr)
    elif method == "weave":
        return np.dot(rotation_matrix_weave(axis, theta), arr)
    else:
        raise NameError("method for rotation matrix is 'numpy' or 'weave'")

if __name__ == "__main__":
    v = np.array([3, 5, 0])
    axis = np.array([4, 4, 1])
    theta = 1.2

    print("Rotation with Numpy:")
    print(np.dot(rotation_matrix_numpy(axis, theta), v))
    print("Rotation with Scipy.Weave:")
    print(np.dot(rotation_matrix_weave(axis, theta), v))


import numpy as np

# Tri Diagonal Matrix Algorithm(a.k.a. Thomas algorithm) solver
def tdma_solver(a, b, c, d):
    """
    TDMA solver, a b c d can be NumPy array type or Python list type.
    refer to https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm
    and to https://www.cfd-online.com/Wiki/Tridiagonal_matrix_algorithm_-_TDMA_(Thomas_algorithm)
    """
    nf = len(d)  # number of equations
    ac, bc, cc, dc = map(np.array, (a, b, c, d))  # copy arrays
    for it in range(1, nf):
        mc = ac[it - 1] / bc[it - 1]
        bc[it] = bc[it] - mc * cc[it - 1]
        dc[it] = dc[it] - mc * dc[it - 1]

    xc = bc
    xc[-1] = dc[-1] / bc[-1]

    for il in range(nf - 2, -1, -1):
        xc[il] = (dc[il] - cc[il] * xc[il + 1]) / bc[il]

    return xc


# -*- coding: utf-8 -*-
"""ML-M3-PolynomialLinearRegression.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1soqUtQwaW5ZQDLP7DR-JB1-sT351LHD7
"""

#importin libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#importing dataset
dataset = pd.read_csv('Position_Salaries.csv')
X = dataset.iloc[:, 1:-1].values
Y = dataset.iloc[:, -1].values
#print(X)
#print(Y)

#here we will compare 2 models too
#implementing simple linear model

from sklearn.linear_model import LinearRegression
linear_regressor= LinearRegression()
linear_regressor.fit(X,Y)

#implementing the polynomial linear model
#step 1:we will make x_poly....
from sklearn.preprocessing import PolynomialFeatures
polynomial_regressor = PolynomialFeatures(degree = 5)
X_poly = polynomial_regressor.fit_transform(X)
#step 2:just make linear model anf fit X_poly and y
linear_regressor_2 = LinearRegression()
linear_regressor_2.fit(X_poly, Y)

#so lin1 is simple linear model and lin2 is polynomial liner model

#visualising the linear model
plt.plot(X,linear_regressor.predict(X),color='blue')
plt.scatter(X,Y,color="red")
plt.title('Linear Regression')
plt.xlabel('Position Level')
plt.ylabel('Salary')
plt.show()
#you will observe that it is not accurate/well adapted

#visualising the polynomial model
plt.plot(X,linear_regressor_2.predict(polynomial_regressor.fit_transform(X)),color='blue')
plt.scatter(X,Y,color="red")
plt.title('polynomial Regression')
plt.xlabel('Position Level')
plt.ylabel('Salary')
plt.show()

#optional
#visualising previous graph with high resolution
X_grid = np.arange(min(X), max(X), 0.1)
X_grid = X_grid.reshape((len(X_grid), 1))
plt.scatter(X, Y, color = 'red')
plt.plot(X_grid, linear_regressor_2.predict(polynomial_regressor.fit_transform(X_grid)), color = 'blue')
plt.title('Polynomial Regression')
plt.xlabel('Position level')
plt.ylabel('Salary')
plt.show()

#if you want to predict single value
#whhat it is showing?
#value=year of exp. ans=what can be his/her salary?
#print(linear_regressor.predict([[6.9]]))
#print(linear_regressor_2.predict(polynomial_regressor.fit_transform([[6.9]])))


# %%
from pandas_profiling import ProfileReport
from typing import Dict, Tuple
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# %%

TP = 50
FP = 40
TN = 80
FN = 30

# %%
# Let's see the sensitivity of our logistic regression model
TP / float(TP+FN)
# %%
# Let us calculate specificity
TN / float(TN+FP)
# %%
# Calculate false positive rate - predicting churn when customer does not have churned
print(FP / float(TN+FP))
# %%
# positive predictive value
print(TP / float(TP+FP))

# %%
# Negative predictive value
print(TN / float(TN + FN))
# %%
TP = 400
FP = 200
TN = 300
FN = 100
# %%
# Let's see the sensitivity of our logistic regression model
TP / float(TP+FN)
# %%
# Let us calculate specificity
TN / float(TN+FP)
# %%
# Calculate false positive rate - predicting churn when customer does not have churned
print(FP / float(TN+FP))
# %%
# positive predictive value
print(TP / float(TP+FP))

# %%
# Negative predictive value
print(TN / float(TN + FN))
# %%

def TPR(TP: float, FN: float) -> float:

    return TP / float(TP+FN), f"{TP}/{TP+FN}"

def Sensitivity(TP: float, FN: float) -> float:
    return TPR(TP, FN)

def Specificity(TN: float, FP: float) -> float:
    return TN / float(TN+FP), f"{TN}/{TN+FP}"

def FPR(TN: float, FP: float) -> float:
    return 1 - Specificity(TN, FP)[0]

def Precision(TP: float, FP: float) -> float:
    return TP / float(TP+FP), f"{TP}/{TP+FP}"

def Recall(TP: float, FN: float) -> float:
    return TP / float(TP+FN), f"{TP}/{TP+FN}"

def F1Score(precision: float, recall: float) -> float:
    return (2 * precision*recall) / (precision+recall)

def Accuracy(TN: float, FP: float, FN: float, TP: float) -> float:
    return (TN+TP)/(TN+TP+FP+FN), f"{TN+TP}/{TN+TP+FP+FN}"

def get_classification_matrix(TN: float, FP: float, FN: float, TP: float) -> Dict[str, float]:
    precision = Precision(TP, FP)[0]
    recall = Recall(TP, FN)[0]
    return {
        "TPR": TPR(TP, FN),
        "Sensitivity": Sensitivity(TP, FN),
        "Specificity": Specificity(TN, FP),
        "FPR": FPR(TN, FP),
        "Precision": precision,
        "Recall": recall,
        "F1Score": F1Score(precision, recall),
        "Accuracy": Accuracy(TN, FP, FN, TP)
    }

# %%
# %%
%matplotlib inline
# %%
cutoff_df = pd.read_csv("tradeoff.csv")
# %%

cutoff_df.plot.line(x='Probability', y=[
                    'Accuracy', 'Sensitivity', 'Specificity'])
plt.show()

# %%
TP = 150
FP = 100
TN = 400
FN = 50

for k, v in get_classification_matrix(TN, FP, FN, TP).items():
    print(f"{k}: {v}")

# %%
# %%
%matplotlib inline
# %%
df = pd.read_csv("churn_data.csv")
# %%
profile = ProfileReport(df, title="Pandas Profiling Report")
profile

# %%
df.dropna(inplace=True)

# %%
df["Churn"] = df["Churn"].astype('category')
df["TotalCharges"] = df["TotalCharges"].astype(float)
# %%
sns.boxplot(data=df, x="Churn", y="TotalCharges")
# %%
# %%
TP = 359
FP = 234
TN = 1294
FN = 223

for k, v in get_classification_matrix(TN, FP, FN, TP).items():
    print(f"{k}: {v}")
# %%
# %%
for k, v in get_classification_matrix(1200, 400, 350, 1050).items():
    print(f"{k}: {v}")
# %%
for k, v in get_classification_matrix(1200, 400, 350, 1190).items():
    print(f"{k}: {v}")
# %%
0.7083333333333334 - 0.75
# %%
TN = 3
FP = 2
FN = 1
TP = 4
for k, v in get_classification_matrix(TN, FP, FN, TP).items():
    print(f"{k}: {v}")
# %%
TN = 500
FP = 20
FN = 40
TP = 440
for k, v in get_classification_matrix(TN, FP, FN, TP).items():
    print(f"{k}: {v}")
# %%

03Machine Learning 1/02Logistic Regression/02Multivariate Logistic Regression - Model Building/temp.py


import numpy as np
import scipy.stats as stats
import statsmodels.api as sm

def calculate_test_statistic(ts):
    """Calculate the test statistic defined by being
       the top zscore in the timeseries.

    Args:
        ts (list or np.array): The timeseries to compute the test statistic.

    Returns:
        tuple(int, float): The index of the top zscore and the value of the top zscore.

    """
    zscores = abs(stats.zscore(ts, ddof=1))
    max_idx = np.argmax(zscores)
    return max_idx, zscores[max_idx]

def calculate_critical_value(ts, alpha):
    """Calculate the critical value with the formula given for example in
    https://en.wikipedia.org/wiki/Grubbs%27_test_for_outliers#Definition

    Args:
        ts (list or np.array): The timeseries to compute the critical value.
        alpha (float): The significance level.

    Returns:
        float: The critical value for this test.

    """
    size   = len(ts)
    t_dist = stats.t.ppf(1 - alpha / (2 * size), size - 2)

    numerator   = (size - 1) * t_dist
    denominator = np.sqrt(size ** 2 - size * 2 + size * t_dist ** 2)

    return numerator / denominator

def seasonal_esd(ts, seasonality=None, hybrid=False, max_anomalies=10, alpha=0.05):
    """Compute the Seasonal Extreme Studentized Deviate of a time series.
       The steps taken are first to to decompose the timeseries into STL
       decomposition (trend, seasonality, residual). Then, calculate
       the Median Absolute Deviate (MAD) if hybrid (otherwise the median)
       and perform a regular ESD test on the residual, which we calculate as:
                        R = ts - seasonality - MAD or median

       Note: The statsmodel library requires a seasonality to compute the STL
       decomposition, hence the parameter seasonality. If none is given,
       then it will automatically be calculated to be 20% of the total
       timeseries.

    Args:
        ts (list or np.array): The timeseries to compute the ESD.
        seasonality (int): Number of time points for a season.
        hybrid (bool): See Twitter's research paper for difference.
        max_anomalies (int): The number of times the Grubbs' Test will be applied to the ts.
        alpha (float): The significance level.

    Returns:
        list int: The indices of the anomalies in the timeseries.

    """
    ts = np.array(ts)
    seasonal = seasonality or int(0.2 * len(ts)) # Seasonality is 20% of the ts if not given.
    decomp   = sm.tsa.seasonal_decompose(ts, freq=seasonal)
    if hybrid:
        mad      = np.median(np.abs(ts - np.median(ts)))
        residual = ts - decomp.seasonal - mad
    else:
        residual = ts - decomp.seasonal - np.median(ts)
    outliers = esd(residual, max_anomalies=max_anomalies, alpha=alpha)
    return outliers

def esd(timeseries, max_anomalies=10, alpha=0.05):
    """Compute the Extreme Studentized Deviate of a time series.
       A Grubbs Test is performed max_anomalies times with the caveat
       that each time the top value is removed. For more details visit
       http://www.itl.nist.gov/div898/handbook/eda/section3/eda35h3.htm

    Args:
        timeseries (list or np.array): The timeseries to compute the ESD.
        max_anomalies (int): The number of times the Grubbs' Test will be applied to the ts.
        alpha (float): The significance level.

    Returns:
        list int: The indices of the anomalies in the timeseries.

    """
    ts = np.copy(np.array(timeseries))
    test_statistics = []
    total_anomalies = -1
    for curr in range(max_anomalies):
        test_idx, test_val = calculate_test_statistic(ts)
        critical_value     = calculate_critical_value(ts, alpha)
        if test_val > critical_value:
            total_anomalies = curr
        test_statistics.append(test_idx)
        ts = np.delete(ts, test_idx)
    anomalous_indices = test_statistics[:total_anomalies + 1]
    return anomalous_indices

import numpy,import scipy,import statsmodels


import csv

import numpy as np

freqs = np.linspace(-2 * np.pi, 2 * np.pi, 100)
resp = np.sin(3 * freqs) / (6 * np.sin(freqs / 2)) * np.exp(freqs * -5j / 2)

mag = np.abs(resp)
ang = np.angle(resp)

with open("hw01/q6a-mag.csv", 'w') as f:
    writer = csv.writer(f)
    writer.writerow(['n', "q6a-mag"])
    writer.writerows(zip(freqs, mag))

with open("hw01/q6a-ang.csv", 'w') as f:
    writer = csv.writer(f)
    writer.writerow(['n', "q6a-ang"])
    writer.writerows(zip(freqs, ang))

inputs = np.arange(0, 11)

maf_impulse = 1 / 6 * np.logical_and(np.greater_equal(inputs, 0), np.less_equal(inputs, 5))
x = np.cos(np.pi / 3 * inputs) * np.greater_equal(inputs, 0)

with open("hw01/q6b.csv", 'w') as f:
    writer = csv.writer(f)
    writer.writerow(['n', "q6b"])
    writer.writerows(zip(inputs, np.convolve(maf_impulse, x)))


"""
Name: Pham Tuan Anh
Class: K63K2
MSSV: 18020116

You should understand the code you write.
"""

import cv2
import numpy as np
import argparse

def conv_sum(a, b):
    s = 0
    for i in range(len(a)):
        for j in range(len(a[0])):
            s += a[i][j]*b[i][j]
    return s

def my_convolution(I, g, mode='valid', boundary='zero_padding'):
    h, w = len(g), len(g[0])
    H, W = I.shape[0], I.shape[1]

    if mode == 'valid':
        output_h = H - (h - 1)
        output_w = W - (w - 1)
    else:
        output_h = H
        output_w = W

    output = [[0 for _ in range(output_w)] for _ in range(output_h)]
    for i in range(output_h):
        for j in range(output_w):
            output[i][j] = conv_sum(I[i:i + h, j:j + w], g)

    return output

def gradient_sobel(input_file, output_file, s):
    Mx = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
    My = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])

    img = cv2.imread(input_file, cv2.IMREAD_GRAYSCALE)
    smoothed_img = cv2.GaussianBlur(img, (s, s), 0)
    img_x = my_convolution(smoothed_img, Mx)
    # cv2.imshow('Horizontal image', np.array(img_x).astype(np.uint8))

    img_y = my_convolution(smoothed_img, My)
    # cv2.imshow('Vertical image', np.array(img_y).astype(np.uint8))

    gradient = np.sqrt(np.square(img_x) + np.square(img_y))
    cv2.imwrite(output_file, np.array(gradient).astype(np.uint8))
    cv2.imshow('Gradient', np.array(gradient).astype(np.uint8))
    cv2.waitKey(0)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("--input_file", "-i", type=str, help="Path to input image")
    parser.add_argument("--output_file", "-o", type=str, help="Path to output image")
    parser.add_argument("--size", "-s", type=int, default=3, help="Size of gaussian filter")

    args = parser.parse_args()

    gradient_sobel(args.input_file, args.output_file, args.size)


import numpy as np
from numpy.testing import assert_allclose

from pyfftlog import fhti, fht

def test_fftlog():
    # This is the example provided in `fftlogtest.f` of the original code. It
    # is the same test that is shown as an example in the gallery.
    # See the example for more details.

    # Parameters.
    logrmin = -4
    logrmax = 4
    n = 64
    mu = 0
    q = 0
    kr = 1
    kropt = 1
    tdir = 1
    logrc = (logrmin + logrmax)/2
    nc = (n + 1)/2.0
    dlogr = (logrmax - logrmin)/n
    dlnr = dlogr*np.log(10.0)

    # Calculate input function: $r^{\mu+1}\exp\left(-\frac{r^2}{2}\right)$.
    r = 10**(logrc + (np.arange(1, n+1) - nc)*dlogr)
    ar = r**(mu + 1)*np.exp(-r**2/2.0)

    # Initialize FFTLog transform - note fhti resets `kr`
    kr, xsave = fhti(n, mu, dlnr, q, kr, kropt)
    assert_allclose(kr, 0.953538967579)
    logkc = np.log10(kr) - logrc
    # rk = 10**(logrc - logkc)

    # Transform
    # ak = fftl(ar.copy(), xsave, rk, tdir)
    ak = fht(ar.copy(), xsave, tdir)

    # Calculate Output function: $k^{\mu+1}\exp\left(-\frac{k^2}{2}\right)$
    k = 10**(logkc + (np.arange(1, n+1) - nc)*dlogr)
    theo = k**(mu + 1)*np.exp(-k**2/2.0)

    # Check values
    assert_allclose(theo[theo > 1e-3], ak[theo > 1e-3], rtol=1e-8, atol=5e-5)


import numpy as np

print("Hi! Welcome to the magic square algorithm")
print("Please enter the number for which you would want a magic sqaure to be printed. Please enter an odd number")

# The odd number for which the magic square is created is stored in the variable N

N  = int(input())

# create a matrix with values 0 using numpy. The datatype is int for the elements in the matrix
magic_square = np.zeros((N,N), dtype=int)

n = 1
i, j = 0, N//2

# n iterates from 1 to N**2. The loop exits when n is equal to N**2
while n <= N**2:

	# Start in the middle of the first row.
	# (i = 0 and j = N//2 ) and the element at magic_square[i,j] is the middle in the first row.
	# insert n = 1 to begin with at magic_square[i,j]
	magic_square[i, j] = n
	# increment n by 1
	n += 1

	    # Move diagonally up and right, wrapping to the first column or last row if the move leads outside the grid

	new_i, new_j = (i-1) % N, (j+1)% N

    # if the cell is already filled with a number, move vertically down one space.
	if magic_square[new_i, new_j]:
		i += 1
	else:
        	i, j = new_i, new_j

print(magic_square)


from __future__ import print_function
import numpy
import time
import sys

def solve(n):
    A = numpy.random.randn(n, n)
    b = numpy.random.randn(n)
    start = time.time()
    x = numpy.linalg.solve(A, b)
    end = time.time()
    print("Runtime for n = %d: %d" % (n, end - start))

def jacobi(A, b, max_iter=1024, termination_l2=1.0e-12):
    # get size
    n = len(A[0])

    # initialize variables
    start = time.time()
    x = numpy.zeros(n)
    D = numpy.diag(A)
    R = A - numpy.diagflat(D)

    # use jacobi till maxiteration or termination criteria
    for i in range(0, max_iter):
        x = (b - numpy.dot(R, x))/D
        if (numpy.linalg.norm(numpy.dot(A, x) - b) < termination_l2):
            break
    end = time.time()
    l2 = numpy.linalg.norm(numpy.dot(A, x) - b)
    print("Jacobi: n = %d: time %fs, l2 %e" % (n, end - start, l2))
    return x

def jacobi_test(n):
    A = 100.0*numpy.random.randn(n, n)
    b = numpy.random.randn(n)
    row_sums = numpy.linalg.norm(A, 1)
    # make sure A is diagonally dominant
    A = A + row_sums*numpy.identity(n)
    #print(A)
    start = time.time()
    x = jacobi(A, b)
    end = time.time()
    #print(x)
    print("Total Runtime for n = %d: %d" % (n, end - start))

def write_rand_problem(n, name="input"):
    A = rand_matrix(n)
    A.tofile(name + "_A.bin")
    b = rand_result(n)
    b.tofile(name + "_b.bin")
    x = jacobi(A, b)
    print(A)
    print(b)
    print(numpy.dot(A, b))

def check_result(file_A, file_b, file_x):
    # read input
    b = numpy.fromfile(file_b)
    print(b)
    n = b.size
    A = numpy.fromfile(file_A)
    if A.size != n*n:
        print("File dimensions do not match")
        return
    A = A.reshape((n, n))
    print(A)
    x = numpy.fromfile(file_x)
    if x.size != n:
        print("File dimensions do not match")
        return
    # check result
    if n < 256:
        real_x = numpy.linalg.solve(A, b)
    else:
        real_x = jacobi(A, b)

    if not numpy.allclose(x, real_x, 1e-10):
        print("Error: output is not close to input")
    else:
        print("Output is correct!")

def main():
    if len(sys.argv) < 4:
        print("Usage: python check_output.py <input_A> <input_b> <output_x>")
        return
    check_result(sys.argv[1], sys.argv[2], sys.argv[3])

if __name__ == '__main__':
    main()


import numpy as np
import os
import torch
import copy
from math import cos, sqrt, pi

def dct(x, y, v, u, n):
    # Normalisation
    def alpha(a):
        if a == 0:
            return sqrt(1.0 / n)
        else:
            return sqrt(2.0 / n)

    return alpha(u) * alpha(v) * cos(((2 * x + 1) * (u * pi)) / (2 * n)) * cos(((2 * y + 1) * (v * pi)) / (2 * n))

def generate_2d_dct_basis(root_path, image_height, sub_dim=75):
    path = "{}/attacked_images/GeoDA/2d_dct_basis_height_{}_subdim_{}.npy".format(root_path, image_height, sub_dim)
    os.makedirs(os.path.dirname(path),exist_ok=True)
    if os.path.exists(path):
        return np.load(path)
    n = image_height  # Assume square image, so we don't have different xres and yres

    # We can get different frequencies by setting u and v
    # Here, we have a max u and v to loop over and display
    # Feel free to adjust
    maxU = sub_dim
    maxV = sub_dim

    dct_basis = []
    for u in range(0, maxU):
        for v in range(0, maxV):
            basisImg = np.zeros((n, n))
            for y in range(0, n):
                for x in range(0, n):
                    basisImg[y, x] = dct(x, y, v, u, max(n, maxV))
            dct_basis.append(basisImg)
    dct_basis = np.mat(np.reshape(dct_basis, (maxV*maxU, n*n))).transpose()
    np.save(path, dct_basis)
    return dct_basis

def clip_image_values(x, minv, maxv):
    if not isinstance(minv, torch.Tensor):
        return torch.clamp(x,min=minv,max=maxv)
    return torch.min(torch.max(x, minv), maxv)

def valid_bounds(img, delta=255):

    im = copy.deepcopy(np.asarray(img))
    im = im.astype(np.int)

    # General valid bounds [0, 255]
    valid_lb = np.zeros_like(im)
    valid_ub = np.full_like(im, 255)

    # Compute the bounds
    lb = im - delta
    ub = im + delta

    # Validate that the bounds are in [0, 255]
    lb = np.maximum(valid_lb, np.minimum(lb, im))
    ub = np.minimum(valid_ub, np.maximum(ub, im))

    # Change types to uint8
    lb = lb.astype(np.uint8)
    ub = ub.astype(np.uint8)

    return lb, ub

def inv_tf(x, mean, std):

    for i in range(len(mean)):

        x[i] = np.multiply(x[i], std[i], dtype=np.float32)
        x[i] = np.add(x[i], mean[i], dtype=np.float32)

    x = np.swapaxes(x, 0, 2)
    x = np.swapaxes(x, 0, 1)

    return x

def inv_tf_pert(r):

    pert = np.sum(np.absolute(r), axis=0)
    pert[pert != 0] = 1

    return pert

def get_label(x):
    s = x.split(' ')
    label = ''
    for l in range(1, len(s)):
        label += s[l] + ' '

    return label

def nnz_pixels(arr):
    return np.count_nonzero(np.sum(np.absolute(arr), axis=0))


import numpy as np
import math

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

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

    return matrix, vec

def GetDiagsFromTridiagMatrix(matrix):
    aVec = [matrix[i][0] for i in range(1, len(matrix))]

    bVec = [matrix[i][1] for i in range(1, len(matrix))]
    bVec.insert(0, matrix[0][0])

    cVec = [matrix[i][2] for i in range(1, len(matrix) - 1)]
    cVec.insert(0, matrix[0][1])

    return aVec, bVec, cVec

def GetPV(aVec, bVec, cVec, xVec):
    pVec = [0 for i in range(len(bVec))]
    qVec = pVec.copy()
    pVec[0] = -cVec[0] / bVec[0]
    qVec[0] = xVec[0] / bVec[0]

    for i in range(1, len(bVec) - 1):
        pVec[i] =  -cVec[i] / (bVec[i] + aVec[i - 1] * pVec[i - 1])

        qVec[i] = (xVec[i] - aVec[i - 1] * qVec[i - 1]) / (bVec[i] + aVec[i - 1] * pVec[i - 1])

    qVec[-1] = (xVec[-1] - aVec[-1] * qVec[-2]) / (bVec[-1] + aVec[-1] * pVec[-2])

    return pVec, qVec

def SolveSLAU(pVec, qVec):
    xVec = qVec.copy()

    for i in reversed(range(len(qVec) - 1)):
        xVec[i] = pVec[i] * xVec[i + 1] + qVec[i]

    return xVec

def TridiagMatrixAlg(matrix, vec):
    aVec, bVec, cVec = GetDiagsFromTridiagMatrix(matrix)

    print("a diagonal:")
    print(np.matrix(aVec).transpose())
    print("b diagonal:")
    print(np.matrix(bVec).transpose())
    print("c diagonal:")
    print(np.matrix(cVec).transpose())
    print("Vector:")
    print(np.matrix(vec).transpose())

    pVec, qVec = GetPV(aVec, bVec, cVec, vec)

    print("P vector:")
    print(np.matrix(pVec).transpose())
    print("Q vector:")
    print(np.matrix(qVec).transpose())

    result = SolveSLAU(pVec, qVec)

    return result

if __name__ == "__main__":
    matrix, vec = ReadMatrixAndVec()

    res = TridiagMatrixAlg(matrix, vec)

    print("Result vector:")
    print(np.matrix(res).transpose())


import matplotlib.pyplot as plt
import scipy.stats
import helper_functions
import loaddata

separator = '---------------------------------------------------------------'
tab: str = "\t"
# Do Dragon Type Pokemon tend to be taller than all Pokemon? Non Dragon Type Pokemon?
dh_null_hypothesis = "Dragon Type Pokemon tend to be taller than Non Dragon Type Pokemon."

def are_dragons_taller():
    # ----------------------------------------------------------------------------------
    print(f'{separator + separator}')
    print(f'{tab * 11}- - - Pokemon Data Analysis - - -')
    print(f'{tab * 14}Group 18')
    print(f'{separator + separator}\n')
    print(f'{tab * 7}Relevant data about the figures will be printed to the console to\n'
          f'{tab * 6}conserve space, please refer to the console using the figure numbers provided.\n'
          f'{tab * 14}Thank you!\n')
    print(f'{separator + separator}')
    print(f'{separator + separator}\n')
    print(f'{tab * 3}Do Dragon Type Pokemon tend to be taller than Non Dragon Type Pokemon?\n')
    print(f'{separator + separator}\n')
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # Dragon Type Pokemon
    # Displaying height(m) distribution of all Dragon Type Pokemon
    curr_fig = "1"
    print(f'{separator + separator}\n')
    print(f'{tab * 6}- - - Figure {curr_fig}: Height(m) distribution of Dragon Type Pokemon - - -\n')
    print(helper_functions.basic_stats_string(loaddata.dragon_type_height.describe(), "Height(m)"))
    plt.xlabel('Height(m)')
    plt.ylabel('Frequency')
    plt.title(f'Figure {curr_fig}: Height(m) distribution of Dragon Type Pokemon')
    counts_d = plt.hist(loaddata.dragon_type_height, bins=100)
    plt.show()
    print(f'{separator + separator}\n')
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # PMF for height(m) of all Dragon Pokemon
    curr_fig = "1b"
    bin_center_d = (counts_d[1][1:] + counts_d[1][:-1]) / 2
    dragon_h_pmf = counts_d[0] / len(loaddata.dragon_types)
    print(f'{separator + separator}\n')
    print(f'{tab * 6}- - - Figure {curr_fig}: PMF: Height(m) of Dragon Type Pokemon - - -\n')
    plt.xlabel('Height(m)')
    plt.ylabel('Probability')
    plt.title(f'Figure {curr_fig}: PMF: Height(m) of Dragon Type Pokemon')
    plt.bar(bin_center_d, dragon_h_pmf, width=.2)
    plt.show()
    print(f'{separator + separator}\n')
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # CDF plot using sort function - Dragon Types
    curr_fig = "1c"
    print(f'{separator + separator}\n')
    print(f'{tab * 6}- - - Figure {curr_fig}: CDF: Height(m) of Dragon Type Pokemon - - -\n')
    print(helper_functions.basic_stats_string(loaddata.prob_h_d_stats, "Probability ( Height(m) <= x)"))
    plt.xlabel('Height(m)')
    plt.ylabel('P(height $\leq$ x)')
    plt.title(f"Figure {curr_fig}: CDF: Height(m) of Dragon Type Pokemon")
    plt.plot(loaddata.dragon_heights_sorted, loaddata.prob_h_d)
    plt.show()
    print(f'{separator + separator}\n')
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # PMF vs CDF of dragon types for 10,20,30 bins
    curr_fig = "1d"
    print(f'{separator + separator}\n')
    print(f'{tab * 6}- - - Figure {curr_fig}: PMF vs CDF Height(m) of Dragon Type Pokemon - - -\n')
    plt.xlabel('Height(m)')
    plt.ylabel('Probability (Height(m))')
    plt.title(f"Figure {curr_fig}: PMF vs CDF Height(m) of Dragon Type Pokemon")
    plt.plot(loaddata.bin10_d, loaddata.freq10_d, '-*',
             loaddata.bin20_d, loaddata.freq20_d, ':o',
             loaddata.bin30_d, loaddata.freq30_d, '-.v')
    plt.legend(('10 bins', '20 bins', '30 bins'))
    plt.show()
    print(f'{separator + separator}\n')
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # Non Dragon Type Pokemon
    # Displaying height(m) distribution of all Non Dragon Type Pokemon
    curr_fig = "2"
    print(f'{separator + separator}\n')
    print(f'{tab * 6}- - - Figure {curr_fig}: Height(m) distribution of Non Dragon Type Pokemon - - -\n')
    print(helper_functions.basic_stats_string(loaddata.not_dragon_type_height.describe(), "Height(m)"))
    plt.xlabel('Height(m)')
    plt.ylabel('Frequency')
    plt.title(f' Figure {curr_fig}: Height(m) distribution of Non Dragon Type Pokemon')
    counts_nd = plt.hist(loaddata.not_dragon_type_height, bins=100)
    plt.show()
    print(f'{separator + separator}\n')
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # PMF for height(m) of all Non Dragon Type Pokemon
    curr_fig = "2b"
    bin_center_nd = (counts_nd[1][1:] + counts_nd[1][:-1]) / 2
    non_dragon_h_pmf = counts_nd[0] / sum(counts_nd[0])
    print(f'{separator + separator}\n')
    print(f'{tab * 6}- - - Figure {curr_fig}: PMF: Height(m) of Non Dragon Type Pokemon - - -\n')
    plt.xlabel('Height(m)')
    plt.ylabel('Probability')
    plt.title(f'Figure {curr_fig}: PMF: Height(m) of Non Dragon Type Pokemon')
    plt.bar(bin_center_nd, non_dragon_h_pmf, width=.2)
    plt.show()
    print(f'{separator + separator}\n')
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # CDF plot using sort function - Non Dragon Types
    curr_fig = "2c"
    print(f'{separator + separator}\n')
    print(f'{tab * 6}- - - Figure {curr_fig}: CDF: Height(m) of Non Dragon Type Pokemon - - -\n')
    print(helper_functions.basic_stats_string(loaddata.prob_h_nd_stats, "Probability ( Height(m) <= x)"))
    plt.xlabel('Height(m)')
    plt.ylabel('P(height $\leq$ x)')
    plt.title(f"Figure {curr_fig}: CDF: Height(m) of Non Dragon Type Pokemon")
    plt.plot(loaddata.not_dragon_heights_sorted, loaddata.prob_h_nd)
    plt.show()
    print(f'{separator + separator}\n')
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # PMF vs CDF of dragon types for 10,20,30 bins
    curr_fig = "2d"
    print(f'{separator + separator}\n')
    print(f'{tab * 6}- - - Figure {curr_fig}: PMF vs CDF Height(m) of Non Dragon Type Pokemon - - -\n')
    plt.xlabel('Height(m)')
    plt.ylabel('Probability (Height(m))')
    plt.title(f"Figure {curr_fig}: PMF vs CDF Height(m) of Non Dragon Type Pokemon")
    plt.plot(loaddata.bin10_nd, loaddata.freq10_nd, '-*',
             loaddata.bin20_nd, loaddata.freq20_nd, ':o',
             loaddata.bin30_nd, loaddata.freq30_nd, '-.v')
    plt.legend(('10 bins', '20 bins', '30 bins'))
    plt.show()
    print(f'{separator + separator}\n')
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # PMF For height of Dragon vs Not Dragon Pokemon
    curr_fig = "3"
    print(f'{separator + separator}\n')
    print(f'{tab * 6}- - - Figure {curr_fig}: PMF: Height(m) of Dragon vs Non Dragon Type Pokemon - - -\n')
    plt.xlabel('Height(m)')
    plt.ylabel('Probability')
    plt.title(f"Figure {curr_fig}: PMF: Height(m) of Dragon vs Non Dragon Type Pokemon")
    plt.plot(bin_center_d, counts_d[0] / len(loaddata.dragon_types), '-o',
             bin_center_nd, counts_nd[0] / len(loaddata.not_dragon_type), '-+')
    plt.legend(('Dragon Type', 'Not Dragon Type'))
    plt.show()
    print(f'{separator + separator}\n')
    # ----------------------------------------------------------------------------------

    # ----------------------------------------------------------------------------------
    # t-test going up means more likely to be a Dragon
    curr_fig = "4"

    d_c_test = counts_d[0] / len(loaddata.dragon_types)
    nd_c_test = counts_nd[0] / len(loaddata.not_dragon_type)

    t_test_dragon_height = d_c_test - nd_c_test
    t_test_dh_t_val = scipy.stats.ttest_ind(d_c_test, nd_c_test)
    t_test_dh_statistic_val = t_test_dh_t_val.statistic
    t_test_dh_p_val = t_test_dh_t_val.pvalue
    print(f'{separator + separator}\n')
    print(f'{tab * 6}- - - Figure {curr_fig}: T-Test: Do Dragon Types tend to be taller than Non Dragon Types - - -\n')
    print(f'{tab * 4}T Test Values:')
    print(f'{tab * 5}Statistic: {round(t_test_dh_statistic_val, 3)}\n{tab * 5}P Value: {round(t_test_dh_p_val, 3)}\n')
    if t_test_dh_p_val > .05:
        print(f"{tab * 4}Accept the null Hypothesis!")
    else:
        print(f"{tab * 4}Reject the null Hypothesis!")
    print(f"{tab * 5}{dh_null_hypothesis}\n")
    plt.xlabel(f'Height(m)')
    plt.ylabel(f'P[Dragon] - P[Not Dragon]')
    plt.title(f"Figure {curr_fig}: Do Dragon Types tend to be taller than Non Dragon Types")
    plt.bar(bin_center_nd, t_test_dragon_height)
    plt.show()
    print(f'{separator + separator}\n')
    # ----------------------------------------------------------------------------------
    return


"""
Lorenz system of ODEs.
Created on Sun Jul 11 21:39:25 2021
@author: j
"""
import numpy as np
from scipy.integrate import odeint
from matplotlib import pyplot as plt

# Lorenz system of equations. Strange atractor. Parameters sigma, beta and rho
# are specified directly.
def lorenz(state, t, sigma=10.0, beta=8.0/3.0, rho=28.0):
    x, y, z = state
    dx = sigma * (y - x)
    dy = x * (rho - z) - y
    dz = x * y - beta * z
    return [dx, dy, dz]

# We are gonna solve the lorenz system for 9 initial conditions. We want the
# butterfly shape fast, and that is why we use many initial conditions. All
# will be random numbers between -15 and 15. We use a seed for the
# np.random.random function so the graphics are the same allways. The
# simulation time will be of 20 units of time, using 8000 points.
np.random.seed(10) # Try: 6, 7, 10*, 15
N   = 9
x0  = -15 + 30 * np.random.random((N, 3))
t   = np.linspace(0, 20, 8000)

# Solutions to Lorenz are stored in a tensor. Results will all be ploted in a
# 3D projection using matplotlib
xt  = np.asarray([odeint(lorenz, i, t) for i in x0])

# Figure object of one axis only. All will be 3D projections on a plane. We
# turn off the axis so we only wet the plot. We define the limits of the plot.
fig = plt.figure(figsize=(12, 12))
ax  = fig.add_subplot(1, 1, 1, projection='3d')
ax.axis('off')
ax.set_xlim((-25, 25))
ax.set_ylim((-35, 35))
ax.set_zlim((5, 55))

# Each solution curve in phase space will be plotted with a color. All collors
# used are in this list:
colors = ['darkslategray', 'slateblue', 'blue', 'navy', 'black', 'gray',
          'silver','royalblue','gainsboro']

# Using a forloop we plot all sets of points in the solution tensor. We pick
# the colors for each curve in order
for i in range(N):
    ax.plot3D(xt[i,:,0], xt[i,:,1], xt[i,:,2], colors[i])

# We set the angles at which we see the 3D plot. Then we save a transparent
# image to be used in the CV
ax.view_init(-25, -40)
name = "lorenz_attractor.png"
plt.savefig(name, transparent=True, dpi=300, bbox_inches=0.0, pad_inches=0.0)
plt.show()
print('The PNG image may be cropped later.')


import numpy as np

def lrpd(a):
    """L,R,P,D,DA from LR = PDA factorization
    Method: Dahmen W., Reusken A.; Numerik fuer Ingenieure und Naturwissenschaeftler; Springer S. 79
    :param a: numpy.matrix NxN
    """
    n = a.shape[0]
    p = np.matrix(np.eye(n).astype(dtype=float))
    d = np.matrix(np.eye(n).astype(dtype=float))
    da = np.matrix(np.zeros_like(p))
    l = np.matrix(np.eye(n))
    r = np.matrix(np.zeros_like(p))
    indexes_r = range(n)
    for i in range(n):
        d[i, i] = 1 / abs(a[i]).sum()
        # scaling
        da[i] = d[i, i] * a[i]
    for j in range(n):
        indexes_r[j] = j + abs(da[j:, j]).argmax()
        # columns pivoting
        da[[j, indexes_r[j]]] = da[[indexes_r[j], j]]
        p[[j, indexes_r[j]]] = p[[indexes_r[j], j]]
        for i in range(j + 1, n):
            # new entries in L
            da[i, j] = da[i, j] / da[j, j]
            for k in range(j + 1, n):
                # new entries in R
                da[i, k] = da[i, k] - da[i, j] * da[j, k]
    for i in range(n):
        l[i + 1:n, i] = da[i + 1:n, i]
        r[i, i:n] = da[i, i:n]
    return l, r, p, d, da

def gauss_elimination(a, b):
    """Solution of the system Ax = b (LRx=PDb) through forward substitution of Ly = Pb, and then
    backward substitution of Rx = y
    :param a: numpy.matrix n X n
    :param b: numpy.matrix n X 1
    """
    n = a.shape[0]
    x = np.matrix(np.zeros_like(b))
    y = np.matrix(np.zeros_like(b))
    l, r, p, d, da = lrpd(a)
    pdb = p * d * b
    sum_lik_xk = 0
    sum_lik_yk = 0
    for j in range(0, n, +1):
        # Forward substitution Ly = PDb
        for k in range(0, j, +1):
            sum_lik_yk = sum_lik_yk + l[j, k] * y[k]
        y[j] = (pdb[j, 0] - sum_lik_yk) / 1.0
        sum_lik_yk = 0
    for j in range(n - 1, -1, -1):
        # Backward substitution Rx = y
        for k in range(n - 1, j, -1):
            sum_lik_xk = sum_lik_xk + r[j, k] * x[k]
        x[j] = (y[j, 0] - sum_lik_xk) / r[j, j]
        sum_lik_xk = 0
    return x

# noinspection PyAugmentAssignment
def nr_ls(x0, f, j, tol, max_it, inner_loop_condition,
          notify_status_func, method_loops, process_func_handle):
    x = x0
    # Newton method: G(x) = J(x)^-1 * F(x)
    outer_it_k = 0
    inner_it_j = 0
    j_val = j(x)
    f_val = f(x)
    y = np.matrix(np.ones(len(x))).T * tol / (np.sqrt(len(x)) * tol)
    magnitude_f = np.sqrt((f_val.T * f_val).item())
    # Line search variable lambda
    lambda_ls = 0.0
    accum_step = 0.0
    # For progress bar, use log scale to compensate for quadratic convergence
    log10_to_o_max_magnitude_f = np.log10(tol / magnitude_f)
    progress_k = (1.0 - np.log10(tol / magnitude_f) /
                  log10_to_o_max_magnitude_f) * 100.0
    diff = np.matrix(np.empty([len(x), 1]))
    diff.fill(np.nan)
    stop = False
    divergent = False
    # Non-functional status notification
    notify_status_func(progress_k, stop, outer_it_k,
                       inner_it_j, lambda_ls, accum_step,
                       x, diff, f_val, j_val, lambda_ls * y,
                       method_loops)
    # End non-functional notification
    while outer_it_k <= max_it and not stop:
        outer_it_k += 1
        method_loops[1] += 1
        inner_it_j = 0
        lambda_ls = 1.0
        accum_step += lambda_ls
        x_k_m_1 = x
        progress_k_m_1 = progress_k
        y = gauss_elimination(j_val, -f_val)
        # First attempt without backtracking
        x = x + lambda_ls * y
        diff = x - x_k_m_1
        j_val = j(x)
        f_val = f(x)
        magnitude_f = np.sqrt((f_val.T * f_val).item())
        if magnitude_f < tol and inner_loop_condition(x):
            stop = True  # Procedure successful
        else:
            # Non-functional status notification
            notify_status_func(progress_k, stop, outer_it_k,
                               inner_it_j, lambda_ls, accum_step,
                               x, diff, f_val, j_val, lambda_ls * y,
                               method_loops)
            # End non-functional notification

            # For progress use log scale to compensate for quadratic
            # convergence
            progress_k = (1.0 - np.log10(tol / magnitude_f) /
                          log10_to_o_max_magnitude_f) * 100.0
            if np.isnan(magnitude_f) or np.isinf(magnitude_f):
                # TODO: Re-implement steepest descent
                stop = True  # Divergent method
                divergent = True
                progress_k = 0.0
            else:
                pass
            if progress_k == progress_k_m_1:
                # Non-functional gui processing
                process_func_handle()
                # End non-functional processing
                # if form.progress_var.wasCanceled():
                # stop = True
        while inner_it_j <= max_it and \
                not inner_loop_condition(x) and \
                not stop:
            # Backtrack if any conc < 0. Line search method.
            # Ref. http://dx.doi.org/10.1016/j.compchemeng.2013.06.013
            inner_it_j += 1
            lambda_ls = lambda_ls / 2.0
            accum_step += -lambda_ls
            x = x_k_m_1
            progress_k = progress_k_m_1
            x = x + lambda_ls * y
            diff = x - x_k_m_1
            j_val = j(x)
            f_val = f(x)
            # Non-functional status notification
            notify_status_func(progress_k, stop, outer_it_k,
                               inner_it_j, lambda_ls, accum_step,
                               x, diff, f_val, j_val, lambda_ls * y,
                               method_loops)
            # End non-functional notification
            method_loops[0] += 1
    if stop and not divergent:
        progress_k = 100.0
    elif divergent:
        progress_k = 0.0
    # Non-functional status notification
    notify_status_func(progress_k, stop, outer_it_k,
                       inner_it_j, lambda_ls, accum_step,
                       x, diff, f_val, j_val, lambda_ls * y,
                       method_loops)
    # End non-functional notification
    return progress_k, stop, outer_it_k,\
        inner_it_j, lambda_ls, accum_step,\
        x, diff, f_val, lambda_ls * y,\
        method_loops


"""This module provides functions to sample from the unit simplex.
"""
import numpy as np
from scipy.special import comb

def sample(dimension, n_points=1):
    """Draw random samples from the unit simplex in R^d.

    Parameters
    ----------
    dimension : int
        number of variables.
    n_points : int, optional
        number of points to sample, by default 1

    Returns
    -------
    numpy array
        Random samples from the unit simplex
    """
    s = np.random.standard_exponential((n_points, dimension))
    return (s.T / s.sum(axis=1)).T

def grid(dimension, levels=2):
    """Construct a regular grid on the unit simplex in R^d.

    Parameters
    ----------
    dimension : int
        Number of variables.
    levels : int
        Number of levels between 0 and 1 for each variable.

    Returns
    -------
    ndarray of shape (n_points, n_dim)
        Regularily spaced grid points on the unit simplex.

    References
    ----------
    Nijenhuis and Wilf, Combinatorial Algorithms, Chapter 5, Academic Press, 1978.

    Examples
    --------
    >>> simplex.grid(3, 3)
    array([
        [0. , 0. , 1. ],
        [0. , 0.5, 0.5],
        [0. , 1. , 0. ],
        [0.5, 0. , 0.5],
        [0.5, 0.5, 0. ],
        [1. , 0. , 0. ]
    ])
    """
    m = dimension
    n = levels - 1
    n_points = comb(n + m - 1, m - 1, exact=True)

    x = np.zeros(m, dtype=int)
    x[-1] = n

    out = np.empty((n_points, m), dtype=int)
    out[0] = x

    h = m
    for i in range(1, n_points):
        h -= 1

        val = x[h]
        x[h] = 0
        x[h - 1] += 1
        x[-1] = val - 1

        if val != 1:
            h = m

        out[i] = x

    return out / n


import numpy

def find_step_length(f, fd, x, alpha, direction, c2):
  g = lambda alpha: f(x+alpha*direction)
  gd = lambda alpha: numpy.dot(fd(x + alpha*direction), direction)
  return interpolation(g, gd, alpha, c2)

def wolf1(f, fd, alpha):
  c1 = 1e-4
  return f(alpha) <= f(0) + c1*alpha*fd(alpha)

def wolf_strong(f, fd, alpha, c2):
  return abs(fd(alpha)) <= -c2*fd(0)

def simple_backtracking(f, fd, alpha, c2):
  rate = 0.5
  while not (wolf1(f, fd, alpha) or wolf_strong(f, fd, alpha, c2)):
    alpha = rate*alpha
  return alpha

def interpolation(f, fd, alpha, c2):
  lo = 0.0
  hi = 1.0

  for i in range(0, 20):
    if wolf1(f, fd, alpha):
      if wolf_strong(f, fd, alpha, c2):
        return alpha

    half = (lo+hi)/2.0
    alpha = - (fd(lo)*hi*hi) / (2*(f(hi)-f(lo)-fd(lo)*hi))

    if alpha < lo or alpha > hi: # quadratic interpolation failed. reduce by half instead
      alpha = half
    if fd(alpha) > 0:
      hi = alpha
    elif fd(alpha) <= 0:
      lo = alpha
  return alpha

Computational Mathematics | Python/Line_search.py


import numpy as np

class Derivative(object):
    def __init__(self, f, h=0.001, order=1, n_points=3, vectorized=False):
        self.f = np.vectorize(f) if vectorized else f
        self.h = h
        self.order = order
        self.n_points = n_points
        self.weights = self._weights()

    def _weights(self):
        if self.order == 1:
            if self.n_points == 3:
                return [0.5, -3, 4, -1]
            if self.n_points == 5:
                return [1 / 12, -25, 48, -36, 16, -3]

    def __str__(self):
        return "Difference Method"

    def description(self):
        pass

    def __call__(self, x0):
        fp = 0
        for i, w in enumerate(self.weights):
            if i == 0:
                continue
            fp += w * self.f(x0 + (i - 1) * self.h)
        fp *= self.weights[0] / self.h
        return fp


import numpy as np

def centroid(X):
    """
    Centroid is the mean position of all the points in all of the coordinate
    directions, from a vectorset X.
    https://en.wikipedia.org/wiki/Centroid
    C = sum(X)/len(X)
    Parameters
    ----------
    X : array
        (N,D) matrix, where N is points and D is dimension.
    Returns
    -------
    C : float
        centroid
    """
    C = X.mean(axis=0)
    return C

def rmsd(V, W):
    """
    Calculate Root-mean-square deviation from two sets of vectors V and W.
    Parameters
    ----------
    V : array
        (N,D) matrix, where N is points and D is dimension.
    W : array
        (N,D) matrix, where N is points and D is dimension.
    Returns
    -------
    rmsd : float
        Root-mean-square deviation between the two vectors
    """
    D = len(V[0])
    N = len(V)
    result = 0.0
    for v, w in zip(V, W):
        result += sum([(v[i] - w[i])**2.0 for i in range(D)])
    return np.sqrt(result/N)

def kabsch_rmsd(P, Q, translate=False):
    """
    Rotate matrix P unto Q using Kabsch algorithm and calculate the RMSD.
    Parameters
    ----------
    P : array
        (N,D) matrix, where N is points and D is dimension.
    Q : array
        (N,D) matrix, where N is points and D is dimension.
    translate : bool
        Use centroids to translate vector P and Q unto each other.
    Returns
    -------
    rmsd : float
        root-mean squared deviation
    """
    if translate:
        Q = Q - centroid(Q)
        P = P - centroid(P)

    P = kabsch_rotate(P, Q)
    return rmsd(P, Q)

def kabsch_rotate(P, Q):
    """
    Rotate matrix P unto matrix Q using Kabsch algorithm.
    Parameters
    ----------
    P : array
        (N,D) matrix, where N is points and D is dimension.
    Q : array
        (N,D) matrix, where N is points and D is dimension.
    Returns
    -------
    P : array
        (N,D) matrix, where N is points and D is dimension,
        rotated
    """
    U = kabsch(P, Q)

    # Rotate P
    P = np.dot(P, U)
    return P

def kabsch(P, Q):
    """
    Using the Kabsch algorithm with two sets of paired point P and Q, centered
    around the centroid. Each vector set is represented as an NxD
    matrix, where D is the the dimension of the space.
    The algorithm works in three steps:
    - a centroid translation of P and Q (assumed done before this function
      call)
    - the computation of a covariance matrix C
    - computation of the optimal rotation matrix U
    For more info see http://en.wikipedia.org/wiki/Kabsch_algorithm
    Parameters
    ----------
    P : array
        (N,D) matrix, where N is points and D is dimension.
    Q : array
        (N,D) matrix, where N is points and D is dimension.
    Returns
    -------
    U : matrix
        Rotation matrix (D,D)
    """

    # Computation of the covariance matrix
    C = np.dot(np.transpose(P), Q)

    # Computation of the optimal rotation matrix
    # This can be done using singular value decomposition (SVD)
    # Getting the sign of the det(V)*(W) to decide
    # whether we need to correct our rotation matrix to ensure a
    # right-handed coordinate system.
    # And finally calculating the optimal rotation matrix U
    # see http://en.wikipedia.org/wiki/Kabsch_algorithm
    V, S, W = np.linalg.svd(C)
    d = (np.linalg.det(V) * np.linalg.det(W)) < 0.0

    if d:
        S[-1] = -S[-1]
        V[:, -1] = -V[:, -1]

    # Create Rotation matrix U
    U = np.dot(V, W)

    return U


import math

try:
    from ulab import scipy, numpy as np
except ImportError:
    import scipy
    import numpy as np

## test cholesky solve
L = np.array([[3, 0, 0, 0], [2, 1, 0, 0], [1, 0, 1, 0], [1, 2, 1, 8]])
b = np.array([4, 2, 4, 2])

# L needs to be a lower triangular matrix
result = scipy.linalg.cho_solve(L, b)
ref_result = np.array([-0.01388888888888906, -0.6458333333333331, 2.677083333333333, -0.01041666666666667])

for i in range(4):
        print(math.isclose(result[i], ref_result[i], rel_tol=1E-6, abs_tol=1E-6))

## test cholesky and cho_solve together
C = np.array([[18, 22,  54,  42], [22, 70,  86,  62], [54, 86, 174, 134], [42, 62, 134, 106]])
L = np.linalg.cholesky(C)

# L is a lower triangular matrix obtained by performing cholesky of positive-definite linear system
result = scipy.linalg.cho_solve(L, b)
ref_result = np.array([6.5625, 1.1875, -2.9375, 0.4375])

for i in range(4):
        print(math.isclose(result[i], ref_result[i], rel_tol=1E-6, abs_tol=1E-6))


import numpy as np
import math

def norm(u: np.ndarray) -> np.ndarray:
    u = np.array(u)
    _min = u.min()
    _max = u.max()

    return (u - _min) / (_max - _min)

def norm_max(u: np.ndarray) -> np.ndarray:
    return u / np.finfo(np.float).max

def ztest(mean1, mean2, std1, std2, n_data_points) -> float:
    # http://homework.uoregon.edu/pub/class/es202/ztest.html
    """ If the Z-statistic is less than 2, the two samples are the same.
        If the Z-statistic is between 2.0 and 2.5, the two samples are marginally different
        If the Z-statistic is between 2.5 and 3.0, the two samples are significantly different
        If the Z-statistic is more then 3.0, the two samples are highly signficantly different """
    sigma1 = std1 / math.sqrt(n_data_points)
    sigma2 = std2 / math.sqrt(n_data_points)

    return abs((mean1 - mean2) / math.sqrt(sigma1 ** 2 + sigma2 ** 2))

def check_size(u: np.ndarray, v: np.ndarray):
    if len(u) != len(v):
        raise ValueError(f'u and v must be of the same size')

def hellinger(u: np.ndarray, v: np.ndarray) -> float:
    """ If returns 0.0 matchs
        if returns 1.0 mismatch"""

    check_size(u, v)

    u = norm(u)
    v = norm(v)

    return np.sqrt(np.sum((np.sqrt(u) - np.sqrt(v)) ** 2)) / np.sqrt(2)

def hellinger2(u: np.ndarray, v: np.ndarray) -> float:
    check_size(u, v)

    u1 = norm([u, v])[0]
    v1 = norm([u, v])[1]

    print(u1)
    print(v1)

    u = u1
    v = v1

    return np.sqrt(np.sum((np.sqrt(u) - np.sqrt(v)) ** 2)) / np.sqrt(2)

def pearson(u: np.ndarray, v: np.ndarray) -> float:
    """ If returns 1.0 matchs
        If returns 0.5 half matchs
        if returns 0.0 mismatch"""

    check_size(u, v)

    u1 = norm([u, v])[0]
    v1 = norm([u, v])[1]

    _u = np.mean(u)
    _v = np.mean(v)

    a = np.sum((u - _u) * (v - _v))
    b = np.sqrt(np.sum((u - _u) ** 2) * np.sum((v - _v) ** 2))

    p = a / b

    # return p - (-1) / (1 - (-1))
    return p

def pearson2(u: np.ndarray, v: np.ndarray) -> float:
    """ If returns 1.0 matchs
        If returns 0.5 half matchs
        if returns 0.0 mismatch"""

    check_size(u, v)

    u1 = norm([u,v])[0]
    v1 = norm([u,v])[1]

    _u = np.mean(u1)
    _v = np.mean(v1)

    a = np.sum((u1 - _u) * (v1 - _v))
    b = np.sqrt(np.sum((u1 - _u) ** 2) * np.sum((v1 - _v) ** 2))

    return a/b

def chisquare(u: np.ndarray, v: np.ndarray) -> float:
    """ If returns 0.0 matchs
        if returns unbounded mismatch"""

    check_size(u, v)

    return np.sum(((u - v) ** 2) / (u + v))

def cosine(u: np.ndarray, v: np.ndarray) -> float:
    check_size(u, v)

    return 1 - np.sum(u * v)

def kullback(u: np.ndarray, v: np.ndarray) -> float:
    check_size(u, v)

    return np.sum(u * np.log(u / v))

def intersection(u: np.ndarray, v: np.ndarray) -> float:
    check_size(u, v)

    u = norm(u)
    v = norm(v)

    return np.sum(np.minimum(u, v))

if __name__ == '__main__':
    mu_1 = 0.5  # mean of the first distribution
    mu_2 = 0.5  # mean of the second distribution
    data_1 = np.random.normal(mu_1, 0., 1000)
    data_2 = np.random.normal(mu_2, 0., 1000)
    hist_1, _ = np.histogram(data_1, bins=100, range=[-15, 15])
    hist_2, _ = np.histogram(data_2, bins=100, range=[-15, 15])

    data_1 = hist_1
    data_2 = hist_2

    ztest1 = ztest(76.4, 102, 12.97, 4.08, 300 // 15)

    # print(f'ztest: {ztest1}')
    print(f'helli: {hellinger(data_1, data_2)}')
    print(f'pears: {pearson(data_1, data_2)}')
    # print(f'chisq: {chisquare(data_1, data_2)}')
    # print(f'chial: {chisquare_alt(data_1, data_2)}')
    # print(f'kullb: {kullback(data_1, data_2)}')
    # print(f'inter: {intersection(data_1, data_2)}')


# 3.2.2 カテゴリ分布の学習と予測

#%%

# 3.2.2項で利用するライブラリ
import numpy as np
import math # 対数ガンマ関数:lgamma()
#from scipy.stats import dirichlet # ディリクレ分布
import matplotlib.pyplot as plt

#%%

## 真のモデルの設定

# 次元数:(固定)
K = 3

# 真のパラメータを指定
pi_truth_k = np.array([0.3, 0.5, 0.2])

# x軸の値を作成
k_line = np.arange(1, K + 1)

#%%

# 全てのパターンのデータを作成
s_kk = np.identity(K)

# 確率を計算:式(2.29)
true_model = np.prod(pi_truth_k**s_kk, axis=1)

# 確率を計算:SciPy ver
from scipy.stats import multinomial # 多項分布
true_model = multinomial.pmf(x=s_kk, n=1, p=pi_truth_k)
print(true_model)

# 尤度を作図
plt.bar(x=k_line, height=pi_truth_k, color='purple') # 真のモデル
plt.xlabel('k')
plt.ylabel('prob')
plt.xticks(ticks=k_line, labels=k_line) # x軸目盛
plt.suptitle('Categorical Distribution', fontsize=20)
plt.title('$\pi=(' + ', '.join([str(k) for k in  pi_truth_k]) + ')$', loc='left')
plt.ylim(0, 1)
plt.show()

#%%

## 観測データの生成

# データ数を指定
N = 50

# (観測)データを生成
s_nk = np.random.multinomial(n=1, pvals=pi_truth_k, size=N)

# 観測のデータを確認
print(np.sum(s_nk, axis=0))

#%%

# 観測データのヒストグラムを作図
plt.bar(x=k_line, height=np.sum(s_nk, axis=0)) # 観測データ
plt.xlabel('k')
plt.ylabel('count')
plt.xticks(ticks=k_line, labels=k_line) # x軸目盛
plt.suptitle('Observation Data', fontsize=20)
plt.title('$N=' + str(N) +
          ', \pi=(' + ', '.join([str(k) for k in pi_truth_k]) + ')$', loc='left')
plt.show()

#%%

## 事前分布の設定

# 事前分布のパラメータを指定
alpha_k = np.array([1.0, 1.0, 1.0])

#%%

# 作図用の点を設定
point_vec = np.arange(0.0, 1.001, 0.02)

# 格子状の点を作成
X, Y, Z = np.meshgrid(point_vec, point_vec, point_vec)

# 確率密度の計算用にまとめる
pi_point = np.array([list(X.flatten()), list(Y.flatten()), list(Z.flatten())]).T
pi_point = pi_point[1:, :] # (0, 0, 0)の行を除去
pi_point /= np.sum(pi_point, axis=1, keepdims=True) # 正規化
pi_point = np.unique(pi_point, axis=0) # 重複を除去

#%%

# 事前分布(ディリクレ分布)の確率密度を計算:式(2.41)
ln_C_dir = math.lgamma(np.sum(alpha_k)) - np.sum([math.lgamma(a) for a in alpha_k]) # 正規化項(対数)
prior = np.exp(ln_C_dir) * np.prod(pi_point**(alpha_k - 1), axis=1)

# 事前分布(ディリクレ分布)の確率密度を計算:SciPy ver
#prior = np.array([
#    dirichlet.pdf(x=pi_point[i], alpha=alpha_k) for i in range(len(pi_point))
#])

#%%

# 三角座標に変換
tri_x = pi_point[:, 1] + pi_point[:, 2] / 2
tri_y = np.sqrt(3) * pi_point[:, 2] / 2

# 事前分布を作図
plt.scatter(tri_x, tri_y, c=prior, cmap='jet') # 事前分布
plt.xlabel('$\pi_1, \pi_2$') # x軸ラベル
plt.ylabel('$\pi_1, \pi_3$') # y軸ラベル
plt.xticks(ticks=[0.0, 1.0], labels=['(1, 0, 0)', '(0, 1, 0)']) # x軸目盛
plt.yticks(ticks=[0.0, 0.87], labels=['(1, 0, 0)', '(0, 0, 1)']) # y軸目盛
plt.suptitle('Dirichlet Distribution', fontsize=20)
plt.title('$\\alpha=(' + ', '.join([str(k) for k in alpha_k]) + ')$', loc='left')
plt.colorbar() # 凡例
plt.gca().set_aspect('equal') # アスペクト比
plt.show()

#%%

## 事後分布の計算

# 事後分布のパラメータを計算:式(3.28)
alpha_hat_k = np.sum(s_nk, axis=0) + alpha_k
print(alpha_hat_k)

# 事後分布(ディリクレ分布)の確率密度を計算:式(2.41)
ln_C_dir = math.lgamma(np.sum(alpha_hat_k)) - np.sum([math.lgamma(a) for a in alpha_hat_k]) # 正規化項(対数)
posterior = np.prod(pi_point**(alpha_hat_k - 1), axis=1)
posterior *= np.exp(ln_C_dir)

# 事後分布(ディリクレ分布)の確率密度を計算:SciPy ver
#posterior = np.array([
#    dirichlet.pdf(x=pi_point[i], alpha=alpha_hat_k) for i in range(len(pi_point))
#])

#%%

# 真のパラメータの値を三角座標に変換
tri_x_truth = pi_truth_k[1] + pi_truth_k[2] / 2
tri_y_truth = np.sqrt(3) * pi_truth_k[2] / 2

# 事後分布を作図
plt.scatter(tri_x, tri_y, c=posterior, cmap='jet') # 事後分布
plt.xlabel('$\pi_1, \pi_2$') # x軸ラベル
plt.ylabel('$\pi_1, \pi_3$') # y軸ラベル
plt.xticks(ticks=[0.0, 1.0], labels=['(1, 0, 0)', '(0, 1, 0)']) # x軸目盛
plt.yticks(ticks=[0.0, 0.87], labels=['(1, 0, 0)', '(0, 0, 1)']) # y軸目盛
plt.suptitle('Dirichlet Distribution', fontsize=20)
plt.title('$\\alpha=(' + ', '.join([str(k) for k in alpha_hat_k]) + ')$', loc='left')
plt.colorbar() # 凡例
plt.gca().set_aspect('equal') # アスペクト比
plt.scatter(tri_x_truth, tri_y_truth, marker='x', color='black', s=200) # 真のパラメータ
plt.show()

#%%

## 予測分布の計算

# 予測分布のパラメータを計算
pi_hat_star_k = alpha_hat_k / np.sum(alpha_hat_k)
pi_hat_star_k = (np.sum(s_nk, axis=0) + alpha_k) / np.sum(np.sum(s_nk, axis=0) + alpha_k)
print(pi_hat_star_k)

#%%

# 予測分布を作図
plt.bar(x=k_line, height=pi_truth_k, label='truth',
        alpha=0.5, color='white', edgecolor='red', linestyle='dashed') # 真のモデル
plt.bar(x=k_line, height=pi_hat_star_k, label='predict',
        alpha=0.5, color='purple') # 予測分布
plt.xlabel('k')
plt.ylabel('prob')
plt.xticks(ticks=k_line, labels=k_line) # x軸目盛
plt.suptitle('Categorical Distribution', fontsize=20)
plt.title('$N=' + str(N) + ', \hat{\pi}_{*}=(' + ', '.join([str(k) for k in np.round(pi_hat_star_k, 2)]) + ')$', loc='left')
plt.ylim(0, 1)
plt.show()

#%%

### アニメーション

# 利用するライブラリ
import numpy as np
from scipy.stats import dirichlet # ディリクレ分布
import matplotlib.pyplot as plt
import matplotlib.animation as animation

#%%

# 描画用の点を設定
point_vec = np.arange(0.0, 1.001, 0.025)

# 格子状の点を作成
X, Y, Z = np.meshgrid(point_vec, point_vec, point_vec)

# 確率密度の計算用にまとめる
pi_point = np.array([list(X.flatten()), list(Y.flatten()), list(Z.flatten())]).T
pi_point = pi_point[1:, :] # (0, 0, 0)の行を除去
pi_point /= np.sum(pi_point, axis=1, keepdims=True) # 正規化
pi_point = np.unique(pi_point, axis=0) # 重複を除去

# 三角座標に変換
tri_x = pi_point[:, 1] + pi_point[:, 2] / 2
tri_y = np.sqrt(3) * pi_point[:, 2] / 2

#%%

## 推論処理

# 次元数:(固定)
K = 3

# 真のパラメータを指定
pi_truth_k = np.array([0.3, 0.5, 0.2])

# 事前分布のパラメータを指定
alpha_k = np.array([1.0, 1.0, 1.0])

# 初期値による予測分布のパラメータを計算
mu_star_k = alpha_k / np.sum(alpha_k)

# データ数を指定
N = 100

# 記録用の受け皿を初期化
s_nk = np.empty((N, K))
trace_alpha = [list(alpha_k)]
trace_posterior = [[dirichlet.pdf(x=pi_point[i], alpha=alpha_k) for i in range(len(pi_point))]]
trace_predict = [list(mu_star_k)]

# ベイズ推論
for n in range(N):
    # (観測)データを生成
    s_nk[n] = np.random.multinomial(n=1, pvals=pi_truth_k, size=1)[0]

    # 事後分布のパラメータを更新
    alpha_k += s_nk[n]

    # 値を記録
    trace_alpha.append(list(alpha_k))

    # 事後分布(ディリクレ分布)の確率密度を計算
    trace_posterior.append(
        [dirichlet.pdf(x=pi_point[i], alpha=alpha_k) for i in range(len(pi_point))]
    )

    # 予測分布のパラメータを更新
    mu_star_k = alpha_k / np.sum(alpha_k)

    # 予測分布(カテゴリ分布)の確率を記録
    trace_predict.append(list(mu_star_k))

    # 途中経過を表示
    print('n=' + str(n + 1) + ' (' + str(np.round((n + 1) / N * 100, 1)) + '%)')

# 観測のデータを確認
print(np.sum(s_nk, axis=0))

#%%

## 事後分布の推移をgif画像化

# 真のパラメータの値を三角座標に変換
tri_x_truth = pi_truth_k[1] + pi_truth_k[2] / 2
tri_y_truth = np.sqrt(3) * pi_truth_k[2] / 2

# 画像サイズを指定
fig = plt.figure(figsize=(12, 9))

# 作図処理を関数として定義
def update_posterior(n):
    # 前フレームのグラフを初期化
    plt.cla()

    # nフレーム目の事後分布を作図
    plt.scatter(tri_x, tri_y, c=trace_posterior[n], cmap='jet') # 事後分布
    plt.scatter(tri_x_truth, tri_y_truth, marker='x', color='black', s=200) # 真のパラメータ
    plt.xlabel('$\pi_1, \pi_2$') # x軸ラベル
    plt.ylabel('$\pi_1, \pi_3$') # y軸ラベル
    plt.xticks(ticks=[0.0, 1.0], labels=['(1, 0, 0)', '(0, 1, 0)']) # x軸目盛
    plt.yticks(ticks=[0.0, 0.87], labels=['(1, 0, 0)', '(0, 0, 1)']) # y軸目盛
    plt.suptitle('Dirichlet Distribution', fontsize=20)
    plt.title('$N=' + str(n) + ', \hat{\\alpha}=(' + ', '.join([str(a) for a in trace_alpha[n]]) + ')$', loc='left')
    plt.gca().set_aspect('equal') # アスペクト比

# gif画像を作成
posterior_anime = animation.FuncAnimation(fig, update_posterior, frames=N + 1, interval=100)
posterior_anime.save("ch3_2_2_Posterior.gif")

#%%

## 予測分布の推移をgif画像化

# x軸の値を作成
k_line = np.arange(1, K + 1)

# 画像サイズを指定
fig = plt.figure(figsize=(12, 9))

# 作図処理を関数として定義
def update_predict(n):
    # 前フレームのグラフを初期化
    plt.cla()

    # nフレーム目の予測分布を作図
    plt.bar(x=k_line, height=pi_truth_k, label='truth',
            alpha=0.5, color='white', edgecolor='red', linestyle='dashed') # 真の分布
    plt.bar(x=k_line, height=trace_predict[n], label='predict',
            alpha=0.5, color='purple') # 予測分布
    plt.xlabel('k')
    plt.ylabel('prob')
    plt.xticks(ticks=k_line, labels=k_line) # x軸目盛
    plt.suptitle('Categorical Distribution', fontsize=20)
    plt.title('$N=' + str(n) + ', \hat{\pi}_{*}=(' + ', '.join([str(k) for k in np.round(trace_predict[n], 2)]) + ')$', loc='left')
    plt.ylim(0, 1)
    plt.legend()

# gif画像を作成
predict_anime = animation.FuncAnimation(fig, update_predict, frames=N + 1, interval=100)
predict_anime.save("ch3_2_2_Predict.gif")

#%%

print('end')


import numpy as np
import math

'''
Y is the column vector containing the set of yns and
Y_pred is the predicted ys represented in a l x N array
where N is the number of points in the training set
'''
def MSE(Y_pred,Y,N, verbose=False):
    """Getting the Mean Squared Error """

    temp = []
    for i in range(0, len(Y_pred)):
        sub = np.subtract(Y.T, Y_pred[i])
        msq_error=0
        for i in range(0, N):
            sq_error = math.pow(sub[0,i], 2)
            if verbose :
                print("the square error for n = ",i,"is: ",sq_error)
            msq_error += sq_error
        msq_error = msq_error/N
        temp.append(msq_error)

    MSE = min(temp)
    return MSE


import numpy as np
from MLlib.activations import Sigmoid, Relu
from MLlib.activations import unit_step

def test_Sigmoid():
    X = np.random.random((3, 2))
    assert np.array_equal(
        (1 / (1 + np.exp(-X))),
        Sigmoid.activation(X)
        ) is True
    assert np.array_equal(
        (1 / (1 + np.exp(-X)))*(1-(1 / (1 + np.exp(-X)))),
        Sigmoid.derivative(X)) is True

def test_Relu():
    X = np.array([[1, -2, 3], [-1, 2, 1]])
    assert np.array_equal(
        np.maximum(0, X),
        Relu.activation(X)
        ) is True
    assert np.array_equal(
        np.greater(X, 0).astype(int),
        Relu.derivative(X)) is True

def test_unit_step():
    X = np.array([[1, -2, 3], [-1, 2, 1]])
    assert np.array_equal(
        np.heaviside(X, 1),
        unit_step(X)
        ) is True


import numpy as np
import matplotlib.pyplot as plt

class Perceptron:
    def __init__(self):
        np.random.seed(1)
        self.weights = self.__random_init(2)
        self.bias = self.__random_init(1)

    @staticmethod
    def __random_init(size):
        return 2 * np.random.rand(size) - 1

    @staticmethod
    def __transfer(x):
        return 1 / (1 + np.exp(-x))

    @staticmethod
    def __prediction(x):
        return int(round(x))

    def __activation(self, x):
        return self.__prediction(self.__transfer(np.dot(self.weights, x) + self.bias))

    @staticmethod
    def __plot_loss(loss_plot, mse):
        loss_plot.clear()
        loss_plot.set_title('Train Loss')
        loss_plot.set_xlabel('Epoch')
        loss_plot.set_ylabel('MSE')

        loss_plot.plot(mse)
        plt.pause(.0001)

    def __plot_rule(self, rule_plot, training):
        rule_plot.clear()
        rule_plot.set_title('Decision Rule')

        space = np.arange(np.min(training)[0]-.5, np.max(training)[0]+1)
        x_grid, y_grid = np.meshgrid(space, space)
        z_grid = self.__transfer(x_grid * self.weights[0] + y_grid * self.weights[1] + self.bias)
        rule_plot.contourf(x_grid, y_grid, z_grid, levels=[0, 0.5, 1], alpha=.5)

        for observation, expectation in training:
            prediction = self.__activation(observation)
            c = 'green' if prediction == expectation[0] else 'red'
            plt.plot(observation[0], observation[1], marker='v', markersize=10, color=c)
            rule_plot.annotate('{0}$\mapsto${1}'.format(observation, prediction), xy=np.add(observation, -.1))

    def fit(self, samples, epochs=100, info=True):
        if info:
            plt.ion()
            loss_plot = plt.subplot(121)
            rule_plot = plt.subplot(122)

        mse = []
        for epoch in range(epochs):
            square_losses = []
            for sample in np.random.permutation(samples):
                observation, expectation = sample
                prediction = self.__transfer(np.dot(self.weights, observation) + self.bias)
                loss = expectation - prediction
                square_losses.append(loss**2)
                self.weights += loss * observation
                self.bias += loss

            if info:
                mse.append(np.average(square_losses))
                self.__plot_loss(loss_plot, mse)
                self.__plot_rule(rule_plot, samples)
                print('Epoch:\t{0}\tMSE:\t{1:.13f}'.format(epoch, mse[-1]))

if __name__ == '__main__':
    data = [([0, 0], [0]),
            ([0, 1], [0]),
            ([1, 1], [1]),
            ([1, 0], [0])]

    p = Perceptron()
    p.fit(data)


import numpy
from math import *

# On met dans ce fichier la fonction modifiée pour résoudre un polynome de degré 2
def SecondDegres(a,b,c):
	# Classiquement le polynome est ax²+bx+c

	# On calcule le discriminant
	Delta = b**2 - 4*a*c

	if (Delta >= 0):
		x1 = (-b - sqrt(Delta))/(2*a)
		x2 = (-b + sqrt(Delta))/(2*a)

		# On renvoie le couple
		return [x1, x2]
	else:
		# On ne prend pas de nombres complexes
		# On renvoie simplement une liste vide

		return []

def SupSecondDegres(a,b, c, alpha, beta):
	# Dans cette fonction on se donne ax²+bx+c définie sur [alpha,beta] et on cherche en quel point le sup |f| est atteint
	# Elle renvoie une liste [x,P(x)] où x est le point où le sup est atteint

	# On déclare une variable intermédiaire
	gamma = -(b/2*a)

	# On distingue les cas
	if (gamma > alpha and gamma < beta):
		# Cas gamma € ]alpha,beta[
		if (a < 0):
			# Le maximum est forcément atteint en gamma

			P = a*(gamma**2) + b*gamma + c

			# On renvoie la valeur max et gamma
			return [P, gamma]

		if (a > 0):
			# Ce cas est plus complexe
			P_alpha = abs(a*(alpha**2) + b*alpha + c)
			P_beta = abs(a*(beta**2) + b*beta + c)
			P_gamma = abs(a*(gamma**2) + b*gamma + c)

			if (P_alpha > P_beta and P_alpha > P_gamma):
				# P_alpha est le plus grand
				return [P_alpha, alpha]

			if (P_beta > P_alpha and P_beta > P_gamma):
				# P_beta est le plus grand
				return [P_beta, beta]

			if (P_gamma > P_beta and P_gamma > P_alpha):
				# P_gamma est le plus grand
				return [P_gamma, gamma]

	else:
		# Cas gamma non € ]alpha,beta[
		# On a juste le choix entre alpha et beta
		P_alpha = abs(a*(alpha**2) + b*alpha + c)
		P_beta = abs(a*(beta**2) + b*beta + c)

		if (P_alpha > P_beta):
			return [P_alpha, alpha]

		else:
			return [P_beta, beta]


import numpy as np
from tqdm import tqdm

def kMeans(X, K, maxIters = 10):

    centroids = X[np.random.choice(np.arange(len(X)), K), :]
    for i in tqdm(range(maxIters)):
        # Cluster Assignment step
        C = np.array([np.argmax([np.dot(x_i, y_k)/(np.linalg.norm(x_i)*np.linalg.norm(y_k)) for y_k in centroids]) for x_i in X])
        # Move centroids step
        centroids = [X[C == k].mean(axis = 0) for k in range(K)]
    return np.array(centroids) , C


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

def sign(x):
	if x >= 0:
		return 1
	else:
		return -1

def logistic(x):
	return 1 / (1 + math.exp(-x))

def err01(x, y):
	if sign(x) == y:
		return 0
	else:
		return 1

def err1(x, y):
	return max(0, 1 - y * x)

def err2(x, y):
	return pow(max(0, 1 - y * x), 2)

def err3(x, y):
	return max(0, -y * x)

def err4(x, y):
	return logistic(-y * x)

def err5(x, y):
	return math.exp(-y * x)

x_range = np.arange(-2, 2, 0.0001)
y_log = []
err_01 = []
err_1 = []
err_2 = []
err_3 = []
err_4 = []
err_5 = []
y = 1

for i in range(len(x_range)):
	y_log.append(logistic(x_range[i]))
	err_01.append(err01(x_range[i], y))
	err_1.append(err1(x_range[i], y))
	err_2.append(err2(x_range[i], y))
	err_3.append(err3(x_range[i], y))
	err_4.append(err4(x_range[i], y))
	err_5.append(err5(x_range[i], y))

plt.figure(figsize = (20, 7))
plt.subplot(321)
plt.plot(x_range, y_log, label = r'$\frac{1}{1 + \mathrm{exp(-w^Tx)}}$', color = 'red' )
plt.plot(x_range, err_01, label = r'$err0/1$' )
plt.legend()

plt.subplot(322)
plt.plot(x_range, err_1, label = r'$(max(0, 1-y\mathrm{\mathbf{w^Tx}}))^2$', color = 'blue' ) # max(0, 1 − ywT x)
plt.plot(x_range, err_01, label = r'$[[sign(\mathrm{\mathbf{w^Tx}} )\neq y]]$' )
plt.legend()

plt.subplot(323)
plt.plot(x_range, err_2, label = r'$(max(0, 1-y\mathrm{\mathbf{w^Tx}}))^2$', color = 'black' ) #  pow(max(0, 1 − ywT x), 2)
plt.plot(x_range, err_01, label = r'$[[sign(\mathrm{\mathbf{w^Tx}} )\neq y]]$' )
plt.legend()

plt.subplot(324)
plt.plot(x_range, err_3, label = r'$max(0, -y\mathrm{\mathbf{w^Tx}})$', color = 'yellow' ) # max(0, −ywT x)
plt.plot(x_range, err_01, label = r'$[[sign(\mathrm{\mathbf{w^Tx}} )\neq y]]$' )
plt.legend()

plt.subplot(325)
plt.plot(x_range, err_4, label = r'$\theta(-y\mathrm{\mathbf{w^Tx}})$', color = 'green' ) # θ(−ywT x)
plt.plot(x_range, err_01, label = r'$[[sign(\mathrm{\mathbf{w^Tx}} )\neq y]]$' )
plt.legend()

plt.subplot(326)
plt.plot(x_range, err_5, label = r'$exp(-y\mathrm{\mathbf{w^Tx}})$', color = '#AE0000' ) # exp(−ywT x)
plt.plot(x_range, err_01, label = r'$[[sign(\mathrm{\mathbf{w^Tx}} )\neq y]]$' )
plt.legend()

plt.savefig('hw3_2.png', dpi = 100)
plt.show()


import numpy as np
from scipy.special import jv, jn_zeros, jnp_zeros

from .mode_basis import ModeBasis
from ..aperture import circular_aperture
from ..field import Field

def disk_harmonic(n, m, D=1, bc='dirichlet', grid=None):
	'''Create a disk harmonic.

	Parameters
	----------
	n : int
		Radial order
	m : int
		Azimuthal order
	D : scalar
		The diameter of the pupil.
	bc : string
		The boundary conditions to use. This can be either 'dirichlet', or
		'neumann' for a Dirichlet or Neumann boundary condition respectively.
	grid : Grid
		The grid on which to evaluate the function.

	Returns
	-------
	Field
		The disk harmonic function evaluated on `grid`.

	Raises
	------
	ValueError
		If the boundary condition is not recognized.
	'''
	polar_grid = grid.as_('polar')
	r = 2 * polar_grid.r / D
	theta = polar_grid.theta

	m_negative = m < 0
	m = abs(m)

	if bc == 'dirichlet':
		lambda_mn = jn_zeros(m, n)[-1]
		norm = 1
	elif bc == 'neumann':
		lambda_mn = jnp_zeros(m, n)[-1]
		norm = 1
	else:
		raise ValueError('Boundary condition not recognized.')

	if m_negative:
		z = norm * jv(m, lambda_mn * r) * np.sin(m * theta)
	else:
		z = norm * jv(m, lambda_mn * r) * np.cos(m * theta)

	# Do manual normalization for now...
	mask = circular_aperture(D)(grid) > 0.5
	norm = np.sqrt(np.sum(z[mask]**2))

	return Field(z * mask / norm, grid)

def disk_harmonic_energy(n, m, bc='dirichlet'):
	'''Get the energy of a disk harmonic function.

	This allows for functions to sort a disk harmonic mode basis on energy.

	Parameters
	----------
	n : int
		Radial order
	m : int
		Azimuthal order
	bc : string
		The boundary conditions to use. This can be either 'dirichlet', or
		'neumann' for a Dirichlet or Neumann boundary condition respectively.

	Returns
	-------
	scalar
		The energy corresponding to the mode.

	Raises
	------
	ValueError
		If the boundary condition is not recognized.
	'''
	m = abs(m)

	if bc == 'dirichlet':
		lambda_mn = jn_zeros(m, n)[-1]
	elif bc == 'neumann':
		lambda_mn = jnp_zeros(m, n)[-1]
	else:
		raise ValueError('Boundary condition not recognized.')

	return lambda_mn**2

def get_disk_harmonic_orders_sorted(num_modes, bc='dirichlet'):
	'''Return the orders for the first `num_modes` modes.

	Parameters
	----------
	num_modes : int
		The number of modes to return.
	bc : string
		The boundary conditions to use. This can be either 'dirichlet', or
		'neumann' for a Dirichlet or Neumann boundary condition respectively.

	Returns
	-------
	list of tuples
		A list of orders (n, m).
	'''
	orders = [(1,0)]
	energies = [disk_harmonic_energy(1, 0, bc)]

	results = []
	while len(results) < num_modes:
		k = np.argmin(energies)
		order = orders[k]

		if order[1] != 0:
			results.append((order[0], -order[1]))
		results.append(order)

		del orders[k]
		del energies[k]

		new_order = (order[0], order[1] + 1)
		if new_order not in results and new_order not in orders:
			orders.append(new_order)
			energies.append(disk_harmonic_energy(new_order[0], new_order[1], bc))
		new_order = (order[0] + 1, order[1])
		if new_order not in results and new_order not in orders:
			orders.append(new_order)
			energies.append(disk_harmonic_energy(new_order[0], new_order[1], bc))

	return results[:num_modes]

def make_disk_harmonic_basis(grid, num_modes, D=1, bc='dirichlet'):
	'''Create a disk harmonic mode basis.

	Parameters
	----------
	grid : Grid
		The grid on which to evaluate the disk harmonic modes.
	num_modes : int
		The number of modes to create.
	D : scalar
		The diameter of the disk.
	bc : string
		The boundary conditions to use. This can be either 'dirichlet', or
		'neumann' for a Dirichlet or Neumann boundary condition respectively.

	Returns
	-------
	ModeBasis
		The evaluated disk harmonic modes.
	'''
	orders = get_disk_harmonic_orders_sorted(num_modes, bc)

	modes = [disk_harmonic(order[0], order[1], D, bc, grid) for order in orders]
	return ModeBasis(modes, grid)


"""
Lorenz 96 model
From https://en.wikipedia.org/wiki/Lorenz_96_model
"""
import numpy as np
from scipy.integrate import odeint

def lorenz96_rhs(x, t, F):

    N = len(x)

    # compute state derivatives
    d = np.zeros(N)
    # first the 3 edge cases: i=1,2,N
    d[0] = (x[1] - x[N - 2]) * x[N - 1] - x[0]
    d[1] = (x[2] - x[N - 1]) * x[0] - x[1]
    d[N - 1] = (x[0] - x[N - 3]) * x[N - 2] - x[N - 1]
    # then the general case
    for i in range(2, N - 1):
        d[i] = (x[i + 1] - x[i - 2]) * x[i - 1] - x[i]
    # add the forcing term
    d = d + F

    # return the state derivatives
    return d

def run(n_init=20):
    # these are our constants
    N = 36  # number of variables
    F = 8  # forcing
    t = np.arange(0.0, 40.0, 0.01)
    out = []
    for n in range(n_init):
        x0 = F * np.ones(N)  # initial state (equilibrium)
        x0 = x0 + np.random.randn(N)*.01
        x = odeint(lorenz96_rhs, x0, t, args=(F, ))
        out.append(x)

    return t, np.stack(out)


# This module plots user-specified trig functions

# Import all the definitions from the numpy and plotting libraries
import numpy as np
import matplotlib.pyplot as plt

# Define the plotting function
def makeplot(funcname):

    # Define the x array
    x = np.arange(0, 2*np.pi, 0.01)

    # Check if the user entered the sin, cos, or tan function
    if funcname=='sin':
        plt.plot(x, np.sin(x))
    elif funcname=='cos':
        plt.plot(x, np.cos(x))
    elif funcname=='tan':
        plt.plot(x, np.tan(x))
    else:
        print("Unrecognized function "+str(funcname))

# Define a new plotting function
def makeplot_2(funcname, wavelength=[2*np.pi]):

    # Define the x array
    x=np.arange(0, 2*np.pi, 0.01)

    # Loop over wavelengths
    for w in wavelength:

        # Check if the user entered the sin, cos, or tan function
        if funcname=='sin':
            plt.plot(x, np.sin(x*2*np.pi/w))
        elif funcname=='cos':
            plt.plot(x, np.cos(x*2*np.pi/w))
        elif funcname=='tan':
            plt.plot(x, np.tan(x*2*np.pi/w))
        else:
            print("Unrecognized function "+str(f))
            return

# Define the plotting function that handles exceptions
def makeplot_3(funcname, wavelength=[2*np.pi]):

    # Define the x array
    x=np.arange(0, 2*np.pi, 0.01)

    # Try to loop over wavelengths to make sure it's possible. If not,
    # turn wavelengths into a list.
    try:
        for w in wavelength:
            pass
    except TypeError:
        wavelength=[wavelength]

    # Loop over wavelengths
    for w in wavelength:

        # Check if the user entered the sin, cos, or tan function
        if funcname=='sin':
            plt.plot(x, np.sin(x*2*np.pi/w))
        elif funcname=='cos':
            plt.plot(x, np.cos(x*2*np.pi/w))
        elif funcname=='tan':
            plt.plot(x, np.tan(x*2*np.pi/w))
        else:
            print("Unrecognized function "+str(f))
            return


# Reconstruct SVD
from numpy import array
from numpy import diag
from scipy.linalg import svd

# define a matrix
A = array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(A)
# Singular-value decomposition
U, s, VT = svd(A)
# create n x n Sigma matrix
Sigma = diag(s)
# reconstruct matrix
B = U.dot(Sigma.dot(VT))
print(B)


import numpy as np
from math import floor, ceil
from .grids import divergent

def circle(r, size=None, centered=True, dtype=np.bool_):
    '''
    Makes a circle with specified dtype. If bool or int, can be used as a mask.

    Parameters
    ----------
    r : numeric
        The radius of the circle.
    size : tuple, optional
        The size of the output array that contains the circle. Defaults to
        (round(2*r+1), round(2*r+1)).
    centered : boolean, optional
        If true, the circle will be centered in the middle of the array
        at pixel (size[0]//2, size[1]//2). If false, the circle will be centered
        at the origin pixel (0,0). Defaults to True.
    dtype : object, optional
        A valid numpy dtype. Defaults to boolean.

    Returns
    -------
    circle : ndarray
        A circle that obeys the equation :math:`x^2 + y^2 < r^2`
    '''

    if size is None:
        size = (round(2*r+1), round(2*r+1))

    X, Y = divergent(size, centered)

    return (X**2 + Y**2 <= r**2).astype(dtype)

def donut(r_outer, r_inner, size=None, centered=True, dtype=np.bool_):
    '''
    Makes a 2d donut with specified dtype. If bool or int, can be used as a mask.

    Parameters
    ----------
    r_outer : numeric
        The radius of the outer border.
    r_inner : numeric
        The radius of the inner border.
    size : tuple, optional
        The size of the output array that contains the donut. Defaults to
        (round(2*r_outer+1), round(2*r_outer+1)).
    centered : boolean, optional
        If true, the donut will be centered in the middle of the array
        at pixel (size[0]//2, size[1]//2). If false, the donut will be centered
        at the origin pixel (0,0). Defaults to True.
    dtype : object, optional
        A valid numpy dtype. Defaults to boolean.

    Returns
    -------
    donut : ndarray
        A donut that obeys the equation :math:`r_inner^2 < x^2 + y^2 < r_outer^2`
    '''

    if size is None:
        size = (round(2*r_outer+1), round(2*r_outer+1))

    X, Y = divergent(size, centered)

    D = X**2 + Y**2

    return np.logical_and(D <= r_outer**2, D>=r_inner**2).astype(dtype)

def line(a, size, width=None, r=None, centered=True, dtype=np.bool_):
    X, Y = divergent(size, centered)

    if width:
        line = np.logical_and(np.sin(a)*X + np.cos(a)*Y < width, np.sin(a)*X + np.cos(a)*Y > -width)
    else:
        line = (np.sin(a)*X + np.cos(a)*Y) == 0

    if r:
        line = np.logical_and(X**2+Y**2 <= r, line)

    return line.astype(dtype)

def line_gen(n, size, width=None, r=None, start=0, centered=True, dtype=np.bool_):
    return (line(a, size=size, width=width, r=r) for a in np.linspace(start, np.pi-np.pi/n+start, n))

def wheel(n_quad, size, width=None, r=None, start=0, centered=True, dtype=np.bool_):
    '''
    Makes a 2d wheel with specified dtype. If bool or int, can be used as a mask.

    Parameters
    ----------
    n_quad : int
        The number of spokes per quadrant (graph quadrant).
    size : tuple, optional
        The size of the output array that contains the wheel.
    width : int
        The width of a spoke.
    r : numeric, optional
        The maximum length of a spoke. Optional.
    start : float, optional
        Offset of the first spoke from 0 in radians.
    centered : boolean, optional
        If true, the wheel will be centered in the middle of the array
        at pixel (size[0]//2, size[1]//2). If false, the wheel will be centered
        at the origin pixel (0,0).
    dtype : object, optional
        A valid numpy dtype.

    Returns
    -------
    wheel : ndarray
        A wheel that is composed of lines (called spokes) that are evenly rotated
        around the center pixel.
    '''

    wheel = np.zeros(size)

    for a in np.linspace(start, np.pi-np.pi/(2*n_quad)+start, 2*n_quad):
        mask = line(a, size=size, width=width, start=start)
        wheel = np.logical_or(wheel, mask)

    if r:
        wheel = np.logical_and(X**2+Y**2 <= r, wheel)

    return wheel.astype(dtype)


import numpy as np
from scipy.integrate import quad
import matplotlib.pyplot as plt
plt.figure(figsize=(32.0, 6.0))

def f(x):
    return 1 - np.sqrt(1 - x ** 2)

SAMPLE_SIZE = 1000
Ef = quad(lambda x: f(x), 0, 1)[0]
Varf = quad(lambda x: (f(x) - Ef) ** 2, 0, 1)[0]

rand_x = np.random.rand(SAMPLE_SIZE)
rand_y = f(rand_x)
plot_x = np.linspace(start=0, stop=1.0, num=101, endpoint=True)
for i in range(5):
    plt.subplot(1, 5, i+1)
    plt.xlim(0, 1)
    plt.ylim(0, 1)
    plt.xlabel("$x$")
    plt.ylabel("$y$")
    plt.plot(plot_x, f(plot_x))
    plt.bar(x=0, height=rand_y[i], width=1.0, align="edge", color=(1.0, 0.0, 0.0, 0.5))
plt.savefig("pi_crude.png")

pi_empirical = 4 * (1.0 - np.sum(rand_y)/SAMPLE_SIZE)
print(f"Estimate: {pi_empirical:.6f}")
print(f"Empirical uncertainty: {4 * np.sqrt(np.var(rand_y) / SAMPLE_SIZE) / pi_empirical * 100:.4f}%")
print(f"Expected uncertainty: {4 * np.sqrt(Varf / SAMPLE_SIZE) / np.pi * 100:.4f}%")


import sympy as sp

sp.init_printing()
"""
problem:
2*x + 3*y = 1
1*x + 2*y = 1

answer:
x = -1
y =  1
"""
sp.var('x, y')
eq1=sp.Eq(2*x+3*y, 1)
eq2=sp.Eq(1*x+2*y, 1)
print(sp.solve ([eq1, eq2], [x, y]) )
#print(x,y)


""" Orbital Mechanics for Engineering Students Problem 1.3
Question:
Given
    A = 8*i + 9*j + 12*k
    B = 9*i + 6*j + k
    C = 3*i + 5*j + 10*k
Calculate the projection of C, cAB, on the plane of A and B.
Written by: J.X.J. Bannwarth
"""
from numpy import array, dot, cross, sqrt
from numpy.linalg import norm

# Title
print("Orbital Mechanics for Engineering Students Problem 1.3")

# Vectors
A = array([8., 9., 12.])
B = array([9., 6., 1.])
C = array([3., 5., 10.])

# Unit normal to AB plane
uN = cross(A, B) / norm(cross(A, B))

# Projection of C on uN
cN = dot(C, uN)

# Projection of C on AB plane
cAB = sqrt(norm(C)**2 - cN**2)
print(f"c_AB = {cAB:.2f}")


# Michal Lyskawinski
# Date: 11/28/2016
# Black's Model
# Assume that the forward bond price volatility is 7%. Price a two
# year European call option with strike 0.8 on a seven-year pure
# discount bond.

from math import exp, log, sqrt
from scipy.stats import norm

# Parameters for option
OM = 2  # Maturity of the option in years
Or = 0.04  # Term structure of interest rate
K = 0.8  # Strike

# Parameters for the bond
Br = 0.04
BM = 7  # Maturity pure discount bond in years
FBPV = 0.07  # Forward bond price volatility

def PDBprice(r,M):
    P = exp(-r*M)
    return P

Bpdb = PDBprice(Br, BM)
Opdb = PDBprice(Or, OM)

Pf = Bpdb/Opdb

d1 = (1/(FBPV*sqrt(OM)))*((log(Pf/K))+((FBPV**2)/2)*OM)
d2 = d1 - FBPV*sqrt(OM)

C = Opdb*(Pf*norm.cdf(d1) - K*norm.cdf(d2))

print(C)