import numpy as np
import control

# g = 9.8
# L = 1.5
# m = 1.0 # mass of bob (kg)
# M = 5.0  # mass of cart (kg)
# d1 = 1.0
# d2 = 0.5

    #   pendulum_mass: 1.0 (m)
    #   cart_mass: 5.0  (M)
    #   pendulum_length: 2.0
    #   damping_coefficient: 20.0
    #   gravity: -9.8
    #   max_cart_force: 1000.0
    #   noise_level: 0.0

g = 9.8
L = 1.5
m = 1.0
M = 5.0
d1 = 1.0
d2 = 0.5

# Pendulum up (linearized eq)
# Eigen val of A : array([[ 1.        , -0.70710678, -0.07641631,  0.09212131] )
_q = (m+M) * g / (M*L)
A = np.array([\
            [0,1,0,0], \
            [0,-d1, -g*m/M,0],\
            [0,0,0,1.],\
            [0,d1/L,_q,-d2] ] )

B = np.expand_dims( np.array( [0, 1.0/M, 0., -1/(M*L)] ), 1 )

# Pendulum Down - Verified correct.
# Eigen Values of this: array([ 0.00+0.j        , -1.00+0.j        , -0.25+2.78881695j,       -0.25-2.78881695j])
# A = np.array([\
#             [0,1,0,0], \
#             [0,-d1, -g*m/(2*m+M),0],\
#             [0,0,0,1],\
#             [0,0,-(M+m)*g/(M*L),-d2] ] )

#B = np.array( [] )

print ('A\n', A)
print ('B\n', B)

# Controllability
print ('---Controllability\n')
print ('rank of ctrb(A,b) \n' , np.linalg.matrix_rank( control.ctrb( A, B ) ))
print ('Eigenvalues of A \n', np.linalg.eig( A ))

# Pole Placement
K = control.place( A, B, [-1, -2, -4, -5] )
print ('---Pole Placement\nK=\n', K)

# Verification of Eigen values of A-BK
print ('---Verification of Eigen values of A-BK')
print ('Eigenvalues of A-BK \ n', np.linalg.eig( A-np.matmul(B,K) ))


from scipy.integrate import odeint
from numpy import arange
import matplotlib.pyplot as plt

def SIRS(state,t):

  # Initialization of States
  S = state[0]
  I = state[1]
  R = state[2]

  # Appropriate Constants
  beta = 0.25 # Rate of infection; needs to be divided by N in the system of ODEs
  gamma = 0.2 # Proportion leaving infected to become resistant
  rho = 0.1 # Proportion leaving resistant to become susceptible.
  N = S + I + R
  # compute state derivatives
  dS = (rho*R) - ((beta/N)*S*I)
  dI = ((beta/N)*S*I) - (gamma*I)
  dR = (gamma*I) - (rho*R)

  # return the state derivatives
  return [dS, dI, dR]

state0 = [33, 33, 33]
t = arange(0.0, 100, 0.01)

state = odeint(SIRS, state0, t)

# Plots

susceptible = state[:, 0]
infected = state[:, 1]
resistant = state[:, 2]

fig = plt.figure(figsize=(15,5))
fig.subplots_adjust(wspace = 0.5, hspace = 0.3)
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)

ax1.plot(susceptible, 'b-', label = "Susceptible")
ax1.plot(infected, 'r-', label = "Infected")
ax1.plot(resistant, 'g-', label = "Resistant")
ax1.set_title("Sample Dynamics of SIRS Model in Time")
ax1.set_xlabel("Time")
ax1.grid()
ax1.legend(loc = 'best', fontsize = 'small')

ax2.plot(susceptible, infected, color = "purple", label = 'S-I Phase')
ax2.plot(susceptible, resistant, color = "cyan", label = 'S-R Phase')
ax2.plot(infected, resistant, color = "yellow", label = 'I-R Phase')
ax2.set_title("SIRS Sample Phase Space")
ax2.legend(loc = 'best', fontsize = 'small')
ax2.grid()

extent = ax1.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
fig.savefig('timedynamics5.png', bbox_inches=extent.expanded(1.3, 1.3))
extent = ax2.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
fig.savefig('phase5.png', bbox_inches=extent.expanded(1.2, 1.2))

plt.show()


# %% [markdown]
"""
# Maximum Mean Discrepancy

This example demonstrates the maximum mean discrepancy using data drawn from two
different distributions. Additionally, we demonstrate the empirical witness function,
which displays the difference between the two distributions.

To run the example, use the following command:

```shell
    python examples/kernel/maximum_mean_discrepancy.py
```

"""

# %%
import numpy as np
from gym_socks.kernel.probability import maximum_mean_discrepancy
from gym_socks.kernel.probability import witness_function

from sklearn.metrics.pairwise import rbf_kernel
from functools import partial

# %% [markdown]
# ## Generate the Sample
#
# Define the kernel function and generate the data.
#
# We generate two samples, one from a Gaussian distribution and another from a Laplacian
# distribution to mimic the example from literature. Higher sample sizes will lead to a
# more accurate result.

# %%
sigma = 0.25
kernel_fn = partial(rbf_kernel, gamma=1 / (2 * (sigma ** 2)))

m = 5000  # sample size for P
n = 5000  # sample size for Q

X = np.random.standard_normal(size=(m, 1))
Y = np.random.laplace(size=(n, 1))

# %% [markdown]
# ## Compute the MMD
#
# We then compute the maximum mean discrepancy using both the unbiased and biased
# statistics.

# %%
maximum_mean_discrepancy(X, Y, kernel_fn=kernel_fn, biased=True, squared=False)

# %%
maximum_mean_discrepancy(X, Y, kernel_fn=kernel_fn, biased=False, squared=False)

# %% [markdown]
# ## Plot the Witness Function
#
# The witness function is used to view the difference between the two distributions.
#
# We plot the witness function, along with the true PDF of both the Gaussian and
# Laplacian distributions to illustrate the difference between the two samples.
# Intuitively, the witness function should have values closer to zero where the two
# distributions are similar, and have larger values (further from zero) where the
# distributions are dissimilar.
#
# This depends on the kernel used, the kernel parameters (the bandwidth in the case of
# the RBF kernel), and the density of sample information (which is highest close to the
# mean, i.e. the witness function will be more accurate in areas where the sample
# density is high).

# %%
import matplotlib
import matplotlib.pyplot as plt

from scipy import stats

t = np.linspace(-5, 5, 1000).reshape(-1, 1)
z = witness_function(X, Y, t, kernel_fn=kernel_fn)

pdf_gaussian = stats.norm.pdf(t, 0, 1)
pdf_laplacian = stats.laplace.pdf(t, 0, 1)

fig = plt.figure()
ax = plt.axes()
plt.grid()

plt.plot(t, z, label="Witness Function")
plt.plot(t, pdf_gaussian, label="Gaussian PDF")
plt.plot(t, pdf_laplacian, label="Laplacian PDF")

plt.legend()
plt.show()

# %%
fig = plt.figure()
ax = plt.axes()
plt.grid()

plt.plot(t, z, label="Witness Function")
plt.plot(t, pdf_gaussian - pdf_laplacian, label="Actual Difference")

plt.legend()
plt.show()


import numpy
from matplotlib import pyplot

def rk4(f, x_end, y0, N):
    x, dx = numpy.linspace(0, x_end, N+1, retstep=True)
    y = numpy.zeros((len(y0),N+1))
    y[:,0] = y0
    for n in range(N):
        k1 = dx * f(x[n]         , y[:,n]         )
        k2 = dx * f(x[n] + dx / 2, y[:,n] + k1 / 2)
        k3 = dx * f(x[n] + dx / 2, y[:,n] + k2 / 2)
        k4 = dx * f(x[n] + dx    , y[:,n] + k3    )
        y[:,n+1] = y[:,n] + (k1 + 2 * (k2 + k3) + k4) / 6
    return x, dx, y

A_am5 = numpy.array([ [1.0, 1, 1, 1, 1],
                      [4.0, 3, 2, 1, 0],
                      [12, 6, 2, 0, 0],
                      [24, 6, 0, 0, 0],
                      [24, 0, 0, 0, 0]])
rhs_am5 = numpy.array([1.0, 1/2, -1/6, 1/4, -19/30])
b_am5 = numpy.linalg.solve(A_am5, rhs_am5)

A_ab5 = numpy.array([ [1.0, 1, 1, 1, 1],
                      [4.0, 3, 2, 1, 0],
                      [12, 6, 2, 0, 0],
                      [24, 6, 0, 0, 0],
                      [24, 0, 0, 0, 0]])
rhs_ab5 = numpy.array([1.0, -1/2, 5/6, -9/4, 251/30])
b_ab5 = numpy.linalg.solve(A_ab5, rhs_ab5)

def am5(f, x_end, y0, N):
    x, dx = numpy.linspace(0, x_end, N+1, retstep=True)
    y = numpy.zeros((len(y0),N+1))
    fn = numpy.zeros((len(y0),N+1))
    y[:,0] = y0
    x_rk4, dx_rk4, y_rk4 = rk4(f, 4*dx, y0, 4)
    y[:,:5] = y_rk4[:,:5]
    for n in range(5):
        fn[:,n] = f(x[n], y[:,n])
    for n in range(4,N):
        fn[:,n] = f(x[n], y[:,n])
        yp = y[:,n] + dx * (b_ab5[4] * fn[:,n] +
                            b_ab5[3] * fn[:,n-1] +
                            b_ab5[2] * fn[:,n-2] +
                            b_ab5[1] * fn[:,n-3] +
                            b_ab5[0] * fn[:,n-4])
        fp = f(x[n+1], yp)
        y[:,n+1] = y[:,n] + dx * (b_am5[4] * fp +
                                  b_am5[3] * fn[:,n] +
                                  b_am5[2] * fn[:,n-1] +
                                  b_am5[1] * fn[:,n-2] +
                                  b_am5[0] * fn[:,n-3])
    return x, dx, y

if __name__=="__main__":

    def f_sin(x, y):
        return -numpy.sin(x)
    print("RK4")
    x, dx, y = rk4(f_sin, 0.5, [1], 10)
    print("dx=", dx, "y(0.5)=", y[0,-1])
    x, dx, y = rk4(f_sin, 0.5, [1], 100)
    print("dx=", dx, "y(0.5)=", y[0,-1])
    Npoints = 5*2**numpy.arange(1,7)
    dx_all = 0.5/Npoints
    errors = numpy.zeros_like(dx_all)
    for i, N in enumerate(Npoints):
        x, dx, y = rk4(f_sin, 0.5, [1], N)
        errors[i] = abs(y[0,-1] - numpy.cos(0.5))
        dx_all[i] = dx
    pyplot.figure(figsize=(12,6))
    pyplot.loglog(dx_all, errors, 'kx')
    pyplot.loglog(dx_all, errors[0]*(dx_all/dx_all[0])**4, 'b-',
                  label=r"$\propto \Delta x^4$")
    pyplot.legend(loc='upper left')
    pyplot.xlabel(r"$\Delta x$")
    pyplot.ylabel("Error")
    pyplot.show()

    print("Adams-Moulton 5")
    x, dx, y = am5(f_sin, 0.5, [1], 10)
    print("dx=", dx, "y(0.5)=", y[0,-1])
    x, dx, y = am5(f_sin, 0.5, [1], 100)
    print("dx=", dx, "y(0.5)=", y[0,-1])
    Npoints = 5*2**numpy.arange(1,7)
    dx_all = 0.5/Npoints
    errors = numpy.zeros_like(dx_all)
    for i, N in enumerate(Npoints):
        x, dx, y = am5(f_sin, 0.5, [1], N)
        errors[i] = abs(y[0,-1] - numpy.cos(0.5))
        dx_all[i] = dx
    pyplot.figure(figsize=(12,6))
    pyplot.loglog(dx_all, errors, 'kx')
    pyplot.loglog(dx_all, errors[0]*(dx_all/dx_all[0])**5, 'b-',
                  label=r"$\propto \Delta x^5$")
    pyplot.legend(loc='upper left')
    pyplot.xlabel(r"$\Delta x$")
    pyplot.ylabel("Error")
    pyplot.show()


# generar una normal de altura y peso
import numpy as np

height = np.round(np.random.normal(1.75, 0.20, 5000), 2)
weight = np.round(np.random.normal(60.32, 15, 5000), 2)
np_city = np.column_stack((height, weight))

print(np_city)

# Print mean height (first column)
avg = round(np.mean(np_city[:,0]),2)
print("Average: " + str(avg))

# Print median height.
med = np.median(np_city[:,0])
print("Median: " + str(med))

# Print out the standard deviation on height.
stddev = round(np.std(np_city[:,0]),2)
print("Standard Deviation: " + str(stddev))

# Print out correlation between first and second column.
corr = np.corrcoef(np_city[:,0],np_city[:,1])
print("Correlation: " + str(corr))


import pandas as pd
import scipy.stats
from scipy import stats
from scipy.stats import f_oneway

# Input parameters: sample (pd df), population mean (float), significance level (optional float)
# Return values: p-value, t-value, confidence interval (lower), confidence interval (upper), mean of sample, reject/accept (1 = accept, 0 = reject)
def t_test_1_samp(x, pop_mean, sig_lvl=0.05):

    out = 0

    if out:
        print("One Sample t-test")

    samp_mean = float(x.mean())
    samp_sd = float(x.std())
    n = x.shape[0]

    t = float((samp_mean - pop_mean) / (samp_sd / pow(n, 0.5)))
    p = scipy.stats.t.sf(abs(t), df=n - 1) * 2
    con_1, con_2 = scipy.stats.t.interval(
        alpha=1 - sig_lvl, df=n - 1, loc=samp_mean, scale=scipy.stats.sem(x)
    )

    con_1 = float(con_1)
    con_2 = float(con_2)

    if out:
        print("t = " + str(t))
        print("df = " + str(n - 1))
        print("p-value = " + str(p))

    accept = 1
    if p > sig_lvl:
        if out:
            print("Alternative hypothesis: true mean is not equal to " + str(pop_mean))
        accept = 0
    else:
        if out:
            print("Null hypothesis: true mean is equal to " + str(pop_mean))

    if out:
        print(
            str(100 * (1 - sig_lvl))
            + "% confidence interval: "
            + str(con_1)
            + " "
            + str(con_2)
        )
        print("Mean of x: " + str(samp_mean))

    result = {
        "p_value": p,
        "t_value": t,
        "con_low": con_1,
        "con_up": con_2,
        "sample_mean_1": samp_mean,
        "accept": accept,
    }

    return result

# Input parameters: sample 1 (pd df), sample 2 (pd df), significance level (optional float)
# Return values: p-value, t-value, confidence interval (lower), confidence interval (upper), mean of sample 1, mean of sample 2, reject/accept (1 = accept, 0 = reject)
def t_test_welch(x, y, sig_lvl=0.05):

    out = 0

    if out:
        print("Welch Two sample t-test (unequal variance)")

    mu_1 = float(x.mean())
    mu_2 = float(y.mean())
    s1 = x.std()
    s2 = y.std()
    n1 = x.shape[0]
    n2 = y.shape[0]

    t, p = stats.ttest_ind(x, y, equal_var=False)
    t = float(t)
    p = float(p)

    con_1 = float(
        (mu_1 - mu_2)
        - (
            scipy.stats.t.ppf((1 - sig_lvl / 2), n1 + n2 - 2)
            * pow(((((n1 - 1) * s1 * s1) + ((n2 - 1) * s2 * s2)) / (n1 + n2 - 2)), 0.5)
            * pow((1 / n1 + 1 / n2), 0.5)
        )
    )
    con_2 = float(
        (mu_1 - mu_2)
        + (
            scipy.stats.t.ppf((1 - sig_lvl / 2), n1 + n2 - 2)
            * pow(((((n1 - 1) * s1 * s1) + ((n2 - 1) * s2 * s2)) / (n1 + n2 - 2)), 0.5)
            * pow((1 / n1 + 1 / n2), 0.5)
        )
    )

    if out:
        print("t = " + str(t))
        print("df = " + str(n1 + n2 - 2))
        print("p-value = " + str(p))

    accept = 1
    if p > sig_lvl:
        if out:
            print("Alternative hypothesis: true difference in means is not equal to 0")
        accept = 0
    else:
        if out:
            print("Null hypothesis: true difference in means is equal to 0")

    if out:
        print(
            str(100 * (1 - sig_lvl))
            + "% confidence interval: "
            + str(con_1)
            + " "
            + str(con_2)
        )
        print("Mean of x and mean of y (respectively): " + str(mu_1) + ", " + str(mu_2))
        print()

    result = {
        "p_value": p,
        "t_value": t,
        "con_low": con_1,
        "con_up": con_2,
        "sample_mean_1": mu_1,
        "sample_mean_2": mu_2,
        "accept": accept,
    }
    return result

# Input parameters: sample 1 (pd df), sample 2 (pd df), significance level (optional float)
# Return values: p-value, t-value, confidence interval (lower), confidence interval (upper), mean of sample 1, mean of sample 2, reject/accept (1 = accept, 0 = reject)
def t_test_2_samp_equal_var(x, y, sig_lvl=0.05):

    out = 0

    if out:
        print("Two sample t-test (equal variance)")

    mu_1 = float(x.mean())
    mu_2 = float(y.mean())
    s1 = x.std()
    s2 = y.std()
    n1 = x.shape[0]
    n2 = y.shape[0]

    t = float((mu_1 - mu_2) / (pow((s1 * s1 / n1) + (s2 * s2 / n2), 0.5)))

    p = scipy.stats.t.sf(abs(t), df=n1 + n2 - 2) * 2
    con_1 = float(
        (mu_1 - mu_2)
        - (
            scipy.stats.t.ppf((1 - sig_lvl / 2), n1 + n2 - 2)
            * pow(((((n1 - 1) * s1 * s1) + ((n2 - 1) * s2 * s2)) / (n1 + n2 - 2)), 0.5)
            * pow((1 / n1 + 1 / n2), 0.5)
        )
    )
    con_2 = float(
        (mu_1 - mu_2)
        + (
            scipy.stats.t.ppf((1 - sig_lvl / 2), n1 + n2 - 2)
            * pow(((((n1 - 1) * s1 * s1) + ((n2 - 1) * s2 * s2)) / (n1 + n2 - 2)), 0.5)
            * pow((1 / n1 + 1 / n2), 0.5)
        )
    )

    if out:
        print("t = " + str(t))
        print("df = " + str(n1 + n2 - 2))
        print("p-value = " + str(p))

    accept = 1
    if p > sig_lvl:
        if out:
            print("Alternative hypothesis: true difference in means is not equal to 0")
        accept = 0
    else:
        if out:
            print("Null hypothesis: true difference in means is equal to 0")

    if out:
        print(
            str(100 * (1 - sig_lvl))
            + "% confidence interval: "
            + str(con_1)
            + " "
            + str(con_2)
        )
        print("Mean of x and mean of y (respectively): " + str(mu_1) + ", " + str(mu_2))
        print()

    result = {
        "p_value": p,
        "t_value": t,
        "con_low": con_1,
        "con_up": con_2,
        "sample_mean_1": mu_1,
        "sample_mean_2": mu_2,
        "accept": accept,
    }
    return result

# Input parameters: sample (pd df), population mean (float), significance level (optional float)
# Return values: p-value, z-value, confidence interval (lower), confidence interval (upper), mean of sample, reject/accept (1 = accept, 0 = reject)
def z_test_1_samp(x, pop_mean, sig_lvl=0.05):

    out = 0

    if out:
        print("1 sample z-test (two-tailed)")

    samp_mu = float(x.mean())
    pop_std = float(x.std())
    n = float(x.shape[0])

    z = float((samp_mu - pop_mean) / (pop_std / pow(n, 0.5)))
    p = scipy.stats.norm.sf(abs(z)) * 2

    if out:
        print("z: " + str(z))
        print("p-value: " + str(p))

    accept = 1
    if p > sig_lvl:
        if out:
            print(
                "Alternative hypothesis: the sample mean and population means are NOT equal"
            )
        accept = 0
    else:
        if out:
            print("Null hypothesis: the sample mean and population means are equal")

    con_1 = float(
        samp_mu - scipy.stats.norm.ppf(1 - sig_lvl / 2) * pop_std / pow(n, 0.5)
    )
    con_2 = float(
        samp_mu + scipy.stats.norm.ppf(1 - sig_lvl / 2) * pop_std / pow(n, 0.5)
    )

    if out:
        print(
            str(100 * (1 - sig_lvl))
            + "% confidence interval: "
            + str(con_1)
            + " "
            + str(con_2)
        )
        print("Mean of x: " + str(samp_mu))
        print()

    result = {
        "p_value": p,
        "z_value": z,
        "con_low": con_1,
        "con_up": con_2,
        "sample_mean_1": samp_mu,
        "accept": accept,
    }
    return result

# Input parameters: sample 1 (pd df), sample 2 (pd df), significance level (optional float)
# Return values: p-value, z-value, confidence interval (lower), confidence interval (upper), mean of sample 1, mean of sample 2, reject/accept (1 = accept, 0 = reject)
def z_test_2_samp(x, y, sig_lvl=0.05):

    out = 0

    if out:
        print("2 sample z-test (two tailed)")

    mu_1 = float(x.mean())
    mu_2 = float(y.mean())
    std_1 = float(x.std())
    std_2 = float(y.std())
    n1 = x.shape[0]
    n2 = y.shape[0]

    z = (mu_1 - mu_2) / pow((std_1 ** 2 / n1 + std_2 ** 2 / n2), 0.5)
    p = scipy.stats.norm.sf(abs(z)) * 2

    if out:
        print("z: " + str(z))
        print("p-value: " + str(p))

    accept = 1
    if p > sig_lvl:
        if out:
            print("Alternative hypothesis: the population means are NOT equal")
        accept = 0
    else:
        if out:
            print("Null hypothesis: the population means are equal")

    con_1 = float(
        (mu_1 - mu_2)
        - (
            scipy.stats.norm.ppf((1 - sig_lvl / 2))
            * pow(
                (
                    (((n1 - 1) * std_1 * std_1) + ((n2 - 1) * std_2 * std_2))
                    / (n1 + n2 - 2)
                ),
                0.5,
            )
            * pow((1 / n1 + 1 / n2), 0.5)
        )
    )
    con_2 = float(
        (mu_1 - mu_2)
        + (
            scipy.stats.norm.ppf((1 - sig_lvl / 2))
            * pow(
                (
                    (((n1 - 1) * std_1 * std_1) + ((n2 - 1) * std_2 * std_2))
                    / (n1 + n2 - 2)
                ),
                0.5,
            )
            * pow((1 / n1 + 1 / n2), 0.5)
        )
    )

    if out:
        print(
            str(100 * (1 - sig_lvl))
            + "% confidence interval: "
            + str(con_1)
            + " "
            + str(con_2)
        )
        print("Mean of x and mean of y (respectively): " + str(mu_1) + ", " + str(mu_2))
        print()

    result = {
        "p_value": p,
        "z_value": z,
        "con_low": con_1,
        "con_up": con_2,
        "sample_mean_1": mu_1,
        "sample_mean_2": mu_2,
        "accept": accept,
    }
    return result

# Input parameters: pd df of group categoricals, pd df of corresponding values, significance level (optional)
# Return values: p-value, f-value, variance between, var within, degrees of freedom between, df within, df total, Sum of Squares between, ss within, ss total, accept (1 = accept, 0 = reject)
def one_way_anova(dictionary, sig_lvl=0.05):

    out = 0

    if out:
        print("One way ANOVA")

    cat_val = ""
    num_val = ""

    if "cat_NaN_found" in dictionary:
        cat_val = dictionary.pop("cat_NaN_found")
    if 'num_NaN_found' in dictionary:
        num_val = dictionary.pop("num_NaN_found")
    sep_values = [list(value) for key, value in dictionary.items()]
    f, p = f_oneway(*sep_values)

    if out:
        print(f, p)

    unique_groups = pd.DataFrame(list(dictionary.keys()))
    k = unique_groups.shape[0]
    n = sum([len(value) for key, value in dictionary.items()])
    df_between = k - 1
    df_within = n - k
    df_total = n - 1

    grand_mean = sum([item for sublist in sep_values for item in sublist]) / n
    total = 0
    for i in range(len(sep_values)):
        group_mean = 0
        for j in range(len(sep_values[i])):
            group_mean = group_mean + sep_values[i][j]
        group_mean = group_mean / len(sep_values[i])
        total = total + (grand_mean - group_mean) ** 2 * len(sep_values[i])
    total2 = 0
    for i in range(len(sep_values)):
        gm = 0
        for j in range(len(sep_values[i])):
            gm = gm + sep_values[i][j]
        gm = gm / len(sep_values[i])
        for j in range(len(sep_values[i])):
            total2 = total2 + (sep_values[i][j] - gm) ** 2

    ss_between = float(total)
    ss_within = float(total2)
    ss_total = float(total + total2)
    var_between = float(total / df_between)
    var_within = float(total2 / df_within)

    row_headers = ["Sum of Squares", "d.f.", "Variance", "F", "p"]
    col_headers = ["Between Groups", "Within Groups", "Total"]
    data = [
        [
            str("%.2f" % ss_between),
            str("%.0f" % df_between),
            str("%.2f" % var_between),
            str("%.6f" % f),
            str("%.6f" % p),
        ],
        [
            str("%.2f" % ss_within),
            str("%.0f" % df_within),
            str("%.2f" % var_within),
            "--",
            "--",
        ],
        [str("%.2f" % ss_total), str("%.0f" % df_total), "--", "--", "--"],
    ]

    if out:
        print(pd.DataFrame(data, col_headers, row_headers))

    accept = 1
    if p > sig_lvl:
        if out:
            print("Alternative hypothesis: true difference in means is not equal to 0")
        accept = 0
    else:
        if out:
            print("Null hypothesis: true difference in means is equal to 0")

    if out:
        print()

    result = {
        "p_value": p,
        "f_value": f,
        "var_between": var_between,
        "var_within": var_within,
        "df_between": df_between,
        "df_within": df_within,
        "df_total": df_total,
        "ss_between": ss_between,
        "ss_within": ss_within,
        "ss_total": ss_total,
        "accept": accept,
    }
    dictionary["cat_NaN_found"] = cat_val
    dictionary["num_NaN_found"] = num_val
    return result

if __name__ == "__main__":

    ### Testing ###
    x = pd.DataFrame([1, 40, 60, 110])
    y = pd.DataFrame([5, 6, 7, 8])
    groups = pd.DataFrame(["A", "A", "A", "A", "B", "B", "B", "B", "C", "C", "C", "C"])
    values = pd.DataFrame([1, 2, 3, 4, 4, 6, 5, 9, 12, 12, 1, 11])
    dictio = {
        "A": [1.0, 2.0, 3.0, 4.0],
        "B": [4.0, 6.0, 5.0, 9.0],
        "C": [12.0, 12.0, 1.0, 11.0],
        "cat_NaN_found": False,
        "num_NaN_found": False,
    }

    # T tests
    t_test_1_samp(x, 3)
    t_test_2_samp_equal_var(x, y)
    t_test_welch(x, y)

    # Z tests
    z_test_1_samp(x, 50)
    z_test_2_samp(x, y)

    # ANOVA
    print(one_way_anova(dictio))


import os, sys
sys.path.insert(0, os.path.join(os.pardir, 'src-vib'))
from vib_undamped import solver, u_exact, visualize
import numpy as np

def convergence_rates(m, solver_function, num_periods=8):
    """
    Return m-1 empirical estimates of the convergence rate
    based on m simulations, where the time step is halved
    for each simulation.
    solver_function(I, w, dt, T) solves each problem, where T
    is based on simulation for num_periods periods.
    """
    from math import pi
    w = 0.35; I = 0.3       # just chosen values
    P = 2*pi/w              # period
    dt = P/30               # 30 time step per period 2*pi/w
    T = P*num_periods
    energy_const = 0.5*I**2*w**2    # initial energy when V = 0

    dt_values = []
    E_u_values = []         # error in u
    E_energy_values = []    # error in energy
    for i in range(m):
        u, t = solver_function(I, w, dt, T)
        u_e = u_exact(t, I, w)
        E_u = np.sqrt(dt*np.sum((u_e-u)**2))
        E_u_values.append(E_u)
        energy = 0.5*((u[2:] - u[:-2])/(2*dt))**2 + \
                                    0.5*w**2*u[1:-1]**2
        E_energy = energy - energy_const
        E_energy_norm = np.abs(E_energy).max()
        E_energy_values.append(E_energy_norm)
        dt_values.append(dt)
        dt = dt/2

    r_u = [np.log(E_u_values[i-1]/E_u_values[i])/
         np.log(dt_values[i-1]/dt_values[i])
         for i in range(1, m, 1)]
    r_E = [np.log(E_energy_values[i-1]/E_energy_values[i])/
         np.log(dt_values[i-1]/dt_values[i])
         for i in range(1, m, 1)]
    return r_u, r_E

def test_convergence_rates():
    r_u, r_E = convergence_rates(
        m=5,
        solver_function=solver,
        num_periods=8)
    # Accept rate to 1 decimal place
    tol = 0.1
    assert abs(r_u[-1] - 2.0) < tol
    assert abs(r_E[-1] - 2.0) < tol

if __name__ == '__main__':
    test_convergence_rates()


import numpy
import matplotlib.pyplot as pyplot
import os
import shutil

animation_dir = "animation"

"""notes on things tried
* increased L to 200.0, Nx to 2000 - movement of wavepacket was slower
* increased L to 1000.0, Nx to 10000 - movement of wavepacket stopped
"""

#periodic unit size
L = 100.0
print "L:  {}".format(L)

Nx = 1000
print "Nx:  {}".format(Nx)
dx = L / float(Nx)
print "dx:  {}".format(dx)
x = numpy.array(range(Nx)) * dx
print "x[:10]:\n{}".format(x[:10])

duration = 1599*2
Nt = duration/2
dt = duration / float(Nt)
t = numpy.array(range(Nt)) * dt

#spatial wavefunction is exp(ikx)*sqrt(1/L)
#k = 2*pi*n/L
#n is integer positive or negative
#https://en.wikipedia.org/wiki/Particle_in_a_one-dimensional_lattice

#energy E = hbar^2 * k^2 / (2m)
#https://en.wikipedia.org/wiki/Particle_in_a_box
#in atomic units:  E = k^2 / 2
#(use mass of an electron)
#https://en.wikipedia.org/wiki/Atomic_units

#time wavefunction is exp(-iEt/hbar)
#atomic units:  exp(-iEt)
#http://hyperphysics.phy-astr.gsu.edu/hbase/quantum/Scheq.html

def calculate_wavefunction(state_indexes, state_coefs, periodic_length, x):
    psi = numpy.zeros(x.shape)
    for (i, si) in enumerate(state_indexes):
        k = 2 * numpy.pi * float(si) / periodic_length
        phi = numpy.exp(1j*k*(x - periodic_length/2.0)) * numpy.sqrt(1.0 / periodic_length)

        sc = state_coefs[i]
        psi = psi + sc*phi

    return psi

def test_calculate_wavefunction():
    print "test_calculate_wavefunction"

    all_psi = []

    psi = calculate_wavefunction(numpy.array([1]), numpy.array([1]), L, x)
    all_psi.append(psi)
    print "psi[:10]:\n{}".format(psi[:10])
    test_integral = numpy.vdot(psi, psi.T) * dx
    print "test_integral:  {}".format(test_integral)
    pyplot.figure(101)
    pyplot.plot(x, numpy.real(psi))
    pyplot.plot(x, numpy.imag(psi))
    pyplot.title("test_calculate_wavefunction01")
    pyplot.savefig("test_calculate_wavefunction01.png")

    psi = calculate_wavefunction(numpy.array([2]), numpy.array([1]), L, x)
    all_psi.append(psi)
    print "psi[:10]:\n{}".format(psi[:10])
    test_integral = numpy.vdot(psi, psi.T) * dx
    print "test_integral:  {}".format(test_integral)
    pyplot.figure(102)
    pyplot.plot(x, numpy.real(psi))
    pyplot.plot(x, numpy.imag(psi))
    pyplot.title("test_calculate_wavefunction02")
    pyplot.savefig("test_calculate_wavefunction02.png")

    psi = calculate_wavefunction(numpy.array([1, 2]), numpy.array([0.70710678, 0.70710678]), L, x)
    all_psi.append(psi)
    print "psi[:10]:\n{}".format(psi[:10])
    test_integral = numpy.vdot(psi, psi.T) * dx
    print "test_integral:  {}".format(test_integral)
    pyplot.figure(103)
    pyplot.plot(x, numpy.real(psi))
    pyplot.plot(x, numpy.imag(psi))
    pyplot.title("test_calculate_wavefunction03")
    pyplot.savefig("test_calculate_wavefunction03.png")

    pyplot.figure(104)
    for psi in all_psi:
        pyplot.plot(x, numpy.real(psi))
    pyplot.title("test_calculate_wavefunction04")
    pyplot.savefig("test_calculate_wavefunction04.png")
    pyplot.figure(105)
    for psi in all_psi:
        pyplot.plot(x, numpy.imag(psi))
    pyplot.title("test_calculate_wavefunction05")
    pyplot.savefig("test_calculate_wavefunction05.png")

state_indexes = numpy.array(range(1,21))

state_coefs = numpy.exp(-numpy.power(state_indexes - 10, 2) / 2.0)
norm = numpy.sqrt(numpy.sum(numpy.power(state_coefs, 2)))
print "normalization for state_coefs - norm:  {}".format(norm)
state_coefs = state_coefs / norm
print "check normalization of state_coefs:  {}".format(numpy.sum(numpy.power(state_coefs, 2)))
print "state_coefs:\n{}".format(state_coefs)

initial_psi = calculate_wavefunction(state_indexes, state_coefs, L, x)
initial_prob_dens = numpy.conj(initial_psi) * initial_psi

state_wavenumbers = 2.0 * numpy.pi * state_indexes / L
state_energies = numpy.power(state_wavenumbers, 2.0) / 2.0

time_psi = []
time_prob_dens = []
for cur_t in t[:]:
    time_modifiers = numpy.exp(-1j * state_energies * cur_t)
    # print "time_modifiers:\n{}".format(time_modifiers)
    # print numpy.vdot(time_modifiers, time_modifiers.T)

    cur_state_coefs = state_coefs * time_modifiers

    psi = calculate_wavefunction(state_indexes, cur_state_coefs, L, x)
    time_psi.append(psi)

    prob_dens = numpy.conj(psi) * psi
    # print "cur_t:  {}  prob_dens normalization check:  {}".format(cur_t, numpy.sum(prob_dens) * dx)
    time_prob_dens.append(prob_dens)

fig_ind=1
pyplot.figure(fig_ind)
pyplot.plot(state_indexes, state_coefs, marker=".")
pyplot.xlabel("state_indexes")
pyplot.ylabel("state_coefs")
pyplot.savefig("state_coefs.png")

if False:
    test_calculate_wavefunction()

fig_ind = fig_ind+1
pyplot.figure(fig_ind)
pyplot.plot(x, numpy.real(initial_psi))
pyplot.plot(x, numpy.imag(initial_psi))
pyplot.xlabel("x")
pyplot.ylabel("initial_psi")
pyplot.savefig("initial_psi.png")
fig_ind = fig_ind+1
pyplot.figure(fig_ind)
pyplot.plot(x, numpy.real(initial_prob_dens))
pyplot.plot(x, numpy.imag(initial_prob_dens))
pyplot.xlabel("x")
pyplot.ylabel("initial_prob_dens")
pyplot.savefig("initial_prob_dens.png")

if os.path.exists("animation"):
    shutil.rmtree("animation")
os.mkdir("animation")

initial_file_ind = 150
fig_ind = fig_ind+1

if True:
    for (i, psi) in enumerate(time_psi):
        file_index = "%05d" % (i + initial_file_ind)
        cur_t = t[i]

        if False:
            pyplot.figure(fig_ind)
            pyplot.plot(x, numpy.real(psi))
            pyplot.plot(x, numpy.imag(psi))
            pyplot.xlabel("x")
            pyplot.ylabel("psi")
            pyplot.title("psi at i:  {}  time:  {}".format(i, cur_t))

            filename = os.path.join(animation_dir, "psi{}.png".format(file_index))
            pyplot.savefig(filename)
            pyplot.close(fig_ind)

            pyplot.figure(fig_ind)
            pyplot.plot(x, numpy.real(time_prob_dens[i]))
            pyplot.xlabel("x")
            pyplot.ylabel("prob_dens")
            pyplot.title("prob_dens at i:  {}  time:  {}".format(i, cur_t))

            filename = os.path.join(animation_dir, "prob_dens{}.png".format(file_index))
            pyplot.savefig(filename)
            pyplot.close(fig_ind)

        pyplot.figure(fig_ind)
        fig, ax1 = pyplot.subplots()
        pd_line = ax1.plot(x, numpy.real(time_prob_dens[i]), label="prob_dens")
        ax1.set_xlabel("x")
        ax1.set_ylabel("prob_dens")
        ax1.set_ylim(-0.001, 0.0375)

        pyplot.title("prob_dens and psi at index i:  {}  time:  {}".format(i, cur_t))
        ax2 = ax1.twinx()
        rp_line = ax2.plot(x, numpy.real(psi), "purple", label="real(psi)", lw=0.5)
        ip_line = ax2.plot(x, numpy.imag(psi), "orange", label="imag(psi)", lw=0.5)
        ax2.set_ylim(-0.21, 0.21)
        ax2.set_ylabel("wavefunction psi")

        h, l = ax1.get_legend_handles_labels()
        all_h = list(h)
        all_l = list(l)
        h, l = ax2.get_legend_handles_labels()
        all_h.extend(h)
        all_l.extend(l)
        pyplot.legend(handles = all_h)
        fig.tight_layout()

        filename = os.path.join(animation_dir, "combined{}.png".format(file_index))
        pyplot.savefig(filename)
        pyplot.close(fig_ind)

        if i%10 == 0:
            print "animation figures progress i:  {}".format(i)

for i in [0, len(time_psi)-1]:
    psi = time_psi[i]
    cur_t = t[i]
    tpd = numpy.real(time_prob_dens[i])
    max_ind = numpy.argmax(tpd)
    max_val = tpd[max_ind]
    half_max = max_val / 2.0
    left_half_max_x = numpy.interp(half_max, tpd[:max_ind], x[:max_ind])
    right_half_max_x = numpy.interp(half_max, tpd[-1:max_ind:-1], x[-1:max_ind:-1])

    pyplot.figure(fig_ind)
    fig, ax1 = pyplot.subplots()
    pd_line = ax1.plot(x, tpd, label="prob_dens")
    ax1.set_xlabel("x")
    ax1.set_ylabel("prob_dens")
    ax1.set_ylim(-0.001, 0.0375)
    ax1.plot([left_half_max_x, left_half_max_x], [half_max, max_val*1.05])
    ax1.plot([right_half_max_x, right_half_max_x], [half_max, max_val*1.05])

    pyplot.title("prob_dens at index i:  {}  time:  {}".format(i, cur_t))

    ax2 = ax1.twinx()
    rp_line = ax2.plot(x, numpy.real(psi), "purple", label="real(psi)", lw=0.25)
    ip_line = ax2.plot(x, numpy.imag(psi), "orange", label="imag(psi)", lw=0.25)
    ax2.set_ylim(-0.21, 0.21)
    ax2.set_ylabel("wavefunction psi")

    h, l = ax1.get_legend_handles_labels()
    all_h = list(h)
    all_l = list(l)
    h, l = ax2.get_legend_handles_labels()
    all_h.extend(h)
    all_l.extend(l)
    pyplot.legend(handles = all_h)
    pyplot.text(15, 0.175, "initial width:\n{}".format("%.2f"%(right_half_max_x-left_half_max_x)))
    fig.tight_layout()

    file_int = 0 if i == 0 else i+1+initial_file_ind
    file_index = "%05d" % file_int
    source_filename = "combined{}.png".format(file_index)
    pyplot.savefig(os.path.join(animation_dir, source_filename))
    pyplot.close(fig_ind)

    for j in xrange(1, initial_file_ind):
        file_index = "%05d" % (j + file_int)
        print file_index
        filename = os.path.join(animation_dir, "combined{}.png".format(file_index))
        os.symlink(source_filename, filename)


# coding: utf-8

# # Statistical parameters using probability density function
# ### Given probability density function, $p(x)$
#
# $ p = 2x/b^2$, $0 < x < b$
#
# ### The mean value of $x$ is estimated analytically:
# $\overline{x} = \int\limits_0^b x\, p(x)\, dx = \int\limits_0^b 2x^2/b^2 = \left. 2x^3/3b^2\right|_0^b =2b^3/3b^2 = 2b/3$
#
#
# ### the median
# median: $ \int\limits_0^m p(x)\,dx = 1/2 = \int\limits_0^m 2x/b^2\,dx = \left. x^2/b^2 \right|_0^m = m^2/b^2 = 1/2$, $m = b/\sqrt(2)$
#
# ### the second moment
# second moment: $x^{(2)} = \int\limits_0^b x^2\, p(x)\, dx = \int\limits_0^b 2x^3/b^2 = \left. x^4/2b^2\right|_0^b =b^4/2b^2 = b^2/2$
#
# ### the variance is the second moment less the squared mean value
# $var(x) = x^{(2)} - \overline{x}^2 = b^2/2 - 4b^2/9 = b^2/18$
#
#

# In[42]:

def p(x,b):
    return 2*x/(b**2)

# In[59]:

b = 2
x = linspace(0,b,200)
y = p(x,b)

# In[63]:

plot(x,y)
xlabel('$x$')
ylabel('$p(x)$')

# In[61]:

# approximate using the numerical integration
print trapz(y*x,x)
print 2.*b/3

# In[62]:

print trapz(y*x**2,x)
print b^2/18

# In[64]:

import sympy

# In[113]:

sympy.var('x,b,p,m')
p = 2*x/b**2
print p

# In[114]:

sympy.integrate(p*x,(x,0,b))

# In[115]:

sympy.integrate(p*x**2,(x,0,b))

# In[119]:

sympy.integrate(p,(x,0,m))

# In[124]:

sympy.solve(m**2/b**2 - 0.5,m)

# In[ ]:


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

import numpy as np
from scipy import sparse
from scipy.sparse import linalg
import matplotlib.pyplot as plt
np.set_printoptions(threshold=np.nan)
np.set_printoptions(precision=5)

#  Solves the steady-state heat equation in a square with conductivity
#  c(x,y) = 1 + x^2 + y^2:
#
#     -d/dx( (1+x^2+y^2) du/dx ) - d/dy( (1+x^2+y^2) du/dy ) = f(x),
#                                                       0 < x,y < 1
#     u(x,0) = u(x,1) = u(0,y) = u(1,y) = 0
#
#  Uses a centered finite difference method.

# return A and b to solve steady state heat equation
def Ab(n):
    #  Set up grid.
    #n = int(input(' Enter number of subintervals in each direction: '));
    h = 1/n
    N = (n-1)**2

    # Form block tridiagonal finite difference matrix A and right-hand side
    # vector b.
    A = sparse.csr_matrix((N,N));
    b = np.ones((N,1));         # Use right-hand side vector of all 1's.

    # Loop over grid points in y direction.
    for j in range (n-1):
        yj = (j+1)*h
        yjph = yj+h/2;  yjmh = yj-h/2

        # Loop over grid points in x direction.
        for i in range(n-1):
            xi = (i+1)*h
            xiph = xi+h/2;  ximh = xi-h/2
            aiphj = 1 + xiph**2 + yj**2
            aimhj = 1 + ximh**2 + yj**2
            aijph = 1 + xi**2 + yjph**2
            aijmh = 1 + xi**2 + yjmh**2
            k = (j)*(n-1) + i
            A[k,k] = aiphj+aimhj+aijph+aijmh
            if i > 0: A[k,k-1] = -aimhj
            if i < n-2: A[k,k+1] = -aiphj
            if j > 0: A[k,k-(n-1)] = -aijmh
            if j < n-2: A[k,k+(n-1)] = -aijph

    return (A/h**2,b)   # Remember to multiply A by (1/h^2).

#n = int(input(' Enter number of subintervals in each direction: '));
def direct_solve():
    n = 8
    A,b = Ab(n)

    # Solve linear system.
    u_comp = sparse.linalg.spsolve(A,b)

#<startJacobi>
def jacobi(A,b,tol,max_iter=20):
    n = np.shape(A)[1]
    x = sparse.csc_matrix((n,1))

    M = sparse.diags(A.diagonal(), format='csc')

    residual_norm=np.zeros(max_iter)
    iter_tol = -1
    for iter in range(max_iter):
        residual = b-A.dot(x)
        x += sparse.linalg.spsolve_triangular(M,residual)
        residual_norm[iter] = np.linalg.norm(residual)/np.linalg.norm(b)
        if residual_norm[iter] < tol:
            iter_tol = iter
            break

    return (x,residual_norm,iter_tol)
#<endJacobi>

#<startGS>
def gauss_seidel(A,b,tol,max_iter=20):
    n = np.shape(A)[1]
    x = sparse.csc_matrix((n,1))

    M = sparse.tril(A,0, format='csc')

    residual_norm=np.zeros(max_iter)
    iter_tol = -1
    for iter in range(max_iter):
        residual = b-A.dot(x)
        x += sparse.linalg.spsolve_triangular(M,residual)
        residual_norm[iter] = np.linalg.norm(residual)/np.linalg.norm(b)
        if residual_norm[iter] < tol:
            iter_tol = iter
            break

    return (x,residual_norm,iter_tol)
#<endGS>

#<startSOR>
def SOR(A,b,w,tol,max_iter=20,opt=False):
    n = np.shape(A)[1]
    x = sparse.csc_matrix((n,1))

    D = sparse.diags(A.diagonal(), format='csc')
    L = sparse.tril(A,-1, format='csc')
    M = D/w+L

    if opt:
        G = sparse.eye(n) - sparse.diags(1/A.diagonal(),format='csc').dot(A)
        p = np.linalg.norm(sparse.linalg.eigs(G,1,which='LM')[0])
        w = 2/(1+np.sqrt(1-p**2))
        print(w)
    residual_norm=np.zeros(max_iter)

    iter_tol = -1
    for iter in range(max_iter):
        residual = b-A.dot(x)
        x += sparse.linalg.spsolve_triangular(M,residual)
        residual_norm[iter] = np.linalg.norm(residual)/np.linalg.norm(b)
        if residual_norm[iter] < tol:
            iter_tol = iter
            break

    return (x,residual_norm,iter_tol)
#<endSOR>

def tests():
    n = 20
    A,b = Ab(n)

    max_iter = 175
    tol = 1e-15
    res_jacobi = jacobi(A,b,tol,max_iter)
    res_GS = gauss_seidel(A,b,tol,max_iter)
    res_SOR3 = SOR(A,b,1.3,tol,max_iter)
    res_SOR5 = SOR(A,b,1.5,tol,max_iter)
    res_SOR7 = SOR(A,b,1.7,tol,max_iter)
#    res_SOR_opt = SOR(A,b,1,tol,max_iter,opt=True)

    plt.yscale('log')
    plt.plot(range(len(res_jacobi[1])),res_jacobi[1])
    plt.plot(range(len(res_GS[1])),res_GS[1])
    plt.plot(range(len(res_SOR3[1])),res_SOR3[1])
    plt.plot(range(len(res_SOR5[1])),res_SOR5[1])
    plt.plot(range(len(res_SOR7[1])),res_SOR7[1])
#    plt.plot(range(len(res_SOR_opt[1])),res_SOR_opt[1])
    plt.savefig('img/1/iter_convergence_'+str(n)+'.pdf')

def CG_tests():
    n = 20
    A,b = Ab(n)
    residual_CG_ichol = []
    residual_CG = []

    def CG_callback(x):
        nonlocal residual_CG
        residual_CG = np.append(residual_CG,np.linalg.norm(b-A.dot(x))/np.linalg.norm(b))

    def CG_callback_ichol(x):
        nonlocal residual_CG_ichol
        residual_CG_ichol = np.append(residual_CG_ichol,np.linalg.norm(b-A.dot(x))/np.linalg.norm(b))

    max_iter = 300

    tol = 1e-15
    N = (n-1)**2

#<startCG>
    lu = sparse.linalg.spilu(A,drop_tol = 1e-3)
    M = lu.solve(np.identity(N))
#<endCG>

    sparse.linalg.cg(A,b,x0=np.zeros((n-1)**2),tol=tol,maxiter=max_iter,callback=CG_callback)
    sparse.linalg.cg(A,b,x0=np.zeros((n-1)**2),tol=tol,maxiter=max_iter,M=M,callback=CG_callback_ichol)

    plt.yscale('log')
    plt.plot(range(len(residual_CG)),residual_CG)
    plt.plot(range(len(residual_CG_ichol)),residual_CG_ichol)
    plt.savefig('img/1/cg_convergence_'+str(n)+'.pdf')

def iter_vs_h():
    iterj = []
    iter0 = []
    iter3 = []
    iter5 = []
    iter7 = []
    h = []
    tol = 1e-5
    max_iter = 2000

    for n in [3,4,5,7,10,14,20,30]:
        A,b = Ab(n)
        h = np.append(h,1/(n+1))
        iterj = np.append(iterj,jacobi(A,b,tol,max_iter=max_iter)[2])
        iter0 = np.append(iter0,SOR(A,b,1,tol,max_iter=max_iter)[2])
        iter3 = np.append(iter3,SOR(A,b,1.3,tol,max_iter=max_iter)[2])
        iter5 = np.append(iter5,SOR(A,b,1.5,tol,max_iter=max_iter)[2])
        iter7 = np.append(iter7,SOR(A,b,1.7,tol,max_iter=max_iter)[2])

    plt.yscale('log')
    plt.plot(h,iterj)
    plt.plot(h,iter0)
    plt.plot(h,iter3)
    plt.plot(h,iter5)
    plt.plot(h,iter7)
    plt.savefig('img/1/iter_vs_h.pdf')

def iter_vs_h_cg():
    global iter_cg_temp
    global iter_pcg_temp
    iter_cg_temp = 0
    iter_pcg_temp = 0

    def CG_callback(x):
        global iter_cg_temp
        iter_cg_temp += 1

    def PCG_callback(x):
        global iter_pcg_temp
        iter_pcg_temp += 1

    iter_cg = []
    iter_pcg = []

    h = []
    tol = 1e-16
    max_iter = 2000

    for n in [3,5,10,20,30]:
        iter_cg_temp = 0
        iter_pcg_temp = 0

        N = (n-1)**2

        A,b = Ab(n)
        h = np.append(h,1/(n+1))
        lu = sparse.linalg.spilu(A)
        Pr = sparse.csc_matrix((N, N))
        Pr[lu.perm_r, np.arange(N)] = 1
        Pc = sparse.csc_matrix((N, N))
        Pc[np.arange(N), lu.perm_c] = 1

        M =  Pc.dot((sparse.linalg.inv(lu.U).dot( sparse.linalg.inv(lu.L)) ).dot(Pr))

        sparse.linalg.cg(A,b,x0=np.zeros((n-1)**2),tol=tol,maxiter=max_iter,callback=CG_callback)
        sparse.linalg.cg(A,b,x0=np.zeros((n-1)**2),tol=tol,maxiter=max_iter,M=M,callback=PCG_callback)

        iter_cg = np.append(iter_cg,iter_cg_temp)
        iter_pcg = np.append(iter_pcg,iter_pcg_temp)

    plt.plot(h,iter_cg)
    plt.plot(h,iter_pcg)
    plt.savefig('img/1/iter_vs_h_cg.pdf')


#
#  file:  numpy_matmul.py
#
#  NumPy matrix multiplication examples
#
#  RTK, 12-Apr-2020
#  Last update:  12-Apr-2020
#
################################################################

import numpy as np

def dot(a,b):
    try:
        return np.dot(a,b)
    except:
        return "fails"

def matmul(a,b):
    try:
        return np.matmul(a,b)
    except:
        return "fails"

#  the different vectors and matrices
a1 = np.array([1,2,3])
ar = a1.reshape((1,3))
ac = a1.reshape((3,1))
b1 = np.array([1,2,3])
br = b1.reshape((1,3))
bc = b1.reshape((3,1))
A = np.array([[1,2,3],[4,5,6],[7,8,9]])
B = np.array([[9,8,7],[6,5,4],[3,2,1]])

print()
print("np.dot examples:")
print("dot(a1,b1):"); print(dot(a1,b1))
print("dot(a1,br):"); print(dot(a1,br))
print("dot(a1,bc):"); print(dot(a1,bc))
print("dot(ar,b1):"); print(dot(ar,b1))
print("dot(ar,br):"); print(dot(ar,br))
print("dot(ar,bc):"); print(dot(ar,bc))
print("dot(ac,b1):"); print(dot(ac,b1))
print("dot(ac,br):"); print(dot(ac,br))
print("dot(ac,bc):"); print(dot(ac,bc))
print("dot(A,a1):"); print(dot(A,a1))
print("dot(A,ar):"); print(dot(A,ar))
print("dot(A,ac):"); print(dot(A,ac))
print("dot(a1,A):"); print(dot(a1,A))
print("dot(ar,A):"); print(dot(ar,A))
print("dot(ac,A):"); print(dot(ac,A))
print("dot(A,B):"); print(dot(A,B))
print()

print()
print("np.matmul examples:")
print("matmul(a1,b1):"); print(matmul(a1,b1))
print("matmul(a1,br):"); print(matmul(a1,br))
print("matmul(a1,bc):"); print(matmul(a1,bc))
print("matmul(ar,b1):"); print(matmul(ar,b1))
print("matmul(ar,br):"); print(matmul(ar,br))
print("matmul(ar,bc):"); print(matmul(ar,bc))
print("matmul(ac,b1):"); print(matmul(ac,b1))
print("matmul(ac,br):"); print(matmul(ac,br))
print("matmul(ac,bc):"); print(matmul(ac,bc))
print("matmul(A,a1):"); print(matmul(A,a1))
print("matmul(A,ar):"); print(matmul(A,ar))
print("matmul(A,ac):"); print(matmul(A,ac))
print("matmul(a1,A):"); print(matmul(a1,A))
print("matmul(ar,A):"); print(matmul(ar,A))
print("matmul(ac,A):"); print(matmul(ac,A))
print("matmul(A,B):"); print(matmul(A,B))
print()


import numpy as np

### Functions for you to fill in ###

# pragma: coderesponse template

def polynomial_kernel(X, Y, c, p):
    """
        Compute the polynomial kernel between two matrices X and Y::
            K(x, y) = (<x, y> + c)^p
        for each pair of rows x in X and y in Y.

        Args:
            X - (n, d) NumPy array (n datapoints each with d features)
            Y - (m, d) NumPy array (m datapoints each with d features)
            c - a coefficient to trade off high-order and low-order terms (scalar)
            p - the degree of the polynomial kernel

        Returns:
            kernel_matrix - (n, m) Numpy array containing the kernel matrix
    """
    # YOUR CODE HERE
    # raise NotImplementedError
    kernel_matrix = (np.matmul(X, Y.T) + c) ** p

    return kernel_matrix
# pragma: coderesponse end

# pragma: coderesponse template

def rbf_kernel(X, Y, gamma):
    """
        Compute the Gaussian RBF kernel between two matrices X and Y::
            K(x, y) = exp(-gamma ||x-y||^2)
        for each pair of rows x in X and y in Y.

        Args:
            X - (n, d) NumPy array (n datapoints each with d features)
            Y - (m, d) NumPy array (m datapoints each with d features)
            gamma - the gamma parameter of gaussian function (scalar)

        Returns:
            kernel_matrix - (n, m) Numpy array containing the kernel matrix
    """

    # YOUR CODE HERE
    # raise NotImplementedError
    n_rows_Y, n_cols_Y = Y.shape
    Y_ = Y.reshape(n_rows_Y, 1, n_cols_Y)
    k = np.exp(-gamma * np.sum((X - Y_)**2, axis=2))
    return k.T
# pragma: coderesponse end


import numpy as np

def R2calc(Y, Yhat):
    """Function to determine the determination coefficient

    Parameters
    ------------
    Y: np.array
       Measured values
    Yhat: np.array
       Estimated values from the fit

    Returns
    ------------
    R2: float
        The coeficient of determination
    """
    ##Average of our measurements
    Ybar = np.mean(Y)

    #Sum Squared of residues
    SSres = np.sum((Y - Yhat)**2)
    #Total Sum Squared
    SStot = np.sum((Y - Ybar)**2)

    R2 = 1 - SSres / SStot

    return R2


# --------------
# Code starts here

import numpy as np

# Code starts here

# Adjacency matrix
adj_mat = np.array([[0,0,0,0,0,0,1/3,0],
                   [1/2,0,1/2,1/3,0,0,0,0],
                   [1/2,0,0,0,0,0,0,0],
                   [0,1,0,0,0,0,0,0],
                  [0,0,1/2,1/3,0,0,1/3,0],
                   [0,0,0,1/3,1/3,0,0,1/2],
                   [0,0,0,0,1/3,0,0,1/2],
                   [0,0,0,0,1/3,1,1/3,0]])

# Compute eigenvalues and eigencevectrs
eigenvalues, eigenvectors = np.linalg.eig(adj_mat)

# Eigen vector corresponding to 1
eigen_1 = abs(eigenvectors[:,0])/np.linalg.norm(eigenvectors[:,0],1)

# most important page
page = np.where(eigen_1 == eigen_1.max())[0][0]+1
print(page)

# Code ends here

# --------------
# Code starts here

# Initialize stationary vector I
init_I = [1,0,0,0,0,0,0,0]

# Perform iterations for power method
for i in range(10):
    init_I = np.dot(adj_mat,init_I)
power_page = np.argmax(init_I)+1
power_page

# Code ends here

# --------------
# Code starts here

# New Adjancency matrix
# New Adjancency matrix
new_adj_mat = np.array([[0,0,0,0,0,0,0,0],
                   [1/2,0,1/2,1/3,0,0,0,0],
                  [1/2,0,0,0,0,0,0,0],
                   [0,1,0,0,0,0,0,0],
                   [0,0,1/2,1/3,0,0,1/2,0],
                   [0,0,0,1/3,1/3,0,0,1/2],
                   [0,0,0,0,1/3,0,0,1/2],
                   [0,0,0,0,1/3,1,1/2,0]])

# Initialize stationary vector I
new_init_I = [1,0,0,0,0,0,0,0]

# Perform iterations for power method
for i in range(10):
    new_init_I = np.dot(new_adj_mat, new_init_I)
new_init_I

# Code ends here

# --------------
# Alpha value
alpha = 0.85

# Code starts here

# Modified adjancency matrix
n = len(new_adj_mat)
G = (alpha * new_adj_mat) + (((1 - alpha) * (1/n)) * np.ones(new_adj_mat.shape))

# Initialize stationary vector I
final_init_I = [1,0,0,0,0,0,0,0]

# Perform iterations for power method
for i in range(1000):
    final_init_I = np.dot(G,final_init_I)
    final_init_I /= np.linalg.norm(final_init_I,1)
final_init_I

# Code ends here


from typing import Tuple
import numpy as np

def particle_elastic_collision(
        ux1: float,
        uy1: float,
        ux2: float,
        uy2: float,
        m1: float,
        m2: float
    ) -> Tuple[float, float, float, float]:
    """2D elastic collision of two particles.

    The model assumes the particles have zero radius. The larger
    the particles are, the less accurate this model is.

    Args:
        ux1: x-velocity of particle 1
        uy1: y-velocity of particle 1
        ux2: x-velocity of particle 2
        uy2: y-velocity of particle 2
        m1: mass of particle 1
        m2: mass of particle 2

    Return:
        resulting velocities (vx1, vy1, vx2, vy2)
    """
    vx1 = (ux1 * (m1 - m2) / (m1 + m2)) + (ux2 * 2 * m2 / (m1 + m2))
    vx2 = (ux1 * 2 * m1 / (m1 + m2)) + (ux2 * (m2 - m1) / (m1 + m2))
    vy1 = (uy1 * (m1 - m2) / (m1 + m2)) + (uy2 * 2 * m2 / (m1 + m2))
    vy2 = (uy1 * 2 * m1 / (m1 + m2)) + (uy2 * (m2 - m1) / (m1 + m2))

    return (vx1, vy1, vx2, vy2)

def ball_elastic_collision(
        u1: np.array,
        u2: np.array,
        m1: float,
        m2: float,
        c1: np.array,
        c2: np.array,
        dissipation: float = 0.
    ) -> Tuple[np.array, np.array]:
    """2D elastic collision of two balls (particles with non-zero radius).

    The model assumes the balls have non-zero radius.
    The resulting velocities depend not only on the
    initial velocities and masses, but also on the position
    of the balls at the moment of collision.

    Args:
        u1: velocity vector of ball 1
        u2: velocity vector of ball 2
        m1: mass of ball 1
        m2: mass of ball 2
        c1: center position of ball 1
        c2: center position of ball 2

    Return:
        resulting velocities (v1, v2)
    """
    # Reference: https://scipython.com/blog/two-dimensional-collisions/
    mtot = m1 + m2
    d = np.linalg.norm(c1 - c2) ** 2
    if d < 1e-3:
        # For numerical stability, do not allow too little distance
        d = 1e-3
    v1 = u1 - 2 * m2 / mtot * np.dot(u1 - u2, c1 - c2) / d * (c1 - c2)
    v2 = u2 - 2 * m1 / mtot * np.dot(u2 - u1, c2 - c1) / d * (c2 - c1)

    v1 *= 1. - dissipation / 2.
    v2 *= 1. - dissipation / 2.

    return (v1, v2)


"""Bell state."""
import numpy as np

from toqito.states import basis

def bell(idx: int) -> np.ndarray:
    r"""
    Produce a Bell state [WikBell]_.

    Returns one of the following four Bell states depending on the value of :code:`idx`:

    .. math::
        \begin{equation}
            \begin{aligned}
                u_0 = \frac{1}{\sqrt{2}} \left( |00 \rangle + |11 \rangle \right), &
                \qquad &
                u_1 = \frac{1}{\sqrt{2}} \left( |00 \rangle - |11 \rangle \right), \\
                u_2 = \frac{1}{\sqrt{2}} \left( |01 \rangle + |10 \rangle \right), &
                \qquad &
                u_3 = \frac{1}{\sqrt{2}} \left( |01 \rangle - |10 \rangle \right).
            \end{aligned}
        \end{equation}

    Examples
    ==========

    When :code:`idx = 0`, this produces the following Bell state:

    .. math::
        u_0 = \frac{1}{\sqrt{2}} \left( |00 \rangle + |11 \rangle \right).

    Using :code:`toqito`, we can see that this yields the proper state.

    >>> from toqito.states import bell
    >>> import numpy as np
    >>> bell(0)
    [[0.70710678],
     [0.        ],
     [0.        ],
     [0.70710678]]

    References
    ==========
    .. [WikBell] Wikipedia: Bell state
        https://en.wikipedia.org/wiki/Bell_state

    :param idx: A parameter in [0, 1, 2, 3]
    :return: Bell state with index :code:`idx`.
    """
    e_0, e_1 = basis(2, 0), basis(2, 1)
    if idx == 0:
        return 1 / np.sqrt(2) * (np.kron(e_0, e_0) + np.kron(e_1, e_1))
    if idx == 1:
        return 1 / np.sqrt(2) * (np.kron(e_0, e_0) - np.kron(e_1, e_1))
    if idx == 2:
        return 1 / np.sqrt(2) * (np.kron(e_0, e_1) + np.kron(e_1, e_0))
    if idx == 3:
        return 1 / np.sqrt(2) * (np.kron(e_0, e_1) - np.kron(e_1, e_0))
    raise ValueError("Invalid integer value for Bell state.")


import numpy as np

# using alternating least squares method for collaborative filtering:
# http://www.quuxlabs.com/blog/2010/09/matrix-factorization-a-simple-tutorial-and-implementation-in-python/
def get_error(Q, X, Y, W):
    return np.sum((W * (Q - np.dot(X, Y)))**2)

def matrix_factorization(R, P, Q, K, steps=10000, alpha=0.0002, beta=0.02):
    Q = Q.T
    for step in range(steps):
        for i in range(len(R)):
            for j in range(len(R[i])):
                if R[i][j] > 0:
                    eij = R[i][j] - np.dot(P[i, :], Q[:, j])
                    for k in range(K):
                        P[i][k] = P[i][k] + alpha * (2 * eij * Q[k][j] - beta * P[i][k])
                        Q[k][j] = Q[k][j] + alpha * (2 * eij * P[i][k] - beta * Q[k][j])
        eR = np.dot(P, Q)
        e = 0
        for i in range(len(R)):
            for j in range(len(R[i])):
                if R[i][j] > 0:
                    e = e + pow(R[i][j] - np.dot(P[i, :], Q[:, j]), 2)
                    for k in range(K):
                        e = e + (beta/2) * (pow(P[i][k], 2) + pow(Q[k][j], 2))
        if e < 0.0001:
            break
    return P, Q.T

def initialiseVariables():
    R = np.array(
        [[0, 1, np.nan],
         [1, np.nan, 1],
         [np.nan, 1, 2]]
    )
    N = len(R)
    M = len(R[0])
    K = 1  # number of rows

    P = np.random.rand(N, K)
    Q = np.random.rand(M, K)
    return M, N, K, P, Q, R

def checkAgainst(_nR):
    desired_matrix = np.array(
        [[0, 1, np.nan],
         [1, np.nan, 1],
         [np.nan, 1, 2]]
    )
    for i in range(len(desired_matrix)):
        for j in range(len(desired_matrix[0])):
            # skip these numbers
            if i == 0 and j == 2 or i == 1 and j == 1 or i == 2 and j == 0:
                continue
            else:
                if round(_nR[i][j]) != desired_matrix[i][j]:
                    return False
    return True

if __name__ == '__main__':
    M, N, K, P, Q, R = initialiseVariables()

    nP, nQ = matrix_factorization(R, P, Q, K)
    nR = np.dot(nP, nQ.T)
    print(nR)
    print(nP)
    print(nQ)
    print(checkAgainst(nR))


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

from io_utilities import load_data
from visualizations import show_clusters_centroids

def distance(a,b):
    """
    Compute Euclidean Distance Between Two Points
    Input:
        a (list): an n-dimensional list or array
        b (list): an n-dimensional list or array
    Output:
        The Euclidean Distance between vectors a and b
    """

    # All you need to do here is calculate the Euclidean Distance between
    # points a and b and return it

    euc_dist = # You code here!

    return euc_dist

def get_clusters(points,centroids):
    """
    Returns a list of clusters given all the points in the dataset and
    the current centroids.
    Input:
        points (numpy array): a 2D (M,N) Array with the data to cluster.
        M = Instances, N = Variables.
        centroids (list of numpy arrays): A list with the k current centroids
    Output:
        clusters (list of lists of numpy arrays): A List of Clusters. Each cluster
        is also a list of numpy arrays.
    """
    clusters = [[] for f in centroids]

    for i, point in enumerate(points):
        point_to_centroids = []
        for j, centroid in enumerate(centroids):
            # Make sure you find the distance from each point to the
            # centroid and append it to point_to_centroids
        # Now find the index of the smallest value in point_to_centroids
        # and use it to add the point to the corresponding cluster

    return clusters

def update_centroids(clusters):
    """
    Given a list of clusters (as prepared by get_clusters()) get the new centroids
    Input:
        clusters (list of numpy arrays): A List of Clusters. Each cluster
        is a 2D Array, rows = instances, columns=variables
    Output:
        A (list of numpy arrays): The new centroids.
    """
    new_centroids = []

    for cluster in clusters:
        # Find the average for each row in the cluster.
        # TIP: use the power of numpy!

        centroid = # You Code here
        new_centroids.append(centroid)

    return new_centroids

def k_means(points, k, iterations=10):
    """
    K Means Unsupervised ML Algorithm Implementation with Forgy Initialization
    Input:
        points (numpy array): a 2D (M,N) Array with the data to cluster.
        M = Instances, N = variables.
        k (int): The number of clusters to find
    """
    idx = np.random.randint(len(points),size=k)

    centroids = points[idx,:]
    clusters = get_clusters(points,centroids)

    for i in range(iterations):

        # Use get_clusters() and update_centroids() for each iteration.

    return clusters,centroids

if __name__ == "__main__":
    data = load_data('./data/iris.data')
    k = 3

    X = np.array([f[:-1] for f in data])
    y = np.array([f[-1] for f in data])

    clusters,centroids = k_means(X,3)

    show_clusters_centroids(clusters, centroids, "Result", keep=True)


import math
import numpy as np

from logger import log

def point_distance(point1, point2):
    """

    @param point1:
    @param point2:
    @return:
    """
    x1, y1 = point1
    x2, y2 = point2

    return np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)

def mid_joint(i, joints):
    """
    given a list containing two joints, it calculates a new join between them
    @param i: set of two indexes
    @param joints: set of joints
    @return: returns the generated joint
    """
    if type(i) == list:
        if len(i) == 2:
            x1, y1 = joints[i[0]]
            x2, y2 = joints[i[1]]

            x = (x1 + x2) / 2
            y = (y1 + y2) / 2
            return (x, y)
        else:
            raise Exception("Mid joint for more than 2 points not implemented yet.")
    else:
        return joints[i]

def create_angle(p1, p2, p3, decimal=2):
    """
    auxiliary method that finds the value of the angle given three points in 2D space
    @param p1: first point
    @param p2: second point
    @param p3: third point or a reference axis ["axis_x", "axis_y"]
    @return: returns the angle in degrees
    """
    flag = 'axis' in p3

    # x2, y2 = p2
    #
    # if "axis_y" in p3:
    #     p3 = x2, 0
    # elif "axis_x" in p3:
    #     p3 = 0, y2

    x1, y1 = p1
    x2, y2 = p2

    if "axis_y" in p3:
        p3 = x2, y1
    elif "axis_x" in p3:
        p3 = x1, y2

    try:
        p12 = point_distance(p1, p2)
        p13 = point_distance(p1, p3)  # np.sqrt((x1 - x3) ** 2 + (y1 - y3) ** 2)
        p23 = point_distance(p3, p2)  # np.sqrt((x3 - x2) ** 2 + (y3 - y2) ** 2)

        a = np.arccos((p12 ** 2 + p23 ** 2 - p13 ** 2) / (2 * p12 * p23))

        if np.isnan(a):
            a_deg = None
        else:
            a_deg = math.degrees(a)  # *180/math.pi

    except:
        log.debug("Exception for angle occurred.")
        a_deg = None
    # finally:
    #     if flag:
    #         a_deg = np.abs(90 - a_deg) + 90

    return round(a_deg, decimal)


import math
import numpy as np

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

def g(x):
    return np.sin(x) / x

def trapezoid_formula(inte, func):
    """ Calculate the integral by trapezoid formula

    Args:
        inte: ndarray, the integrand interval
        func: function object, the integrand function

    Returns:
        double, the integral value by trapezoid formula
    """

    return (inte[1] - inte[0]) * np.sum(func(inte)) / 2

def simpson_formula(inte, func):
    """ Calculate the integral by Simpson formula

    Args:
        inte: ndarray, the integrand interval
        func: function object, the integrand function

    Returns:
        double, the integral value by Simpson formula
    """
    # get the nodes
    x_list = np.linspace(inte[0], inte[1], 3)
    # cofficient vector
    C = np.array([1, 4, 1])

    return (inte[1] - inte[0]) * np.sum(C.T.dot(func(x_list))) / sum(C)

if __name__ == '__main__':
    # integrand interval
    inte = np.array([1e-32, 1])
    # trapezoid formula
    print(f"The value of the first integral by trapezoid formula is {trapezoid_formula(inte, f)}")
    print(f"The value of the second integral by trapezoid formula is {trapezoid_formula(inte, g)}")
    # Simpson formula
    print(f"The value of the first integral by Simpson formula is {simpson_formula(inte, f)}")
    print(f"The value of the second integral by Simpson formula is {simpson_formula(inte, g)}")


# 二項分布

# 利用するライブラリ
import numpy as np
from scipy.stats import binom, multinomial # 二項分布, 多項分布
from scipy.special import gamma, loggamma # ガンマ関数, 対数ガンマ関数
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

#%%

### 確率の計算

# パラメータを指定
phi = 0.3

# 試行回数を指定
M = 10

# 確率変数の値を指定:(x <= M)
x = 3

# ベクトルに変換
x_v = np.array([M - x, x])
phi_v = np.array([1.0 - phi, phi])

# 定義式により確率を計算
C = gamma(M + 1) / gamma(M - x + 1) / gamma(x + 1)
prob = C * phi**x * (1 - phi)**(M - x)
print(prob)

# 対数をとった定義式により確率を計算
log_C = loggamma(M + 1) - loggamma(M - x + 1) - loggamma(x + 1)
log_prob = log_C + x * np.log(phi) + (M - x) * np.log(1 - phi)
pron = np.exp(log_prob)
print(prob, log_prob)

# 二項分布の関数により確率を計算
prob = binom.pmf(k=x, n=M, p=phi)
print(prob)

# 二項分布の対数をとった関数により確率を計算
log_prob = binom.logpmf(k=x, n=M, p=phi)
prob = np.exp(log_prob)
print(prob, log_prob)

# 多項分布の関数により確率を計算
prob = multinomial.pmf(x=x_v, n=M, p=phi_v)
print(prob)

# 多項分布の対数をとった関数により確率を計算
log_prob = multinomial.logpmf(x=x_v, n=M, p=phi_v)
prob = np.exp(log_prob)
print(prob, log_prob)

#%%

### 統計量の計算

# パラメータを指定
phi = 0.3

# 試行回数を指定
M = 10

# 平均を計算
E_x = M * phi
print(E_x)

# ベルヌーイ分布の関数により平均を計算
print(binom.mean(n=M, p=phi))

# 分散を計算
V_x = M * phi * (1.0 - phi)
print(V_x)

# ベルヌーイ分布の関数により分散を計算
print(binom.var(n=M, p=phi))

#%%

### グラフの作成

# 作図用のxの値を作成
x_vals = np.arange(M + 1)

# 分布を計算
probability = binom.pmf(k=x_vals, n=M, p=phi)

# 二項分布を作図
plt.figure(figsize=(12, 8)) # 図の設定
plt.bar(x=x_vals, height=probability, color='#00A968') # 棒グラフ
#plt.vlines(x=E_x, ymin=0.0, ymax=np.max(probability), color='orange', linestyle='--', label='$E[x]$') # 平均
#plt.vlines(x=E_x - V_x, ymin=0.0, ymax=np.max(probability), color='orange', linestyle=':', label='$E[x] - \sqrt{V[x]}$') # 平均 - 標準偏差
#plt.vlines(x=E_x + V_x, ymin=0.0, ymax=np.max(probability), color='orange', linestyle=':', label='$E[x] + \sqrt{V[x]}$') # 平均 + 標準偏差
plt.xlabel('x') # x軸ラベル
plt.ylabel('probability') # y軸ラベル
plt.suptitle('Binomial Distribution', fontsize=20) # 図タイトル
plt.title('$\phi=' + str(phi) + ', M=' + str(M) + '$', loc='left') # タイトル
plt.xticks(ticks=x_vals) # x軸目盛
#plt.legend() # 凡例
plt.grid() # グリッド線
plt.show() # 描画

#%%

### パラメータと分布の形状の関係

## phiを変更した場合

# 作図用のphiの値を作成
phi_vals = np.arange(start=0.0, stop=1.01, step=0.01)

# 図を初期化
fig = plt.figure(figsize=(12, 8))

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

    # i回目の値を取得
    phi = phi_vals[i]

    # 分布を計算
    probability = binom.pmf(k=x_vals, n=M, p=phi)

    # 二項分布を作図
    plt.bar(x=x_vals, height=probability, color='#00A968') # 棒グラフ
    plt.xlabel('x') # x軸ラベル
    plt.ylabel('probability') # y軸ラベル
    plt.suptitle('Binomial Distribution', fontsize=20) # 図タイトル
    plt.title('$\phi=' + str(np.round(phi, 2)) + ', M=' + str(M) + '$', loc='left') # タイトル
    plt.xticks(ticks=x_vals) # x軸目盛
    plt.grid() # グリッド線
    plt.ylim(-0.1, 1.1) # y軸の表示範囲

# gif画像を作成
anime_prob = FuncAnimation(fig, update, frames=len(phi_vals), interval=100)

# gif画像を保存
anime_prob.save('ProbabilityDistribution/Binomial_prob_phi.gif')

#%%

## Mを変更した場合

# パラメータを指定
phi = 0.3

# 試行回数の最大値を指定
M_max = 100

# 図を初期化
fig = plt.figure(figsize=(12, 8))

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

    # 作図用のxの値を作成
    x_vals = np.arange(M + 1)

    # 分布を計算
    probability = binom.pmf(k=x_vals, n=M, p=phi)

    # 二項分布を作図
    plt.bar(x=x_vals, height=probability, color='#00A968') # 棒グラフ
    plt.xlabel('x') # x軸ラベル
    plt.ylabel('probability') # y軸ラベル
    plt.suptitle('Binomial Distribution', fontsize=20) # 図タイトル
    plt.title('$\phi=' + str(np.round(phi, 2)) + ', M=' + str(M) + '$', loc='left') # タイトル
    #plt.xticks(ticks=x_vals) # x軸目盛
    plt.grid() # グリッド線
    plt.ylim(-0.1, 1.1) # y軸の表示範囲

# gif画像を作成
anime_prob = FuncAnimation(fig, update, frames=M_max, interval=100)

# gif画像を保存
anime_prob.save('ProbabilityDistribution/Binomial_prob_M.gif')

#%%

### 乱数の生成

## 乱数の可視化

# パラメータを指定
phi = 0.3

# 試行回数を指定
M = 10

# データ数を指定
N = 1000

# 二項分布に従う乱数を生成
x_n = np.random.binomial(n=M, p=phi, size=N)

# 乱数を集計
frequency = np.array([np.sum(x_n == m) for m in range(M + 1)])

#%%

# サンプルのヒストグラムを作成
plt.figure(figsize=(12, 8)) # 図の設定
plt.bar(x=x_vals, height=frequency, color='#00A968') # ヒストグラム
plt.xlabel('x') # x軸ラベル
plt.ylabel('frequency') # y軸ラベル
plt.suptitle('Binomial Distribution', fontsize=20) # 図タイトル
plt.title('$\phi=' + str(phi) + ', N=' + str(N) +
          '=(' + ', '.join([str(f) for f in frequency]) + ')$', loc='left') # タイトル
plt.xticks(ticks=x_vals) # x軸目盛
plt.grid() # グリッド線
plt.show() # 描画

# サンプルの構成比を作図
plt.figure(figsize=(12, 8)) # 図の設定
plt.bar(x=x_vals, height=probability, color='white', edgecolor='green', linestyle='--') # 分布
plt.bar(x=x_vals, height=frequency / N, color='#00A968', alpha=0.8) # 構成比
plt.xlabel('x') # x軸ラベル
plt.ylabel('proportion') # y軸ラベル
plt.suptitle('Binomial Distribution', fontsize=20) # 図タイトル
plt.title('$\phi=' + str(phi) + ', N=' + str(N) +
          '=(' + ', '.join([str(f) for f in frequency]) + ')$', loc='left') # タイトル
plt.xticks(ticks=x_vals) # x軸目盛
plt.grid() # グリッド線
plt.show() # 描画

#%%

## アニメーションによる可視化

# フレーム数を指定
N = 100

# 図を初期化
fig = plt.figure(figsize=(12, 8))

# 頻度の最大値を取得
y_max = np.max([np.sum(x_n[:N] == m) for m in range(M + 1)])

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

    # n個の乱数を集計
    frequency = np.array([np.sum(x_n[:(n+1)] == m) for m in range(M + 1)])

    # サンプルのヒストグラムを作成
    plt.bar(x=x_vals, height=frequency, color='#00A968', zorder=1) # ヒストグラム
    plt.scatter(x=x_n[n], y=0.0, color='orange', s=100, zorder=2) # サンプル
    plt.xlabel('x') # x軸ラベル
    plt.ylabel('frequency') # y軸ラベル
    plt.suptitle('Binomial Distribution', fontsize=20) # 図タイトル
    plt.title('$\phi=' + str(phi) + ', N=' + str(n) +
              '=(' + ', '.join([str(f) for f in frequency]) + ')$', loc='left') # タイトル
    plt.xticks(ticks=x_vals) # x軸目盛
    plt.grid() # グリッド線
    plt.ylim(-1.0, y_max + 1.0) # y軸の表示範囲

# gif画像を作成
anime_freq = FuncAnimation(fig, update, frames=N, interval=100)

# gif画像を保存
anime_freq.save('ProbabilityDistribution/Binomial_freq.gif')

#%%

# 図を初期化
fig = plt.figure(figsize=(9, 6))

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

    # n個の乱数を集計
    frequency = np.array([np.sum(x_n[:(n+1)] == m) for m in range(M + 1)])

    # サンプルの構成比を作成
    plt.bar(x=x_vals, height=probability, color='white', edgecolor='green', linestyle='--', zorder=1) # 分布
    plt.bar(x=x_vals, height=frequency / (n + 1), color='#00A968', alpha=0.8, zorder=2) # 構成比
    plt.scatter(x=x_n[n], y=0.0, color='orange', s=100, zorder=3) # サンプル
    plt.xlabel('x') # x軸ラベル
    plt.ylabel('proportion') # y軸ラベル
    plt.suptitle('Binomial Distribution', fontsize=20) # 図タイトル
    plt.title('$\phi=' + str(phi) + ', N=' + str(n) +
              '=(' + ', '.join([str(f) for f in frequency]) + ')$', loc='left') # タイトル
    plt.xticks(ticks=x_vals) # x軸目盛
    plt.grid() # グリッド線
    plt.ylim(-0.1, 1.1) # y軸の表示範囲

# gif画像を作成
anime_prop = FuncAnimation(fig, update, frames=N, interval=100)

# gif画像を保存
anime_prop.save('ProbabilityDistribution/Binomial_prop.gif')

#%%

print('end')


import numpy as np
from util import *

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

def costFunction(theta, X, y):
    m = y.size
    h = sigmoid(X.dot(theta))

    J = -1.0 * (1.0 / m) * (np.log(h + eps).T.dot(y) + np.log(1 - h + eps).T.dot(1 - y))

    if np.isnan(J[0]):
        return (np.inf)
    return J[0]

def costFunctionReg(theta, reg, XX, y, *args):
    m = y.size
    h = sigmoid(XX.dot(theta))

    J = -1.0*(1.0/m)*(np.log(h + eps).T.dot(y)+np.log(1-h + eps).T.dot(1-y)) + (reg/(2.0*m))*np.sum(np.square(theta[1:]))

    if np.isnan(J[0]):
        return(np.inf)
    return(J[0])

def gradient(theta, X, y):
    m = y.size
    h = sigmoid(X.dot(theta.reshape(-1, 1)))

    grad = (1.0 / m) * X.T.dot(h - y)

    return (grad.flatten())

def gradientReg(theta, reg, XX, y, *args):
    m = y.size
    h = sigmoid(XX.dot(theta.reshape(-1,1)))

    grad = (1.0/m)*XX.T.dot(h-y) + (reg/m)*np.r_[[[0]],theta[1:].reshape(-1,1)]

    return(grad.flatten())

def predict(theta, X, threshold=0.5):
    p = sigmoid(X.dot(theta.T)) >= threshold
    return (p.astype('int'))


import numpy as np
from functools import wraps

"""Kernel Module

This Module implements kernel functions."""

def linear():
    """Linear kernel.

    Returns:
        closure: A Linear kernel K(x, y) = x.T * y
    """

    def linnear_kernel(x:np.ndarray, y:np.ndarray):

        return np.matmul(x, y.T)

    return linnear_kernel

def gaussian(sigma):
    """Gaussian kernel.

    Args:
        sigma: The standard error of the gaussian kernel.

    Returns:
        closure: A gaussian kernel K(x, y) = exp(- |x - y|^2 / 2 sigma^2)
    """

    g = -1.0 / (2 * (sigma ** 2))

    def gaussian_kernel(x, y):

        x_norm = np.sum(x**2, axis=1).reshape((-1, 1))
        y_norm = np.sum(y**2, axis=1).reshape((1, -1))
        w = -2 * np.matmul(x, y.T)
        w += x_norm
        w += y_norm

        return np.exp(w * g)

    return gaussian_kernel


"""
This script shows how to use FASTA to solve regularized least-square problem:
        min  .5||Ax-b||^2 + mu*|x|
Where A is an MxN matrix, b is an Mx1 vector of measurements, and x is the Nx1 vector of unknowns.
The parameter 'mu' controls the strength of the regularizer.

@author: Proloy DAS

"""

import numpy as np
from scipy import linalg
from fastapy import Fasta
import matplotlib.pyplot as plt
import time

def shrink(x, mu):
    """
    Soft theresholding function
    mu = threshold
    """
    return np.multiply(np.sign(x), np.maximum(np.abs(x) - mu, 0))

def setup_rls():
    np.random.seed(0)
    # Define problem parameters
    M = 200  # number of measurements
    N = 1000  # dimension of sparse signal
    K = 10    # signal sparsity
    mu = .02  # regularization parameter
    sigma = 0.01  # The noise level in 'b'

    print('Testing sparse least-squares with N={:}, M={:}'.format(N, M))

    # Create sparse signal
    x = np.zeros((N, 1))
    perm = np.random.permutation(N)
    x[perm[0:K]] = 1

    # define random Gaussian matrix
    A = np.random.randn(M, N)
    A = A/linalg.norm(A, 2)  # Normalize the matrix so that our value of 'mu' is fairly invariant to N

    # Define observation vector
    b = np.dot(A, x)
    b = b + sigma * np.random.randn(*b.shape)  # add noise

    #  The initial iterate:  a guess at the solution
    x0 = np.zeros((N, 1))

    # Create function handles
    def f(x): return 0.5 * linalg.norm(np.dot(A, x) - b, 2)**2  # .5||Ax-b||^2

    def gradf(x): return np.dot(A.T, np.dot(A, x) - b)  # gradient of f(x)

    def g(x): return mu * np.abs(x).sum()  # mu*|x|

    def proxg(x, t): return shrink(x, mu*t)  # proximal operator for g(x)

    return f, gradf, g, proxg, x0, x

def test_rls(debugging=False):
    f, gradf, g, proxg, x0, x = setup_rls()
    # Set up Fasta solver
    lsq = Fasta(f, g, gradf, proxg)
    # Call Solver
    lsq.learn(x0, verbose=True)

    assert lsq.residuals[-1] / lsq.residuals[0] < 1e-4

    if debugging:
        plt.figure('sparse least-square')
        plt.subplot(2, 1, 1)
        plt.stem(x,  markerfmt='go', linefmt='g:', label='Ground truth')
        plt.stem(lsq.coefs_, markerfmt='bo', label='Fasta solution')
        plt.xlabel('Index')
        plt.ylabel('Signal Value')

        plt.subplot(2, 1, 2)
        plt.semilogy(lsq.residuals)

        plt.show()

def test_fix_stepsize(debugging=False):
    f, gradf, g, proxg, x0, x = setup_rls()
    # Set up Fasta solver
    lsq = Fasta(f, g, gradf, proxg)
    # custom stepsize
    def fixed_step(*args): return 2
    # Call Solver
    lsq.learn(x0, verbose=True, linesearch=False, next_stepsize=fixed_step)

    assert lsq.residuals[-1] / lsq.residuals[0] < 1e-4

    if debugging:
        plt.figure('sparse least-square')
        plt.subplot(2, 1, 1)
        plt.stem(x,  markerfmt='go', linefmt='g:', label='Ground truth')
        plt.stem(lsq.coefs_, markerfmt='bo', label='Fasta solution')
        plt.xlabel('Index')
        plt.ylabel('Signal Value')

        plt.subplot(2, 1, 2)
        plt.semilogy(lsq.residuals)

        plt.show()


import numpy as np

A = np.array([[1, 2], [-1, 4]])
b = np.array([3, 5])

A_inv = np.linalg.inv(A)

print(A_inv)

X = A_inv.dot(b)

print(X)

x = X[0]
y = X[1]

print(f"{x + 2 * y} == 3")
print(f"{-x + 4 * y} == 5")

print(np.linalg.solve(A, b))


import pandas as pd
import numpy as np

from datetime import datetime

from scipy import optimize
from scipy import integrate

%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
########################################

def SIR_model(SIR,beta,gamma,N0):
    '''Simple SIR model
        S: susceptible population
        I: infected population
        R: recovered population
        beta: infection rate
        gamma: recovery rate
        N0: Total population

        overall condition is that the sum of changes (differnces) sum up to 0
        dS+dI+dR=0
        S+I+R= N (constant size of population)

     Parameters:
        ----------
        SIR : numpy.ndarray
        beta: float
        gamma: float
    '''

    S,I,R = SIR
    dS_dt=-beta*S*I/N0
    dI_dt=beta*S*I/N0-gamma*I
    dR_dt=gamma*I
    return(dS_dt,dI_dt,dR_dt)

if __name__ == '__main__':

    pd_JH_data=pd.read_csv('../data/processed/COVID_relational_confirmed.csv',sep=';',parse_dates=[0])
    pd_JH_data=pd_JH_data.sort_values('date',ascending=True).copy()


import math
import scipy.stats as st
import numpy as np
import pandas as pd
from scipy.stats import shapiro
from scipy.stats import pearsonr
from scipy.stats import spearmanr
from scipy.stats import kendalltau
from tools import get_type_columns
from sklearn.feature_selection import f_regression, mutual_info_regression

# CALCULATE Z VALUE
def get_z(confidence_level:float)->float:
    """
    Calculate Z value for a given confidence level.

    confidence_level -- confidence level into percent.
    return -- z value.
    """
    return st.norm.ppf(1-(1-confidence_level/100.)/2)

# CALCULATE THE SAMPLE SIZE
def sample_size(population_size:int, confidence_level:float, confidence_interval:float)->int:
    """
    Calculate the sample size using the Cochran’s Sample Size Formula.

    population_size -- the total population size.
    confidence_level -- the seleceted confidence level in percent.
    confidence_interval -- the selected confidence interval in percent.
    return -- sample size with the correction for smaller population (no large).
    """
    Z = 0.0
    p = 0.5
    e = confidence_interval/100.0
    N = population_size
    n_0 = 0.0
    n = 0.0

    # FIND THE NUM STD DEVIATIONS FOR THAT CONFIDENCE LEVEL
    Z = get_z(confidence_level)

    if Z == 0.0:
        return -1

    # CALC SAMPLE SIZE
    n_0 = ((Z**2) * p * (1-p)) / (e**2)

    # ADJUST SAMPLE SIZE FOR FINITE POPULATION
    n = n_0 / (1 + ((n_0 - 1) / float(N)) )

    return int(math.ceil(n)) # THE SAMPLE SIZE

## Tests whether a data sample has a Gaussian distribution according Shapiro test
def test_shapiro(data:np.array, significance:float = 0.05, verbose:bool = False) ->bool:
    """
    Tests whether a data sample has a Gaussian distribution according Shapiro test.

    Parameters
    ----------
    data : np.array()
        Data to be tested.
    significance : float, optional
        Level of significance. The default is 0.05.
    verbose : bool, optional
        Display information or not. The default is False.

    Returns
    -------
    bool
        If data has a Gaussian distribution or not.

    """
    # estimate cofindence level
    confidence = (1 - significance) * 100
    # test
    stat, p = shapiro(data)
    # display
    if verbose:
        print('stat=%.3f, p=%.3f' % (stat, p))
    # check result and return
    if p > significance:
        if verbose:
            print(f'Probably Gaussian (confidence level = {confidence}%)')
        return True
    else:
        if verbose:
            print(f'Probably not Gaussian (confidence level = {confidence}%)')
        return False

## Normality test analysis for several columns in a dataframe
def analysis_normality(df:pd.DataFrame, numerical_columns: list, significance:float = 0.05, verbose:bool = False)->(dict,list):
    """
    Normality test analysis for several columns in a dataframe.

    Parameters
    ----------
    df : pd.DataFrame
        Dataframe to be tested.
    numerical_columns : list
        Variables to be tested.
    significance : float, optional
        Level of significance. The default is 0.05.
    verbose : bool, optional
        Display information. The default is False.

    Returns
    -------
    (dict,list)
        Results of test stored in a dictionary. List of reports.

    """

    # validate columns
    for c in numerical_columns:
        assert c in df.columns.tolist(), f'column "{c}" is required.'
    # estimate cofindence level
    confidence = (1 - significance) * 100
    # initialize
    disnormal = dict()
    lreports = list()
    # loop of columns
    for col in numerical_columns:
        # collect data
        data = df[col].values
        # Shapiro test
        result_shapiro = test_shapiro(data, significance = significance, verbose = verbose)
        # add result
        disnormal[col] = result_shapiro
        # build report
        if result_shapiro:
            sreport = f'"{col}": Probably Gaussian (confidence level = {confidence}%) according to "Shapiro test"'
            # append
            lreports.append(sreport)
        else:
            sreport = f'"{col}": Probably NOT Gaussian (confidence level = {confidence}%) according to "Shapiro test"'
        # display
        if verbose:
            print(sreport)
    # return
    return disnormal, lreports

## Calculate Pearson's coefficient
def correlation_pearson(data1:np.array, data2:np.array, significance:float = 0.05, verbose:bool = False)->float:
    """
    Calculate Pearson's coefficient.

    Parameters
    ----------
    data1 : np.array
        First data array to be used.
    data2 : np.array
        Second data array to be used.
    significance : float, optional
        Level of significance. The default is 0.05.
    verbose : bool, optional
        Display information. The default is False.

    Returns
    -------
    float
        Correlation value.

    """
    # estimate cofindence level
    confidence = (1 - significance) * 100
    # calculate Pearson's correlation
    corr, p = pearsonr(data1, data2)
    # display
    # check result and return
    if p < significance:
        if verbose:
            print("Pearson's correlation: %.3f (confidence interval = %s %s)"%(corr, confidence, '%'))
        return corr
    else:
        if verbose:
            print("Pearson's correlation is not trusted: %.3f (confidence interval = %s %s)"%(corr, confidence, '%'))
        return np.nan

## Calculate a Spearman correlation coefficient
def correlation_spearman(data1:np.array, data2:np.array, significance:float = 0.05, verbose:bool = False)->float:
    """
    Calculate a Spearman correlation coefficient.

    Parameters
    ----------
    data1 : np.array
        First data array to be used.
    data2 : np.array
        Second data array to be used.
    significance : float, optional
        Level of significance. The default is 0.05.
    verbose : bool, optional
        Display information. The default is False.

    Returns
    -------
    float
        Correlation value.

    """
    # estimate cofindence level
    confidence = (1 - significance) * 100
    # calculate Pearson's correlation
    corr, p = spearmanr(data1, data2)
    # display
    # check result and return
    if p < significance:
        if verbose:
            print("Spearman's correlation: %.3f (confidence interval = %s %s)"%(corr, confidence, '%'))
        return corr
    else:
        if verbose:
            print("Spearman's correlation is not trusted: %.3f (confidence interval = %s %s)"%(corr, confidence, '%'))
        return np.nan

## Calculate Kendall’s tau, a correlation measure for ordinal data
def correlation_kendalltau(data1:np.array, data2:np.array, significance:float = 0.05, verbose:bool = False)->float:
    """
    Calculate Kendall’s tau, a correlation measure for ordinal data.

    Parameters
    ----------
    data1 : np.array
        First data array to be used.
    data2 : np.array
        Second data array to be used.
    significance : float, optional
        Level of significance. The default is 0.05.
    verbose : bool, optional
        Display information. The default is False.

    Returns
    -------
    float
        Correlation value.

    """
    # estimate cofindence level
    confidence = (1 - significance) * 100
    # calculate Pearson's correlation
    corr, p = kendalltau(data1, data2)
    # display
    # check result and return
    if p < significance:
        if verbose:
            print("Kendall’s tau correlation: %.3f (confidence interval = %s %s)"%(corr, confidence, '%'))
        return corr
    else:
        if verbose:
            print("Kendall’s tau correlation is not trusted: %.3f (confidence interval = %s %s)"%(corr, confidence, '%'))
        return np.nan

## Calculate a F-test regression (linear dependency)
def f_test_regression(data1:np.array, data2:np.array, significance:float = 0.05, verbose:bool = False)->float:

    # estimate cofindence level
    confidence = (1 - significance) * 100
    # calculate F-test
    corr, p = spearmanr(data1, data2)
    # display
    # check result and return
    if p < significance:
        if verbose:
            print("Spearman's correlation: %.3f (confidence interval = %s %s)"%(corr, confidence, '%'))
        return corr
    else:
        if verbose:
            print("Spearman's correlation is not trusted: %.3f (confidence interval = %s %s)"%(corr, confidence, '%'))
        return np.nan

## Correlation analysis for a couple of columns in a dataframe (for numerical and ordinal data)
def analysis_correlation(data:pd.DataFrame, couple_columns: list, dnormality:dict = None, significance:float = 0.05, verbose:bool = False)->float:
    """
    ## Correlation analysis for a couple of columns in a dataframe (for numerical and ordinal data).

    Parameters
    ----------
    data : pd.DataFrame
        Dataframe to be used.
    couple_columns : list
        Couple of columns names to be used.
    dnormality : dict, optional
        Dictionary with results of normality test per column . The default is None.
    significance : float, optional
        Level of significance. The default is 0.05.
    verbose : bool, optional
        Display information. The default is False.

    Returns
    -------
    float
        Correlation value.

    """

    # validate columns
    for c in couple_columns:
        assert c in data.columns.tolist(), f'column "{c}" is required.'
    # initialize
    col1 = couple_columns[0]
    col2 = couple_columns[1]
    # collect data and remove records with NaN values
    df = data[couple_columns].dropna()
    nsample = len(df)
    v1 = data[col1].values
    v2 = data[col2].values
    # validate type of data
    dtypecols = get_type_columns(df)
    typecol1 = dtypecols[col1]
    typecol2 = dtypecols[col2]
    # clean
    del df

    ## analysis

    # case: ord - ord
    if typecol1 == 'ord' and typecol2 == 'ord':
        # get number of unique values of ordinal variables
        n_unique_var1 = len(list(set(list(v1))))
        n_unique_var2 = len(list(set(list(v2))))
        # select technique
        if n_unique_var1 >= 5 and n_unique_var2 >= 5:
            corr = correlation_spearman(v1, v2, significance = significance, verbose = verbose)
        else:
            corr = correlation_kendalltau(v1, v2, significance = significance, verbose = verbose)
    # case: num - num
    elif typecol1 == 'num' and typecol2 == 'num':
        # get normality
        if dnormality is None:
            is_norm_var1 = False
            is_norm_var2 = False
        else:
            is_norm_var1 = dnormality[col1]
            is_norm_var2 = dnormality[col2]
        # select technique
        if nsample >= 100:
            corr = correlation_pearson(v1, v2, significance = significance, verbose = verbose)
        else:
            if is_norm_var1 and is_norm_var2:
                corr = correlation_pearson(v1, v2, significance = significance, verbose = verbose)
            else:
                corr = correlation_spearman(v1, v2, significance = significance, verbose = verbose)
    # case: num - ord
    elif typecol1 == 'num' and typecol2 == 'ord':
        # get number of unique values of ordinal variables
        n_unique_var2 = len(list(set(list(v2))))
        # select technique
        if n_unique_var2 < 5:
            corr = correlation_kendalltau(v1, v2, significance = significance, verbose = verbose)
        else:
            if nsample >= 100:
                corr = correlation_pearson(v1, v2, significance = significance, verbose = verbose)
            else:
                corr = correlation_spearman(v1, v2, significance = significance, verbose = verbose)
    # case: ord - num
    elif typecol1 == 'ord' and typecol2 == 'num':
        # get number of unique values of ordinal variables
        n_unique_var1 = len(list(set(list(v1))))
        # select technique
        if n_unique_var1 < 5:
            corr = correlation_kendalltau(v1, v2, significance = significance, verbose = verbose)
        else:
            if nsample >= 100:
                corr = correlation_pearson(v1, v2, significance = significance, verbose = verbose)
            else:
                corr = correlation_spearman(v1, v2, significance = significance, verbose = verbose)
    # other case
    else:
        corr = np.na
        # display
        if verbose:
            print('It was not possible to identify correctly columns types.')
    # return
    return corr


#
# Valuation of European Call Options in Black-Scholes-Merton Model
# Including Vega Function and implied volatility Estimation
# bsm_functions.py
#

# Analytical Black-Scholes-Merton (BSM) Formula

def bsm_call_value(S0, K, T, r, sigma):
    """
    Valuation of European call option in BSM model.

    Parameters
    ==========
    s0 : Float
      initial stock/index level
    K : Float
      Strike Price
    T: Float
      Constant risk-free short rate
    sigma: Float
      Volatility Factor in Diffusion Term

    Returns
    =======

    value: Float
      Present value of the European call option]
    """

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

    s0 = float(s0)
    d1 = (log(s0/ K) + (r + 0.5 * sigma ** 2) * T) / (sigma * sqrt(T))
    d2 = (log(s0/ K) + (r - 0.5 * sigma ** 2) * T) / (sigma * sqrt(T))
    value = (s0 * stats.norm.cdf(d1, 0.0, 1.0)
            - K * exp(-r * T) * stats.norm.cdf(d2, 0.0, 1.0))

    # stats.norm.cdf -> Cumulative distribution function for normal distribution
    #

    return value

# Vega Function

def bsm_vega(S0, K, T, r, sigma):
    """
    Vega of european option in BSM Model.

    Parameters
    ==========
    s0 : Float
        initial stock/index level
    K : Float
        strike price
    T : Float
        Maturity date (in year fractions)
    r : float
        constant risk-free short rate
    sigma : float
        volatility factor in diffusion term
    Returns
    =======
    vega : Float
        Partial derivative of BSM formula with respect to sigma, i.e. Vega
    """

    from math import log, sqrt
    from scipy import stats

    S0 = float(S0)
    d1 = (log(S0 / K) + (r + 0.5 * sigma ** 2) * T / (sigma * sqrt(T))
    vega = S0 * stats.normcdf(d1, 0.0, 1.0) * sqrt(T)
    return vega

# Implied volatility function

def bsm_call_imp_vol(S0, K, T, r, C0, sigma_est, it = 100):
    """
    Implied volatility of European call option in BSM model

    Parameters
    ==========
    S0 : Float
        Initial stock/index level
    K : Float
        Strike Price
    T : Float
        Maturity Date (in year fractions)
    r : Float
        Constant risk-free short rate
    sigma_est : Float
        Estimate of impl. volatility
    it : integer
        Number of iterations

    Returns
    =======
    sigma_est : Float
        Numerically estimated implied volatility
    """
    for i in range(it):
        sigma_est -= ((bsm_call_value(S0, K, T, r, sigma_est) - C0)
                        / bsm_vega(S0, K, T, r, sigma_est))
    return sigma_est


import math
from IntegralMethods.RectangleIntegration import leftrectangle, rightrectangle
from IntegralMethods.TrapezoidIntegration import trapezoid
from IntegralMethods.SimpsonIntegration import simpson
from math import sin, exp, pi
import numpy as np
import matplotlib.pyplot as plt

leftrect = []
rightrect = []
trapez = []
simps = []
sol = (2/13)+(3/13*np.e**(3/4*np.pi))
step = [10**0,10**-1,10**-2,10**-3,10**-4, 10**-5,10**-6,10**-7,10**-8]

def f(x):
    return np.e**(3*x)*np.sin(2*x)

if __name__ == "__main__":

    for i in step:
        leftrect.append(abs(sol - leftrectangle(0, pi/4, i, f)))
        rightrect.append(abs(sol - rightrectangle(0, pi/4, i, f)))
        trapez.append(abs(sol - trapezoid(0, pi/4, i, f)))
        simps.append(abs(sol-simpson(0, pi/4, i, f)))

    print(leftrect)
    print(rightrect)
    print(trapez)
    print(simps)

    plt.loglog(step, leftrect)
    plt.loglog(step, rightrect)
    plt.loglog(step, trapez)
    plt.loglog(step, simps)
    plt.legend(["Left", "Right", "Trap","Simpson"])
    plt.ylim([10**-9,10])
    plt.xlabel("h")
    plt.ylabel("Error")
    plt.xlim([10,10**-8])
    plt.show()


import numpy as np

def check_linearity_independent(matrix):
    (m, n) = matrix.shape
    if m != n:
        # Ta có ma trận A không là ma trận vuông
        # Tính hạng của ma trận A
        RA = np.linalg.matrix_rank(matrix)
        if RA == m:
            return True
        if RA < m:
            return False

    if m == n:
        # Ta có ma trận A là ma trận vuông
        # Tính định thức của ma trận A
        det = np.linalg.det(matrix)
        if det != 0:
            return True
        elif det == 0:
            return False

# Test :v
u1 = np.array([-1, 2, -1, 2])
u2 = np.array([2, 2, -4, 2])
u3 = np.array([1, 3, 1, 2])

# Hãy kiểm tra xem u1 , u2 , u3 độc lập tuyến tính hay phụ thuộc tuyến tính?

matrix = np.array([u1.T, u2.T, u3.T])

print(check_linearity_independent(matrix))


"""README, Author - Jigyasa Gandhi(mailto:jigsgandhi97@gmail.com)
Requirements:
  - scikit-fuzzy
  - numpy
  - matplotlib
Python:
  - 3.5
"""
# Create universe of discourse in python using linspace ()
import numpy as np
X = np.linspace(start=0, stop=75, num=75, endpoint=True, retstep=False)

# Create two fuzzy sets by defining any membership function (trapmf(), gbellmf(),gaussmf(), etc).
import skfuzzy as fuzz
abc1=[0,25,50]
abc2=[25,50,75]
young = fuzz.membership.trimf(X,abc1)
middle_aged = fuzz.membership.trimf(X,abc2)

# Compute the different operations using inbuilt functions.
one = np.ones(75)
zero = np.zeros((75,))
#1. Union = max(µA(x), µB(x))
union = fuzz.fuzzy_or(X, young, X, middle_aged)[1]
#2. Intersection = min(µA(x), µB(x))
intersection = fuzz.fuzzy_and(X, young, X, middle_aged)[1]
#3. Complement (A) = (1- min(µA(x))
complement_a = fuzz.fuzzy_not(young)
#4. Difference (A/B) = min(µA(x),(1- µB(x)))
difference = fuzz.fuzzy_and(X, young, X, fuzz.fuzzy_not(middle_aged)[1])[1]
#5. Algebraic Sum = [µA(x) + µB(x) – (µA(x) * µB(x))]
alg_sum = young + middle_aged - (young*middle_aged)
#6. Algebraic Product = (µA(x) * µB(x))
alg_product = young*middle_aged
#7. Bounded Sum = min[1,(µA(x), µB(x))]
bdd_sum = fuzz.fuzzy_and(X, one, X, young+middle_aged)[1]
#8. Bounded difference = min[0,(µA(x), µB(x))]
bdd_difference = fuzz.fuzzy_or(X, zero, X, young-middle_aged)[1]

#max-min composition
#max-product composition

# Plot each set A, set B and each operation result using plot() and subplot().
import matplotlib.pyplot as plt

plt.figure()

plt.subplot(4,3,1)
plt.plot(X,young)
plt.title("Young")
plt.grid(True)

plt.subplot(4,3,2)
plt.plot(X,middle_aged)
plt.title("Middle aged")
plt.grid(True)

plt.subplot(4,3,3)
plt.plot(X,union)
plt.title("union")
plt.grid(True)

plt.subplot(4,3,4)
plt.plot(X,intersection)
plt.title("intersection")
plt.grid(True)

plt.subplot(4,3,5)
plt.plot(X,complement_a)
plt.title("complement_a")
plt.grid(True)

plt.subplot(4,3,6)
plt.plot(X,difference)
plt.title("difference a/b")
plt.grid(True)

plt.subplot(4,3,7)
plt.plot(X,alg_sum)
plt.title("alg_sum")
plt.grid(True)

plt.subplot(4,3,8)
plt.plot(X,alg_product)
plt.title("alg_product")
plt.grid(True)

plt.subplot(4,3,9)
plt.plot(X,bdd_sum)
plt.title("bdd_sum")
plt.grid(True)

plt.subplot(4,3,10)
plt.plot(X,bdd_difference)
plt.title("bdd_difference")
plt.grid(True)

plt.subplots_adjust(hspace = 0.5)
plt.show()