import numpy as np
import pandas as pd
import networkx as nx
import random

def SIR(G, i_rate=0.5, r_rate=1, init=1, max_time=20):
    """Simulate an SIR epidemic on a network.

    Arguments:
    G -- A NetworkX graph object

    Keyword arguments:
    i_rate -- the constant per-edge rate of infection (default 0.5)
    r_rate -- the constant recovery rate of infected nodes (default 1)
    init -- the initial number of infections (default 1)
    max_time -- belt & braces variable to ensure loop terminates (default 20)
    """
    # initialise network and event queue
    queue = []
    nx.set_node_attributes(G, "S", "status")
    init_infecteds = random.sample(list(G.nodes()), init)
    for node in init_infecteds:
        G.nodes[node]["status"] = "I"
        r_time = np.random.exponential(r_rate)
        queue.append({"time": r_time,
                      "node": node,
                      "type": "R"})
        for neighbor in G.neighbors(node):
            i_time = np.random.exponential(i_rate)
            if i_time < r_time:
                queue.append({"time": i_time,
                      "node": neighbor,
                      "type": "I"})
    queue.sort(key=lambda k: k["time"], reverse=True)
    s_count = nx.number_of_nodes(G) - init
    i_count = init
    r_count = 0
    output = [{"time": 0,
               "S": s_count,
               "I": i_count,
               "R": r_count}]

    # Main loop
    while queue and queue[-1]["time"] < max_time:
        # unpack the event variables from the queued event
        time, node, event_type = (queue[-1]["time"],
                                  queue[-1]["node"],
                                  queue[-1]["type"])
        # if it's a revovery event and the node is infected, the node recovers
        if event_type == "R" and G.nodes[node]["status"] == "I":
            G.nodes[node]["status"] = event_type
            i_count -= 1
            r_count += 1
            output.append({"time": time,
                           "S": s_count,
                           "I": i_count,
                           "R": r_count})
        # if it's an infection event and the node is susceptible, infect!
        if event_type == "I" and G.nodes[node]["status"] == "S":
            G.nodes[node]["status"] = event_type
            # create a recovery event and queue it
            r_time = np.random.exponential(r_rate)
            queue.append({"time": r_time + time,
                          "node": node,
                          "type": "R"})
            s_count -= 1
            i_count += 1
            output.append({"time": time,
                           "S": s_count,
                           "I": i_count,
                           "R": r_count})
            # then create infection events for neighbors
            for neighbor in G.neighbors(node):
                i_time = np.random.exponential(i_rate)
                if i_time < r_time:
                    queue.append({"time": i_time + time,
                                  "node": neighbor,
                                  "type": "I"})
        # sort the queue by time and pop the event we've just processed
        queue.sort(key=lambda k: k["time"], reverse=True)
        queue.remove(queue[-1])
    # convert output to a DataFrame and rename the columns
    df = pd.DataFrame(output)
    df.rename(columns={"S": "Susceptible", "I": "Infected", "R": "Recovered"},
              inplace=True)
    return df

def timeshift(df, threshold, criterion="Infected", time="time"):
    """Add a series of adjusted times, zeroed on a threshold number
    of infections.

    Arguments:
    df -- A Pandas dataframe in the format output by the SIR function
    threshold -- an integer number of infections to be set to time zero

    Keyword arguments:
    criterion -- the column in df containing the critrion to which the
    threshold applies (default "Infected")
    time -- the column in df containing the time variable to adjust (default
    "time")
    """
    timeshift = df[df[criterion] >= threshold][time].min()
    df["time_adj"] = df[time] - timeshift
    return df


import numpy as np
import scipy;

def ridge_filter(im, orient, freq, kx, ky):
    angleInc = 3;
    im = np.double(im);
    rows,cols = im.shape;
    newim = np.zeros((rows,cols));

    freq_1d = np.reshape(freq,(1,rows*cols));
    ind = np.where(freq_1d>0);

    ind = np.array(ind);
    ind = ind[1,:];

    non_zero_elems_in_freq = freq_1d[0][ind];
    non_zero_elems_in_freq = np.double(np.round((non_zero_elems_in_freq*100)))/100;

    unfreq = np.unique(non_zero_elems_in_freq);

    sigmax = 1/unfreq[0]*kx;
    sigmay = 1/unfreq[0]*ky;

    sze = np.round(3*np.max([sigmax,sigmay])).astype('int');

    x,y = np.meshgrid(np.linspace(-sze,sze,(2*sze + 1)),np.linspace(-sze,sze,(2*sze + 1)));

    reffilter = np.exp(-(( (np.power(x,2))/(sigmax*sigmax) + (np.power(y,2))/(sigmay*sigmay)))) * np.cos(2*np.pi*unfreq[0]*x);

    filt_rows, filt_cols = reffilter.shape;

    gabor_filter = np.array(np.zeros((int(180/angleInc),int(filt_rows),int(filt_cols))));

    for o in range(0,int(180/angleInc)):

        rot_filt = scipy.ndimage.rotate(reffilter,-(o*angleInc + 90),reshape = False);
        gabor_filter[o] = rot_filt;

    maxsze = int(sze);

    temp = freq>0;
    validr,validc = np.where(temp)

    temp1 = validr>maxsze;
    temp2 = validr<rows - maxsze;
    temp3 = validc>maxsze;
    temp4 = validc<cols - maxsze;

    final_temp = temp1 & temp2 & temp3 & temp4;

    finalind = np.where(final_temp);

    maxorientindex = np.round(180/angleInc);
    orientindex = np.round(orient/np.pi*180/angleInc);

    for i in range(0,rows):
        for j in range(0,cols):
            if(orientindex[i][j] < 1):
                orientindex[i][j] = orientindex[i][j] + maxorientindex;
            if(orientindex[i][j] > maxorientindex):
                orientindex[i][j] = orientindex[i][j] - maxorientindex;
    finalind_rows,finalind_cols = np.shape(finalind);
    sze = int(sze);
    for k in range(0,finalind_cols):
        r = validr[finalind[0][k]];
        c = validc[finalind[0][k]];

        img_block = im[r-sze:r+sze + 1][:,c-sze:c+sze + 1];

        newim[r][c] = np.sum(img_block * gabor_filter[int(orientindex[r][c]) - 1]);

    return(newim);


"""Plot streamlines of the 2D field:
u(x,y) = -1 - x^2 + y
v(x,y) =  1 + x   - y^2
"""
from vtkplotter import *
import numpy as np

# a grid with a vector field (U,V):
X, Y = np.mgrid[-5:5 :15j, -4:4 :15j]
U = -1 - X**2 + Y
V =  1 + X    - Y**2

# optionally, pick some random points as seeds:
prob_pts = np.random.rand(200, 2)*8 - [4,4]

sp = streamplot(X,Y, U,V,
                lw=0.001,            # line width in abs. units
                direction='forward', # 'both' or 'backward'
                probes=prob_pts,     # try comment out this
               )

pts = Points(prob_pts, r=5, c='white')

show(sp, pts,
     Text2D(__doc__, c='w'),
     axes=1, bg='bb')


#-------------------------------------------------------------------------------
# Name:        module1
# Purpose:
#
# Author:      milad
#
# Created:     01/01/2021
# Copyright:   (c) milad 2021
# Licence:     <your licence>
#-------------------------------------------------------------------------------
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# generate data
np.random.seed(123)
N = 20
beta0 = -4
beta1 = 2
x = np.random.randn(N)
e = np.random.randn(N)
y = beta0 + beta1*x + e
true_x = np.linspace(min(x), max(x), 100)
true_y = beta0 + beta1*true_x

# estimate model
beta1_hat = sum((x - np.mean(x))*(y - np.mean(y)))/sum((x - np.mean(x))**2)
beta0_hat = np.mean(y) - beta1_hat*np.mean(x)
fit_y = beta0_hat + beta1_hat*true_x

# plot
fig, ax = plt.subplots()
sns.scatterplot(x, y, s = 40, label = 'Data')
sns.lineplot(true_x, true_y, color = 'red', label = 'True Model')
sns.lineplot(true_x, fit_y, color = 'purple', label = 'Estimated Model')
ax.set_xlabel('x', fontsize = 14)
ax.set_title(fr"Linear Regression for $y = {beta0} + ${beta1}$x + \epsilon$", fontsize = 16)
ax.set_ylabel('y', fontsize=14, rotation=0, labelpad=10)
ax.legend(loc = 4)
sns.despine()

plt.show()

02_Simple Linear Regression with Estimate Model on random data.py


import numpy as np
import sys

def integration_alg(func, lower_bound, upper_bound, number_of_steps):
    """

    :param func: function to use in integration, when given a radius, will return the value at that point
    :param lower_bound: lower bound of integration
    :param upper_bound: upper bound of integration
    :param number_of_steps: number of steps to do
    :return:
    """

    # Current method if the midpoint rule, as the function is an improper integral from the lower bound being 0

    # Need to integrate from lower_bound to upper_bound in number_of_steps

    # lower bound is 0, if there is a radius of 0, then no satallites in it
    integration_value = 0
    step_size = (upper_bound - lower_bound) / number_of_steps  # The number of steps to take
    for i in range(number_of_steps):
        if i != 0:
            # Current step can be just i*step_size but only if integral always starts at 0
            # since it might not, need a starting point otherwise:
            current_step = lower_bound + i * step_size
            prev_step = lower_bound + (i - 1) * step_size

            # Current midpoint is the current step + the prev step divided by 2
            # F(mk) where mk = (tk + tk-1)/2
            current_midpoint = (current_step + prev_step) / 2
            integration_value += func(current_midpoint)

    # Last bit is the multiplication by the step size to get the full value
    integration_value *= step_size

    return integration_value

def part_four_a():
    Omega_M = 0.3
    Omega_Lambda = 0.7

    def integrand(a):
        """
        Integrand for the LGF
        :param a:
        :return:
        """
        return (1 / a ** 3) / (Omega_M / a ** 3 + Omega_Lambda) ** 1.5

    def a_from_z(z):
        """
        Gets a from z
        :param z:
        :return:
        """
        return 1 / (z + 1)

    a0 = 0
    final_a = a_from_z(50)  # z = 50, a = (z+1)
    sys.stdout = open('4a.txt', 'w')
    integral = integration_alg(integrand, a0, final_a, 20000)
    print("Integral value for the Integrand: {}".format(integral))

    lgf = 5 * Omega_M / 2 * np.sqrt(Omega_M / final_a ** 3 + Omega_Lambda) * integral
    print("LGF at z = 50: {}".format(lgf))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri May 10 14:46:37 2019

Funções de forma ok!

VERIFICAR POIS FOI ALTERADA A ORDEM DOS NÓS NAS FUNÇÕES DE INTERPOLAÇÃO!!!

@author: markinho
"""

import sympy as sp
import numpy as np

import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import axes3d, Axes3D

from matplotlib import rcParams
rcParams['mathtext.fontset'] = 'stix'
rcParams['font.family'] = 'STIXGeneral'

import meshio

#elemento padrão
l = sp.Symbol('l')

r1 = 1
s1 = 1

r2 = -1
s2 = 1

r3 = -1
s3 = -1

r4 = 1
s4 = -1

u1 = sp.Symbol('u1')
u2 = sp.Symbol('u2')
u3 = sp.Symbol('u3')
u4 = sp.Symbol('u4')

#polinomio completo do segundo grau completo
#c0 + c1 x1 + c2 x2 + c3 x1**2 + c4 x1 x2 + c5 x2**2

Mat_Coef = sp.Matrix([[1, r1, s1, r1*s1],  #no1
                      [1, r2, s2, r2*s2],  #no2
                      [1, r3, s3, r3*s3],  #no3
                      [1, r4, s4, r4*s4]]) #no4

U = sp.Matrix([u1, u2, u3, u4])

Coefs = Mat_Coef.inv() * U

A = Coefs[0]
B = Coefs[1]
C = Coefs[2]
D = Coefs[3]

r = sp.Symbol('r')
s = sp.Symbol('s')

Ns = sp.expand(A + B*r + C*s + D*r*s)

N1 = sp.Add(*[argi for argi in Ns.args if argi.has(u1)]).subs(u1, 1)
N2 = sp.Add(*[argi for argi in Ns.args if argi.has(u2)]).subs(u2, 1)
N3 = sp.Add(*[argi for argi in Ns.args if argi.has(u3)]).subs(u3, 1)
N4 = sp.Add(*[argi for argi in Ns.args if argi.has(u4)]).subs(u4, 1)

N = sp.Matrix([N1, N2, N3, N4])

##grafico das funcoes de forma -------------------------------------------------------------------
nN1 = sp.utilities.lambdify([r, s], N1, "numpy")
nN2 = sp.utilities.lambdify([r, s], N2, "numpy")
nN3 = sp.utilities.lambdify([r, s], N3, "numpy")
nN4 = sp.utilities.lambdify([r, s], N4, "numpy")
#
#rl = np.linspace(-1., 1., 30)
#sl = np.linspace(-1., 1., 30)
#
#rm, sm = np.meshgrid(rl, sl)
#
##plotagem com o matplotlib -------------------------------------------------------------------------------
#fig = plt.figure()
##ax = Axes3D(fig)
#
#ax = fig.add_subplot(2, 2, 1, projection='3d')
#surf = ax.plot_surface(rm, sm, nN1(rm, sm), cmap=cm.jet, linewidth=0, antialiased=False)
#fig.colorbar(surf, shrink=0.7)
#
#ax = fig.add_subplot(2, 2, 2, projection='3d')
#surf = ax.plot_surface(rm, sm, nN2(rm, sm), cmap=cm.jet, linewidth=0, antialiased=False)
#fig.colorbar(surf, shrink=0.7)
#
#ax = fig.add_subplot(2, 2, 3, projection='3d')
#surf = ax.plot_surface(rm, sm, nN3(rm, sm), cmap=cm.jet, linewidth=0, antialiased=False)
#fig.colorbar(surf, shrink=0.7)
#
#ax = fig.add_subplot(2, 2, 4, projection='3d')
#surf = ax.plot_surface(rm, sm, nN4(rm, sm), cmap=cm.jet, linewidth=0, antialiased=False)
#fig.colorbar(surf, shrink=0.7)
#
#plt.show()

## plotagem usando plotly -----------------------------------------------------------------------------
#dados1 = plty.graph_objs.Surface(z=list(nN1(rm, sm)), x=list(rm), y=list(sm), colorscale='Jet')
#dados2 = plty.graph_objs.Surface(z=list(nN2(rm, sm)), x=list(rm), y=list(sm), colorscale='Jet')
#dados3 = plty.graph_objs.Surface(z=list(nN3(rm, sm)), x=list(rm), y=list(sm), colorscale='Jet')
#dados4 = plty.graph_objs.Surface(z=list(nN4(rm, sm)), x=list(rm), y=list(sm), colorscale='Jet')
#
#fig = plty.subplots.make_subplots(rows=2, cols=2,
#    specs=[[{'type': 'surface'}, {'type': 'surface'}],
#           [{'type': 'surface'}, {'type': 'surface'}]])
#
#fig.add_trace(dados1, row=1, col=1)
#fig.add_trace(dados2, row=1, col=2)
#fig.add_trace(dados3, row=2, col=1)
#fig.add_trace(dados4, row=2, col=2)
#
#fig.update_layout(title="Funções de forma do elemento bilinear" , autosize=True, width=900, height=700)
#
#fig.write_html('funcoesForma.html')
#fig.write_image("funcoesForma.svg")
##-------------------------------------------------------------------------------------------------------------

# #primeira derivada em r
# dN1r = sp.diff(N1, r)#.subs({r: r1, s: s1})
# dN2r = sp.diff(N2, r)#.subs({r: r2, s: s2})
# dN3r = sp.diff(N3, r)#.subs({r: r3, s: s3})
# dN4r = sp.diff(N4, r)#.subs({r: r4, s: s4})
# #convertendo para função lambda nuympy
# ndN1r = sp.utilities.lambdify([r, s], dN1r, "numpy")
# ndN2r = sp.utilities.lambdify([r, s], dN2r, "numpy")
# ndN3r = sp.utilities.lambdify([r, s], dN3r, "numpy")
# ndN4r = sp.utilities.lambdify([r, s], dN4r, "numpy")

# #primeira derivada em s
# dN1s = sp.diff(N1, s)#.subs({r: r1, s: s1})
# dN2s = sp.diff(N2, s)#.subs({r: r2, s: s2})
# dN3s = sp.diff(N3, s)#.subs({r: r3, s: s3})
# dN4s = sp.diff(N4, s)#.subs({r: r4, s: s4})
# #convertendo para função lambda nuympy
# ndN1s = sp.utilities.lambdify([r, s], dN1s, "numpy")
# ndN2s = sp.utilities.lambdify([r, s], dN2s, "numpy")
# ndN3s = sp.utilities.lambdify([r, s], dN3s, "numpy")
# ndN4s = sp.utilities.lambdify([r, s], dN4s, "numpy")

# ##gerando a matriz dNdx analítica ---------------------------------------------------------------------------
# x1 = sp.Symbol('x1')
# y1 = sp.Symbol('y1')
# x2 = sp.Symbol('x2')
# y2 = sp.Symbol('y2')
# x3 = sp.Symbol('x3')
# y3 = sp.Symbol('y3')
# x4 = sp.Symbol('x4')
# y4 = sp.Symbol('y4')

# #Matriz dos nós de um elemento
# Xe = sp.Matrix([[x1, y1],[x2, y2], [x3, y3], [x4, y4]])
# #Matriz das derivadas das funções de interpolação do elemento padrão no sistema r s
# dNds = sp.Matrix([[dN1r, dN1s], [dN2r, dN2s], [dN3r, dN3s], [dN4r, dN4s]])

# #Jacobiano analítico
# J = Xe.T * dNds
# JI = J.inv()

# #derivadas das funções de interpolação do elemento no sistema local x y
# dNdx = dNds * JI

# dNdrsPG1 = np.array([[ndN1r(1/np.sqrt(3), 1/np.sqrt(3)), ndN1s(1/np.sqrt(3), 1/np.sqrt(3))],
#                      [ndN2r(1/np.sqrt(3), 1/np.sqrt(3)), ndN2s(1/np.sqrt(3), 1/np.sqrt(3))],
#                      [ndN3r(1/np.sqrt(3), 1/np.sqrt(3)), ndN3s(1/np.sqrt(3), 1/np.sqrt(3))],
#                      [ndN4r(1/np.sqrt(3), 1/np.sqrt(3)), ndN4s(1/np.sqrt(3), 1/np.sqrt(3))]])
# dNdrsPG2 = np.array([[ndN1r(-1/np.sqrt(3), 1/np.sqrt(3)), ndN1s(-1/np.sqrt(3), 1/np.sqrt(3))],
#                      [ndN2r(-1/np.sqrt(3), 1/np.sqrt(3)), ndN2s(-1/np.sqrt(3), 1/np.sqrt(3))],
#                      [ndN3r(-1/np.sqrt(3), 1/np.sqrt(3)), ndN3s(-1/np.sqrt(3), 1/np.sqrt(3))],
#                      [ndN4r(-1/np.sqrt(3), 1/np.sqrt(3)), ndN4s(-1/np.sqrt(3), 1/np.sqrt(3))]])
# dNdrsPG3 = np.array([[ndN1r(-1/np.sqrt(3), -1/np.sqrt(3)), ndN1s(-1/np.sqrt(3), -1/np.sqrt(3))],
#                      [ndN2r(-1/np.sqrt(3), -1/np.sqrt(3)), ndN2s(-1/np.sqrt(3), -1/np.sqrt(3))],
#                      [ndN3r(-1/np.sqrt(3), -1/np.sqrt(3)), ndN3s(-1/np.sqrt(3), -1/np.sqrt(3))],
#                      [ndN4r(-1/np.sqrt(3), -1/np.sqrt(3)), ndN4s(-1/np.sqrt(3), -1/np.sqrt(3))]])
# dNdrsPG4 = np.array([[ndN1r(1/np.sqrt(3), -1/np.sqrt(3)), ndN1s(-1/np.sqrt(3), -1/np.sqrt(3))],
#                      [ndN2r(1/np.sqrt(3), -1/np.sqrt(3)), ndN2s(-1/np.sqrt(3), -1/np.sqrt(3))],
#                      [ndN3r(1/np.sqrt(3), -1/np.sqrt(3)), ndN3s(-1/np.sqrt(3), -1/np.sqrt(3))],
#                      [ndN4r(1/np.sqrt(3), -1/np.sqrt(3)), ndN4s(-1/np.sqrt(3), -1/np.sqrt(3))]])

# def Jnum(Xe, pg):
#     r = pg[0]
#     s = pg[1]
#     x1 = Xe[0,0]
#     y1 = Xe[1,0]
#     x2 = Xe[0,1]
#     y2 = Xe[1,1]
#     x3 = Xe[0,2]
#     y3 = Xe[1,2]
#     x4 = Xe[0,3]
#     y4 = Xe[1,3]
#     return np.array([[x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4), x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4)],
#                    [y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4), y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)]])

# Xe1 = np.array([[150, 0, 0, 150],
#                [170, 170, 0, 0]])

# Xe2 = np.array([[150, 0, 0, 150],
#                [340, 340, 170, 170]])

# Xe3 = np.array([[150, 0, 0, 150],
#                [510, 510, 340, 340]])

# Xe4 = np.array([[150, 0, 0, 150],
#                [680, 680, 510, 510]])

# Xe5 = np.array([[150, 0, 0, 150],
#                [850, 850, 680, 680]])

# PG = np.array([[0.5773502691896258, 0.5773502691896258],
#                [-0.5773502691896258, 0.5773502691896258],
#                [-0.5773502691896258, -0.5773502691896258],
#                [0.5773502691896258, -0.5773502691896258]])

# Xet = np.array([[90, 50, 0, 100],
#                [110, 90, 0, 30]])

# J1_p1 = Jnum(Xe1, PG[0])
# J1_p2 = Jnum(Xe1, PG[1])
# J1_p3 = Jnum(Xe1, PG[2])
# J1_p4 = Jnum(Xe1, PG[3])

# J2_p1 = Jnum(Xe2, PG[0])
# J2_p2 = Jnum(Xe2, PG[1])
# J2_p3 = Jnum(Xe2, PG[2])
# J2_p4 = Jnum(Xe2, PG[3])

# J3_p1 = Jnum(Xe3, PG[0])
# J3_p2 = Jnum(Xe3, PG[1])
# J3_p3 = Jnum(Xe3, PG[2])
# J3_p4 = Jnum(Xe3, PG[3])

# J4_p1 = Jnum(Xe4, PG[0])
# J4_p2 = Jnum(Xe4, PG[1])
# J4_p3 = Jnum(Xe4, PG[2])
# J4_p4 = Jnum(Xe4, PG[3])

# J5_p1 = Jnum(Xe5, PG[0])
# J5_p2 = Jnum(Xe5, PG[1])
# J5_p3 = Jnum(Xe5, PG[2])
# J5_p4 = Jnum(Xe5, PG[3])

# Jt_p1 = Jnum(Xet, PG[0])
# Jt_p2 = Jnum(Xet, PG[1])
# Jt_p3 = Jnum(Xet, PG[2])
# Jt_p4 = Jnum(Xet, PG[3])

# JnumInv = np.linalg.inv(J1_p1)
# dNdxyPG1 = np.matmul(dNdrsPG1, JnumInv)
# dNdxyPG2 = np.matmul(dNdrsPG2, JnumInv)
# dNdxyPG3 = np.matmul(dNdrsPG3, JnumInv)
# dNdxyPG4 = np.matmul(dNdrsPG4, JnumInv)

# BPG1 = np.array([[dNdxyPG1[0,0],   0, dNdxyPG1[1,0],   0, dNdxyPG1[2,0],   0, dNdxyPG1[3,0],   0],
#                  [  0, dNdxyPG1[0,1],   0, dNdxyPG1[1,1],   0, dNdxyPG1[2,1],   0, dNdxyPG1[3,1]],
#                  [dNdxyPG1[0,1], dNdxyPG1[0,0], dNdxyPG1[1,1], dNdxyPG1[1,0], dNdxyPG1[2,1], dNdxyPG1[2,0], dNdxyPG1[3,1], dNdxyPG1[3,0]]])
# BPG2 = np.array([[dNdxyPG2[0,0],   0, dNdxyPG2[1,0],   0, dNdxyPG2[2,0],   0, dNdxyPG2[3,0],   0],
#                  [  0, dNdxyPG2[0,1],   0, dNdxyPG2[1,1],   0, dNdxyPG2[2,1],   0, dNdxyPG2[3,1]],
#                  [dNdxyPG2[0,1], dNdxyPG2[0,0], dNdxyPG2[1,1], dNdxyPG2[1,0], dNdxyPG2[2,1], dNdxyPG2[2,0], dNdxyPG2[3,1], dNdxyPG2[3,0]]])
# BPG3 = np.array([[dNdxyPG3[0,0],   0, dNdxyPG3[1,0],   0, dNdxyPG3[2,0],   0, dNdxyPG3[3,0],   0],
#                  [  0, dNdxyPG3[0,1],   0, dNdxyPG3[1,1],   0, dNdxyPG3[2,1],   0, dNdxyPG3[3,1]],
#                  [dNdxyPG3[0,1], dNdxyPG3[0,0], dNdxyPG3[1,1], dNdxyPG3[1,0], dNdxyPG3[2,1], dNdxyPG3[2,0], dNdxyPG3[3,1], dNdxyPG3[3,0]]])
# BPG4 = np.array([[dNdxyPG4[0,0],   0, dNdxyPG4[1,0],   0, dNdxyPG4[2,0],   0, dNdxyPG4[3,0],   0],
#                  [  0, dNdxyPG4[0,1],   0, dNdxyPG4[1,1],   0, dNdxyPG4[2,1],   0, dNdxyPG4[3,1]],
#                  [dNdxyPG4[0,1], dNdxyPG4[0,0], dNdxyPG4[1,1], dNdxyPG4[1,0], dNdxyPG4[2,1], dNdxyPG4[2,0], dNdxyPG4[3,1], dNdxyPG4[3,0]]])

# ## vetor de forças nodais equivalentes de corpo --------------------------------------------------------------
# Nest = sp.Matrix([[ N[0],    0, N[1],    0, N[2],    0, N[3],    0 ],
#                   [ 0,    N[0],    0, N[1],    0, N[2],    0, N[3] ]])
# Np = [ np.array(Nest.subs({r: PG[0,0], s: PG[0,1]}), dtype=float).T,
#        np.array(Nest.subs({r: PG[1,0], s: PG[1,1]}), dtype=float).T,
#        np.array(Nest.subs({r: PG[2,0], s: PG[2,1]}), dtype=float).T,
#        np.array(Nest.subs({r: PG[3,0], s: PG[3,1]}), dtype=float).T ]

# fe = np.zeros((8,1))
# gamma = np.array([[0 ], [-0.000025]])
# for e in Np:
#     fe += np.matmul(e, gamma) * 20. * 6375.
# #------------------------------------------------------------------------------------------------------------

# ##geração da malha via GMSH API ------------------------------------------------------------------------------------------------------
# #gmsh.initialize()
# #
# #gmsh.option.setNumber("General.Terminal", 1) #Should information be printed on the terminal (if available)? 1 sim 0 não
# #gmsh.option.setNumber("Mesh.Algorithm", 8) #2D mesh algorithm (1: MeshAdapt, 2: Automatic, 5: Delaunay, 6: Frontal-Delaunay, 7: BAMG, 8: Frontal-Delaunay for Quads, 9: Packing of Parallelograms)
# #gmsh.option.setNumber("Mesh.RecombinationAlgorithm", 3) #Mesh recombination algorithm (0: simple, 1: blossom, 2: simple full-quad, 3: blossom full-quad)
# #gmsh.option.setNumber("Mesh.SecondOrderExperimental", 1) #Element order
# #gmsh.option.setNumber("Mesh.SecondOrderLinear", 1) #Should second order nodes (as well as nodes generated with subdivision algorithms) simply be created by linear interpolation?
# #gmsh.option.setNumber("Mesh.CharacteristicLengthMin", 75) #Minimum mesh element size
# #gmsh.option.setNumber("Mesh.CharacteristicLengthMax", 75) #Maximum mesh element size
# #gmsh.option.setNumber("Mesh.Format", 16) #Mesh output format (1: msh, 2: unv, 10: auto, 16: vtk, 19: vrml, 21: mail, 26: pos stat, 27: stl, 28: p3d, 30: mesh, 31: bdf, 32: cgns, 33: med, 34: diff, 38: ir3, 39: inp, 40: ply2, 41: celum, 42: su2, 47: tochnog, 49: neu, 50: matlab)
# #
# #gmsh.model.add("parede") #Add a new model, with name "name", and set it as the current model.
# #
# #
# #gmsh.model.geo.addPoint(0, 0, 0, 0, 1) #parametros (x, y, z, meshSize, tag) meshSize is > 0, add a meshing constraint at that point. If tag is positive, set the tag explicitly; otherwise a new tag is selected automatically.
# #gmsh.model.geo.addPoint(150, 0, 0, 0, 2)
# #gmsh.model.geo.addPoint(150, 850, 0, 0, 3)
# #gmsh.model.geo.addPoint(0, 850, 0, 0, 4)
# #
# #gmsh.model.geo.addLine(1, 2, 1) #parametros (startTag, endTag, tag) Add a straight line segment between the two points with tags startTag and endTag. If tag is positive, set the tag explicitly.
# #gmsh.model.geo.addLine(2, 3, 2)
# #gmsh.model.geo.addLine(3, 4, 3)
# #gmsh.model.geo.addLine(4, 1, 4)
# #
# #gmsh.model.geo.addCurveLoop([1, 2, 3, 4], 1) #parametros (curveTags, tag) Add a curve loop (a closed wire) formed by the curves curveTags. curveTags should contain (signed) tags of model enties of dimension 1 forming a closed loop: a negative tag signifies that the underlying curve is considered with reversed orientation. If tag is positive, set the tag explicitly
# #
# #gmsh.model.geo.addPlaneSurface([1], 1) #parametros (wireTags, tag) Add a plane surface defined by one or more curve loops wireTags. The first curve loop defines the exterior contour; additional curve loop define holes. If tag is positive, set the tag explicitly
# #
# #gmsh.model.geo.synchronize() #Synchronize the built-in CAD representation with the current Gmsh model.
# #
# #
# #gmsh.model.mesh.generate(2) # Generate a mesh of the current model, up to dimension dim (0, 1, 2 or 3)
# #gmsh.model.mesh.recombine() # Recombine the mesh of the current model, usei para fazer os quads
# #
# #teste = gmsh.model.mesh.getElements()
# #
# ##gmsh.write('teste.vtk')
# #
# ##mesh = gmsh_api.Mesh.from_gmsh(gmsh)
# ##gmsh.finalize()
# #
# ##print(mesh.nodes)
# ##print(mesh.elements)
# #--------------------------------------------------------------------------------------------------------------------------

# #### iniciando do código numérico ---------------------------------------------------------------------------------------------------------------------
# #def dNdx(Xe, pg):
# #    '''
# #    Função para a determinação da matriz das derivadas das funções de interpolação já no sistema x y e do jacobiano
# #
# #    Parâmetros
# #    ----------
# #
# #    Xe: array numpy com as coordenadas de cada nó dos elementos dispostas no sentido horário, com o primeiro nó o correspondente ao segundo quadrante
# #
# #    >>>
# #        2 ----- 1
# #        |       |
# #        |       |
# #        3-------4
# #
# #    >>> Xe = np.array([ [x1, y1], [x2, y2], [x3, y3], [x4, y4] ])
# #
# #    pg: coordenadas do ponto de gauss utilizado
# #
# #    >>> pg = np.array([ [xpg, ypg] ])
# #
# #    retorna a matriz B para cada ponto de gauss
# #    '''
# #    r = pg[0]
# #    s = pg[1]
# #    x1 = Xe[0,0]
# #    y1 = Xe[0,1]
# #    x2 = Xe[1,0]
# #    y2 = Xe[1,1]
# #    x3 = Xe[2,0]
# #    y3 = Xe[2,1]
# #    x4 = Xe[3,0]
# #    y4 = Xe[3,1]
# #
# #    J = np.array([ [x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4), x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4)],
# #                    [y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4), y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)]])
# #
# #    dNdx = np.array([ [ (r/4 + 1/4)*(-y1*(s/4 + 1/4) - y2*(-s/4 - 1/4) - y3*(s/4 - 1/4) - y4*(-s/4 + 1/4))/(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4))) + (s/4 + 1/4)*(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(-y1*(s/4 + 1/4) - y2*(-s/4 - 1/4) - y3*(s/4 - 1/4) - y4*(-s/4 + 1/4)) - (x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)))/((-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)))*(x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))),   (r/4 + 1/4)*(x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))/(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4))) - (s/4 + 1/4)*(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))/(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)))],
# #                       [(-r/4 + 1/4)*(-y1*(s/4 + 1/4) - y2*(-s/4 - 1/4) - y3*(s/4 - 1/4) - y4*(-s/4 + 1/4))/(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4))) + (-s/4 - 1/4)*(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(-y1*(s/4 + 1/4) - y2*(-s/4 - 1/4) - y3*(s/4 - 1/4) - y4*(-s/4 + 1/4)) - (x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)))/((-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)))*(x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))), (-r/4 + 1/4)*(x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))/(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4))) - (-s/4 - 1/4)*(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))/(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)))],
# #                       [  (r/4 - 1/4)*(-y1*(s/4 + 1/4) - y2*(-s/4 - 1/4) - y3*(s/4 - 1/4) - y4*(-s/4 + 1/4))/(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4))) + (s/4 - 1/4)*(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(-y1*(s/4 + 1/4) - y2*(-s/4 - 1/4) - y3*(s/4 - 1/4) - y4*(-s/4 + 1/4)) - (x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)))/((-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)))*(x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))),   (r/4 - 1/4)*(x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))/(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4))) - (s/4 - 1/4)*(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))/(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)))],
# #                       [(-r/4 - 1/4)*(-y1*(s/4 + 1/4) - y2*(-s/4 - 1/4) - y3*(s/4 - 1/4) - y4*(-s/4 + 1/4))/(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4))) + (-s/4 + 1/4)*(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(-y1*(s/4 + 1/4) - y2*(-s/4 - 1/4) - y3*(s/4 - 1/4) - y4*(-s/4 + 1/4)) - (x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)))/((-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)))*(x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))), (-r/4 - 1/4)*(x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))/(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4))) - (-s/4 + 1/4)*(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))/(-(x1*(r/4 + 1/4) + x2*(-r/4 + 1/4) + x3*(r/4 - 1/4) + x4*(-r/4 - 1/4))*(y1*(s/4 + 1/4) + y2*(-s/4 - 1/4) + y3*(s/4 - 1/4) + y4*(-s/4 + 1/4)) + (x1*(s/4 + 1/4) + x2*(-s/4 - 1/4) + x3*(s/4 - 1/4) + x4*(-s/4 + 1/4))*(y1*(r/4 + 1/4) + y2*(-r/4 + 1/4) + y3*(r/4 - 1/4) + y4*(-r/4 - 1/4)))]])
# #    B1x = dNdx[0,0]
# #    B1y = dNdx[0,1]
# #    B2x = dNdx[1,0]
# #    B2y = dNdx[1,1]
# #    B3x = dNdx[2,0]
# #    B3y = dNdx[2,1]
# #    B4x = dNdx[3,0]
# #    B4y = dNdx[3,1]
# #    B = np.array([[B1x,   0, B2x,   0, B3x,   0, B4x,   0],
# #                  [  0, B1y,   0, B2y,   0, B3y,   0, B4y],
# #                  [B1y, B1x, B2y, B2x, B3y, B3x, B4y, B4x]])
# #    return B, J
# #
# #def ke(Xe, E, nu, t):
# #    '''
# #    Função para a geração das matrizes de rigidez dos elementos função das coordenadas dos elementos no sistema global, o módulo de elasticidade
# #    do material (E), o corficiente de poisson do material (nu) e da espessura (t), considerando 4 pontos de gauss para a integração
# #
# #    Parâmetros
# #    ----------
# #
# #    Xe: array numpy com as coordenadas de cada nó dos elementos dispostas no sentido antihorário, com o primeiro nó o correspondente ao primeiro quadrante.
# #
# #    >>> Xe = np.array([ [x1, y1], [x2, y2], [x3, y3], [x4, y4] ])
# #    '''
# #    #matriz constitutiva do material
# #    D = E/(1 - nu**2) * np.array([[1, nu, 0],
# #                                  [nu, 1, 0],
# #                                  [0, 0, (1 - nu**2)/(2 + 2*nu)]])
# #    #número de graus de liberdade por elemento
# #    GLe = 8
# #    #coordenadas e pesos dos pontos de Gauss
# #    PG = np.array([[0.5773502691896258, 0.5773502691896258],
# #                   [-0.5773502691896258, 0.5773502691896258],
# #                   [-0.5773502691896258, -0.5773502691896258],
# #                   [0.5773502691896258, -0.5773502691896258]])
# #    wPG = np.array([[1., 1.],
# #                    [1., 1.],
# #                    [1., 1.],
# #                    [1., 1.]])
# #    Be = []
# #    Ke = np.zeros((GLe, GLe))
# #    for p in range(PG.shape[0]):
# #        B, J = dNdx(Xe, PG[p])
# #        Be.append(B)
# #        Ke += np.matmul( np.matmul(np.transpose(B), D), B) * wPG[p, 0] * wPG[p, 1] * np.linalg.det(J) * t
# #    return Ke, Be
# #
# ##coordenadas dos nós da estrutura
# #NOS = np.array([ [0., 0.],
# #                 [150., 0.],
# #                 [0., 170.],
# #                 [150., 170.],
# #                 [0., 340.],
# #                 [150., 340.],
# #                 [0., 510.],
# #                 [150., 510.],
# #                 [0., 680.],
# #                 [150., 680.],
# #                 [0., 850.],
# #                 [150., 850.]])
# #
# ##incidência dos elementos !!! DEVE SEGUIR A ORDEM DAS FUNÇÕES DE INTERPOLAÇÃO DEFINIDA NA FUNÇÃO dNdx !!!
# #IE = np.array([[ 3,  2,  0,  1],
# #               [ 5,  4,  2,  3],
# #               [ 7,  6,  4,  5],
# #               [ 9,  8,  6,  7],
# #               [11, 10,  8,  9]])
# #
# ##malha de elementos
# #Xe = []
# #for e in IE:
# #    Xe.append( np.array([ NOS[e[0]], NOS[e[1]], NOS[e[2]], NOS[e[3]] ]) )
# #
# ##propriedades mecânicas do material da estrutura e espessura
# #E = 33130.0468 #kN/cm2
# #nu = 0.2
# #t = 20. #cm
# ##resistência a compressão e a tração para aplicação do critério de Christensen, concreto C35
# #Sc = 35. #kN/cm2
# #St = 3.5 #kN/cm2
# ##coesão e o ângulo de atrito para os critérios de Mohr-Coulomb e Drucker-Prager (http://www.pcc.usp.br/files/text/publications/BT_00231.pdf)
# #phi = 51. * np.pi/180.
# #coesao = 0.00073 #kN/cm2
# #
# ##determinação da matriz de rigidez dos elementos
# #Ke1, Be1 = ke(Xe[0], E, nu, t)
# #Ke2, Be2 = ke(Xe[1], E, nu, t)
# #Ke3, Be3 = ke(Xe[2], E, nu, t)
# #Ke4, Be4 = ke(Xe[3], E, nu, t)
# #Ke5, Be5 = ke(Xe[4], E, nu, t)
# #
# ##indexação dos graus de liberdade
# #ID1 = np.repeat(IE[0]*2, 2) + np.tile(np.array([0, 1]), 4)
# #ID2 = np.repeat(IE[1]*2, 2) + np.tile(np.array([0, 1]), 4)
# #ID3 = np.repeat(IE[2]*2, 2) + np.tile(np.array([0, 1]), 4)
# #ID4 = np.repeat(IE[3]*2, 2) + np.tile(np.array([0, 1]), 4)
# #ID5 = np.repeat(IE[4]*2, 2) + np.tile(np.array([0, 1]), 4)
# #
# ##graus de liberdade da estrutura
# #GL = NOS.shape[0]*2
# #DOF = GL - 4
# #
# ##montagem da matriz de rigidez da estrutura
# #K = np.zeros((GL, GL))
# #for i in range(8):
# #    for j in range(8):
# #        K[ ID1[i], ID1[j] ] += Ke1[i, j]
# #        K[ ID2[i], ID2[j] ] += Ke2[i, j]
# #        K[ ID3[i], ID3[j] ] += Ke3[i, j]
# #        K[ ID4[i], ID4[j] ] += Ke4[i, j]
# #        K[ ID5[i], ID5[j] ] += Ke5[i, j]
# #
# ##separação das matrizes de rigidez
# #Ku = K[:DOF, :DOF]
# #Kr = K[DOF:, :DOF]
# #
# ##vetor de forças nodais
# #F = np.zeros(GL)
# #F[7] = -150. #kN
# #F[15] = -150. #kN
# #
# #Fu = F[:DOF]
# #Fr = F[DOF:]
# #
# #Uu = np.linalg.solve(Ku, Fu)
# #Rr = np.matmul(Kr, Uu) - Fr
# #
# #U = np.zeros(GL)
# #U[:DOF] = Uu
# #
# #Uxy = U.reshape(NOS.shape)
# #
# ###visualização dos deslocamentos ---------------------------------------------------------------------------------------------------------------------
# ##fig = go.Figure(data = go.Contour(z=Uxy[:,0], x=NOS[:,0], y=NOS[:,1], colorscale='Jet', contours=dict(
# ##            showlabels = True, # show labels on contours
# ##            labelfont = dict(size = 12, color = 'white') ) ) )
# ##fig.update_layout(title="Deslocamentos em X", autosize=True, width=1200, height=400)
# ##fig.write_html('deslocamentos.html')
# #
# ###visualização dos vetores de deslocamentos dos nós
# ##fig = plty.figure_factory.create_quiver(NOS[:,0], NOS[:,1], Uxy[:,0], Uxy[:,1])
# ##fig.write_html('deslocamentosVetor.html')
# #
# ###geração do arquivo vtu
# ##pontos = NOS
# ##celulas = {'quad': IE}
# ##meshio.write_points_cells(
# ##        "teste.vtu",
# ##        pontos,
# ##        celulas,
# ##        # Optionally provide extra data on points, cells, etc.
# ##        point_data = {"U": Uxy},
# ##        # cell_data=cell_data,
# ##        # field_data=field_data
# ##        )
# #
# ##-----------------------------------------------------------------------------------------------------------------------------------------------------
# #
# ##determinação dos deslocamentos por elemento
# #Ue = []
# #Ue.append( U[ID1] )
# #Ue.append( U[ID2] )
# #Ue.append( U[ID3] )
# #Ue.append( U[ID4] )
# #
# #
# ##determinação das deformações por ponto de Gauss -----------------------------------------------------------------------------------------------------
# #epsilon1 = []
# #epsilon2 = []
# #epsilon3 = []
# #epsilon4 = []
# #for b in range(4): #range na quantidade de pontos de Gauss
# #    epsilon1.append( np.matmul(Be1[b], Ue[0]) )
# #    epsilon2.append( np.matmul(Be2[b], Ue[1]) )
# #    epsilon3.append( np.matmul(Be3[b], Ue[2]) )
# #    epsilon4.append( np.matmul(Be4[b], Ue[3]) )
# #
# ##determinação das tensões por ponto de Gauss ---------------------------------------------------------------------------------------------------------
# ##matriz constitutiva do material
# #D = E/(1 - nu**2) * np.array([[1, nu, 0],
# #                              [nu, 1, 0],
# #                              [0, 0, (1 - nu**2)/(2 + 2*nu)]])
# #
# #sigma1 = []
# #sigma2 = []
# #sigma3 = []
# #sigma4 = []
# #for b in range(4): #range na quantidade de pontos de Gauss
# #    sigma1.append( np.matmul(D, epsilon1[b]) )
# #    sigma2.append( np.matmul(D, epsilon2[b]) )
# #    sigma3.append( np.matmul(D, epsilon3[b]) )
# #    sigma4.append( np.matmul(D, epsilon4[b]) )
# #
# ##cálculo das tensões principais nos pontos de Gauss---------------------------------------------------------------------------------------------------
# ##tensão principal máxima, tensão principal mínima, ângulo das tensões principais, tensão máxima de cisalhamento, tensão equivalente de von Mises
# #sigmaPP1 = []
# #sigmaPP2 = []
# #sigmaPP3 = []
# #sigmaPP4 = []
# #
# #def principaisPG(sigmas):
# #    '''
# #    Função para a determinação da tensão principal 1 (sigmaMAX), tensão principal 2 (sigmaMIN),
# #    ângulo das tensões principais, tensão máxima de cisalhamento, tensão equivalente de von Mises, de Christensen para materiais frágeis com
# #    sigmaC <= 0.5 sigmaT (que deve ser menor que 1), de Morh-Coulomb de Drucker-Prager para a tensão fora do plano igual a zero
# #
# #    sigmas é um array de uma dimensão contendo sigma_x, sigma_y e tau_xy
# #
# #    retorna um array de uma dimensão com as quantidades acima
# #    '''
# #    sigma_x = sigmas[0]
# #    sigma_y = sigmas[1]
# #    tay_xy = sigmas[2]
# #
# #    sigmaMAX = (sigma_x + sigma_y)/2 + np.sqrt( ((sigma_x - sigma_y)/2)**2 + tay_xy**2 )
# #    sigmaMIN = (sigma_x + sigma_y)/2 - np.sqrt( ((sigma_x - sigma_y)/2)**2 + tay_xy**2 )
# #    theta = 1./2. * np.arctan( 2*tay_xy/(sigma_x - sigma_y) )
# #    tauMAX = (sigmaMAX - sigmaMIN)/2
# #    sigmaEQvM = np.sqrt( sigmaMAX**2 - sigmaMAX*sigmaMIN + sigmaMIN**2 )
# #    sigmaEQc = (1/St - 1/Sc)*(sigmaMAX + sigmaMIN) + 1/(St*Sc)*(sigmaMAX**2 - sigmaMAX*sigmaMIN + sigmaMIN**2)
# #    sigmaEQmc = 2*( (sigmaMAX + sigmaMIN)/2.*np.sin(phi) + coesao*np.cos(phi) )/(sigmaMAX - sigmaMIN)
# #    A = 2*1.4142135623730951*np.sin(phi)/(3 - np.sin(phi))
# #    B = 3.*coesao*np.cos(phi)/np.sin(phi)
# #    sigmaEQdp = ( (sigmaMAX - sigmaMIN)**2 + sigmaMAX**2 + sigmaMIN**2 )/( A**2*(sigmaMAX + sigmaMIN + B)**2 )
# #
# #    return np.array([ sigmaMAX, sigmaMIN, theta, tauMAX, sigmaEQvM, sigmaEQc, sigmaEQmc, sigmaEQdp ])
# #
# #for p in range(4):
# #    sigmaPP1.append( principaisPG(sigma1[p]) )
# #    sigmaPP2.append( principaisPG(sigma2[p]) )
# #    sigmaPP3.append( principaisPG(sigma3[p]) )
# #    sigmaPP4.append( principaisPG(sigma4[p]) )
# #
##cálculo das tensões nos nós, interpolando com as funções de interpolação dos elementos


import matplotlib.pylab as plt
from numpy import pi, linspace, sin, cos, append

def save_plt(plt, filename):
    fig = plt.gcf()
    fig_size = fig.get_size_inches()
    fig.set_size_inches(fig_size[0] * 2, fig_size[1] * 2)
    fig.savefig('{}.png'.format(filename), dpi=100)

def _motion_back(_x, _t):
    return _t/_x - 1/(2*pi)*1/_x*sin(2*pi*_t)

def _motion_front(_x, _t):
    return cos(2*pi*(_t-_x)) + 1/(2*pi)*(1/_x)*sin(2*pi*(_t-_x))-1/(2*pi)*1/_x*sin(2*pi*_t)

def motion(_x):
    _t = linspace(0, 2*_x, 2000)
    y = append(
        _motion_back(_x, _t[:500]), _motion_front(_x, _t[500:])
    )
    return _t, y

x = 2, 12
motion_12 = motion(12)
motion_2 = motion(2)

plt.figure(1)
plt.xlabel('t/T_n')
plt.ylabel('R_d')
plt.title('Problem 2 A')
plt.plot(motion_2[0], motion_2[1])

save_plt(plt, 'Problem_2_A')

plt.figure(2)
plt.xlabel('t/T_n')
plt.ylabel('R_d')
plt.title('Problem 2 B')
plt.plot(motion_12[0], motion_12[1])

save_plt(plt, 'Problem_2_B')


# -*- coding: utf-8 -*-
"""
Created on Sun May 10 13:15:08 2020

@author: CodeAndQuarks
Desc: A modified derivative calculator I made in my final year.*
      *Still in development for improvement
      Written in Python 3.7.1
"""
#Imports
import numpy as np
from matplotlib import pyplot as plt
#-----------------------------------------------------------------------------
#functions for plotting
def derivative_2nd(f,x,h):
    """function to calaculate 2nd derivative"""
    h = float(h)
    func=f(x)
    return (f(x+h)-(2*func)+(f(x-h)))/(h*h)

def three_point_derivative(f,x,h):
    """#3-point function to calaculate 1st derivative"""
    h = float(h)
    return (1/(2*h))*(f(x-2*h) - 4*f(x-h) + 3*f(x))

def five_point_derivative(f,x,h):
    """#5-point function to calaculate 1st derivative"""
    h = float(h)
    return (1/(12*h))*(f(x-2*h)-f(x+2*h)-
            8*f(x-h)+8*f(x+h))
def f(x):
    """Tan(X)/X"""
    return (np.tan(x)/x)

def g(x):
    """Cos(X)/X"""
    return (np.cos(x)/x)
def k(x):
    """Sin(X)/X"""
    return (np.sin(x)/x)
def checkTitle(func, r):
    """Change title according to function in use"""
    a=f(r)
    b=g(r)
    c=k(r)
    comp=func(r)
    #.all() checks all values in each array match
    if (comp==a).all():
        Title='Tan(X)/X'
    elif (comp==b).all():
        Title='Cos(X)/X'
    elif (comp==c).all():
        Title='Sin(X)/X'
    return Title
def plotresults(func, x1, x2):
    """Graph Function"""
    #create range
    r = np.linspace(x1, x2,1000)
    #update title
    Title=''+checkTitle(func,r)
    plt.figure()
    plt.plot(r,func(r),'b')
    plt.plot(r,three_point_derivative(func,r,h),'r--')
    plt.plot(r,derivative_2nd(func,r,h),'g')
    plt.plot(r,five_point_derivative(func,r,h),'m--')
    plt.xlim(x1,x2)
    plt.ylim(-0.45,1)

    #label axis and title
    plt.xlabel('x',fontsize=14,color='r')
    plt.ylabel('y',fontsize=14,color='r')
    plt.title(r''+Title+' Point Derivatives',color='r')
    #set y-axis limit
    plt.legend(["f(x)", " 3-point derivative","d2f/dx", '5-point derivative'],
            loc='upper right')
    #format grid
    ax = plt.gca()
    ax.grid(True)
    #draw to memory
    plt.draw()
    #show graph
    plt.show()

#------------------------------------------------------------------------------
#take h=0.01
h=0.01
#Take in user input for a range of  values
x1=int(input('Please set X1, for range x1<=X<=x2, example, -20:'))
x2=int(input('Please set X2, for range x1<=X<=x2, example,  20:'))
try:
    if x2<=x1:
       #error check
       x2=x1+10
       print('X1>=X2, X2 has been altered to provide suitable visuals')
    #Plotting
    plotresults(f, x1,x2)
    plotresults(g, x1,x2)
    plotresults(k, x1,x2)
except ValueError:
    x1=-20
    x2=20
    print('ValueError generated, (X1,X2) has defaulted to (-20,20)')
    #Plotting
    plotresults(f, x1,x2)
    plotresults(g, x1,x2)
    plotresults(k, x1,x2)


import numpy as np
np.random.seed(0)
L = np.random.random(100)
print(np.sum(L))
big_array = np.random.random(1000000)
#%timeit sum(big_array)
#timeit np.sum(big_array)

#sum != np.sum

#min and max
print(min(big_array))
print(max(big_array))
print((np.min(big_array), np.max(big_array)))
#shorter syntax
print(big_array.sum(), big_array.min(), big_array.max())

#multi dimensional aggragates
M = np.random.random((3,4))
print(M)

print(M.sum())
print(M.min(axis=0)) #min in each row
print(M.min(axis=1)) #min in each collum

#axis is the dimension collapsed not returned
#hence axis=0 collapses along the first dimension, aggregating each collum in a 2d array

#example, avg height of us presidents

import pandas as pd
data = pd.read_csv('data/president_heights.csv')
heights = np.array(data['height(cm)'])
print(heights)


import logging
from typing import Tuple
from numpy import pi, exp, sin, linspace, ndarray
from numpy.random import randint, uniform

from problems.test_case import TestCase, TestCaseTypeEnum
from problems.solutions.definite_integrals import area_of_rectangles

logger = logging.getLogger(__name__)

FUNCTION_NAME = "area_of_rectangles"
INPUT_VARS = ['rectangle_heights', 'rectangle_width']
OUTPUT_VARS = ['area']

STATIC_RESOURCES = []

PHYSICAL_CONSTANTS = {}
ATOL = {
    'area': 1e-6
}
RTOL = {}

class TestCaseType(TestCaseTypeEnum):
    ZERO = ("Zero function (rectangles with no height)", 1)
    CONSTANT = ("Constant function (all rectangles have the same height)", 1)
    LINEAR = ("Linear function", 1)
    QUADRATIC = ("Quadratic polynomial", 1)
    EXPONENTIAL = ("Exponential function", 1)
    SINE = ("Sine function", 1)
    RANDOM = ("Random function", 1)

class ProblemTestCase(TestCase):
    def input_tuple(self) -> tuple:
        return self.input['rectangle_heights'], self.input['rectangle_width']

    def output_tuple(self) -> tuple:
        return self.output['area'],

def generate_test_case(test_type: TestCaseType) -> ProblemTestCase:
    test_case = ProblemTestCase(test_type)

    if test_type is TestCaseType.ZERO:
        N = randint(5, 10)
        f = [0.0 for _ in range(N)]
        dx = 1

    elif test_type is TestCaseType.CONSTANT:
        N = randint(5, 10)
        c = uniform(-5, 5)
        f = [c for _ in range(N)]
        dx = 1

    elif test_type is TestCaseType.LINEAR:
        N = randint(10, 20)
        x1, x2 = uniform(0, 2), uniform(3, 5)
        dx = (x2 - x1) / N

        a, b = uniform(-5, 5), uniform(-5, 5)
        f = [a*x + b for x in linspace(x1, x2, N)]

    elif test_type is TestCaseType.QUADRATIC:
        N = randint(15, 30)
        x1, x2 = uniform(-5, -1), uniform(2, 5)
        dx = (x2 - x1) / N

        a, b, c = uniform(-1, 1), uniform(-1, 1), uniform(-1, 1)
        f = [a*x**2 + b*x + c for x in linspace(x1, x2, N)]

    elif test_type is TestCaseType.EXPONENTIAL:
        N = randint(20, 40)
        x1, x2 = 0, uniform(3, 5)
        dx = (x2 - x1) / N
        f = [exp(x) for x in linspace(x1, x2, N)]

    elif test_type is TestCaseType.SINE:
        N = randint(50, 75)
        x1, x2 = 0, 2*pi
        dx = (x2 - x1) / N
        f = [sin(x) for x in linspace(x1, x2, N)]

    elif test_type is TestCaseType.RANDOM:
        N = randint(40, 60)
        x1, x2 = 0, 1
        dx = (x2 - x1) / N
        f = uniform(-1, 1, size=N).tolist()

    else:
        raise ValueError(f"Unrecognized test case: {test_type}")

    test_case.input = {
        "rectangle_heights": f,
        "rectangle_width": float(dx)
    }

    test_case.output['area'] = float(area_of_rectangles(f, dx))

    return test_case


import numpy as np

"""
This is the solution for problem one of programming porject 2.
The problem is defined in the 4th edition Cryptography Theory and Practice
by Stinson and Paterson under problem 4.16.
For this whole problem we consider that the s-boxes are bijective.
"""

# Question a

def delta_set(x_prime, m):
    """
    Returns the set of all the ordered pairs having an input x-or equal
    to x_prime. It is the set of the ordered pairs (x, x_prime + x) modulo 2.
    m is the number of elements of the substitution box.
    """
    delta = set()
    for x in range(m):
        delta.add((x, x ^ x_prime))

    return delta

def table_ND(s_box):
    """
    Compute the difference distribution table ND of the s_box.
    s_box is a permutation of its indexes.
    """
    m = len(s_box)
    table = np.zeros((m, m), dtype=int)
    for x_prime in range(m):
        delta = delta_set(x_prime, m)
        for x, x_star in delta:
            y_prime = s_box[x] ^ s_box[x_star]
            table[x_prime][y_prime] += 1

    return table

s_box = [0xE, 0x2, 0x1, 0x3,
         0xD, 0x9, 0x0, 0x6,
         0xF, 0x4, 0x5, 0xA,
         0x8, 0xC, 0x7, 0xB]

serpent_s3 = [0, 15, 11, 8, 12, 9, 6, 3, 13, 1, 2, 4, 10, 7, 5, 14]
print(table_ND(serpent_s3)/16)
# Question b


# -*- coding: utf-8 -*-

from normalidad import *
from scipy.stats import jarque_bera

################################################################
#  Funciones de test
################################################################
def test_muestra_histograma():
    muestra_histograma(FRECUENCIAS)
    muestra_histograma(PESOS)
    muestra_histograma(SINTETICA)

def test_calcula_momento_central():
    # El momento central de grado 1 es 0 (o muy cercano)
    print("Momento central(1) - Frecuencias: ", calcula_momento_central(FRECUENCIAS, grado=1))
    # El momento central de grado 2 coincide con la varianza
    print("Momento central(2) - Frecuencias: ", calcula_momento_central(FRECUENCIAS), "\n")

def test_calcula_asimetria():
    # La distribución de FRECUENCIAS no es simétrica
    print("Asimetría - Frecuencias: ", calcula_asimetria(FRECUENCIAS))
    # La distribución de PESOS es simétrica
    print("Asimetría - Pesos: ", calcula_asimetria(PESOS))
    # La distribución SINTETICA es muy simétrica
    print("Asimetría - Sintética: ", calcula_asimetria(SINTETICA), "\n")

def test_calcula_curtosis():
    # La distribución de FRECUENCIAS es más 'picuda'
    print("Curtosis - Frecuencias: ", calcula_curtosis(FRECUENCIAS))
    # La distribución de PESOS es más 'acampanada'
    print("Curtosis - Pesos: ", calcula_curtosis(PESOS))
    # La distribución SINTETICA es muy 'acampanada'
    print("Curtosis - Sintética: ", calcula_curtosis(SINTETICA), "\n")

def test_calcula_jarque_bera():
    # La distribución de FRECUENCIAS 'no es normal'
    print("JarqueBera - Frecuencias: ", calcula_jarque_bera(FRECUENCIAS))
    # La distribución de PESOS 'es más normal'
    print("JarqueBera - Pesos: ", calcula_jarque_bera(PESOS))
    # La distribución SINTETICA 'es muy normal'
    print("JarqueBera - Sintética: ", calcula_jarque_bera(SINTETICA), "\n")

def test_calcula_pvalue():
    # No podemos afirmar que FRECUENCIAS es normal
    jb_frec = calcula_jarque_bera(FRECUENCIAS)
    print("Pvalue - Frecuencias: ", calcula_pvalue(jb_frec, valores_chi2_2, pvalues_chi2_2))
    # No podemos afirmar que PESOS es normal
    jb_peso = calcula_jarque_bera(PESOS)
    print("Pvalue - Pesos: ", calcula_pvalue(jb_peso, valores_chi2_2, pvalues_chi2_2))
    # Podemos afirmar que SINTETICA es normal con un nivel de significación de 0.95
    jb_sint = calcula_jarque_bera(SINTETICA)
    print("Pvalue - Sintética: ", calcula_pvalue(jb_sint, valores_chi2_2, pvalues_chi2_2))
    # Cálculo del estadístico Jarque-Bera y el pvalue con la implementación de Scipy
    print("JarqueBera/Pvalue (Scipy) - Frecuencias: ", jarque_bera(FRECUENCIAS))
    print("JarqueBera/Pvalue (Scipy) - Pesos: ", jarque_bera(PESOS))
    print("JarqueBera/Pvalue (Scipy) - Sintética: ", jarque_bera(SINTETICA))

################################################################
#  Programa principal
################################################################
FRECUENCIAS = lee_serie('../data/frecuencias.csv')
print("Frecuencias[:10] ->", FRECUENCIAS[:10])
PESOS = lee_serie('../data/pesos.csv', float)
print("Pesos[:10] ->", PESOS[:10])
SINTETICA = lee_serie('../data/1000-puntos-normal-0-1.csv', float)
print("Sintética[:10] -> ", SINTETICA[:10], "\n")

#test_muestra_histograma()
#test_calcula_momento_central()
#test_calcula_asimetria()
#test_calcula_curtosis()
#test_calcula_jarque_bera()
#test_calcula_pvalue()


"""
https://projecteuler.net/problem=4
Problem 4 - Largest palindrome product

A palindromic number reads the same both ways. The largest palindrome
made from the product of two 2-digit numbers is 9009 = 91 × 99.

Find the largest palindrome made from the product of two 3-digit numbers.
"""
#%%
import numpy as np

def check_palindrome(number):
    stringNumber = str(number)
    return stringNumber == stringNumber[::-1]

listDigits = list(range(100, 1000))
palList = []
xyList = []
for x in listDigits:
    for y in listDigits:
        if check_palindrome(x * y) == True:
            palList.append(x * y)
            xyList.append([x, y])

print(max(palList))
xyList[palList.index(max(palList))]
# %%


# Alexis Mendoza Valencia
# Estudiante Tecnológico de Monterrey, campus guadalajara

# Metodo Regresion polinomial

"""
Este método lo que busca es encontrar una linea que modele
con cierto error todos los valores posibles en una grafica.
El método funcionara aun cuando los valores tiendan a
infinito, pero siempre tendra cierto error.

Para el correcto uso de este metodo, es importante contar
con las librerias matplotlib y numpy.

Si no los tienes, te recomiendo utilizar una pagina
llamada cocalc. Abre un cuaderno de Jupyter Notebook
y el codigo funcionara a la perfeccion.

"""

import matplotlib.pyplot as plt
import numpy as np

def createMatrix(m,n,v):
    C = []
    for i in range(m):
        C.append([v]*n)
    return C

def getDimensions(A):
    return (len(A),len(A[0]))

def copyMatrix(B):
    m,n = getDimensions(B)
    A = createMatrix(m,n,0)
    for i in range(m):
        for j in range(n):
            A[i][j] = B[i][j]
    return A

def sumaMatrix(A,B):
    Am,An = getDimensions(A)
    Bm,Bn = getDimensions(B)
    if Am != Bm or An != Bn:
        print("Error las dimensiones deben ser iguales")
        return []
    C = createMatrix(Am,An,0)
    for i in range(Am):
        for j in range(An):
            C[i][j] = A[i][j] + B[i][j]
    return C

def restaMatrix(A,B):
    Am,An = getDimensions(A)
    Bm,Bn = getDimensions(B)
    if Am != Bm or An != Bn:
        print("Error las dimensiones deben ser iguales")
        return []
    C = createMatrix(Am,An,0)
    for i in range(Am):
        for j in range(An):
            C[i][j] = A[i][j] - B[i][j]
    return C

def multMatrix(A,B):
    Am,An = getDimensions(A)
    Bm,Bn = getDimensions(B)
    if An != Bm:
        print("Error las dimensiones deben ser conformable")
        return []
    C = createMatrix(Am,Bn,0)
    for i in range(Am):
        for j in range(Bn):
            for k in range(An):
                    C[i][j] += A[i][k] * B[k][j]
    return C

def getAdyacente(A,r,c):
    Am,An = getDimensions(A)
    C = createMatrix(Am-1,An-1,0)
    for i in range(Am):
        if i == r:
            continue
        for j in range(An):
            if j == c:
                continue
            ci = 0
            cj = 0
            if(i < r):
                ci = i
            else:
                ci = i - 1
            if(j < c):
                cj = j
            else:
                cj = j - 1
            C[ci][cj] = A[i][j]
    return C

def detMatrix(A):
    m,n = getDimensions(A)
    if m != n:
        print("La matriz no es cuadrada")
        return []
    if m == 1:
        return A[0][0]
    if m == 2:
        return A[0][0]*A[1][1] - A[1][0]*A[0][1]
    det = 0
    for j in range(m):
        det += ((-1)**j)*A[0][j]*detMatrix(getAdyacente(A,0,j))
    return det

def getMatrizTranspuesta(A):
    m,n = getDimensions(A)
    C = createMatrix(n,m,0)
    for i in range(m):
        for j in range(n):
            C[j][i] = A[i][j]
    return C

def getMatrizAdjunta(A):
    m,n = getDimensions(A)
    if m != n:
        print("La matriz no es cuadrada")
        return []
    C = createMatrix(m,n,0)
    for i in range(m):
        for j in range(n):
            C[i][j] = ((-1)**(i+j))*detMatrix(getAdyacente(A,i,j))
    return C

def getMatrizInversa(A):
    m,n = getDimensions(A)
    if m != n:
        print("La matriz no es cuadrada")
        return []
    detA = detMatrix(A)
    if detA == 0:
        print("La matriz no tiene inversa")
        return []
    At = getMatrizTranspuesta(A)
    adjA = getMatrizAdjunta(At)
    invDetA = 1/detA
    C = createMatrix(m,n,0)
    for i in range(m):
        for j in range(n):
            C[i][j] = invDetA * adjA[i][j]
    return C

x = [  0,  1,   2,   3,   4,   5]
y = [2.1,7.7,13.6,27.2,40.9,61.1]
plt.plot(x,y,'rx')

def regPolinominal(grado,x,y):
    grado += 1
    A = createMatrix(grado,grado,0)
    for i in range(grado):
        for j in range(grado):
            A[i][j] = sum ( xi ** (i+j) for xi in x)
    C = createMatrix(grado,1,0)
    for i in range(grado):
        C[i][0] = sum ((xi**(i))*yi  for xi,yi in zip(x,y))
    invA = getMatrizInversa(A)
    return multMatrix(invA, C)

def evalPolinomio(coef,x):
    y = []
    coef = np.asarray(coef)
    for i in range(len(x)):
        y.append(0)
        for c in range(len(coef)):
            y[i] += (x[i]**c) * coef[c]
    return y

coef = regPolinominal(2,x,y)
print("coeficientes",coef)
x2 = np.linspace(0, 5, 100)
y2 = evalPolinomio(coef,x2)
plt.plot(x2,y2)
plt.show()


import json

import numpy as np
import wandb
from matplotlib import pyplot as plt

from src.utils import draw_digit, load_data

class LeakyReLU:
	# The Leaky Rectifier function will serve as our activation function
	def __init__(self, alpha):
		self.alpha = alpha  # Parameter for the function

	def f(self, z):
		# The Leaky Rectifier is computed as:
		# f(z) = {        z,   z >= 0
		#        {alpha * z,   z < 0
		return np.where(z >= 0, z, self.alpha * z)

	def d(self, a):
		# The derivative of the function is given by:
		# f'(z) = {    1,   z >= 0 which implies f(z) >= 0
		#         {alpha,    z < 0 which implies f(z) < 0
		return np.where(a >= 0, 1, self.alpha)

def log_loss(y, a):
	# Our chosen error function is the Log Loss function.
	# This is also called the "Cross Entropy Loss" and is computed as:
	# f(a) = -y * log(a) - (1 - y) * log(1 - a)
	# i.e, -log(a) if y is 1, and -log(1 - a) if y is 0.
	return np.where(y, -np.log(a), -np.log(1 - a)).sum()

def softmax(z):
	# We offset each element of z by the maximum to prevent overflows.
	# nan_to_num is used to handle extremely small values. These are
	# made 0.
	z = np.nan_to_num(np.exp(z - np.max(z)))
	z_sum = np.sum(z)
	return np.nan_to_num(z / z_sum)

class NeuralNetwork:
	def __init__(self, ns, eta=0.5, lmbda=0, alpha=0.05):
		print(f'ns: {ns}, eta: {eta}, lambda: {lmbda}, alpha: {alpha}')
		# Network Structure
		self.n = len(ns)  # Number of layers
		self.ns = ns  # Number of neurons in each layer

		# Hyper Parameters
		self.eta = eta  # Learning rate
		self.lmbda = lmbda  # Coefficient of Regularization
		# Note: The coefficient is called "lmbda" as "lambda" is a keyword.

		# Activation Function Object
		self.act_fn = LeakyReLU(alpha)  # Parameter for LReLU

		# Log hyperparameters in wandb to analyze later.
		wandb.config.update({
			'architecture': ns, 'eta': eta, 'lambda': lmbda, 'alpha': alpha
		})

		# Randomly initialize thetas (weights) with a normal distribution
		# of mean zero and variance as the reciprocal of the number of inputs
		# received by the particular neuron.
		self.thetas = [
			np.random.randn(ns[i], ns[i - 1]) / np.sqrt(ns[i - 1])
			for i in range(1, self.n)
		]

		# Similarly, initialize the biases with a distribution of mean zero
		# and standard deviation and variance 1
		self.biases = [np.random.randn(x) for x in ns[1:]]

		# We use this performance variable to keep a track of how
		# the network is performing. We will use it plot graph(s) between
		# the number of correct predictions on the validation data and epochs.
		self.performance = []

	def predict(self, x):
		# Our prediction is simply the activations of the output (last) layer.
		return self.get_activations(x)[-1]

	def train(self, data, validation_data=None, epochs=10, batch_size=20):
		# We generate all the indices for the training data.
		# We will shuffle these indices each epoch to randomly order the data.
		# This is more efficient than zipping and shuffling the arrays directly
		perm = np.arange(len(data))
		self.performance = []
		n_validation = len(validation_data)

		# Log hyperparameters in wandb to analyze later.
		wandb.config.update({'epochs': epochs, 'batch_size': batch_size})

		if validation_data is not None:
			correct = self.validate(validation_data)
			percentage = 100 * correct / n_validation
			print(f'Initial: {correct} / {n_validation} ({percentage}%)')
			wandb.log({'epoch': 0, 'accuracy': percentage})

		for i in range(1, epochs + 1):
			np.random.shuffle(perm)

			# We split the training data in batches, each of size batch_size.
			for j in range(0, len(data), batch_size):
				# From the shuffled indices, we select a range
				# and pick all the examples in that range.
				batch = [data[x] for x in perm[j:j + batch_size]]

				# Each batch is then used to train the network
				self.train_batch(batch)

			if validation_data is not None:
				correct = self.validate(validation_data)
				percentage = 100 * correct / n_validation

				# Log the data in wandb and also locally.
				wandb.log({'epoch': i, 'accuracy': percentage})
				self.performance.append(percentage)
				print(f'Epoch {i}: {correct} / {n_validation} ({percentage}%)')

	def plot(self, filename=None):
		if not self.performance:
			return

		plt.figure()
		plt.plot(
			range(1, len(self.performance) + 1),
			self.performance, 'r'
		)
		plt.title(
			f'ns: {self.ns}, eta: {self.eta}, '
			f'lambda: {self.lmbda}, alpha: {self.act_fn.alpha}.')
		plt.xlabel('Number of Epochs')
		plt.ylabel('Prediction Accuracy (%)')
		if filename:
			plt.tight_layout()
			plt.savefig(filename)
		plt.show()

	def save(self, filename):
		# This function will save all parameters of our network.
		# We use this elaborate setup instead of simply pickling and dumping
		# the network object so that we can still use this data,
		# even if we change the architecture of our class.
		# Unpickling and loading will not work in that case.
		data = {
			'ns': self.ns,
			'eta': self.eta,
			'lmbda': self.lmbda,
			'alpha': self.act_fn.alpha,
			'performance': self.performance,
			'thetas': [t.tolist() for t in self.thetas],
			'biases': [b.tolist() for b in self.biases]
		}
		with open(filename, 'w') as f:
			json.dump(data, f)
		wandb.save(filename)

	@staticmethod
	def load(filename):
		with open(filename) as f:
			data = json.load(f)

		n = NeuralNetwork(
			data['ns'], data['eta'], data['lmbda'], data['alpha']
		)
		n.thetas = [np.array(t) for t in data['thetas']]
		n.biases = [np.array(b) for b in data['biases']]
		n.performance = data['performance']
		return n

	def validate(self, validation_data):
		# Returns the number of correct predictions
		return sum(
			np.argmax(y) == np.argmax(self.predict(x))
				for x, y in validation_data
		)

	def get_activations(self, x):
		# Validate the size of the input.
		self.validate_input(x)

		# We scale down the input to be in [0, 1].
		# Also, we add a 1 to the end to account for the bias.
		activations = [x]

		# Iterate over each layer, excluding the output layer
		for theta, bias in zip(self.thetas[:-1], self.biases[:-1]):
			# The input to this layer is the matrix product of the weights
			# associated with this layer and the activations of the previous
			# layer plus the biases.
			z = np.array(
				np.dot(theta, activations[-1]) + bias, dtype='float64'
			)

			# Apply the activation (LReLU) function to get the activations
			# for this layer, and add a 1 to the end for the bias.
			activations.append(self.act_fn.f(z))

		# For the output layer, we apply the softmax function, computed as:
		# exp(z) / sum(exp(z in zs))
		# The sum of outputs is clearly 1, which gives us
		# a useful interpretation as the 'confidence' for each possible output.
		z = np.dot(self.thetas[-1], activations[-1]) + self.biases[-1]
		activations.append(softmax(z))
		return activations

	def train_batch(self, batch):
		delta_thetas = [
			np.zeros((self.ns[i], self.ns[i - 1]))
			for i in range(1, self.n)
		]
		delta_biases = [np.zeros((x,)) for x in self.ns[1:]]

		# Iterate over all examples in the batch
		for x, y in batch:
			# Activations for the current training example
			activations = self.get_activations(x)

			# We can trivially compute the bias and weight derivatives
			# for the last layer with the help of y and the prediction.
			# These formulae are derived by applying the chain rule to
			# the softmax (activation) and the log loss (error) functions.
			difference = np.array(activations[-1] - y)
			delta_biases[-1] += difference
			delta_thetas[-1] += np.dot(
				difference.reshape((-1, 1)),
				activations[-2].reshape(1, -1)
			)

			# The derivatives array stores the derivatives of the error
			# function
			# with respect to the activations.
			# This array is used for backpropagation.
			derivatives = [np.zeros((x,)) for x in self.ns]
			# Derivative of the second last layer
			# i.e, layer before output layer
			# Change to [-2] or in init make self.ns[1:-1] since
			# input and output layers won't have derivatives.
			derivatives[-2] = np.dot(self.thetas[-1].transpose(), difference)

			# Loop over all hidden layers, backwards
			for i in range(self.n - 3, -1, -1):
				# Assign some variables to make the following code cleaner.
				a_t = activations[i].reshape((1, -1))
				theta_t = self.thetas[i].transpose()

				# We compute a term called the "error".
				# This can be considered similar to the "difference" term above
				# with the derivative of the activation function multiplied.
				error = derivatives[i + 1] * self.act_fn.d(activations[i + 1])
				error_v = error.reshape((-1, 1))

				# The following formulae used to compute the derivatives are
				# derived using the chain rule.
				# Our goal is to compute the derivatives of the error function
				# with respect to each parameter, to tweak them as necessary.
				# These values are added so as to 'accumulate' them
				# over the batch we are currently training on.
				delta_biases[i] += error
				delta_thetas[i] += np.dot(error_v, a_t)
				derivatives[i] = np.dot(theta_t, error)

		scale_factor = self.eta / len(batch)
		for i in range(self.n - 1):
			# L2 regularization term
			self.thetas[i] *= 1 - (scale_factor * self.lmbda)

			# Updates
			self.thetas[i] -= scale_factor * delta_thetas[i]
			self.biases[i] -= scale_factor * delta_biases[i]

	def validate_input(self, x):
		# This is hardly needed - it was added to serve as a sanity check
		# in the event someone forgot to "flatten" the inputs.
		if len(x) != self.ns[0]:
			raise ValueError(
				'Number of inputs != number of input neurons! '
				f'Expected: {self.ns[0]}, received: {len(x)}'
			)

def main():
	# TODO: Animated plotting to show performance change with time.
	#  check scratch.py
	# n = NeuralNetwork([784, 256, 10])
	training, validation, test = load_data()
	# n.train(training[:1000], validation[:500])
	# n.plot()

	for i in range(5):
		draw_digit(training[i][0])

if __name__ == '__main__':
	main()


import numpy as np
import matplotlib.pyplot as plt

class Approximator:
    def __init__(self, N, M, L, mu, target_func, nonLinear):
        # Training data length
        self.N = N
        # Number of neurons
        self.M = M
        # Number of update loops
        self.L = L
        # Learning rate
        self.mu = mu
        # Non-Linear function
        self.nonLinear = nonLinear
        # define training input data (points in unit line)
        self.x_data = np.linspace(0, 1, self.N)
        # Make data matrix to deal with bias
        self.X = np.array([self.x_data, np.ones(self.N)])
        # generate training data from given function f
        self.t = target_func(self.x_data)
        # initialize weights (Gaussian initialization)
        self.W = 0.1*np.random.randn(self.M,2)
        self.alpha = 0.1*np.random.randn(self.M,1)
        # to trace MSE cost function
        self.J_MSE = np.empty(self.L)

    def sigma(self, x):
        return 1/(1+np.exp(-x))

    def d_sigma(self, x):
        return self.sigma(x) * (1 - self.sigma(x))

    def relu(self, x):
        return np.maximum(0, x)

    def d_relu(self, x):
        return (x > 0).astype(int)

    def tanh(self, x):
        return (np.exp(x)-np.exp(-x)) / (np.exp(x)+np.exp(-x))

    def d_tanh(self, x):
        return 1/(1+np.power(x, 2))

    # Weight update
    def W_update(self):
        actF = eval('self.'+ self.nonLinear)
        d_actF = eval('self.'+'d_'+ self.nonLinear)
        for epoch in range(self.L):
            a = np.matmul(self.W, self.X)
            F = np.matmul(self.alpha.T, actF(a))
            d_alpha = 2*np.matmul(self.sigma(a), (F - self.t).T)/self.N
            d_W0 = 2*np.multiply(self.alpha, np.matmul(d_actF(a), np.multiply(self.x_data, (F - self.t)).T))
            d_W1 = 2*np.multiply(self.alpha, np.matmul(d_actF(a), (F - self.t).T))
            self.alpha = self.alpha-self.mu*d_alpha
            self.W = self.W-self.mu*np.concatenate((d_W0, d_W1), axis=1)
            self.J_MSE[epoch]= np.linalg.norm(F-self.t)**2
        return self.J_MSE

def simulate(N, M, L, mu, target_func, nonLinear):
    '''
    Setting (N, M, L, mu) = (Number of data, Number of neuron, Iteration number, Learning rate),
    approximating target_func using Universal Approximation Theorem. Show loss and approximation result
    '''
    _obj = Approximator(N=N, M=M, L=L, mu=mu,target_func=target_func, nonLinear=nonLinear)
    loss = _obj.W_update()
    plt.figure(1)
    plt.plot(loss)
    plt.savefig('L(N, M, L, mu, Non Linear)='+str(N)+','+str(M)+','+str(L)+','+str(mu)+','+nonLinear+'.png')

    act = eval('_obj.' + nonLinear)
    x_eval=np.linspace(0,1,2*N)
    f_eval=f_test(x_eval)
    X_eval=np.array([x_eval, np.ones(2*N)])
    F_eval=np.matmul(_obj.alpha.T, act(np.matmul(_obj.W,X_eval)))
    plt.figure(2)
    plt.plot(x_eval, f_eval)
    plt.plot(x_eval, F_eval.T)
    plt.savefig('A(N, M, L, mu, Non Linear)='+str(N)+','+str(M)+','+str(L)+','+str(mu)+','+nonLinear+'.png')
    plt.show()

## (1) cos(2 * pi * x) approximation

# define target function
def f_test(x):
    return np.cos(2*np.pi*x)

# With Logistic function
simulate(N=100, M=20, L=1000, mu=0.01, target_func=f_test, nonLinear='sigma')
simulate(N=100, M=30, L=10000, mu=0.01, target_func=f_test, nonLinear='sigma')

# With Relu
simulate(N=100, M=20, L=1000, mu=0.05, target_func=f_test, nonLinear='relu')
simulate(N=100, M=30, L=10000, mu=0.01, target_func=f_test, nonLinear='relu')

# With tanh
simulate(N=1000, M=20, L=5000, mu=0.01, target_func=f_test, nonLinear='tanh')
simulate(N=100, M=30, L=10000, mu=0.01, target_func=f_test, nonLinear='tanh')

## (2) sin(x) approximation

# define target function
def f_test(x):
    return np.sin(2*np.pi*x)

# With Logistic function
simulate(N=100, M=20, L=1000, mu=0.05, target_func=f_test, nonLinear='sigma')
simulate(N=1000, M=30, L=10000, mu=0.01, target_func=f_test, nonLinear='sigma')

# With Relu
simulate(N=100, M=20, L=1000, mu=0.05, target_func=f_test, nonLinear='relu')
simulate(N=1000, M=50, L=10000, mu=0.002, target_func=f_test, nonLinear='relu')

# With tanh
simulate(N=100, M=20, L=1000, mu=0.05, target_func=f_test, nonLinear='tanh')
simulate(N=100, M=30, L=10000, mu=0.01, target_func=f_test, nonLinear='tanh')


import tensorflow as tf
import numpy as np

# labels：和logits具有相同type和shape的张量(tensor)，,是一个有效的概率，sum(labels)=1, one_hot=True(向量中只有一个值为1.0，其他值为0.0)。
# 计算方式：对输入的logits先通过softmax函数计算，再计算它们的交叉熵，但是它对交叉熵的计算方式进行了优化，使得结果不至于溢出。
# 适用：每个类别相互独立且排斥的情况，一幅图只能属于一类，而不能同时包含一条狗和一只大象。
# output：不是一个数，而是一个batch中每个样本的loss，所以一般配合tf.reduce_mean(loss)使用。
#
# 计算公式：https://upload-images.jianshu.io/upload_images/5877934-5261229762c60598.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/717/format/webp

def softmax(x):
    sum_raw = np.sum(np.exp(x),axis=-1)
    x1 = np.ones(np.shape(x))
    for i in range(np.shape(x)[0]):
        x1[i] = np.exp(x[i])/sum_raw[i]
    return x1

y = np.array([[1,0,0],[0,1,0],[0,0,1],[1,0,0],[0,1,0]])# 每一行只有一个1
logits =np.array([[12,3,2],[3,10,1],[1,2,5],[4,6.5,1.2],[3,6,1]])
# 按计算公式计算
y_pred =softmax(logits)
E1 = -np.sum(y*np.log(y_pred),-1)
print(E1)
# 按封装方法计算
sess = tf.Session()
y = np.array(y).astype(np.float64)
E2 = sess.run(tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=logits))
print(E2)

if E1.all() == E2.all():
    print("True")
else:
    print("False")
# 输出的E1，E2结果相同


from sklearn.decomposition import PCA

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

class pca_reducer:
    def __init__(self):
        self.pca = PCA(n_components=6)

    def create_transform(self, X):
        self.transform = self.pca.fit(X)

    def info(self):
        print("explained_variance: {}".format(self.pca.explained_variance_))
        print("explained_variance_ratio: {}".format(self.pca.explained_variance_ratio_))
        print("mean: {}".format(self.pca.mean_))
        print("noise_variance: {}".format(self.pca.noise_variance_))

    def transform_enc(self, X):
        return self.transform.transform(X)

    def inverse_pca(self, X):
        return self.transform.inverse_transform(X)

    def save_transform(self,path):
        with open(path, 'wb') as f:
            pickle.dump(self.transform, f, pickle.HIGHEST_PROTOCOL)

    def load_embedder(self,path):
        with open(path, 'rb') as f:
            self.transform = pickle.load(f)

    def plot_cum_var(self):
        plt.plot(np.cumsum(self.pca.explained_variance_ratio_))
        plt.xlabel('number of components')
        plt.ylabel('cumulative explained variance')
        plt.show()

    def plot_main_components(self, set0, set1):
        fig, ax = plt.subplots(figsize=(12, 8))
        plt.scatter(
            set0[:,0], set0[:,1], c='r', cmap="Spectral", s=6.0, label="val"
        )
        plt.scatter(
            set1[:,0], set1[:,1], c='b', cmap="Spectral", s=4.0, label="train"
        )
        ax.legend()
        ax.set_xlabel("PC0: {}%".format(int(self.pca.explained_variance_ratio_[0]*100)))
        ax.set_ylabel("PC1: {}%".format(int(self.pca.explained_variance_ratio_[1]*100)))
        plt.title("PC0 vs PC1, latent space reduced by PCA", fontsize=18)
        plt.show()

    def plot_all_components(self, set0, set1):
        _, num_dim = set0.shape
        fig, axs = plt.subplots(figsize=(18, 3), ncols=num_dim)
        for id in range(num_dim):
            sns.distplot(set0[:,id], hist=False, rug=True, color="r", ax=axs[id])
            sns.distplot(set1[:,id], hist=False, rug=True, color="b", ax=axs[id])
            axs[id].yaxis.set_visible(False)
        plt.show()

if __name__ == '__main__':
    data_dir = '/home/markpp/github/latent_3d_points/scripts/output/'
    val_enc = np.load(data_dir+'val_latent.npy')[:]
    train_enc = np.load(data_dir+'train_latent.npy')[:]

    # pca dim reduction
    pca_red = pca_reducer()
    pca_red.create_transform(train_enc)
    pca_red.save_transform('pca_transform.pkl')
    train_pca = pca_red.transform_enc(train_enc)
    np.save("train_pca.npy", train_pca)
    val_pca = pca_red.transform_enc(val_enc)
    np.save("val_pca.npy", val_pca)
    #pca_red.plot_cum_var()
    pca_red.plot_main_components(val_pca[:,:],train_pca[:,:])
    pca_red.plot_all_components(val_pca[:,:],train_pca[:,:])
    pca_red.info()


# dalam aljabar linier numerik, metode jacobi adalah algoritma iteratif
# untuk menentukan solusi dari sistem persamaan linier yang dominan
# secara diagonal.setiap elemen diagonal diselesaikan, dan nilai
# perkiraan dimasukkan. proses ini kemudian diulang sampe konvergen.
# algoritma ini adalah versi stipped-down dari metode transformasi jacobi
# dari diagonalisasi matriks. metode ini dinamai carl gustav jacob jacobi

from __future__ import annotations

import numpy as np

# metode untuk mencari solusi sistem persamaan linear
def jacobi_iteration_method(
    coefficient_matrix: np.ndarray,
    constant_matrix: np.ndarray,
    init_val: list,
    iterations: int,
) -> list[float]:
    """
    algoritma iteratif untuk menentukan solusi dari
    dominan diagonal tegas sistem persamaan linear

    4x1 + x2 + x3 = 2
     x2 + 5x2 + 2x3 = -6

    >>> coefficient = np.array([[4, 1, 1], [1, 5, 2], [1, 2, 4]])
    >>> constant = np.array([[2], [-6], [-4]])
    >>> init_val = [0.5, -0.5, -0.5]
    >>> iterations = 3
    >>> jacobi_iteration_method(coefficient, constant, init_val, iterations)
    [0.909375, -1.14375, -0.7484375]
    """

    rows1, cols1 = coefficient_matrix.shape
    rows2, cols2 = constant_matrix.shape

    if rows1 != cols1:
        raise ValueError(f"koefisien matriks harus nxn tetapi sekarang {rows1}x{cols1}")

    if cols2 != 1:
        raise ValueError(f"konstanta matriks harus nx1 tetapi sekarang {rows2}x{cols2}")

    if rows1 != rows2:
        raise ValueError(
            f"""koeifisien dan konstanta matriks harus ukuran nxn dan nx1
            tetapi sekarang {rows1}x{cols1} dan {rows2}x{cols2}"""
        )

    if len(init_val) != rows1:
        raise ValueError(
            f"""jumlah nilai awal harus sama dengan jumlah baris dalam
            koefisien matriks tetapi sekarang {len(init_val)} dan {rows1}"""
        )

    if iterations <= 0:
        raise ValueError("iterasi setidaknya harus 1")

    table = np.concatenate((coefficient_matrix, constant_matrix), axis=1)
    rows, cols = table.shape

    strictly_diagonally_dominant(table)

    for i in range(iterations):
        new_val = []
        for row in range(rows):
            temp = 0
            for col in range(cols):
                if col == row:
                    denom = table[row][col]
                elif col == cols - 1:
                    val = table[row][col]
                else:
                    temp += (-1) * table[row][col] * init_val[col]
            temp = (temp + val) / denom
            new_val.append(temp)
        init_val = new_val

    return [float(i) for i in new_val]

# memeriksa apakah matriks yang diberikan benar-benar dominan diagonal
def strictly_diagonally_dominant(table: np.ndarray) -> bool:
    """
    >>> table = np.array([[4, 1, 1, 2], [1, 5, 2, -6], [1, 2, 4, -4]])
    >>> strictly_diagonally_dominant(table)
    True
    """
    rows, cols = table.shape

    is_diagonally_dominant = True

    for i in range(0, rows):
        sum = 0
        for j in range(0, cols - 1):
            if i == j:
                continue
            else:
                sum += table[i][j]

        if table[i][i] <= sum:
            raise ValueError(
                "matriks koefisien tidak sepenuhnya dominan secara diagonal"
            )

    return is_diagonally_dominant

if __name__ == "__main__":
    import doctest

    doctest.testmod()


# Monica Rizzo
#Algorithm from https://uglyduckling.nl/library_files/PRE-PRINT-UD-2014-03.pdf
import numpy as np

def interpolate(x_values,y_values):
  #make sure the x and y arrays are the same size
  if len(x_values)!=len(y_values):
     print("X and Y arrays must be the same length!")
     return

  n=len(x_values)
  h=np.zeros(n)
  m=np.zeros(n)
  beta=np.zeros(n)
  #l=np.zeros(n)
  #mu=np.zeros(n)
  #z=np.zeros(n)
  consts=np.zeros((n,3))

  for i in np.arange(0,n-1,1):
        h[i]=x_values[i+1]-x_values[i]
        m[i]=(y_values[i+1]-y_values[i])/h[i]

  consts[0,0]=m[0]
  consts[n-1,0]=m[-1]

  for i in np.arange(1,n-1,1):
       if (m[i-1]*m[i]<=0.):
           consts[i,0]=0.
       elif (m[i-1]*m[i]>0.):
          beta[i]=(3.*m[i-1]*m[i])/(max(m[i-1],m[i])+2.*min(m[i-1],m[i]))
          if np.sign(m[i-1])==1 and np.sign(m[i])==1:
             consts[i,0]= min(max(0.,beta[i]),3.*min(m[i-1],m[i]))
          elif np.sign(m[i-1])==-1 and np.sign(m[i])==-1:
             consts[i,0]=max(min(0.,beta[i]),3.*max(m[i-1],m[i]))
          else:
             print("We have a problem")

  for i in np.arange(0,n-1,1):
       consts[i,1]=(3*m[i]-consts[i+1,0]-2.*consts[i,0])/h[i]
       consts[i,2]=(consts[i+1,0]+consts[i,0]-2.*m[i])/h[i]**2

  return consts

def lin_extrapolate(x_values,y_values):
   n=len(x_values)

   m1=(y_values[1]-y_values[0])/(x_values[1]-x_values[0])
   b1=y_values[0]-m1*x_values[0]

   m2=(y_values[n-1]-y_values[n-2])/(x_values[n-1]-x_values[n-2])
   b2=y_values[n-1]-m2*x_values[n-1]

   line_consts=np.array([[m1,b1],[m2,b2]])

   return line_consts

def interp_func(x,x_table,y_table,consts,line_consts=None, verbose=False):
    for i in np.arange(0,len(x_table)-1,1):
       if x_table[i]<x and x_table[i+1]>x:
          ans=y_table[i]+consts[i,0]*(x-x_table[i])+consts[i,1]*(x-x_table[i])**2+consts[i,2]*(x-x_table[i])**3
          if verbose==True:
             print("Input", x)
             print("Output", ans)
             return ans
          else:
             return ans

       elif x==x_table[i]:
          ans=y_table[i]
          if verbose==True:
             print("Input", x)
             print("Output", ans)
             return ans
          else:
             return ans

       elif x==x_table[i+1]:
          ans=y_table[i+1]
          if verbose==True:
             print("Input", x)
             print("Output", ans)
             return ans
          else:
             return ans

    if line_consts!=None:
       if x<x_table[0]:
          return line_consts[0,0]*x+line_consts[0,1]
       elif x>x_table[-1]:
          return line_consts[1,0]*x+line_consts[1,1]


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

import operator
from functools import reduce

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

from utilities import str2fun

def omega(points, x, i):
    return reduce(operator.mul, [x - points[j] for j in range(len(points)) if i != j])

def get_coeffs(x, y):
    cnt = len(x)
    coefs = [y[i] for i in range(cnt)]

    for j in range(1, cnt):
        for i in range(cnt - 1, j - 1, -1):
            coefs[i] = float(coefs[i] - coefs[i - 1]) / float(x[i] - x[i - j])

    return coefs

def lagrange_interpolation(points, x, f):
    f = str2fun(f)
    res = 0
    for i in range(len(points)):
        f_w = f(points[i]) / omega(points, points[i], i)
        res += f_w * omega(points, x, i)

    return res

def newton_interpolation(points, x, f):
    f = str2fun(f)
    y = [f(i) for i in points]
    coefs = get_coeffs(points, y)
    cnt = len(coefs) - 1
    res = coefs[cnt]
    for i in range(cnt - 1, -1, -1):
        res = res * (x - points[i]) + coefs[i]
    return res

def main():
    """Интерполяция функции многочленами Лагранжа и Ньютона"""

    init_dict = {
        "f": "exp(x)",
        "x": [
            [-2, -1, 0, 1],
            [-2, -1, 0.2, 1]
        ],
        "x*": -0.5
    }

    x_input = init_dict["x"]
    f = init_dict["f"]
    x_star = init_dict["x*"]

    f_call = str2fun(f)

    plt.rcParams["figure.figsize"] = (5 * len(x_input), 4)

    for i, x_cur in enumerate(x_input):
        plt.subplot(1, len(x_input), i + 1)
        plt.title("$x \in$ " + str(x_cur))

        x = np.arange(-2, 1, .01)
        y = f_call(x)
        plt.plot(x, y, label=f"f(x) = {f}", linewidth=1.5)

        print("x =", x_cur)

        newton = []
        lagrange = []
        for x in x_cur:
            newton.append(newton_interpolation(x_cur, x, f))
            lagrange.append(lagrange_interpolation(x_cur, x, f))

        print("\tМногочлен Лагранжа:\t", np.array(lagrange))
        print("\tМногочлен Ньютона:\t", np.array(newton))
        y_star_lagrange = lagrange_interpolation(x_cur, x_star, f)
        y_star_newton = newton_interpolation(x_cur, x_star, f)
        y_true = f_call(x_star)
        print(f"\tПогрешность в точке x* = {x_star}")
        print("\t\tЛагранж:", abs(y_true - y_star_lagrange))
        print("\t\tНьютон: ", abs(y_true - y_star_newton))

        plt.plot(x_cur, newton, "-o", label="Ньютон", linewidth=3)
        plt.plot(x_cur, lagrange, ":*", label="Лагранж", linewidth=3)

        plt.legend()
        plt.axis("equal")
        plt.grid(True)
    plt.suptitle("Интерполяция функции многочленами Ньютона и Лагранжа")
    plt.savefig("plot.jpg", dpi=300)
    plt.show()

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


"""
Utility functions for angles.
"""

import numpy as np

def normalize_rad(r):
    """
    Normalize a radian to between -np.pi and np.pi.
    """
    return np.mod(r + np.pi, 2 * np.pi) - np.pi

def rotation_rads(r):
    """
    Given an angle or an array of angles in radian, give the 4 perpendicular angles.
    :param r int or (K, 1)
    :return [int] * 4 or (K, 4)
    """
    try:
        float(r)
        output = [r, r + np.pi / 2., r + np.pi, r + np.pi * 3. / 2.]
        return np.sort([normalize_rad(r) for r in output])
    except TypeError:
        assert len(r.shape) == 2 and r.shape[1] == 1
        output = [r, r + np.pi / 2., r + np.pi, r + np.pi * 3. / 2.]
        output = np.concatenate(output, axis=-1)
        output = np.sort(normalize_rad(output), axis=1)
        return output


import numpy as np

def normalize(matrix, nh=1, nl=0):
    """Normalizes each column in a matrix by calculating its maximum
    and minimum values, the parameters nh and nl specify the final range
    of the normalized values"""
    return (matrix - matrix.min(0)) * ((nh - nl) / matrix.ptp(0)) + nl

def one_hot_encoding(array):
    """Encodes each unique label in 'array' in a vector of the same length as
    the number of unique labels. This vector is filled with zeros and a 1
    representing the position assigned to the label"""
    labels = np.unique(array)
    number_of_labels = labels.size
    encoded = {}
    for i in range(number_of_labels):
        encoding = np.zeros(number_of_labels)
        encoding[i] = 1
        encoded[labels[i]] = encoding
    return encoded

def encode(array, encoding):
    """Encodes 'array' with the encoding specified in encoding.
    This value must be a dictionary"""
    encoded = []
    for i in array:
        encoded.append(encoding[i])
    return encoded

def load_data_wrapper(name, input_cols, output_col, output_type="float", delimiter=None):
    """Wrapper to load the desired data in an easier way. It returns the normalized and encoded
    data, alongside with the size of the values in the inputs and outputs to initialize
    the neural network correctly"""
    data_x = np.loadtxt(name, usecols=input_cols, delimiter=delimiter)
    data_x = normalize(data_x)
    data_y = np.loadtxt(name, usecols=output_col, delimiter=delimiter, dtype=output_type)
    encoding = one_hot_encoding(data_y)
    data_y = encode(data_y, encoding)
    # x_len will be the number of input neurons, and y_len the number of output neurons
    x_len = np.shape(data_x)[1]
    y_len = np.shape(data_y)[1]
    data = [[np.reshape(x, (x_len, 1)), np.reshape(y, (y_len, 1))] for x, y in zip(data_x, data_y)]
    return data, x_len, y_len


import matplotlib
matplotlib.use("TKagg")
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()

#unsupervised clustering algorithms
#learn from the properties of data,
#divison or discrete labling of groups of points

def show():
    plt.show()
    plt.clf()

#introducing k-means

#build some data
from sklearn.datasets.samples_generator import make_blobs
X, y_true = make_blobs(n_samples=300, centers=4,
                       cluster_std=0.60, random_state=0)
plt.scatter(X[:, 0], X[:, 1], s=50);
show()

from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=4)
kmeans.fit(X)
y_kmeans = kmeans.predict(X)

plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, s=50, cmap='viridis')

centers = kmeans.cluster_centers_
plt.scatter(centers[:, 0], centers[:, 1], c='black', s=200, alpha=0.5)

#kmeans Algo: Expectation-Maximization (E-M)

#lets wright a kmeans algo

from sklearn.metrics import pairwise_distances_argmin

def find_clusters(X, n_clusters, rseed=2):
    """K means cluster algo"""
    #1. randomly chose some clusters
    rng = np.random.RandomState(rseed)
    i = rng.permutation(X.shape[0])[:n_clusters]
    centers = X[i]

    while True:
        #2a. Assign labels based on closest center
        labels = pairwise_distances_argmin(X, centers)

        #2b. Find new centers from means of points
        new_centers = np.array([X[labels == i].mean(0)
                               for i in range(n_clusters)])

        #2c. check for convergence
        if np.all(centers == new_centers):
            break
        centers = new_centers

    return centers, labels

centers, labels = find_clusters(X, 4)
plt.scatter(X[:, 0], X[:, 1], c=labels,
            s=50, cmap='viridis');
show()
#simple version

##caveats of expectation-maximization
##The globally optimal results may not be achived

centers, labels = find_clusters(X, 4, rseed=0)
plt.scatter(X[:, 0], X[:, 1], c=labels,
            s=50, cmap='viridis');
show() #bad groupings, not globally optimal
#by default it runs from multiple random guesses (n_init defaulted to 10)

###you need to select your cluster count before hand
#it cant learn the optimal cluster amount

labels = KMeans(6, random_state=0).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=labels,
            s=50, cmap='viridis');
show() # too many clusters, are they meaningful?

### k-means is limited to linear cluster boundaries

from sklearn.datasets import make_moons
X, y = make_moons(200, noise=.05, random_state=0)

labels = KMeans(2, random_state=0).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=labels,
            s=50, cmap='viridis');
show() #clearly not what we would expect
#can fix this with SpectralClustering

from sklearn.cluster import SpectralClustering
model = SpectralClustering(n_clusters=2, affinity='nearest_neighbors',
                           assign_labels='kmeans')
labels = model.fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=labels,
            s=50, cmap='viridis');
show() #as expected now

#k-means slows with larger samples

#Example 1: k-means on digits
#get the digit data
from sklearn.datasets import load_digits
digits = load_digits()

#cluster it
kmeans = KMeans(n_clusters=10, random_state=0)
clusters = kmeans.fit_predict(digits.data)
print(kmeans.cluster_centers_.shape) #(10,64)

#what do the clusters look like?
fig, ax = plt.subplots(2, 5, figsize=(8, 3))
centers = kmeans.cluster_centers_.reshape(10, 8, 8)
for axi, center in zip(ax.flat, centers):
    axi.set(xticks=[], yticks=[])
    axi.imshow(center, interpolation='nearest', cmap=plt.cm.binary)
show()

from scipy.stats import mode

labels = np.zeros_like(clusters)
for i in range(10):
    mask = (clusters == i)
    labels[mask] = mode(digits.target[mask])[0]

#lets check how accurate it was
from sklearn.metrics import accuracy_score
print(accuracy_score(digits.target, labels))
#and the confusion matrix
from sklearn.metrics import confusion_matrix
mat = confusion_matrix(digits.target, labels)
sns.heatmap(mat.T, square=True, annot=True, fmt='d', cbar=False,
            xticklabels=digits.target_names,
            yticklabels=digits.target_names)
plt.xlabel('true label')
plt.ylabel('predicted label')
show()

#lets see if we can do better with the
#t-distributed stochastic neighbor embedding (t-SNE) algo
#to preprocess our data

from sklearn.manifold import TSNE

#Project the data: slow
tsne = TSNE(n_components=2, init='random', random_state=0)
digits_proj = tsne.fit_transform(digits.data)

#compute clusters
kmeans = KMeans(n_clusters=10, random_state=0)
clusters = kmeans.fit_predict(digits_proj)

#permute the lables
labels = np.zeros_like(clusters)
for i in range(10):
    mask = (clusters == i)
    labels[mask] = mode(digits.target[mask])[0]

#check accuracy
print(accuracy_score(digits.target, labels)) #92%

##Example 2: k-means for color compression
#lets grab a photo (need pillows package)
# Note: this requires the ``pillow`` package to be installed
from sklearn.datasets import load_sample_image
china = load_sample_image("china.jpg")
ax = plt.axes(xticks=[], yticks=[])
ax.imshow(china);
show()
#3d array (height, width, rgb) (427, 640, 3)

#reshape this to [n_samples x n_features]
data = china / 255.00 #0 ... 1 scale
data = data.reshape(427 * 640, 3)

def plot_pixels(data, title, colors=None, N=10000):
    """ using a subset of 10k colors we can visualize a reshaped image"""
    if colors is None:
        colors = data

    # choose a random subset
    rng = np.random.RandomState(0)
    i = rng.permutation(data.shape[0])[:N]
    colors = colors[i]
    R, G, B = data[i].T

    fig, ax = plt.subplots(1, 2, figsize=(16, 6))
    ax[0].scatter(R, G, color=colors, marker='.')
    ax[0].set(xlabel='Red', ylabel='Green', xlim=(0, 1), ylim=(0, 1))

    ax[1].scatter(R, B, color=colors, marker='.')
    ax[1].set(xlabel='Red', ylabel='Blue', xlim=(0, 1), ylim=(0, 1))

    fig.suptitle(title, size=20);

plot_pixels(data, title='Input color space: 16 million possible colors')
show()

#large dataset, will use mini batch k-means

import warnings; warnings.simplefilter('ignore')  # Fix NumPy issues.

from sklearn.cluster import MiniBatchKMeans as MiniBKM

kmeans = MiniBKM(16)
kmeans.fit(data)
new_colors = kmeans.cluster_centers_[kmeans.predict(data)]

plot_pixels(data, colors=new_colors,
            title="Reduced color space: 16 colors")
show()

#lets rebuild the image

china_recolored = new_colors.reshape(china.shape)

fig, ax = plt.subplots(1, 2, figsize=(16, 6),
                       subplot_kw=dict(xticks=[], yticks=[]))
fig.subplots_adjust(wspace=0.05)
ax[0].imshow(china)
ax[0].set_title('Original Image', size=16)
ax[1].imshow(china_recolored)
ax[1].set_title('16-color Image', size=16);
show()


import numpy as np

from speech_datasets.transform.interface import FuncTrans

def delta(feat, window):
    assert window > 0
    delta_feat = np.zeros_like(feat)
    for i in range(1, window + 1):
        delta_feat[:-i] += i * feat[i:]
        delta_feat[i:] += -i * feat[:-i]
        delta_feat[-i:] += i * feat[-1]
        delta_feat[:i] += -i * feat[0]
    delta_feat /= 2 * sum(i ** 2 for i in range(1, window + 1))
    return delta_feat

def add_deltas(x, window=2, order=2):
    """
    :param x: Features
    :param window: size of the window to use to approximate time derivative computation
    :param order: highest order time derivative to compute
    :return: Features, concatenated with all the relevant derivatives
    """
    feats = [x]
    for _ in range(order):
        feats.append(delta(feats[-1], window))
    return np.concatenate(feats, axis=1)

class AddDeltas(FuncTrans):
    _func = add_deltas
    __doc__ = add_deltas.__doc__


import argparse
import logging
import numpy as np
from PCA.PCAModel import PCAModel

logging.basicConfig(
    level=logging.DEBUG,
    format='[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s'
)

def main():
    logging.info("pca_toy_vector.py main()")
    X = np.array([[0.14, -2.3, 1.58, 1], [-1.2, 1.62, 0.76, -1], [0.1, -0.2, 0.3, -0.4]])
    pcaModel = PCAModel(X)
    pcaModel.TruncateModel(3)
    average = pcaModel.Average()
    eigenpairs = pcaModel.Eigenpairs()
    varianceProportionList = pcaModel.VarianceProportion()

    logging.info("average = {}".format(average))
    logging.info("eigenpairs = {}".format(eigenpairs))
    logging.info("varianceProportionList = {}".format(varianceProportionList))

    projection = pcaModel.Project(X)
    logging.info("projection = {}".format(projection))

    reconstruction = pcaModel.Reconstruct(projection)
    logging.info("reconstruction = {}".format(reconstruction))

if __name__ == '__main__':
    main()