import numpy as np
import sklearn
import math
from scipy.stats import chi2
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
from random import *
from matplotlib.patches import Ellipse
from numpy.linalg import cholesky

import pandas as pd

import matplotlib as mpl
import seaborn as snss

# https://github.com/joferkington/oost_paper_code/blob/master/error_ellipse.py
def plot_point_cov(points, nstd=2, ax=None, **kwargs):
    """
    Plots an `nstd` sigma ellipse based on the mean and covariance of a point
    "cloud" (points, an Nx2 array).
    Parameters
    ----------
        points : An Nx2 array of the data points.
        nstd : The radius of the ellipse in numbers of standard deviations.
            Defaults to 2 standard deviations.
        ax : The axis that the ellipse will be plotted on. Defaults to the
            current axis.
        Additional keyword arguments are pass on to the ellipse patch.
    Returns
    -------
        A matplotlib ellipse artist
    """
    pos = points.mean(axis=0)
    cov = np.cov(points, rowvar=False)
    return plot_cov_ellipse(cov, pos, nstd, ax, **kwargs)

def plot_cov_ellipse(cov, pos, nstd=2, ax=None, **kwargs):
    """
    Plots an `nstd` sigma error ellipse based on the specified covariance
    matrix (`cov`). Additional keyword arguments are passed on to the
    ellipse patch artist.
    Parameters
    ----------
        cov : The 2x2 covariance matrix to base the ellipse on
        pos : The location of the center of the ellipse. Expects a 2-element
            sequence of [x0, y0].
        nstd : The radius of the ellipse in numbers of standard deviations.
            Defaults to 2 standard deviations.
        ax : The axis that the ellipse will be plotted on. Defaults to the
            current axis.
        Additional keyword arguments are pass on to the ellipse patch.
    Returns
    -------
        A matplotlib ellipse artist
    """
    def eigsorted(cov):
        vals, vecs = np.linalg.eigh(cov)
        order = vals.argsort()[::-1]
        return vals[order], vecs[:,order]

    if ax is None:
        ax = plt.gca()

    vals, vecs = eigsorted(cov)
    theta = np.degrees(np.arctan2(*vecs[:,0][::-1]))

    # Width and height are "full" widths, not radius
    width, height = 2 * np.sqrt(nstd * vals)
    ellip = Ellipse(xy=pos, width=width, height=height, angle=theta, **kwargs)

    ax.add_artist(ellip)
    return ellip

# generate a bivariate Gaussian distribution points set
def generate_gaussian(mu, sigma, sample_num = 300):
    # mu = np.array([[1, 5]])
    # sigma = np.array([[1, 0.5], [1.5, 3]])
    R = cholesky(sigma)
    s = np.dot(np.random.randn(sample_num, 2), R) + mu
    return s
    # plt.plot(s[:,0], s[:,1], 'o')
    # plt.show()

def plot_bivariate_gaussian(**kwargs):
    mu = np.array([[10, 5]])
    sigma = np.array([[3, 0.7], [0.7, 2]])
    s1 = generate_gaussian(mu, sigma, sample_num=1000)

    mu = np.array([[15, 20]])
    sigma = np.array([[3, -0.3], [-0.3, 6]])
    s2 = generate_gaussian(mu, sigma, sample_num=1000)

    # kwrg = {'edgecolor':'k', 'linewidth':0.5}

    plt.scatter(s1[:,0], s1[:,1], c='b', marker='o', s=5)
    plt.scatter(s2[:,0], s2[:,1], c='b', marker='o', s=5)
    plot_point_cov(s1, nstd = np.sqrt(chi2.ppf(0.99, 2)), **kwargs)
    plot_point_cov(s1, nstd = np.sqrt(chi2.ppf(0.999, 2)), **kwargs)
    plot_point_cov(s1, nstd = np.sqrt(chi2.ppf(0.9999, 2)), **kwargs)

    plot_point_cov(s2, nstd = np.sqrt(chi2.ppf(0.99, 2)), **kwargs)
    plot_point_cov(s2, nstd = np.sqrt(chi2.ppf(0.999, 2)), **kwargs)
    plt.show()

    plt.xlim(0, 25)
    plt.ylim(-5, 30)

    return plt.gca()

def plot_single_gaussian():
    mu = np.array([[1, 5]])
    sigma = np.array([[1, 0.5], [1.5, 3]])
    s1 = generate_gaussian(mu, sigma)

    mu = np.array([[4, 11]])
    sigma = np.array([[2.4, 3.1], [1.5, 3.7]])
    s2 = generate_gaussian(mu, sigma)

    X = np.hstack((s1[:,0], s2[:,0]))
    Y = np.hstack((s1[:,1], s2[:,1]))
    X.shape = (600, 1)
    Y.shape = (600, 1)
    points = np.c_[X,Y]

    kwrg = {'edgecolor':'k', 'linewidth':0.5}

    plt.plot(s1[:,0], s1[:,1], 'go')
    plt.plot(s2[:,0], s2[:,1], 'go')
    plot_point_cov(points, nstd = 2, alpha = 0.7, color = 'pink', **kwrg)
    plt.show()

# %% Exibe exemplo de gaussianas

from scipy.spatial import distance

np.random.seed(10000)

mu1, mu2 = np.array([[10, 5]]), np.array([[10, 17]])
sigma1, sigma2 = np.array([[3, 0.7], [0.7, 2]]), np.array([[3, -0.3], [-0.3, 6]])

sr1 = generate_gaussian(mu1, sigma1, sample_num=50)
sr2 = generate_gaussian(mu2, sigma2, sample_num=50)

nstd_80 = np.sqrt(chi2.ppf(0.8, 2))
nstd_99 = np.sqrt(chi2.ppf(0.99, 2))
nstd_999 = np.sqrt(chi2.ppf(0.999, 2))

fig, ax = plt.subplots()

ax.set_xlim(3, 16)
ax.set_ylim(-1, 12)

ax.scatter(sr1[:, 0], sr1[:, 1], s=10, zorder=10**2, marker='o')
ax.scatter(mu1[0, 0], mu1[0, 1], color='tab:red', s=17, zorder=10**2, marker='D')

# ax.scatter(sr2[:, 0], sr2[:, 1], s=4, zorder=10**2)

ellkargs = {'edgecolor': 'b', 'linewidth': 0.5, 'fill': True, 'linestyle': '-', 'facecolor': 'tab:blue', 'alpha': 0.2}

plot_cov_ellipse(sigma1, mu1[0, :], nstd_99, ax=ax, **ellkargs)

dist = distance.cdist(sr1, mu1, metric='mahalanobis', VI=np.linalg.pinv(sigma1))

idx = np.argmax(dist)

max_x = sr1[idx]

ax.text(max_x[0] - 3, max_x[1] + 0.6, '$s_{lk}(\\mu, x) < \\tau$', fontdict={'fontsize': 10, 'fontweight': 'normal'})
ax.text(max_x[0] + 6, max_x[1] + 1.5, '$s_{lk}(\\mu, x_i) \\geq \\tau$', fontdict={'fontsize': 10, 'fontweight': 'normal'})

ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')
# plot_cov_ellipse(sigma2, mu2[0, :], nstd_99, ax=ax, **ellkargs)

# %% Distância entre todos

from scipy.spatial import distance

np.random.seed(10000)

mu1 = np.array([[10, 5]])
sigma1 = np.array([[3, 0.7], [0.7, 2]])
sr1 = generate_gaussian(mu1, sigma1, sample_num=50)

nstd_80 = np.sqrt(chi2.ppf(0.8, 2))
nstd_99 = np.sqrt(chi2.ppf(0.99, 2))
nstd_999 = np.sqrt(chi2.ppf(0.999, 2))

fig, ax = plt.subplots(2, 3, sharex=True, sharey=True)

# ax.scatter(sr2[:, 0], sr2[:, 1], s=4, zorder=10**2)

ellkargs_m = {'edgecolor': 'b', 'linewidth': 0.5, 'fill': True, 'linestyle': '-', 'facecolor': 'tab:blue', 'alpha': 0.2}

dist = distance.cdist(sr1, mu1, metric='mahalanobis', VI=np.linalg.pinv(sigma1))

idx = np.argmax(dist)

max_x = sr1[idx]

sr1_all = sr1.copy()

sr1 = sr1[np.random.randint(0, 50, 10)[5:], :]

sr1 = np.vstack((sr1, max_x[None, :]))

# ax.scatter(mu1[0, 0], mu1[0, 1], color='tab:red', s=17, zorder=10**2, marker='D')

colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple', 'tab:cyan']
markers = ['o', 's', '8', 'D', '*', 'P']
t = ['(a)', '(b)', '(c)', '(d)', '(e)', '(f)']

for i, x in enumerate(sr1):

    ellkargs = {'edgecolor': 'b', 'linewidth': 0.5,
                'fill': True, 'linestyle': '-', 'facecolor': colors[0], 'alpha': 0.2}

    col = min(i, 2)

    if (i / 6) < 0.5:
        row = 0
    else:
        row = 1
        col = i - 4

    # fig, ax = plt.subplots()
    ax[row, col].scatter(sr1_all[:, 0], sr1_all[:, 1], s=10, zorder=10**2, marker='o',  color='b')
    # plot_cov_ellipse(sigma1, mu1[0, :], nstd_99, ax=ax[row, col], **ellkargs_m)

    plot_cov_ellipse(sigma1, x, nstd_99, ax=ax[row, col], **ellkargs)
    ax[row, col].scatter(sr1[i, 0], sr1[i, 1], s=10, zorder=100**2, marker='o', color='tab:red')
    ax[row, col].set_xlim(0, 20)
    ax[row, col].set_ylim(-2, 14)

    ax[row, col].spines['top'].set_color('white')
    ax[row, col].spines['right'].set_color('white')
    ax[row, col].spines['top'].set_color('white')
    ax[row, col].spines['right'].set_color('white')

    # ax[row, col].set_xticks([])
    # ax[row, col].set_yticks([])
    # ax[row, col].set_title('$%s$' % t[i], fontdict={'fontsize': 10})

    # for xa in sr1_all:
    #     ax[row, col].plot([x[0], xa[0]], [x[1], xa[1]], linestyle=':', alpha=0.5, linewidth=1, color='tab:green')

    # ax.scatter(sr1_all[:, 0], sr1_all[:, 1], s=10, zorder=10**2, marker='o')
    # plot_cov_ellipse(sigma1, mu1[0, :], nstd_99, ax=ax, **ellkargs_m)

    # plot_cov_ellipse(sigma1, x, nstd_99, ax=ax, **ellkargs)
    # ax.scatter(sr1[i, 0], sr1[i, 1], s=17, zorder=100**2, marker='D', color='tab:red')
    # ax.set_xlim(0, 19)
    # ax.set_ylim(-1, 15)
    # # ax.set_xticks([])
    # # ax.set_yticks([])
    # # ax.set_title('$%s$' % t[i], fontdict={'fontsize': 10})

    # for xa in sr1_all:
    #     ax.plot([x[0], xa[0]], [x[1], xa[1]], linestyle=':', alpha=0.5, linewidth=1, color='tab:green')

# ax.set_xlabel('$x_1$')
# ax.set_ylabel('$x_2$')

# %% Região de composição (Apenas uma imagem)

from scipy.spatial import distance

np.random.seed(10000)

mu1 = np.array([[10, 5]])
sigma1 = np.array([[3, 0.7], [0.7, 2]])
sr1 = generate_gaussian(mu1, sigma1, sample_num=50)

nstd_95 = np.sqrt(chi2.ppf(0.99, 2))
nstd_90 = np.sqrt(chi2.ppf(0.9, 2))
nstd_10 = np.sqrt(chi2.ppf(0.05, 2))

fig, ax = plt.subplots()

dist = distance.cdist(sr1, mu1, metric='mahalanobis', VI=np.linalg.pinv(sigma1))

idxs = dist > (nstd_95)

no_in = sr1[idxs[:, 0]]

sr1 = sr1[np.invert(idxs[:, 0])]

colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple', 'tab:cyan']
markers = ['o', 's', '8', 'D', '*', 'P']
t = ['(a)', '(b)', '(c)', '(d)', '(e)', '(f)']

ellkargs = {'edgecolor': 'purple', 'linewidth': 0.5,
                'fill': True, 'linestyle': '-', 'facecolor': 'c', 'alpha': 0.4}

ellkargs_m = {'edgecolor': 'b', 'linewidth': 0.5, 'fill': True, 'linestyle': '-',
              'facecolor': 'tab:blue', 'alpha': 0.2}

ax.scatter(mu1[0, 0], mu1[0, 1], color='tab:red', s=20, zorder=10**2, marker='D')
ax.scatter(sr1[:, 0], sr1[:, 1], s=10, zorder=10**2, marker='o', color='b')
ax.scatter(no_in[:, 0], no_in[:, 1], s=10, zorder=10**2, marker='o', color='b')

plot_cov_ellipse(sigma1, mu1[0, :], nstd_95, ax=ax, **ellkargs_m)

ax.set_xlim(0, 17)
ax.set_ylim(-1, 15)

for i, x in enumerate(sr1):

    plot_cov_ellipse(sigma1, x, nstd_10, ax=ax, **ellkargs)

ax.text(10, 10, 'class region $(d^2 \\leq d^2_{class})$', fontdict={'fontsize': 10})
ax.text(10, 12, 'point region  $(d^2 \\leq d^2_{point})$', fontdict={'fontsize': 10})

ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')

# %% Região de composição (exemplos variando \gamma_{point})

from scipy.spatial import distance
import numpy as np

np.random.seed(10000)

mu1 = np.array([[10, 5]])
sigma1 = np.array([[3, 0.7], [0.7, 2]])
sr1 = generate_gaussian(mu1, sigma1, sample_num=50)

nstd_95 = np.sqrt(chi2.ppf(0.99, 2))
nstd_90 = np.sqrt(chi2.ppf(0.9, 2))
nstd_10 = np.sqrt(chi2.ppf(0.05, 2))

ns_ = [0.05, 0.2]
nstd = np.sqrt(chi2.ppf(ns_, 2))

fig, ax = plt.subplots(2, 2, sharex=True, sharey=True)
plt.subplots_adjust(wspace=0.05, hspace=0.2, left=0.1, right=0.95, top=0.95, bottom=0.1)

dist = distance.cdist(sr1, mu1, metric='mahalanobis', VI=np.linalg.pinv(sigma1))

idxs = dist > (nstd_95)

no_in = sr1[idxs[:, 0]]

sr1 = sr1[np.invert(idxs[:, 0])]

colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple', 'tab:cyan']
markers = ['o', 's', '8', 'D', '*', 'P']
t = ['(a)', '(b)', '(c)', '(d)', '(e)', '(f)']

ellkargs = {'edgecolor': 'purple', 'linewidth': 0.5,
                'fill': True, 'linestyle': '-', 'facecolor': 'c', 'alpha': 0.4}

ellkargs_m = {'edgecolor': 'b', 'linewidth': 0.5, 'fill': True, 'linestyle': '-',
              'facecolor': 'tab:blue', 'alpha': 0.2}

def get_representative(mat, ns):

    idx = np.random.randint(0, mat.shape[0])

    src = mat.copy()

    c = src[idx]

    src = np.delete(src, idx, axis=0)

    p = []

    while True:

        p.append(c)

        d = distance.cdist(src, c[None, :], metric='mahalanobis', VI=np.linalg.pinv(sigma1))

        src = src[(d > ns)[:, 0], :]

        if src.shape[0] == 0:
            break

        else:

            if src.shape[0] == 1:
                p.append(src[0])
                break

            idx = np.random.randint(0, src.shape[0])
            c = src[idx]

            src = np.delete(src, idx, axis=0)

    return np.array(p)

for i, ns in enumerate(nstd):

    ax[i, 0].scatter(sr1[:, 0], sr1[:, 1], s=10, zorder=10**2, marker='o', color='b')
    ax[i, 0].scatter(no_in[:, 0], no_in[:, 1], s=10, zorder=10**2, marker='o', color='b')

    plot_cov_ellipse(sigma1, mu1[0, :], nstd_95, ax=ax[i, 0], **ellkargs_m)
    plot_cov_ellipse(sigma1, mu1[0, :], nstd_95, ax=ax[i, 1], **ellkargs_m)

    ax[i, 0].set_xlim(0, 19)
    ax[i, 0].set_ylim(-1, 15)

    ax[i, 1].set_xlim(0, 19)
    ax[i, 1].set_ylim(-1, 15)

    ax[i, 0].spines['top'].set_color('white')
    ax[i, 0].spines['right'].set_color('white')
    ax[i, 1].spines['top'].set_color('white')
    ax[i, 1].spines['right'].set_color('white')

    fig.text(10,10, '$\gamma_{point} = %.2f$' % ns_[i], zorder=10**100, fontdict={'fontsize': 10})
    ax[i, 1].set_title('$\gamma_{point} = %.2f$' % ns_[i], fontdict={'fontsize': 10})

    ax[0, 0].set_ylabel('$x_2$')
    ax[1, 0].set_ylabel('$x_2$')
    ax[1, 0].set_xlabel('$x_1$')
    ax[1, 1].set_xlabel('$x_1$')

    for j, x in enumerate(sr1):
        plot_cov_ellipse(sigma1, x, ns, ax=ax[i, 0], **ellkargs)

    src = get_representative(sr1, ns)
    ax[i, 1].scatter(src[:, 0], src[:, 1], s=10, zorder=10**2, marker='o', color='b')

    for j, x in enumerate(src):
        plot_cov_ellipse(sigma1, x, ns, ax=ax[i, 1], **ellkargs)

# %%

alphas = lambda d, t: (-np.log(t) / (d))

t = 0.1

d95 = chi2.ppf(.95, 2)
d99 = chi2.ppf(.99, 2)

alpha95 = alphas(d95, t)
alpha99 = alphas(d99, t)

x = np.linspace(0, max(d95, d99) + 2)

y95 = np.exp(-alpha95 * x)
y99 = np.exp(-alpha99 * x)

# plt.plot(x, y95, lw=1.5)
plt.plot(x, y99, lw=1.5)

plt.yticks(np.arange(0, 1.1, 0.1))
# plt.xticks((d99, ))

plt.grid(linestyle=':')

# plt.scatter(d95, t, s=6 ** 2, zorder=1000)
plt.scatter(d99, t, s=6 ** 2, zorder=1000)

plt.text(d99 - 0.35, t + 0.03, '$s_{lk}(d^2_{max})$', fontdict={'fontsize': 10, 'fontweight': 'normal'})
plt.ylabel('$s_{lk}(d^2)$')
plt.xlabel('statistic distance $(d^2)$')

# %% Exibe clusters (2d) em `alg`.

import numpy as np
import sklearn
import math
from scipy.stats import chi2
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
from random import *
from matplotlib.patches import Ellipse
from numpy.linalg import cholesky

import pandas as pd

import matplotlib as mpl
import seaborn as snss

# https://github.com/joferkington/oost_paper_code/blob/master/error_ellipse.py
def plot_point_cov(points, nstd=2, ax=None, **kwargs):
    """
    Plots an `nstd` sigma ellipse based on the mean and covariance of a point
    "cloud" (points, an Nx2 array).
    Parameters
    ----------
        points : An Nx2 array of the data points.
        nstd : The radius of the ellipse in numbers of standard deviations.
            Defaults to 2 standard deviations.
        ax : The axis that the ellipse will be plotted on. Defaults to the
            current axis.
        Additional keyword arguments are pass on to the ellipse patch.
    Returns
    -------
        A matplotlib ellipse artist
    """
    pos = points.mean(axis=0)
    cov = np.cov(points, rowvar=False)
    return plot_cov_ellipse(cov, pos, nstd, ax, **kwargs)

def plot_cov_ellipse(cov, pos, nstd=2, ax=None, **kwargs):
    """
    Plots an `nstd` sigma error ellipse based on the specified covariance
    matrix (`cov`). Additional keyword arguments are passed on to the
    ellipse patch artist.
    Parameters
    ----------
        cov : The 2x2 covariance matrix to base the ellipse on
        pos : The location of the center of the ellipse. Expects a 2-element
            sequence of [x0, y0].
        nstd : The radius of the ellipse in numbers of standard deviations.
            Defaults to 2 standard deviations.
        ax : The axis that the ellipse will be plotted on. Defaults to the
            current axis.
        Additional keyword arguments are pass on to the ellipse patch.
    Returns
    -------
        A matplotlib ellipse artist
    """
    def eigsorted(cov):
        vals, vecs = np.linalg.eigh(cov)
        order = vals.argsort()[::-1]
        return vals[order], vecs[:,order]

    if ax is None:
        ax = plt.gca()

    vals, vecs = eigsorted(cov)
    theta = np.degrees(np.arctan2(*vecs[:,0][::-1]))

    # Width and height are "full" widths, not radius
    width, height = 2 * np.sqrt(nstd * vals)
    ellip = Ellipse(xy=pos, width=width, height=height, angle=theta, **kwargs)

    ax.add_artist(ellip)
    return ellip

np.random.seed(9)

ellkargs = {'edgecolor': 'b', 'linewidth': 0.5, 'fill': True, 'linestyle': '-', 'facecolor': 'tab:blue', 'alpha': 0.2}

fig, ax = plt.subplots()
# ax.set_xlim(-10, 170)
# ax.set_ylim(-10, 180)

data = pd.read_csv('data/ruspini.csv', sep=';')
# data = (data - data.min()) / (data.max() - data.min())
# data = pd.read_csv('data/entrada.csv', sep=';').iloc[:, [37, 38]]

IdCurto = np.array(output)

idx  = np.random.choice(np.arange(0, 148), 148, replace=False)
colors = np.array(list(mpl.colors.cnames.keys()))[idx.tolist()]

nstd = np.sqrt(chi2.ppf(CONF_MAT_D, 2))

for i, cluster in enumerate(esbm.manager.values()):

    mu = cluster.mu
    sigma = np.linalg.pinv(cluster.inv_sigma)
    D = cluster.D

    plot_cov_ellipse(sigma, mu[0, :], nstd, ax=ax, **ellkargs)

    ax.scatter(data.iloc[IdCurto == i + 1, 1], data.iloc[IdCurto == i + 1, 2], s=12,
                c=colors[i+1], marker='o', edgecolors='k', lw=0.5 )

    ax.scatter(D[:, 0], D[:, 1], s=17, zorder=20**2, marker='s', c=colors[i + 1],  edgecolors='k', lw=0.2)
    ax.scatter(mu[0, 0], mu[0, 1], color='tab:red', s=17, zorder=10**2, marker='s')

# %% Execução eSBM

import pandas as pd
import numpy as np

np.random.seed(10)

data = pd.read_csv('data/ruspini.csv', sep=';')
# data = pd.read_csv('data/entrada.csv', sep=';')

# data = (data - data.min()) / (data.max() - data.min())

# data_norm.iloc[:, 1:39].plot(legend=None)

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

CONF_CLUSTER = 0.7
CONF_ADD_POINT = 0.1
CONF_RESIDUE = 0.44
CONF_MAT_D = 0.6
W = 10

config = {
            'data_path': 'data',
            'sep':  ';',
            'FROM_SCRATCH': 'TRUE',
            'W': W,
            'GAMMA_STATS': CONF_CLUSTER,
            'GAMMA_POINT': CONF_ADD_POINT,
            'GAMMA_CLASS' : CONF_MAT_D,
            'PR_ERROR': CONF_RESIDUE,
            'TAU': 0.0001
        }

from algorithms.esbm import eSBM
from algorithms.ctools.log import Log

from matplotlib.animation import FuncAnimation
from matplotlib import pyplot as plt

log = Log('{}/{}.log'.format(config['data_path'], 'run'), 'run', True, True)

esbm = eSBM(log, config)

output = []
q = []

for row in data.iterrows():

    row = row[1]

    timestamp = row['Timestamp']
    x = row.values[1:3].astype(float)

    info, quality = esbm.process_input(x[None, :], timestamp)

    output.append(info['IdCurto'])
    q.append(quality)

# ----------------------------
# %% Animação base 2d
import matplotlib as mpl
from matplotlib.patches import Ellipse
import pandas as pd
import numpy as np
from scipy.stats import chi2
from scipy import stats

np.random.seed(1011)

sigma = np.array([[10, 7], [7, 15]])
mu = np.array([10, 10])

g1 = stats.multivariate_normal.rvs(mean=mu, cov=sigma, size=35)
g2 = stats.multivariate_normal.rvs(mean=mu * 5.5, cov=sigma * -1.2, size=35)
g3 = stats.multivariate_normal.rvs(mean=mu * 2.5, cov=sigma * -0.8, size=35)

data = pd.read_csv('data/ruspini.csv', sep=';')

# data = pd.DataFrame(columns=['Timestamp', 'x', 'y'])
# d = np.vstack((g1, g2, g3))

# data.x = d[:, 0]
# data.y = d[:, 1]

# data = pd.read_csv('data/entrada.csv', sep=';')

# data = (data - data.min()) / (data.max() - data.min())

# data_norm.iloc[:, 1:39].plot(legend=None)

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

CONF_CLUSTER = 0.999
CONF_ADD_POINT = 0.2
CONF_RESIDUE = 0.75
CONF_MAT_D = 0.999
W = 10

config = {
            'data_path': 'data',
            'sep':  ';',
            'FROM_SCRATCH': 'true',
            'W': W,
            'GAMMA_STATS': CONF_CLUSTER,
            'GAMMA_POINT': CONF_ADD_POINT,
            'GAMMA_CLASS' : CONF_MAT_D,
            'GAMMA_RESIDUE': CONF_RESIDUE,
            'TAU': 1e-5
        }

from algorithms.esbm import eSBM
from algorithms.ctools.log import Log

from matplotlib.animation import FuncAnimation
from matplotlib import animation
from matplotlib import pyplot as plt

log = Log('{}/{}.log'.format(config['data_path'], 'run'), 'run', True, True)

esbm = eSBM(log, config)

idx  = np.random.choice(np.arange(0, 148), 148, replace=False)
colors = np.array(list(mpl.colors.cnames.keys()))[idx.tolist()]
unknow_color = 'k'

markers = mpl.markers.MarkerStyle.filled_markers

fig= plt.figure()
ax = plt.subplot(111)

ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')

ax.set_xlim(data.x.min() - 20, data.x.max() + 40)
ax.set_ylim(data.y.min() - 20, data.y.max() + 30)

# ax.set_xlim(data.x.min() - 0.1, data.x.max() + 0.1)
# ax.set_ylim(data.y.min() - 0.1, data.y.max() + 0.1)

fig.add_subplot(ax)

pargs = {'s': 11, 'color': unknow_color, 'marker': 'o', 'edgecolors': 'k', 'lw' : 0.5}
dargs = {'s': 14, 'marker': 's', 'edgecolors': 'k', 'lw' : 0.5}
muargs = {'s': 11 ** 2, 'marker': '+', 'color': 'b', 'edgecolors': 'b', 'lw' : 1.2}

ellkargs_c = {'edgecolor': 'b', 'linewidth': 0.6, 'fill': False, 'linestyle': '--', 'facecolor': 'tab:blue', 'alpha': 1}
ellkargs_s = {'edgecolor': 'r', 'linewidth': 1, 'fill': False, 'linestyle': 'dotted', 'facecolor': 'tab:blue', 'alpha': 1}

clusters = list(esbm.manager.values())

nstd_class = np.sqrt(chi2.ppf(CONF_MAT_D, 2))
nstd_stats = np.sqrt(chi2.ppf(CONF_RESIDUE, 2))

points = []
unknow_points = []
frames = []
ecclip1 = []
ecclip2 = []
mul = []

out =[]

ests_p = []
ests_a = []
cp = None
ell_conf = None

def func(frame):

    global frames
    global points
    global unknow_points
    global mul
    global ecclip1, ecclip2
    global ests_p, ests_a
    global cp, ell_conf, out

    print(frame)
    try:

        row = data.iloc[frame, :]

        timestamp = row['Timestamp']
        x = row.values[1:3].astype(float)

        info, quality = esbm.process_input(x[None, :], timestamp)

        id_ = info['IdCurto']

        ax.set_title('$t=%d$' % (frame + 1))

        ests, c_max= esbm.ests

        p = data.iloc[frame, 1:3]

        [p.remove() for p in ests_p]
        [p.remove() for p in ests_a]
        [p.remove() for p in ecclip1]

        ests_p = []
        ests_a = []
        ecclip1 = []

        if cp is not None:
            cp.remove()

        cp = ax.scatter(p.x, p.y, s=30, color='r', marker='8')

        for c in esbm.manager.values():
            sigma = np.linalg.pinv(c.inv_sigma)
            ecclip1.append(plot_cov_ellipse(sigma, c.mu[0, :], nstd_class, ax, **ellkargs_c))

        for e in ests:

            cl = esbm.manager[e[0]]

            sigma = np.linalg.pinv(cl.inv_sigma)

            ests_a.append(plot_cov_ellipse(sigma, e[1][-1][0, :], nstd_stats, ax, **ellkargs_s))
            ests_p.append(ax.scatter(e[1][-1][0, 0], e[1][-1][0, 1], zorder=100**5, lw=0.5, edgecolor='k',
                                     s=60, marker='*', color=colors[cl.info['IdCurto'] - 1]))

        if quality == 64:
            unknow_points.append(ax.scatter(p.x, p.y, **pargs))
            frames.append(frame)

        else:

                c = esbm.manager[info['IdLongo']]

                [p.remove() for p in unknow_points]

                # [u.remove() for u in points]
                [g.remove() for g in mul]

                unknow_points = []
                points = []
                mul = []

                ax.scatter(data.iloc[frames, 1], data.iloc[frames, 2], color=colors[id_ - 1], s=9, marker='o', lw=0.5, edgecolor='k')
                ax.scatter(p.x, p.y, color=colors[id_ - 1], s=11, marker='o', lw=0.5, edgecolor='k')

                points.append(ax.scatter(c.D[:, 0], c.D[:, 1], color=colors[id_ - 1], **dargs))
                mul = [ax.scatter(c.mu[0, 0], c.mu[0, 1], **muargs) for c in esbm.manager.values()]

                frames = []

        # if frame + 1 == data.shape[0]:

        #     for e in esbm.manager.values():

        #         ax.text(10 + e.info['IdCurto'] ** 3, 10, '$\hat{x}_{t, %d}$' % e.info['IdCurto'], fontdict={'fontsize': 9, 'fontweight': 'normal'})

    except Exception as e:
            print(e)

    # plt.savefig('data/figs/fig_%d.svg' % frame)

f = np.arange(0, data.shape[0])

Writer = animation.writers['ffmpeg']
writer = Writer(fps=5, metadata=dict(artist='Me'), bitrate=1800)

funcanim = FuncAnimation(fig, func, init_func=lambda : False,  frames=f, interval=30,
                         repeat=False, cache_frame_data=False, save_count=1)

funcanim.save('esbm_ruspini.mp4', writer)
plt.show()

# %% Animação 2d eSBM Plus

import numpy as np
import matplotlib as mpl

from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib import animation
from matplotlib.patches import Ellipse

import pandas as pd

from scipy.stats import chi2
from scipy import stats

from fdiidf.helpers import data as data_m
from fdiidf.evolving.clustering import esbm as m_esbm

np.random.seed(1011)

## Build data

seed = 98
np.random.seed(seed)

mu_1, mu_2 = 1, 30
sigma_1, sigma_2 = 2, 0.5

num_samples = 3000

changes = {'incip': [
                        {'add': 50, 'where': (1000, 1300)},
                        {'add': 0, 'where': (1300, 1450)},
                        {'add': -50, 'where': (1450, 1500)}
                ],
            'sudden': [
                        {'add': -25, 'where': (2000, 2200)}
                ]
            }

x_1, x_2 = data_m.build_2d_gauss_data(mu_1, mu_2, sigma_1, sigma_2,
                                samples=num_samples, changes=changes, w=50, lags=0)

data = np.zeros(shape=(num_samples, 2), dtype=float)
data[:, 0] = x_1
data[:, 1] = x_2

# %%

config = {
    'dim': 2,
    'k': 10,
    'gamma_class': 0.99,
    'gamma_point': 0.2,
    'gamma_res': 0.5,
    'tau': 0.00001

}

esbm = m_esbm.eSBMPlus(**config)
output = []

for x in data:

    x = x.reshape(1, 2)

    q, cstar = esbm.process_input(x)

    output.append(cstar)

fig, axes = plt.subplots(2, 1, sharex=True)

axes[0].plot(data)
axes[1].plot(output)

# %%

from fdiidf.evolving.clustering import esbm
from fdiidf.diagnosis import contribution

esbm_ins = esbm.eSBMPlus
esbm_config = {
    'dim': 2,
    'k': 10,
    'gamma_class': 0.99,
    'gamma_point': 0.2,
    'gamma_res': 0.5,
    'tau': 0.00001

}

grbc_ins = contribution.GRBC
grbc_config = {
    'w_train': 33,
    'w_diag': 5,
    'n_pc': 0.95,
    'conf_level': 0.99,
    'index': 'combined',
    'lags': 0
}

## Monitoring

from fdiidf.monitoring import Monitor

monitor = Monitor(clustering_method=(esbm_ins, esbm_config),
                  diagnosis_method=(grbc_ins, grbc_config))

output = []

for i, x in enumerate(data):

    x = x.reshape(1, 2)
    print('Sample: ', i + 1)

    with np.errstate(all='raise'):
        res = monitor.process_input(x)

    output.append(res)

# %%

## Buil animation

config = {
    'dim': 2,
    'k': 10,
    'gamma_class': 0.999,
    'gamma_point': 0.2,
    'gamma_res': 0.5,
    'tau': 0.00001

}

esbm = m_esbm.eSBMPlus(**config)

idx  = np.random.choice(np.arange(0, 148), 148, replace=False)
colors = np.array(list(mpl.colors.cnames.keys()))[idx.tolist()]
unknow_color = 'k'

markers = mpl.markers.MarkerStyle.filled_markers

fig= plt.figure()
ax = plt.subplot(111)

ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')

# ax.set_xlim(data.x.min() - 20, data.x.max() + 40)
# ax.set_ylim(data.y.min() - 20, data.y.max() + 30)

x_max = np.max(data[:, 0])
x_min = np.min(data[:, 0])

y_max = np.max(data[:, 1])
y_min = np.min(data[:, 1])

ax.set_xlim(x_min - 5, x_max + 5)
ax.set_ylim(y_min - 5, y_max + 5)

fig.add_subplot(ax)

pargs = {'s': 11, 'color': unknow_color, 'marker': 'o', 'edgecolors': 'k', 'lw' : 0.5}
dargs = {'s': 14, 'marker': 's', 'edgecolors': 'k', 'lw' : 0.5}
muargs = {'s': 11 ** 2, 'marker': '+', 'color': 'b', 'edgecolors': 'b', 'lw' : 1.2}

ellkargs_c = {'edgecolor': 'b', 'linewidth': 0.6, 'fill': False, 'linestyle': '--', 'facecolor': 'tab:blue', 'alpha': 1}
ellkargs_s = {'edgecolor': 'r', 'linewidth': 1, 'fill': False, 'linestyle': 'dotted', 'facecolor': 'tab:blue', 'alpha': 1}

nstd_class = chi2.ppf(config['gamma_class'], 2)
nstd_stats = chi2.ppf(config['gamma_res'], 2)

points = []
unknow_points = []
frames = []
ecclip1 = []
ecclip2 = []
mul = []

out =[]

ests_p = []
ests_a = []
cp = None
ell_conf = None

def func(frame):

    global frames
    global points
    global unknow_points
    global mul
    global ecclip1, ecclip2
    global ests_p, ests_a
    global cp, ell_conf, out

    print(frame)
    try:

        x = data[frame].reshape(1, 2)

        quality, cstar = esbm.process_input(x)

        id_ =  cstar

        ax.set_title('$t=%d, c=%d$' % (frame + 1, len(esbm.clusters)))

        ests = esbm.estimations

        [p.remove() for p in ests_p]
        [p.remove() for p in ests_a]
        [p.remove() for p in ecclip1]

        ests_p = []
        ests_a = []
        ecclip1 = []

        if cp is not None:
            cp.remove()

        cp = ax.scatter(x[0, 0], x[0, 1], s=30, color='r', marker='8')

        for c_id, xhat in esbm.estimations:

            # print(x, '\n', xhat)
            c = esbm.clusters[c_id]

            sigma = np.linalg.pinv(c.inv_cov)
            ecclip1.append(plot_cov_ellipse(sigma, c.mean[0, :], nstd_class, ax, **ellkargs_c))

            ests_a.append(plot_cov_ellipse(sigma, xhat[0], nstd_stats, ax, **ellkargs_s))
            ests_p.append(ax.scatter(xhat[0, 0], xhat[0, 1], zorder=100**5, lw=0.5, edgecolor='k',
                                     s=60, marker='*', color=colors[cstar - 1]))

        if not quality:
            unknow_points.append(ax.scatter(x[0, 0], x[0, 1], **pargs))
            frames.append(frame)

        else:
                if cstar in esbm.clusters:
                    c = esbm.clusters[cstar]

                    [p.remove() for p in unknow_points]

                    # [u.remove() for u in points]
                    [g.remove() for g in mul]

                    unknow_points = []
                    points = []
                    mul = []

                    ax.scatter(data[frames, 0], data[frames, 1], color=colors[id_ - 1], s=9, marker='o', lw=0.5,
                               edgecolor='k')
                    ax.scatter(x[0, 0], x[0, 1], color=colors[id_ - 1], s=11, marker='o', lw=0.5, edgecolor='k')

                    points.append(ax.scatter(c.D[:, 0], c.D[:, 1], color=colors[id_ - 1], **dargs))
                    mul = [ax.scatter(c.mean[0, 0], c.mean[0, 1], **muargs) for c in esbm.clusters.values()]

                    frames = []

        # if frame + 1 == data.shape[0]:

        #     for e in esbm.manager.values():

        #         ax.text(10 + e.info['IdCurto'] ** 3, 10, '$\hat{x}_{t, %d}$' % e.info['IdCurto'], fontdict={'fontsize': 9, 'fontweight': 'normal'})

    except Exception as e:

        import traceback
        print(traceback.format_exc())

    # plt.savefig('data/figs/fig_%d.svg' % frame)

f = np.arange(0, data.shape[0])

# Writer = animation.writers['ffmpeg']
# writer = Writer(fps=5, metadata=dict(artist='Me'), bitrate=1800)

funcanim = FuncAnimation(fig, func, init_func=lambda : False,  frames=f, interval=200,
                         repeat=False, cache_frame_data=False, save_count=1)

# funcanim.save('esbm_ruspini.mp4', writer)
plt.show()

# %%

import pandas as pd
import numpy as np

tags = ["CP_30100C_T75_PT_3427=NUM,NORM_MAX_MIN,0.0,250.0",
"CP_30100C_T75_PDIT_3793=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3769=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3765=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3768=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3777=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3776=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3804=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3803=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3778=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3779=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3767=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3802=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3801=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_VXI_3702=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VXI_3704=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VXI_3719=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VXI_3717=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VYI_3702=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VYI_3704=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VYI_3717=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VYI_3719=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VZI_3700A=NUM,NORM_MAX_MIN,-1.0,2.0",
"CP_30100C_T75_VZI_3700B=NUM,NORM_MAX_MIN,-1.0,2.0",
"CP_30100C_T75_VZI_3715A=NUM,NORM_MAX_MIN,-1.0,2.0",
"CP_30100C_T75_VZI_3715B=NUM,NORM_MAX_MIN,-1.0,2.0",
"CP_30100C_T75_FIT_3796=NUM,NORM_MAX_MIN,0.0,250.0",
"CP_30100C_T75_FIT_3795=NUM,NORM_MAX_MIN,0.0,250.0",
"CP_30100C_T75_PT_3324=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_PT_3327=NUM,NORM_MAX_MIN,0.0,250.0",
"CP_30100C_T75_PT_3227=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_PT_3224=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_PT_3127=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_TT_3329=NUM,NORM_MAX_MIN,0.0,200.0", # Este 100 -> 200 (max)
"CP_30100C_T75_TT_3321=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_TT_3121=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_TT_3129=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_TT_3221=NUM,NORM_MAX_MIN,0.0,100.0"]

tags_dict = {tag.split('=')[0] : (float(tag.split(',')[-2]), float(tag.split(',')[-1])) for tag in tags}

data = pd.read_csv('data/entrada.csv', sep=';')

data_norm = pd.DataFrame(columns=data.columns)

for tag, (min_, max_) in tags_dict.items():

    values  = data[tag]

    data_norm[tag] = (values - min_) / (max_ - min_)

# data = pd.read_csv('data/entrada_all.csv', sep=';')

values = data.iloc[:, 1:39]

# data_norm = data.copy()
# data_norm.iloc[:, 1:39] = (values - values.min()) / (values.max() - values.min())

# data_norm.iloc[:, 1:39].plot(legend=None)

# ----------------------
CONF_CLUSTER = 0.99
CONF_ADD_POINT = 0.1
CONF_RESIDUE = 0.4
CONF_MAT_D = 0.99
W = 40

config = {
            'data_path': 'data',
            'sep':  ';',
            'FROM_SCRATCH': 'false',
            'W': W,
            'GAMMA_STATS': CONF_CLUSTER,
            'GAMMA_POINT': CONF_ADD_POINT,
            'GAMMA_CLASS' : CONF_MAT_D,
            'GAMMA_RESIDUE': CONF_RESIDUE,
            'TAU': 0.00001
        }

from algorithms.esbm import eSBM
from algorithms.ctools.log import Log

from matplotlib.animation import FuncAnimation
from matplotlib import pyplot as plt

log = Log('{}/{}.log'.format(config['data_path'], 'run'), 'run', True, True)

esbm = eSBM(log, config)

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

fig, ax = plt.subplots(3, 1, sharex=True)

ax[0].plot(data_norm.iloc[:, 1:39])
vline = ax[0].axvline(0, data_norm.iloc[:, 1:39].min().min(), data.iloc[:, 1:39].max().max(), lw=1.5, color='c')

# line_var = ax[0].plot([], color='g')[0]
line_idcurto = ax[1].plot([], color='b')[0]
line_quality = ax[2].plot([], color='k')[0]

ax[2].set_ylim(60, 200)

vars_v = []
idcurto_v = []
quality_v = []

idx_var = 0
x = []

w = 1000

# ax[0].plot(data_norm.iloc[:, 1:39].iloc[:w, idx_var])

# ax[0].set_title('Sinal')
# ax[1].set_title('IdCurto')
# ax[2].set_title('Qualidade')

def func(frame):

    row = data.iloc[frame, :]

    timestamp = row['Timestamp']
    point = row.values[1:39].astype(float)

    info, quality = esbm.process_input(point[None, :], timestamp)

    # print(quality)

    x.append(frame)
    vars_v.append(point[idx_var])
    idcurto_v.append(info['IdCurto'])
    quality_v.append(quality)

    # line_var.set_data(x, np.array(vars_v))
    line_idcurto.set_data(x, np.array(idcurto_v))
    line_quality.set_data(x, np.array(quality_v))

    x_min = 0

    if frame > w:
        x_min = 0 if frame - w < 0 else frame - w

    vline.set_xdata(frame)

    [a.set_xlim(x_min, frame + w) for a in ax]
    # axv.set_xlim(x_min, frame + w)

    ax[1].set_ylim(0, max(idcurto_v) + 1)
    # axv.set_title(frame)

    return line_quality, line_idcurto, vline

funcanim = FuncAnimation(fig, func, frames=list(range(0, data_norm.shape[0])), interval=5)

plt.tight_layout(pad=0.5, h_pad=0, w_pad=0.1)
plt.show()

# %%

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

tags = ["CP_30100C_T75_PT_3427=NUM,NORM_MAX_MIN,0.0,250.0",
"CP_30100C_T75_PDIT_3793=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3769=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3765=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3768=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3777=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3776=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3804=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3803=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3778=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3779=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3767=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3802=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3801=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_VXI_3702=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VXI_3704=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VXI_3719=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VXI_3717=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VYI_3702=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VYI_3704=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VYI_3717=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VYI_3719=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VZI_3700A=NUM,NORM_MAX_MIN,-1.0,2.0",
"CP_30100C_T75_VZI_3700B=NUM,NORM_MAX_MIN,-1.0,2.0",
"CP_30100C_T75_VZI_3715A=NUM,NORM_MAX_MIN,-1.0,2.0",
"CP_30100C_T75_VZI_3715B=NUM,NORM_MAX_MIN,-1.0,2.0",
"CP_30100C_T75_FIT_3796=NUM,NORM_MAX_MIN,0.0,250.0",
"CP_30100C_T75_FIT_3795=NUM,NORM_MAX_MIN,0.0,250.0",
"CP_30100C_T75_PT_3324=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_PT_3327=NUM,NORM_MAX_MIN,0.0,250.0",
"CP_30100C_T75_PT_3227=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_PT_3224=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_PT_3127=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_TT_3329=NUM,NORM_MAX_MIN,0.0,200.0", # Este 100 -> 200 (max)
"CP_30100C_T75_TT_3321=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_TT_3121=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_TT_3129=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_TT_3221=NUM,NORM_MAX_MIN,0.0,100.0"]

tags_dict = {tag.split('=')[0] : (float(tag.split(',')[-2]), float(tag.split(',')[-1])) for tag in tags}

data = pd.read_csv('data/entrada.csv', sep=';')

data_norm = pd.DataFrame(columns=data.columns)

for tag, (min_, max_) in tags_dict.items():

    values  = data[tag]

    data_norm[tag] = (values - min_) / (max_ - min_)

v0 = 0.1
v1 = 1
v2 = 20
v3 = 85

data = data.iloc[:, 1:39]
data_norm = data_norm.iloc[:, 1:39]

fig = plt.figure()

ax4 = plt.subplot(515,)
ax3 = plt.subplot(514, sharex=ax4)
ax2 = plt.subplot(513, sharex=ax3)
ax1 = plt.subplot(512, sharex=ax2)
ax0 = plt.subplot(511, sharex=ax1)

idx0 = np.nonzero(data.mean() <= v0)[0]

ax0.plot(data_norm.iloc[:, idx0])

idx1 = np.nonzero(data.mean() > v0)[0]
idx1 = np.nonzero(data.iloc[:, idx1].mean() <= v1)[0]

ax1.plot(data_norm.iloc[:, idx1])

idx2 = np.nonzero(data.mean() > v1)[0]
idx2 = np.nonzero(data.iloc[:, idx2].mean() <= v2)[0]

ax2.plot(data_norm.iloc[:, idx2])

idx3 = np.nonzero(data.mean() > v2)[0]
idx3 = np.nonzero(data.iloc[:, idx3].mean() <= v3)[0]
ax3.plot(data_norm.iloc[:, idx3])

ax4.plot(data_norm.iloc[:, np.nonzero(data.mean() > v3)[0]])

fig.add_subplot(ax0)
fig.add_subplot(ax1)
fig.add_subplot(ax2)
fig.add_subplot(ax3)
fig.add_subplot(ax4)

tickslabels = ax0.get_xticklabels()

ax0.set_xticklabels([])

# ax4.set_xticklabels(tickslabels)

plt.tight_layout(pad=0.1, h_pad=0.1, w_pad=0.01)

plt.show()

# %%

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

tags = ["CP_30100C_T75_PT_3427=NUM,NORM_MAX_MIN,0.0,250.0",
"CP_30100C_T75_PDIT_3793=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3769=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3765=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3768=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3777=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3776=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3804=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3803=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3778=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3779=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PIT_3767=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3802=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_PDIT_3801=NUM,NORM_MAX_MIN,0.0,3.0",
"CP_30100C_T75_VXI_3702=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VXI_3704=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VXI_3719=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VXI_3717=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VYI_3702=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VYI_3704=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VYI_3717=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VYI_3719=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_VZI_3700A=NUM,NORM_MAX_MIN,-1.0,2.0",
"CP_30100C_T75_VZI_3700B=NUM,NORM_MAX_MIN,-1.0,2.0",
"CP_30100C_T75_VZI_3715A=NUM,NORM_MAX_MIN,-1.0,2.0",
"CP_30100C_T75_VZI_3715B=NUM,NORM_MAX_MIN,-1.0,2.0",
"CP_30100C_T75_FIT_3796=NUM,NORM_MAX_MIN,0.0,250.0",
"CP_30100C_T75_FIT_3795=NUM,NORM_MAX_MIN,0.0,250.0",
"CP_30100C_T75_PT_3324=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_PT_3327=NUM,NORM_MAX_MIN,0.0,250.0",
"CP_30100C_T75_PT_3227=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_PT_3224=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_PT_3127=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_TT_3329=NUM,NORM_MAX_MIN,0.0,200.0", # Este 100 -> 200 (max)
"CP_30100C_T75_TT_3321=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_TT_3121=NUM,NORM_MAX_MIN,0.0,100.0",
"CP_30100C_T75_TT_3129=NUM,NORM_MAX_MIN,0.0,200.0",
"CP_30100C_T75_TT_3221=NUM,NORM_MAX_MIN,0.0,100.0"]

tags_dict = {tag.split('=')[0] : (float(tag.split(',')[-2]), float(tag.split(',')[-1])) for tag in tags}

labels = np.array(['x_{%d}' % i for i in range(1, 39)])

data = pd.read_csv('data/pr/saida.csv', sep=';')

data_norm = pd.DataFrame(columns=labels)

for i, (tag, (min_, max_)) in enumerate(tags_dict.items()):

    values = data[tag]

    data_norm['x_{%d}' % (i + 1)] = (values - min_) / (max_ - min_)

v0 = 0.1
v1 = 1
v2 = 20
v3 = 85

# data_norm = data_norm.iloc[:, 1:39]

fig, axes = plt.subplots()

import seaborn as sns

np.random.seed(10001)

colors = list(sns.palettes.xkcd_rgb.values())

cm = plt.get_cmap('Accent')

NUM_COLORS = 38
# colors = [cm((i + 0)/NUM_COLORS) for i in range(NUM_COLORS)]

colors_ = [matplotlib.colors.hex2color(c) for c in np.random.choice(colors, NUM_COLORS, replace=False)]

print('UNIQUE:', np.unique(colors_).shape)

axes.set_prop_cycle('color', colors_)

axes.set_ylabel("Signal", fontsize=9)
axes.set_xlabel('Time $(t)$', fontsize=9)
# axes.set_prop_cycle('color', colors)

# plt.ylabel('$aaa$')

# idx0 = np.nonzero(data_norm.mean() <= v0)[0]

# ax0.set_prop_cycle('color', colors[:idx0.shape[0]])

lines = axes.plot(data_norm, lw=0.8)

ticks = np.round(np.arange(0, 1.2, 0.2), decimals=1)
axes.set_yticks(ticks)
axes.set_yticklabels(ticks)
axes.set_ylim(-0.05, 1.05)

p = np.array([490, 1339, 1495, 3191, 4324, 8343])
axes.vlines(p-1, -0.05, 1.05, lw=1.1, linestyle='dotted')
axes.set_xticks(p-1)
axes.set_xticklabels(p, rotation=45, fontdict={'fontsize': 8})
axes.legend(lines, [('$%s$' % l) for l in labels], ncol=9, fontsize=7, framealpha=0.5, columnspacing=0.5, handlelength=0.7, labelspacing=0.25)

plt.tight_layout(pad=0.1, h_pad=0.5, w_pad=0.01)

# %% Resultado todo período
p_created = np.array([40, 525, 1378, 1490, 3169, 3232, 4336, 8382, 9027])
p_detected = np.array(p_created[1:]) - 40

fig = plt.figure(200)
gs = plt.GridSpec(4, 1)

ax1 = fig.add_subplot(gs[:3, 0])
ax2 = fig.add_subplot(gs[3, 0])

import seaborn as sns

np.random.seed(10001)

colors = list(sns.palettes.xkcd_rgb.values())

cm = plt.get_cmap('Accent')

NUM_COLORS = 38
# colors = [cm((i + 0)/NUM_COLORS) for i in range(NUM_COLORS)]

colors_ = [matplotlib.colors.hex2color(c) for c in np.random.choice(colors, NUM_COLORS, replace=False)]

print('UNIQUE:', np.unique(colors_).shape)

ax1.set_prop_cycle('color', colors_)

lines = ax1.plot(data_norm, lw=0.8)
# ax1.vlines(p_detected, -0.04, 0.9, lw=1.1, linestyle='--', color='r')
ax2.plot(data.IdCurto, '.')
ax2.plot(p_detected - 1, data.IdCurto[p_detected-1], linestyle='None', marker=(7, 2, 0), lw=7, color='r')
ax2.plot(p_created - 1, data.IdCurto[p_created-1], linestyle='None', marker=(7, 2, 0), lw=4, color='k')

ax2.set_yticks(np.unique(data.IdCurto))
ax2.set_yticklabels(np.unique(data.IdCurto), fontsize=8)

ax2.set_xticks(p_detected - 1)

ax1.set_xticks(p_detected - 1)
ax1.set_yticklabels(np.round(ax1.get_yticks(), decimals=1), fontsize=8)
ax1.set_ylim(-0.05, 1.05)

ax1.set_xticklabels([])
ax2.set_xticklabels(p_detected, fontsize=8, rotation=45)
ax2.set_ylim(0, data.IdCurto.max() + 1)

ax1.set_ylabel('Signal', fontsize=9)
ax2.set_ylabel('$c$', fontsize=9, rotation=0)
ax2.set_xlabel('Time $(t)$', fontsize=9)

ax1.legend(lines, [('$%s$' % l) for l in labels], ncol=9, fontsize=7, framealpha=0.5, columnspacing=0.5, handlelength=0.7, labelspacing=0.25)

plt.tight_layout(pad=0.1, h_pad=0.5, w_pad=0.01)
plt.show()

# %% Resultado mudança 1

t_min = 480
t_max = 531

p = [490, 1339, 1495, 3191, 4324, 8343]
p_created = [40, 525, 1378, 1490, 3169, 3232, 4336, 8382, 9027]
p_detected = np.array(p_created[1:]) - 40

fig = plt.figure(200)
gs = plt.GridSpec(4, 1)

ax1 = fig.add_subplot(gs[:3, 0])
ax2 = fig.add_subplot(gs[3, 0])

import seaborn as sns

np.random.seed(10001)

colors = list(sns.palettes.xkcd_rgb.values())

cm = plt.get_cmap('Accent')

NUM_COLORS = 38
# colors = [cm((i + 0)/NUM_COLORS) for i in range(NUM_COLORS)]

colors_ = [matplotlib.colors.hex2color(c) for c in np.random.choice(colors, NUM_COLORS, replace=False)]

print('UNIQUE:', np.unique(colors_).shape)

ax1.set_prop_cycle('color', colors_)

lines = ax1.plot(data_norm.iloc[t_min:t_max, :], lw=0.8)
# ax1.vlines(p_detected, -0.04, 0.9, lw=1.1, linestyle='--', color='r')
ax2.plot(data.IdCurto[t_min:t_max], '.')
ax2.plot(p_detected[0] - 1, data.IdCurto[t_min:t_max][p_detected[0]-1], linestyle='None', marker=(7, 2, 0), lw=7, color='r')
ax2.plot(p_created[1] - 1, data.IdCurto[p_created[1]-1], linestyle='None', marker=(7, 2, 0), lw=4, color='k')

ax2.set_yticks(np.unique(data.IdCurto)[:2])
ax2.set_yticklabels(np.unique(data.IdCurto)[:2])

ax2.set_ylim(0, 3)

ax1.set_ylim(-0.05, 1.05)
ax1.set_xticklabels([])

ticks = np.arange(t_min, t_max, 5)
ax2.set_xticks(ticks - 1)
ax1.set_xticks(ticks - 1)
ax2.set_xticklabels(ticks)

ax1.set_ylabel('Signal', fontsize=9)
ax2.set_ylabel('$c$', fontsize=9, rotation=0)
ax2.set_xlabel('Time $(t)$', fontsize=9)
ax1.legend(lines, [('$%s$' % l) for l in labels], ncol=9, fontsize=7, framealpha=0.5, columnspacing=0.5, handlelength=0.7, labelspacing=0.25)

ax1.vlines([p_detected[0] - 1, p_created[1] - 1], -0.05, 1.05, lw=1.1, linestyle='dotted', color='k')

plt.tight_layout(pad=0.1, h_pad=0.5, w_pad=0.01)
plt.show()

# %% Exemplo região residual

from scipy.spatial import distance

import matplotlib

np.random.seed(10000)

mu1, mu2 = np.array([[10, 5]]), np.array([[10, 17]])
sigma1, sigma2 = np.array([[3, 0.7], [0.7, 2]]), np.array([[3, -0.3], [-0.3, 6]])

sr1 = generate_gaussian(mu1, sigma1, sample_num=50)
sr2 = generate_gaussian(mu2, sigma2, sample_num=50)

nstd_80 = np.sqrt(chi2.ppf(0.8, 2))
nstd_99 = np.sqrt(chi2.ppf(0.99, 2))
nstd_999 = np.sqrt(chi2.ppf(0.999, 2))

fig, ax = plt.subplots()

ax.set_xlim(3, 16)
ax.set_ylim(-1, 12)

dist = distance.cdist(sr1, mu1, metric='mahalanobis', VI=np.linalg.pinv(sigma1))

idx = np.argmax(dist)

max_x = sr1[idx]

# ax.scatter(sr1[:, 0], sr1[:, 1], s=10, zorder=10**2, marker='o', color='b')

CONF_CLUSTER = 0.99
CONF_ADD_POINT = 0.2
CONF_RESIDUE = 0.3
CONF_MAT_D = 0.99
W = 40

config = {
            'data_path': 'data',
            'sep':  ';',
            'FROM_SCRATCH': 'TRUE',
            'W': W,
            'GAMMA_STATS': CONF_CLUSTER,
            'GAMMA_POINT': CONF_ADD_POINT,
            'GAMMA_CLASS' : CONF_MAT_D,
            'PR_ERROR': CONF_RESIDUE,
            'TAU': 0.0001
        }

from algorithms.esbm import eSBM
from algorithms.ctools.log import Log

from matplotlib.animation import FuncAnimation
from matplotlib import pyplot as plt

log = Log('{}/{}.log'.format(config['data_path'], 'run'), 'run', True, True)

esbm = eSBM(log, config)

output = []
q = []

for x in sr1:

    info, quality = esbm.process_input(x[None, :], timestamp=None)

    output.append(info['IdCurto'])
    q.append(quality)

# ax.scatter(sr2[:, 0], sr2[:, 1], s=4, zorder=10**2)

ellkargs = {'edgecolor': 'b', 'linewidth': 0.5, 'fill': True, 'linestyle': '-', 'facecolor': 'tab:blue', 'alpha': 0.2}

esbm.process_input(max_x[None, :])

ests, c_max = esbm.ests
est = ests[0][-1][1]

D = esbm.manager[c_max].D
mu = esbm.manager[c_max].mu
sigma = np.linalg.pinv(esbm.manager[c_max].inv_sigma)

plot_cov_ellipse(sigma, mu[0, :], np.sqrt(chi2.ppf(CONF_MAT_D, 2)), ax=ax, **ellkargs)

levels = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.99]

colormap = plt.cm.nipy_spectral

colors = [colormap(i) for i in np.linspace(0.2, 1, 10)]

matplotlib.lines.lineStyles

art = []
for i, c in enumerate(levels[::-1]):

    art.append(plot_cov_ellipse(sigma, est[0, :], np.sqrt(chi2.ppf(c, 2)), ax=ax,
                                                                        **{'edgecolor': colors[i], 'linewidth': 1.5,
                                                                          'fill': False, 'linestyle': '-',
                                                                          'facecolor': colors[i],
                                                                         'alpha': 1, 'label': i}))

ax.set_xlim(0, 18)
ax.set_ylim(0, 15)

lg = plt.legend(art[::-1], levels, ncol=2, markerscale=0.25, title='$\gamma_{res}$', **{'fontsize': 9})

ax.text(8, 12, '$\hat{x}_t$', fontsize=9)
ax.text(6, 12, '$x_t$', fontsize=9)
ax.text(3, 12, 'class region', fontsize=9)

ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')
# [a.set_facecolor('b') for a in lg.get_patches()]
#

# cs = matplotlib.cm.ScalarMappable(cmap=matplotlib.colors.ListedColormap(c))
# mappable = matplotlib.contour.ContourLabeler(ax=ax, levels=levels[::-1], cmap=c)

# cb = plt.colorbar(cs, spacing='proportional')
# cb.set_ticks(levels[::-1])
# cb.set_label('  $\quad \gamma_{res}$', rotation=0)

ax.scatter(max_x[0], max_x[1], s=6**2, zorder=10**2, marker='o', color='r')
ax.scatter(mu[0, 0], mu[0, 1], color='tab:red', s=17, zorder=10**2, marker='D')
ax.scatter(D[:, 0], D[:, 1], color='b', marker='s', s=7**2)

ax.scatter(est[0, 0], est[0, 1], color='r', marker='*', s=6**2, zorder=10*100)

#%%

import numpy as np; import pandas as pd; import matplotlib; import matplotlib.pyplot as plt; import seaborn as sns

# m = 3
data = pd.read_csv('data/saida_at_m3.csv', sep=';')

fig = plt.figure(200)
gs = plt.GridSpec(4, 1)

ax1 = fig.add_subplot(gs[:3, 0])
ax2 = fig.add_subplot(gs[3, 0])

data.iloc[:, 1:39].plot(legend=None, ax=ax1, lw=1)
data.IdCurto.plot(ax=ax2, lw=1.2)

ax1.set_xticklabels([])
ax1.set_ylabel('Amplitude')
ax2.set_yticks(data.IdCurto.unique())
ax2.set_ylim(0, data.IdCurto.max() + 1)
ax2.set_ylabel('Índice cluster', fontsize=10)
ax2.set_xlabel('Amostra $(t)$')

plt.tight_layout(h_pad=0.01, w_pad=0.01)
plt.show()

# m=2

data = pd.read_csv('data/saida_at_m2.csv', sep=';')

fig = plt.figure(201)
gs = plt.GridSpec(4, 1)

ax1 = fig.add_subplot(gs[:3, 0])
ax2 = fig.add_subplot(gs[3, 0])

data.iloc[:, 1:39].plot(legend=None, ax=ax1, lw=1)
data.IdCurto.plot(ax=ax2, lw=1.2)

ax1.set_xticklabels([])
ax1.set_ylabel('Amplitude')
ax2.set_yticks(data.IdCurto.unique())
ax2.set_ylim(0, data.IdCurto.max() + 1)
ax2.set_ylabel('Índice cluster', fontsize=10)
ax2.set_xlabel('Amostra $(t)$')

plt.tight_layout(h_pad=0.01, w_pad=0.01)
plt.show()

# m=1.5

data = pd.read_csv('data/saida_at_m1_5.csv', sep=';')

fig = plt.figure(202)
gs = plt.GridSpec(4, 1)

ax1 = fig.add_subplot(gs[:3, 0])
ax2 = fig.add_subplot(gs[3, 0])

data.iloc[:, 1:39].plot(legend=None, ax=ax1, lw=1)
data.IdCurto.plot(ax=ax2, lw=1.2)

ax1.set_xticklabels([])
ax1.set_ylabel('Amplitude')
ax2.set_ylim(0, data.IdCurto.max() + 1)
ax2.set_ylabel('Índice cluster', fontsize=10)
ax2.set_xlabel('Amostra $(t)$')

plt.tight_layout(h_pad=0.01, w_pad=0.01)
plt.show()

# Segunda base de dados m=3

data = pd.read_csv('data/saida_at_b2_m3.csv', sep=';')

fig = plt.figure(2010)
gs = plt.GridSpec(4, 1)

ax1 = fig.add_subplot(gs[:3, 0])
ax2 = fig.add_subplot(gs[3, 0])

data.iloc[:, 1:39].plot(legend=None, ax=ax1, lw=1)
data.IdCurto.plot(ax=ax2, lw=1.2)

ax1.set_xticklabels([])
ax1.set_ylabel('Amplitude')
ax2.set_ylim(0, data.IdCurto.max() + 1)
ax2.set_ylabel('Índice cluster', fontsize=10)
ax2.set_xlabel('Amostra $(t)$')

plt.tight_layout(h_pad=0.01, w_pad=0.01)
plt.show()

# Segunda base de dados m=3, w=10

data = pd.read_csv('data/saida_at_b2_m3_w10.csv', sep=';')

fig = plt.figure(2011)
gs = plt.GridSpec(4, 1)

ax1 = fig.add_subplot(gs[:3, 0])
ax2 = fig.add_subplot(gs[3, 0])

data.iloc[:, 1:39].plot(legend=None, ax=ax1, lw=1)
data.IdCurto.plot(ax=ax2, lw=1.2)

ax1.set_xticklabels([])
ax1.set_ylabel('Amplitude')
ax2.set_ylim(0, data.IdCurto.max() + 1)
ax2.set_ylabel('Índice cluster', fontsize=10)
ax2.set_xlabel('Amostra $(t)$')

plt.tight_layout(h_pad=0.01, w_pad=0.01)
plt.show()

# AutoCloud, eSBM, OEC

data = pd.read_csv('data/saida_at_m2.csv', sep=';')

fig = plt.figure(203)
gs = plt.GridSpec(4, 1)

ax1 = fig.add_subplot(gs[:2, 0])
ax2 = fig.add_subplot(gs[2:, 0])

data.iloc[:, 1].plot(legend=None, ax=ax1, lw=1, label=data.columns[1])
lat= data.IdCurto.plot(ax=ax2, lw=1.5, label='AutoCloud', color='b', ls='-')

ax1.set_xticklabels([])
ax1.set_ylabel('Amplitude')
ax1.legend(fontsize=8, handlelength=1.8)
ax2.set_ylabel('Índice cluster', fontsize=10)
ax2.set_xlabel('Amostra $(t)$')

data = pd.read_csv('data/saida_esbm.csv', sep=';')
le = data.IdCurto.plot(label='eSBM', lw=1.5, color='g', ax=ax2, ls='dashdot')

data = pd.read_csv('data/saida_oec.csv', sep=';')
lo = data.IdCurto.plot(label='OEC', lw=1.5, color='k', ax=ax2, ls='--')

ax2.legend(fontsize=8, handlelength=1.8)

plt.tight_layout(h_pad=0.01, w_pad=0.01)
plt.show()

# w=1.5 w, 10

data = pd.read_csv('data/saida_at_w10.csv', sep=';')

fig = plt.figure(204)
gs = plt.GridSpec(4, 1)

ax1 = fig.add_subplot(gs[:3, 0])
ax2 = fig.add_subplot(gs[3, 0])

data.iloc[:, 1:39].plot(legend=None, ax=ax1, lw=1)
data.IdCurto.plot(ax=ax2, lw=1.2)

ax1.set_xticklabels([])
ax1.set_ylabel('Amplitude')
ax2.set_ylim(0, data.IdCurto.max() + 1)
ax2.set_ylabel('Índice cluster', fontsize=10)
ax2.set_xlabel('Amostra $(t)$')

plt.tight_layout(h_pad=0.01, w_pad=0.01)
plt.show()

# w=1.5 w, 15

data = pd.read_csv('data/saida_at_w15.csv', sep=';')

fig = plt.figure(205)
gs = plt.GridSpec(4, 1)

ax1 = fig.add_subplot(gs[:3, 0])
ax2 = fig.add_subplot(gs[3, 0])

data.iloc[:, 1:39].plot(legend=None, ax=ax1, lw=1)
data.IdCurto.plot(ax=ax2, lw=1.2)

ax1.set_xticklabels([])
ax1.set_ylabel('Amplitude')
ax2.set_ylim(0, data.IdCurto.max() + 1)
ax2.set_ylabel('Índice cluster', fontsize=10)
ax2.set_xlabel('Amostra $(t)$')

plt.tight_layout(h_pad=0.01, w_pad=0.01)
plt.show()


from factorization.matrixtools import Mattools
from factorization.qr_factorization import householder
import numpy as np
import copy

class URV(Mattools):
    def __init__(self, mat):
        super().__init__(mat)

    def URV_factorization(self):
        '''
        For the URV factorization of any matrix

        Example
        ========
        >>>from factorization import Matrix
        >>>import numpy as np
        >>>a = np.array([[4,8,12,-8],[2,3,2,1],[-3,-1,1,-4]])
        >>>test_object = Matrix(a)
        >>>test_object.URV_factorization()

        array([[ 0.97372899,  0.20462466,  0.02942979, -0.09546984],
        [-0.18257419,  0.9636314 , -0.03927159,  0.19115159],
        [ 0.06085806, -0.06428777, -0.97949468,  0.18097945],
        [ 0.12171612, -0.15940626,  0.19540167,  0.95999636]]),
         array([[ 1.35918623e+01, -2.70100613e-16,  9.30409510e-16,
                  7.99440812e-16],
                [ 1.67486275e+01,  7.45697467e+00, -1.70048074e-17,
                 -1.09712297e-16],
                [ 6.36668910e+00,  4.29004562e+00,  2.53348854e+00,
                 -7.21644966e-16],
                [-3.61921181e-01, -6.10522177e-01, -1.50162168e-02,
                 -5.50147470e-01]]),
         array([[ 0.30223373,  0.50417063,  0.70148075, -0.4029783 ],
                [-0.67882758, -0.26245638,  0.09059456, -0.67978113],
                [ 0.3899655 , -0.82256059,  0.41357157, -0.01671969],
                [ 0.54385181, -0.01796399, -0.57330266, -0.61255739]])

        See alse
        ========

        URV(Mattools)
        '''
        result_mat = copy.deepcopy(self.mat)
        P, R1 = householder(result_mat)
        r = self.rank()
        B = R1[:r, :]
        Q, R2 = householder(B.T)
        T = R2[:r, :r]
        R = np.zeros(result_mat.shape)
        R[:r, :r] = T.T
        return P.T, R, Q

if __name__ == "__main__":
    pass


import numpy as np

def read_file(test = True):
    if test:
        filename = '../tests/day7.txt'
    else:
        filename = '../input/day7.txt'
    with open(filename) as file:
        for line in file:
            temp = list(map(int,line.strip().split(',')))
    return np.array(temp)

def puzzle1(test = True):
    temp = read_file(test)
    lower, upper = temp.min(), temp.max()
    min_total = np.Inf
    min_val = None
    for val in np.arange(lower, upper + 1):
        #print(val)
        diff = np.abs(temp - val)
        #print(diff)
        total = diff.sum()
        #print(total)
        if total < min_total:
            min_total = total
            min_val = val

    print(min_total)

def puzzle2(test = True):
    temp = read_file(test)
    lower, upper = temp.min(), temp.max()
    min_total = np.Inf
    min_val = None
    for val in np.arange(lower, upper + 1):
        #print(val)
        diff = np.abs(temp - val)
        #print(diff)
        total = np.array(list(map(lambda x: (x*(x+1)) // 2, diff))).sum()

        #print(total)
        if total < min_total:
            min_total = total
            min_val = val

    print(min_total)

puzzle1(False)
puzzle2(False)


import numpy as np
from sklearn.decomposition import PCA
import dr

if __name__ == "__main__":
    data = []

    with open('zoo.data') as f:
        for line in f:
            line = line[:-1].split(',')[2:]
            data.append(line)

    data = np.array(data).astype(np.int8)

    X = data[:,:-1] # 101 * 15

    # center X
    x_centered = X - np.mean(X, axis=1).reshape(-1, 1)
    Y = data[:, -1]

    # PCA
    pca = PCA(n_components=2)
    p_com = pca.fit_transform(x_centered)
    #visualize and save images
    dr.visualize(p_com, Y, 'images/PCA.png', 'Visualization of PCA')

    # MDS
    # equal importance of each feature
    new_x = dr.mds(X=x_centered)
    dr.visualize(new_x, Y, 'images/MDS.png', 'Visualization of MDS')

    # assign different importance on each feature
    with open('importance_parameters.txt')  as f:
        important_paras = [i[:-1].split(' ') for i in f]
        important_paras = [[float(i) for i in para] for para in important_paras]
    for index, para in enumerate(important_paras):

        new_x = dr.mds(X=x_centered, important_paras=np.array(para).reshape(1,-1))
        dr.visualize(new_x, Y, 'images/MDS'+str(index)+'.png', 'Visualization of MDS')

    # isomap
    for p in [5,6,7,8,9,10,15,20,30]:
        new_X = dr.isomap(x_centered, p=p)
        dr.visualize(new_X, Y, 'images/Isomap-'+str(p)+'.png', 'Visualization of Isomap with p='+str(p))


import numpy as np
import os
from Node import Node

def plurity_value(examples):
    if len(examples) < 1: return "Example list is empty. No plurity value"
    class_count = {} # class : number of appearances
    for ex in examples:
        target = ex[-1]
        class_count[target] = class_count.get(target, 0) + 1

    return max(class_count, key=class_count.get)

def all_same_class(examples):
    target = examples[0][-1]
    for ex in examples:
        if ex[-1] != target:
            return False
    return True

'''
Entropy is how much uncertainty in the dataset (examples) S
examples - the current examples for which entropy is calculated. NOTE this changes every iteration of ID3
X = set of classes / all the different targets in current dataset (examples)
p(x) = the proportion of the number of elements in class x (target) to the number of elements in the dataset (examples)

When H(S)=0, the set S is perfectly classified (i.e. all elements in current dataset are of the same class).

In ID3, entropy is calculated for each remaining attribute.

The attribute with the smallest entropy is used to split the set S on this iteration.

The higher the entropy, the higher the potential to improve the classification here.

Entropy is also often called H(S)

H(S) = entropy(S) = sum[x in X] -p(x) * log2(p(x)) ; NOTE THE minus sign in the first led!
'''
def entropy(examples):
    # find X (all the different classes \ target values in examples)
    classes = {} # class : number of examples with this class
    for ex in examples: # examples has only examples with the attribute set to the value we are testing
       classes[ex[-1]] = classes.get(ex[-1], 0) + 1

    total_number_of_examples = len(examples)
    probabilities_px = [cls / total_number_of_examples for cls in classes.values()]

    entropy = sum([-px * np.log2(px) for px in probabilities_px])
    return entropy

def informationGain(examples, attribute):
    # number of values for attribute
    # going to need to find out number of different classes
    # number of examples with a given attribute value belongs to each class

    attribute_idx = attributes.index(attribute)
    values = {}
    for ex in examples:
        values[ex[attribute_idx]] = values.get(ex[attribute_idx], 0) + 1

    subsets = []
    for value in values:
        subset_after_split = []
        for ex in examples:
            if ex[attribute_idx] == value:
                subset_after_split.append(ex)
        subsets.append(subset_after_split)

    sum_subsets_entropy = sum([ (len(subset) / len(examples)) * entropy(subset) for subset in subsets ])

    gain = entropy(examples) - sum_subsets_entropy
    return gain

def decisionTree(examples, attributes, parent_examples):
    if len(examples) < 1: return plurity_value(parent_examples)
    elif all_same_class(examples): return examples[-0][-1]
    elif len(attributes) < 1: return plurity_value(examples)

    #A <- argmax(a, Attributes)[IMPORTANCE(a,examples) : GAIN(a, examples)]
    gains = [informationGain(examples, attribute) for attribute in attributes]
    max_value = max(gains)
    max_idx = gains.index(max_value)
    attribute = attributes[max_idx] # remember this is a string, not a integer or index

    #tree <- a new deccision tree with root test A
    tree = Node(attribute)

    # for each value of attribute A
    # first find all the different attribute values
    attribute_idx = attributes.index(attribute)
    values = []
    for ex in examples:
        if ex[attribute_idx] not in values: values.append(ex[attribute_idx])

    # now we can do the foreach
    for value in values:
        ## exs_subset = e : e in examples and e.A = value
        subset_after_split = []
        for ex in examples:
            if ex[attribute_idx] == value:
                subset_after_split.append(ex)
        ## subtree = decisionTree(exs, attributes - A, examples)
        ### remove the attribute we test for in attributes for the next test
        attributs_moded = attributes[:attribute_idx] + attributes[attribute_idx:]
        subtree = decisionTree(subset_after_split, attributs_moded, examples)
        ## a a branch to tree with test (A = value) and subtree (child) = subtree
        tree.add_branch(edge=value, child=subtree)
    # return tree
    return tree

if __name__ == "__main__":
    # Preparations  START
    #examples = np.loadtxt("data/data_same_class.txt", dtype=str, comments="#")
    examples = np.loadtxt("data/data_real.txt", dtype=str, comments="#")
    attributes = ["outlook", "windy", "avalance_risk"]

    print("Examples  peak (head-5)\n{}".format(examples[:5]))
    # Preparations  END

    # Run the algorithm START
    decisionTree = decisionTree(examples, attributes, parent_examples=[])
    # Run the algorithm END

    # Print results Start
    print(decisionTree)
    # print results END


import numpy as np

def AND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.7
    tmp = np.sum(w*x) + b

    if tmp <= 0:
        return 0

    return 1

def NAND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([-0.5, -0.5])
    b = 0.7
    tmp = np.sum(w*x) + b

    if tmp <= 0:
        return 0

    return 1

def OR(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.2
    tmp = np.sum(w*x)+b

    if tmp <= 0:
        return 0

    return 1

if __name__ == "__main__":
    print('AND')
    y = AND(0, 0)
    print(y)
    y = AND(1, 0)
    print(y)
    y = AND(0, 1)
    print(y)
    y = AND(1, 1)
    print(y)
    print('--------------------')

    print('NAND')
    y = NAND(0, 0)
    print(y)
    y = NAND(1, 0)
    print(y)
    y = NAND(0, 1)
    print(y)
    y = NAND(1, 1)
    print(y)
    print('--------------------')

    print('OR')
    y = OR(0, 0)
    print(y)
    y = OR(1, 0)
    print(y)
    y = OR(0, 1)
    print(y)
    y = OR(1, 1)
    print(y)
    print('--------------------')

Deep Learning from Scratch/02 perceptron/AND_NAND_OR.py


# code adopted from Pedro Alcocer,
# https://github.com/pealco/python-mutual-information/blob/master/entropy.py

# not actually sure if this is correct, should probably check that

import numpy as np
import scipy.stats as st

def entropy(counts):
    '''Compute entropy.'''
    ps = counts / float(counts.sum())  # coerce to float and normalize
    ps = ps[np.nonzero(ps)]            # toss out zeros
    H = - (ps * np.log2(ps)).sum()   # compute entropy

    return H

def mi(x, y, bins, normalized=False):
    '''Compute mutual information'''
    counts_xy = np.histogram2d(x, y, bins=bins)[0]
    counts_x  = np.histogram(x, bins=bins)[0]
    counts_y  = np.histogram(y, bins=bins)[0]

    H_xy = entropy(counts_xy)
    H_x  = entropy(counts_x)
    H_y  = entropy(counts_y)

    if normalized:
        return (H_x + H_y - H_xy) / np.sqrt(H_x * H_y)
    else:
        return H_x + H_y - H_xy

def nmi(x, y, bins):
    return mi(x, y, bins, True)

def get_part(x, y, c):
    return ((c[0] <= x) & (x < c[1]) & (c[2] <= y) & (y < c[3]))

def mutinA(x, y):
    assert x.shape[0] > 2 and y.shape[0] > 2

    x0,x1 = np.min(x), np.max(x) + 1e-6
    y0,y1 = np.min(y), np.max(y) + 1e-6

    def calc_t(N):
        return ((N - N.mean())**2).sum() / N.mean() > 7.81

    cells = [(x0,x1,y0,y1)]
    m = []

    if get_part(x, y, cells[0]).sum() <= 2:
        return cells

    while cells:
        c = cells.pop()
        x0,x1,y0,y1 = c
        i = get_part(x, y, c)

        xm = np.median(x[i])
        ym = np.median(y[i])

        new_cells = [(x0, xm, y0, ym),
                     (xm, x1, y0, ym),
                     (x0, xm, ym, y1),
                     (xm, x1, ym, y1)]

        cell_i = [get_part(x, y, mc) for mc in new_cells]

        if calc_t(np.array([i.sum() for i in cell_i])):
            for i,mc in zip(cell_i, new_cells):
                if i.sum() <= 2:
                    m.append(mc)
                else:
                    cells.append(mc)
        else:
            m.append(c)

    return m

def mutin_mI(x, y, cells=None):
    mi = 0.0
    N = x.shape[0]
    logN = np.log(N)

    if cells is None:
        cells = mutinA(x, y)

    for k,c in enumerate(cells):
        N_k = get_part(x, y, c).sum()
        if N_k:
            N_xk = ((c[0] <= x) & (x < c[1])).sum()
            N_yk = ((c[2] <= y) & (y < c[3])).sum()
            mi += N_k * (np.log(N_k) - np.log(N_xk) - np.log(N_yk) + logN)

    return mi / N

def mi_dist(x, y, bins):
    '''Compute the MI-based distance metric'''
    counts_xy = np.histogram2d(x, y, bins=bins)[0]
    counts_x  = np.histogram(x, bins=bins)[0]
    counts_y  = np.histogram(y, bins=bins)[0]

    H_xy = entropy(counts_xy)
    H_x  = entropy(counts_x)
    H_y  = entropy(counts_y)

    return 2 - (H_x + H_y) / H_xy

# if __name__ == '__main__':
    # for s in (1.0, 2.0, 5.0):
    #     print s
    #     for n in (10, 100, 1000, 10000):
    #         x = np.random.randint(0, n, n)
    #         y = x + np.random.normal(scale=s, size=n)
    #
    #         print 'mutual information n=%d (x,y): %g\t%g' % (n, mi(x, y, np.floor(np.sqrt(n))),
    #                                                          nmi(x, y, np.floor(np.sqrt(n))))
    #
    # for n in (10, 100, 1000, 10000):
    #     x = np.random.normal(size=n)
    #     y = np.random.normal(size=n)
    #
    #     print 'mutual information n=%d (x,y): %g\t%g' % (n, mi(x, y, np.floor(np.sqrt(n))),
    #                                                      nmi(x, y, np.floor(np.sqrt(n))))


'''
    Maximum predictability evaluation module described in
    Zhao, Kai, et al. "Predicting taxi demand at high spatial resolution:
    Approaching the limit of predictability." Big Data (Big Data),
    2016 IEEE International Conference on. IEEE, 2016.

    Given the number of unique values N in the time series and its time-correlated entropy S
    the module approximates the theoretical limit of the series predictability Pmax.
'''

import numpy as np

def Function(x, N, S):
    # Calculates the value of the maximum predictability function.
    # inputs:
    #   x (evaluated maximum predictability, Pmax) real number,
    #   N number of unique values in the time series,
    #   S time-correlated entropy of the time series.
    # output:
    #   real value of the function.
    return 1.0*(-x*np.log(x)-(1-x)*np.log(1-x)+(1-x)*np.log(N-1)-S*np.log(2))

def FirstDerivative(x, N):
    # Calculates the value of the first derivative of the maximum predictability function.
    # inputs:
    #   x (evaluated maximum predictability, Pmax) real number,
    #   N number of unique values in the time series.
    # output:
    #   real value of the first derivative.
    return 1.0*(np.log(1-x)-np.log(x)-np.log(N-1))

def SecondDerivative(x):
    # Calculates the value of the second derivative of the maximum predictability function.
    # inputs:
    #   x (evaluated maximum predictability, Pmax) real number.
    # output:
    #   real value of the second derivative.
    return 1.0/((x-1)*x)

def CalculateNewApproximation(x, N, S):
    # Calculates a one-step approximation of the value of the maximum predictability function.
    # inputs:
    #   x (evaluated maximum predictability, Pmax) real number,
    #   N number of unique values in the time series,
    #   S time-correlated entropy of the time series.
    # output:
    #   real value of the function.
    function = Function(x, N, S)
    first_derivative = FirstDerivative(x, N)
    second_derivative = SecondDerivative(x)
    return 1.0*function/(first_derivative-function*second_derivative/(2*first_derivative))

def maximum_predictability(N, S):
    # Evaluates the value of the maximum predictability of the series.
    # inputs:
    #   N number of unique values in time series, integer,
    #   S time-correlated entropy of the time series, real.
    # output:
    #   value of the maximum predictability, Pmax.
    S = round(S, 9)
    if S > round(np.log2(N), 9):
        return "No solutions"
    else:
        if S <= 0.01:
            return 0.999
        else:
            x = 1.0000000001/N
            while abs(Function(x, N, S))>0.00000001:
                x = x - CalculateNewApproximation(x, N, S)
    return round(x, 10)


import numpy as np

from .general_method import Method

class Secant(Method):
    """Secant class for Secant root-finding method.
    """

    def __init__(self, f, x0, x1, tol=1e-2, max_iter=1000):
        Method.__init__(self, f=f, tol=tol, max_iter=max_iter)

        self.x0 = x0
        self.x1 = x1

    def solve(self,):
        """run the secant root-finding method starting with points x0 and x1.
        Stops if tolerance is matched or raise error if max iteration reached.

        x_n = x_(n-1) - f(x_(n-1)) * [ x_(n-1) - x_(n-2) ] / [ f(x_(n-1)) - f(x_(n-2)) ]

        Returns:
            float: computed root within interval.
        """

        ## init
        self.epochs = [self.x0, self.x1]

        ## lucky initial guess
        if 0 == self.f(self.epochs[-1]):
            return self.epochs[-1]
        if 0 == self.f(self.epochs[-2]):
            return self.epochs[-2]

        ## loop until max iter
        for _ in range(self.max_iter):
            dx = self.epochs[-1] - self.epochs[-2]
            df_x = self.f(self.epochs[-1]) - self.f(self.epochs[-2])
            self.epochs.append(self.epochs[-1] - self.f(self.epochs[-1]) * dx / df_x)

            convergence = np.abs(self.f(self.epochs[-2]) - self.f(self.epochs[-1]))
            if self.tol >= convergence:
                return self.epochs[-1]

        raise Exception(
            "Convergence error. Reached maximum number of iterations without finding a stable enough solution"
        )


from numpy import zeros,sqrt,linspace,unique
from scipy import linalg

#======================================================================
# python function to calculate element mass and stiffness matrices for
# vertical bending given beam mass per unit span "m" (mass/length) and
# flexural stiffness "EI" (Force length^2) and element size "le" (length)
#======================================================================

def element_matrices(m,EI,le):

	M 	 	= zeros((4,4))
	K 	 	= zeros((4,4))

#======================================================================
# mass matrix entries for element with uniform mass along its length
#======================================================================

	M[0,0] 	= m*13.0*le/35.0
	M[0,1] 	= m*11.0*le*le/210.0
	M[0,2]  = m*9.0*le/70.0
	M[0,3] 	= m*(-13.0)*le*le/420.0

	M[1,0] 	= M[0,1]
	M[1,1] 	= m*le*le*le/105.0
	M[1,2] 	=-M[0,3]
	M[1,3]  = m*(-le*le*le)/140.0

	M[2,0]  = M[0,2]
	M[2,1]  = M[1,2]
	M[2,2]  = M[0,0]
	M[2,3]  =-M[0,1]

	M[3,0]  = M[0,3]
	M[3,1]  = M[1,3]
	M[3,2]  = M[2,3]
	M[3,3]  = M[1,1]

#======================================================================
# stiffness matrix entries
#======================================================================

	linv 	= 1.0/le
	linsq  	= linv*linv
	lincu  	= linsq*linv
	K[0,0] 	= EI*12.0*lincu
	K[0,1]  = EI* 6.0*linsq
	K[0,2] 	=-K[0,0]
	K[0,3] 	= K[0,1]

	K[1,0] 	= K[0,1]
	K[1,1] 	= EI*4.0*linv
	K[1,2]  =-K[1,0]
	K[1,3] 	= 0.5*K[1,1]

	K[2,0] 	= K[0,2]
	K[2,1] 	= K[1,2]
	K[2,2] 	= K[0,0]
	K[2,3] 	= K[2,1]

	K[3,0] 	= K[0,3]
	K[3,1] 	= K[1,3]
	K[3,2] 	= K[2,3]
	K[3,3] 	= K[1,1]

	return M,K

#======================================================================
# python function to assemble matrices for cantilever beam vibration analysis
#======================================================================

def assemble(A_elem):

	ne 		= len(A_elem)
	ndof 	= 2*ne+2
	nbc 	= 2
	nred 	= ndof-nbc
	Ared 	= zeros((nred,nred)) 		# for a cantilever beam, 2n dof
	for k in range(ne):
		for i in range(4):
			iglobal 	= i + 2*k - nbc
			for j in range(4):
				jglobal = j + 2*k - nbc

				if(iglobal >= 0 and jglobal >= 0):
					Ared[iglobal,jglobal] = Ared[iglobal,jglobal] + A_elem[k][i,j]

	return Ared

#======================================================================
# python function to generate elements so that lumped masses are placed
# at the right ends of certain elements; also tag those elements so we
# know which elements we have to augment the mass matrix for
#======================================================================

def generate_elements(xposn,L,reqd_node=0.0):

	nodes  	= list(linspace(0,L,6))
	for x in xposn:
 		nodes.append(x)
	nodes.append(reqd_node)
	nodes 	= sorted(unique(nodes))
	ne 		= len(nodes)-1
	le 		= []
	ie 		= []
	for i in range(ne): 			 	# loop over elements
		le.append(nodes[i+1]-nodes[i])
		if(nodes[i+1] in xposn):
			ie.append(i) 				# tag element with tip mass at right end
	# print(nodes)
	# print(le)
	# print(ie)
	# quit()
	return le,ie

#======================================================================
# python function to build M,K matrices and return natural frequencies
# for a nonrotating cantilever beam
# inputs are element lengths "le", element mass/span "m" and element
# flexural stiffnesses "EI" as 3 lists
# "elem_id" = element indices which have lumped masses "Masses" at the right
# ends of those elements
#======================================================================

def beam_freq_FEM(m_list, EI_list, le_list, elem_id, Masses):
	Me      = []
	Ke 		= []

#======================================================================
# first build the regular matrix
#======================================================================
	# print('have to add tip mass for this element:',elem_id)
	ie 		= -1
	im 		= 0 						# counter for lumped masses
	# print(m_list,EI_list,le_list)
	for m,EI,le in zip(m_list,EI_list,le_list):
		ie  	= ie + 1
		M,K 	= element_matrices(m,EI,le)

#======================================================================
# append mass matrix with lumped mass at right end: modify 2,2 entry
#======================================================================

		if(ie in elem_id):
			M[2,2] 	= M[2,2] + Masses[im]
			im 		= im + 1
		Me.append(M)
		Ke.append(K)

#======================================================================
# get assembled and reduced matrices for eigenvalue solution
#======================================================================

	wn 		= nat_freq(Me,Ke)

	return wn

#======================================================================
# get natural frequencies from element matrices
#======================================================================

def nat_freq(Me, Ke):
	Mred  	= assemble(Me)
	Kred 	= assemble(Ke)
	a,b  	= linalg.eig(Kred, Mred)
	a 		= sqrt(abs(a))[-1:0:-1] 	 # sorted in ascending order
	return a


import numpy as np

def sigmoid(x):
    """Computes sigmoid of x

    Parameters
    ----------
    x : np.ndarray
        Vector for sigmoid computation

    Returns
    -------
    np.ndarray
        Sigmoid function of x
    """
    return 1 / (1 + np.exp(-x))

def mean_squared_loss(y, y_predicted):
    """Counts mean squared loss of the model

    Parameters
    ----------
    y : np.ndarray
        Class labels
    y_predicted : np.ndarray
        Values predicted by the model

    Returns
    -------
    float
        Mean squared loss of the model
    """
    N: int = y.shape[0]
    y_difference: np.ndarray = y - y_predicted

    return y_difference.dot(y_difference) / (2 * N)

def logistic_loss(y, y_predicted):
    """Counts logistic loss of Logistic regression model

    Parameters
    ----------
    y : np.ndarray
        Class labels
    y_predicted : np.ndarray
        Values predicted by the model

    Returns
    -------
    float
        Logistic loss of the regression model
    """
    N: int = y.shape[0]
    return (1 / N) * np.sum(np.log(1 + np.exp(y_predicted)) - y * y_predicted)

def compute_gradient(y, y_predicted, tx, N=1, regularization=0):
    """Computes gradient of a linear regression model with squared loss function

    Parameters
    ----------
    y : np.ndarray
        Class labels
    y_predicted : np.ndarray
        Labels predicted by model
    tx : np.ndarray
        Data
    N : int
        The size of the dataset
    regularization : int or np.ndarray

    Returns
    -------
    np.ndarray
        Gradient of a mean square loss for linear model
    """
    return -tx.T.dot(y - y_predicted) / N + regularization

def least_squares_GD(y, tx, initial_w, max_iters, gamma):
    """Linear regression using gradient descent

    Parameters
    ----------
    y : np.ndarray
        Class labels
    tx : np.ndarray
        Train data
    initial_w : np.ndarray
        Initial weights of a linear model
    max_iters : int
        Maximal number of iterations
    gamma : float
        Learning rate

    Returns
    -------
    w : np.ndarray
        The parameters of the linear model trained by GD
    float
        The mean squared loss of the model
    """
    w: np.ndarray = initial_w
    N: int = tx.shape[1]

    for _ in range(max_iters):
        w -= gamma * compute_gradient(y, tx.dot(w), tx, N)

    return w, mean_squared_loss(y, tx.dot(w))

def least_squares_SGD(y, tx, initial_w, max_iters, gamma):
    """Linear regression using stochastic gradient descent

    Parameters
    ----------
    y : np.ndarray
        Class labels
    tx : np.ndarray
        Train data
    initial_w : np.ndarray
        Initial weights of the linear model
    max_iters : int
        Maximal number of iterations
    gamma : float
        Learning rate

    Returns
    -------
    w : np.ndarray
        The parameters of the linear model trained by SGD
    float
        The mean squared loss of the final model
    """
    w: np.ndarray = initial_w
    N: int = tx.shape[1]
    random_samples: np.ndarray = np.random.randint(N, size=max_iters)

    for sample in random_samples:
        w -= gamma * compute_gradient(y[sample], tx[sample, :].dot(w), tx[sample, :])

    return w, mean_squared_loss(y, tx.dot(w))

def least_squares(y, tx):
    """Least squares regression using normal equations

    Parameters
    ----------
    y : np.ndarray
        Class labels
    tx : np.ndarray
        Train data

    Returns
    -------
    np.ndarray
        The parameters of a model
    float
        The mean squared loss of the final model
    """
    return ridge_regression(y, tx, 0)

def ridge_regression(y, tx, lambda_):
    """Ridge regression using normal equations

    Parameters
    ----------
    y : np.ndarray
        Class labels
    tx : np.ndarray
        Train data
    lambda_ : float
        The penalty term

    Returns
    -------
    w : np.ndarray
        The parameters of the linear model trained by SGD
    float
        The mean squared loss of the final model
    """
    penalization_matrix = lambda_ * np.identity(tx.shape[1])
    txT_tx_inv = np.linalg.pinv(np.dot(tx.T, tx) - penalization_matrix)
    txT_tx_inv_txT = np.dot(txT_tx_inv, tx.T)
    w = np.dot(txT_tx_inv_txT, y)

    return w, mean_squared_loss(y, tx.dot(w))

def logistic_regression(y, tx, initial_w, max_iters, gamma):
    """Logistic regression using gradient descent

    Parameters
    ----------
    y : np.ndarray
        Class labels
    tx : np.ndarray
        Train data
    initial_w : np.ndarray
        Initial weights
    max_iters : int
        Maximum number of iteration for training
    gamma : float
        Learning rate

    Returns
    -------
    w : np.ndarray
        The parameters of the linear model trained by LR
    float
        The logistic loss of the final model
    """
    w: np.ndarray = initial_w
    N: int = tx.shape[1]

    for _ in range(max_iters):
        y_predicted = sigmoid(tx.dot(w))
        w -= gamma * compute_gradient(y, y_predicted, tx, N)

    return w, logistic_loss(y.T, y_predicted)

def reg_logistic_regression(y, tx, initial_w, max_iters, gamma, lambda_):
    """Regulated logistic regression using gradient descent

    Parameters
    ----------
    y : np.ndarray
        Class labels
    tx : np.ndarray
        Train data
    initial_w : np.ndarray
        Initial weights
    max_iters : int
        Maximum number of iteration for training
    gamma : float
        Learning rate
    lambda_ : float
        Penalty for complexity

    Returns
    -------
    w : np.ndarray
        The parameters of the linear model trained by L2 logistic regression
    float
        The logistic loss with the penalization of the final model
    """
    w: np.ndarray = initial_w
    N: int = tx.shape[1]

    for _ in range(max_iters):
        y_predicted = sigmoid(tx.dot(w))
        reg_parameter = lambda_ * w
        w -= gamma * compute_gradient(y, y_predicted, tx, N, reg_parameter)

    return w, logistic_loss(y.T, y_predicted) + lambda_ / (2 * N * w.T.dot(w))


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

def Eul(func, X0 ,tmin,tmax,h):
    N=int((tmax-tmin)/h)
    t = np.linspace(tmin,tmax,N)
    X  = np.zeros([N, len(X0)])
    X[0] = X0
    for i in range(N-1):
        X[i+1] = X[i] + func(t[i],X[i]) * h
    return X,t

def RK2(func, X0,tmin,tmax,h):
    N=int((tmax-tmin)/h)
    t = np.linspace(tmin,tmax,N)
    X  = np.zeros([N, len(X0)])
    X[0] = X0
    for i in range(N-1):
        k1 =h* func(t[i],X[i])
        k2 = h*func( t[i] + h,X[i] +  k1)
        X[i+1] = X[i] +  (k1 +k2 )/2
    return X,t

def RK4(func, X0,tmin,tmax,h):
    N=int((tmax-tmin)/h)
    t = np.linspace(tmin,tmax,N)
    X  = np.zeros([N, len(X0)])
    X[0] = X0
    for i in range(N-1):
        k1 = func(t[i],X[i])
        k2 = func( t[i] + h/2,X[i] + (h* k1)/2)
        k3 = func( t[i] + h/2,X[i] + h/2* k2)
        k4 = func(t[i] + h,X[i] + h   * k3)
        X[i+1] = X[i] + h / 6. * (k1 + 2. * k2 + 2. * k3 + k4)
    return X,t

def func(t,X):
    x,y=X
    dx_dt=y+x-x**3
    dy_dt=-x
    return np.array([dx_dt, dy_dt])

IC=[[0,-1],[0,-2],[0,-3],[0,-4]];tmax=15;tmin=0;h=0.1
EA=[];R2A=[];R4A=[]
def main1():
    for d in range(0,4):
        res1=RK4(func,IC[d],tmin,tmax,h)
        w1,w2 = res1[0].T
        eu1=Eul(func,IC[d],tmin,tmax,h)
        f1,f2 = eu1[0].T
        re1=RK2(func,IC[d],tmin,tmax,h)
        k1,k2= re1[0].T
        EA.append(f1);EA.append(f2)
        R2A.append(k1);R2A.append(k2)
        R4A.append(w1);R4A.append(w2)
    t=res1[1]
    return EA,R2A,R4A,t
L=main1()
EA,R2A,R4A,t=L[0],L[1],L[2],L[3]
data1= {"t":t,"x (Eul)":EA[0],"x (RK2)":R2A[0],"x (RK4)":R4A[0],"y (Eul)":EA[1],"y (RK2)":R2A[1],"y(RK4)":R4A[1]}
data2= {"t":t,"x (Eul)":EA[2],"x (RK2)":R2A[2],"x (RK4)":R4A[2],"y (Eul)":EA[3],"y (RK2)":R2A[3],"y (RK4)":R4A[3]}
data3= {"t":t,"x (Eul)":EA[4],"x (RK2)":R2A[4],"x (RK4)":R4A[4],"y (Eul)":EA[5],"y (RK2)":R2A[5],"y (RK4)":R4A[5]}
data4= {"t":t,"x (Eul)":EA[6],"x (RK2)":R2A[6],"x (RK4)":R4A[6],"y (Eul)":EA[7],"y (RK2)":R2A[7],"y (RK4)":R4A[7]}

print("-----For x(0) = 0 and y(0) = -1-----")
print(pd.DataFrame(data1))
print("-----For x(0) = 0 and y(0) = -2-----")
print(pd.DataFrame(data2))
print("-----For x(0) = 0 and y(0) = -3-----")
print(pd.DataFrame(data3))
print("-----For x(0) = 0 and y(0) = -4-----")
print(pd.DataFrame(data4))

def xyt_g(t,x1_1,x1_2,x1_3,y1_1,y1_2,y1_3,x2_1,x2_2,x2_3,y2_1,y2_2,y2_3,x3_1,x3_2,x3_3,y3_1,y3_2,y3_3,x4_1,x4_2,x4_3,y4_1,y4_2,y4_3,tit1,tit2,tit3,tit4,titm):
     fig1, axs = plt.subplots(2, 2)
     axs[0, 0].plot(t, y1_1,marker="*",label="y (eul)")
     axs[0, 0].plot(t,x1_1,marker="*",label="x(eul)")
     axs[0, 0].plot(t,y1_2,marker="*",label="y(rk2")
     axs[0, 0].plot(t,x1_2,marker="*",label="x(rk2)")
     axs[0, 0].plot(t,y1_3,marker="*",label="y(rk4)")
     axs[0, 0].plot(t,x1_3,marker="*",label="x(rk4)")
     axs[0,0].set(xlabel = "time",title=tit1)
     axs[0,0].legend(loc = "best")
     axs[0,0].grid()
     axs[1, 0].plot(t,y2_1,marker="*",label="y (eul)")
     axs[1, 0].plot(t,x2_1,marker="*",label="x(eul)")
     axs[1, 0].plot(t,y2_2,marker="*",label="y(rk2")
     axs[1, 0].plot(t,x2_2,marker="*",label="x(rk2)")
     axs[1, 0].plot(t,y2_3,marker="*",label="y(rk4)")
     axs[1, 0].plot(t,y2_3,marker="*",label="x(rk4)")
     axs[1,0].set(xlabel = "time",title=tit2)
     axs[1,0].legend(loc = "best")
     axs[1,0].grid()
     axs[0, 1].plot(t, y3_1,marker="*",label="y (eul)")
     axs[0, 1].plot(t,x3_1,marker="*",label="x(eul)")
     axs[0, 1].plot(t,y3_2,marker="*",label="y(rk2")
     axs[0, 1].plot(t,x3_2,marker="*",label="x(rk2)")
     axs[0, 1].plot(t,y3_3,marker="*",label="y(rk4)")
     axs[0, 1].plot(t,x3_3,marker="*",label="x(rk4)")
     axs[0,1].set(xlabel = "time",title=tit3)
     axs[0,1].legend(loc = "best")
     axs[0,1].grid()
     axs[1, 1].plot(t,y4_1,marker="*",label="y (eul)")
     axs[1, 1].plot(t,x4_1,marker="*",label="x(eul)")
     axs[1, 1].plot(t,y4_2,marker="*",label="y(rk2")
     axs[1, 1].plot(t,x4_2,marker="*",label="x(rk2)")
     axs[1, 1].plot(t,y4_3,marker="*",label="y(rk4)")
     axs[1, 1].plot(t,x4_3,marker="*",label="x(rk4)")
     axs[1,1].set(xlabel = "time",title=tit4)
     axs[1,1].legend(loc = "best")
     axs[1,1].grid()
     fig1.suptitle(titm,c="brown")
     plt.show()
xyt_g(t,EA[0],R2A[0],R4A[0],EA[1],R2A[1],R4A[1],EA[2],R2A[2],R4A[2],EA[3],R2A[3],R4A[3],EA[4],R2A[4],R4A[4],EA[5],R2A[5],R4A[5],EA[6],R2A[6],R4A[6],EA[7],R2A[7],R4A[7],"x(0) = 0 and y(0) = -1","x(0) = 0 and y(0) = -2","x(0) = 0 and y(0) = -3","x(0) = 0 and y(0) = -4","x/y vs t plot")
def xy_g(x1_1,x1_2,x1_3,y1_1,y1_2,y1_3,x2_1,x2_2,x2_3,y2_1,y2_2,y2_3,x3_1,x3_2,x3_3,y3_1,y3_2,y3_3,x4_1,x4_2,x4_3,y4_1,y4_2,y4_3,tit1,tit2,tit3,tit4,main):
    fig2, axs = plt.subplots(2, 2)
    axs[0, 0].plot(x1_1, y1_1,marker=".",label="Eul")
    axs[0, 0].plot(x1_2, y1_2,marker=".",label="RK2")
    axs[0, 0].plot(x1_3, y1_3,marker=".",label="RK4")
    axs[0,0].set(xlabel = "x",ylabel="y",title=tit1)
    axs[0,0].grid()
    axs[0,0].legend()
    axs[1, 0].plot(x2_1, y2_1,marker=".",label="Eul")
    axs[1, 0].plot(x2_2, y2_2,marker=".",label="RK2")
    axs[1, 0].plot(x2_3, y2_3,marker=".",label="RK4")
    axs[1,0].set(xlabel = "x",ylabel="y",title=tit2)
    axs[1,0].grid()
    axs[1,0].legend()
    axs[0, 1].plot(x3_1, y3_1,marker=".",label="Eul")
    axs[0, 1].plot(x3_2, y3_2,marker=".",label="RK2")
    axs[0, 1].plot(x3_3, y3_3,marker=".",label="RK4")
    axs[0,1].set(xlabel = "x",ylabel="y",title=tit3)
    axs[0,1].grid()
    axs[0,1].legend()
    axs[1, 1].plot(x4_1, y4_1,marker=".",label="Eul")
    axs[1, 1].plot(x4_2, y4_2,marker=".",label="RK2")
    axs[1, 1].plot(x4_3, y4_3,marker=".",label="RK4")
    axs[1,1].set(xlabel = "x",ylabel="y",title=tit4)
    axs[1,1].grid()
    axs[1,1].legend()
    fig2.suptitle(main,c="brown")
    plt.show()
xy_g(EA[0],R2A[0],R4A[0],EA[1],R2A[1],R4A[1],EA[2],R2A[2],R4A[2],EA[3],R2A[3],R4A[3],EA[4],R2A[4],R4A[4],EA[5],R2A[5],R4A[5],EA[6],R2A[6],R4A[6],EA[7],R2A[7],R4A[7],"x(0) = 0 and y(0) = -1","x(0) = 0 and y(0) = -2","x(0) = 0 and y(0) = -3","x(0) = 0 and y(0) = -4","y vs x plot")
def func2(t,X):
    x,y=X
    dx_dt=-4*x+4*y+12
    dy_dt=-1.6*x+1.2*y+4.8
    return np.array([dx_dt, dy_dt])
IC=[0,0];tmax=6;tmin=0;h=0.1
re1=Eul(func2,IC,tmin,tmax,h)
k1,k2= re1[0].T
r1=RK2(func2,IC,tmin,tmax,h)
g1,g2= r1[0].T
e1=RK4(func2,IC,tmin,tmax,h)
f1,f2= e1[0].T
N=int((tmax-tmin)/h)
t=np.linspace(0,6,N,endpoint=True)
A1=[ ];A2=[ ]
for i in t :
    I1=-8*np.exp(-2*i)+5*np.exp(-0.8*i)+3
    I2=-4*np.exp(-2*i)+4*np.exp(-0.8*i)
    A1.append(I1)
    A2.append(I2)

fig, (ax1, ax2) = plt.subplots(2)
fig.suptitle('Ques. 2 (Coupled equation in Linear Electric Circuit)',c="r")
ax1.plot(t,A1,marker="*",label=" I1 Ana")
ax1.plot(t,A2,marker="*",label="I2 Ana")
ax1.plot(t,f1,marker="*",label=" I1 RK4")
ax1.plot(t,f2,marker="*",label="I2 RK4")
ax1.plot(t,g1,marker="*",label=" I1 RK2")
ax1.plot(t,g2,marker="*",label="I2 RK2")
ax1.plot(t,k1,marker="*",label=" I1 Eul")
ax1.plot(t,k2,marker="*",label="I2 Eul")
ax1.set(xlabel="time (in sec)",ylabel="Current(in A)",title="Current vs Time plot")
ax1.legend()
ax1.grid()
ax2.plot(A1,A2,marker="*",label="Ana")
ax2.plot(k1,k2,marker="*",label="Eul")
ax2.plot(g1,g2,marker="*",label="RK2")
ax2.plot(f1,f2,marker="*",label="RK4")
ax2.set(xlabel="I1",ylabel="I2",title="I2 vs I1 plot")
ax2.legend()
ax2.grid()
plt.show()
data={"t":re1[1],"I1 (Euler)":k1,"I2(Euler)":k2,"I1 (RK2)":g1,"I2(RK2)":g2,"I1 (RK4)":f1,"I2(RK4)":f2,"I1 (Ana)":A1,"I2(Ana)":A2,}
print(pd.DataFrame(data))


from typing import Optional, Tuple

import numpy as np
import scipy as sp
import scipy.sparse
import scipy.sparse.linalg

def basis(adj: sp.sparse.spmatrix, d: Optional[int] = None) -> Tuple[np.ndarray, np.ndarray]:
    """
    :param adj: (n, n) adjacency matrix
    :param d: () dimension, default n
    :return: (n, d) graph laplacian basis
    """
    n = adj.shape[0]
    if d is None:
        d = n
    # normalized lap
    adj = adj.tocsr()
    adj = abs((adj + adj.T) / 2)  # make adj symmetric, return csr_matrix
    deg_vec = np.array(np.sum(adj, axis=0))[0]
    deg = sp.sparse.diags(deg_vec)
    lap = deg - adj
    if d < n:
        v, w = sp.sparse.linalg.eigsh(lap, k=d, which="SM")
    else:
        v, w = sp.linalg.eigh(lap.toarray())
    w = w.astype(np.float64)
    return w.T, w

def create_grid_adj_matrix(grid_h: int, grid_w: int) -> sp.sparse.coo_matrix:
    """
    :return: adjacency of the grid graph
    """
    coord_list = []
    for h in range(grid_h):
        for w in range(grid_w):
            coord_list.append((h, w))
    n = len(coord_list)

    c2i = {coord: i for i, coord in enumerate(coord_list)}

    def is_inside(h: int, w: int) -> bool:
        if h < 0 or h >= grid_h or w < 0 or w >= grid_h:
            return False
        return True

    adj = np.zeros(shape=(n, n), dtype=bool)
    for h0, w0 in coord_list:
        for dh, dw in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
            h1, w1 = h0 + dh, w0 + dw
            if is_inside(h1, w1):
                i0, i1 = c2i[(h0, w0)], c2i[(h1, w1)]
                adj[i0, i1] = True
    adj = sp.sparse.coo_matrix(adj)
    return adj


#Load dependencies
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from matplotlib import*
import matplotlib.pyplot as plt
from matplotlib.cm import register_cmap
from scipy import stats
from sklearn.decomposition import PCA
import seaborn
import os
import glob

def getPCAEigenPair(dataFrame):
    dataFrame.columns= ['Index','A','B','C','D']
    M=pd.pivot_table(dataFrame,index=['Index'])
    m = M.shape
    #print(M)
    df = M.replace(np.nan,0,regex=True)
    X_std = StandardScaler().fit_transform(df)
    print('NumPy covariance matrix: \n%s' %np.cov(X_std.T))
    pca = PCA(n_components=4)
    print (pca)
    pca.fit_transform(df)
    print (pca.explained_variance_ratio_)
    component = pca.explained_variance_ratio_
    cov_mat = np.cov(X_std.T)
    eig_vals,eig_vecs=np.linalg.eig(cov_mat)
    print('Eigenvectors \n%s' %eig_vecs)
    print('\nEigenvalues \n%s' %eig_vals)
    #Explained variance
    #pca = PCA().fit(X_std)
    #egvco = np.empty(shape = [1,4])
    #plt.plot(np.cumsum(pca.explained_variance_ratio_))
    #plt.xlabel('number of components')
    #plt.ylabel('cumulative explained variance')
    #plt.show()
    #egvco = np.concatenate([eig_vals])
    #return {"eigen_value" : eig_vals, "eigen_vector" : eig_vecs, "pcacomponents" : component, "egvc" : egvco}
    return {"eigen_value" : eig_vals, "eigen_vector" : eig_vecs}

file_key_list = ["p" + str(i+1) +".csv" for i in range(8)]
file_list = [d for d in file_key_list]
#eigen_val_array = np.array([])
componentN = 4
eigen_value_array = np.empty((componentN,0))
for key in file_list:
    print("key\n%s" %key)
    dfp=pd.read_csv(key)
    eigen_data = getPCAEigenPair(dfp)
    egval = np.array(eigen_data["eigen_value"])
    #s = np.array(eigen_data["pcacomponents"])
    #vt = np.array(eigen_data["eigen_vector"])
    #u = np.transpose(vt)
    #print(eigen_val_array)
    print(np.array(getPCAEigenPair(dfp)))
    #eigen_value_array=np.concatenate((eigen_value_array, np.array(getPCAEigenPair(dfp))))
    #A = u.dot(s.dot(vt))
    #print("")
    #print(A)
    #egvl = np.empty(shape = [1,4])
    #egvl = np.concatenate([eigen_data["egvc"]])
    #print (egvl)

# Visually confirm that the list is correctly sorted by decreasing eigenvalues
""" eig_pairs = [(np.abs(eig_vals[i]), eig_vecs[:,i])for i in range(len(eig_vals))]

#print('Eigenvalues in descending order:')
for i in eig_pairs:
    print(i[0])

pca = PCA(n_components=3)
print (pca)
pca.fit_transform(df1)
print (pca.explained_variance_ratio_)

#Explained variance
pca = PCA().fit(X_std)
plt.plot(np.cumsum(pca.explained_variance_ratio_))
plt.xlabel('number of components')
plt.ylabel('cumulative explained variance')
plt.show() """


import numpy as np
from robustsp import propform
'''
 elemfits compute the Nx(N-1)/2 elemental fits, i.e., intercepts b_{0,ij}
 and slopes b_{1,ij}, that define a line y = b_0+b_1 x that passes through
 the data points (x_i,y_i) and (x_j,y_j), i<j, where i, j in {1, ..., N}.
 and the respective weights | x_i - x_j |
 INPUT:
    y : (numeric) 1darray of real-valued outputs (response vector)
    x : (numeric) 1darray vector of inputs (feature vector)
 OUTPUT:
    beta: (numeric) N*(N-1)/2 matrix of elemental fits
    w: (numeric) N*(N-1)/2 matrix of weights

 Note: Numpy uses C memory order whereas Matlab uses Fortran ordering, thus the
     indices of the solution elements are different
'''
def elemfits(y,x):

    y = np.asarray(y)
    x = np.asarray(x)

    N = len(x)
    B = np.repeat(np.arange(1,N+1)[:,np.newaxis],N,axis=1)
    A = B.T
    a = A[A<B] # order of elements different from matlab
    b = B[A<B] #
    w = x[a-1] - x[b-1]
    beta = np.zeros([2,len(a)])
    beta[1,:] = (y[a-1]-y[b-1])/w
    beta[0,:] = (x[a-1]*y[b-1] - x[b-1]*y[a-1])/w
    w= np.abs(w)

    return beta,w