import pandas as pd
import warnings
import os
import Json
import tensorflow as tf
import numpy as np
import copy
import time
import pickle
from sklearn.metrics import accuracy_score
from feature_extraction import Feature_Extractor
from sklearn import model_selection
from sklearn.ensemble import VotingClassifier
from tensorflow.keras.models import Sequential
from keras.utils import to_categorical
from keras.layers import Dense, Dropout
from xgboost import XGBClassifier
from tensorflow import keras
from tensorflow.keras import layers
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
warnings.filterwarnings("ignore")
start_time = time.time()
print("############### Gradient search and voting script starting time ###############",start_time)

#load data
dataset = pd.read_csv('Training_features.txt',sep= '\t', encoding="ISO-8859-1")
# dataset= dataset.dropna()
dict = {'Coorleation': 0, 'Descriptive_stats': 1, 'Model_results': 2, 'Variable_def':3, 'others':4}
X = dataset.iloc[:, 1:10]
Y = dataset['Label'].apply(lambda label: dict[label])

"""split data into training and testing data with test size of 20%"""
train_x, test_x, train_y, test_y = model_selection.train_test_split(X, Y, test_size=0.2, random_state=0)

"""Create keras neural network model"""
# opt = keras.optimizers.Adam(learning_rate=0.01)
input_dim = len(X.columns)
def create_model(dropout_rate = 0.2, optimizer = 'Adam'):
    model = Sequential()
    model.add(Dense(10, input_dim=input_dim, activation='relu'))
    model.add(Dense(10, activation='relu'))
    model.add(Dropout(dropout_rate))
    model.add(Dense(5, activation='sigmoid'))
    model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])
    return model

""" Define a pipeline for Gridsearch"""
def algorithm_pipeline(train_x, test_x, train_y, test_y, model, param_grid ,cv=10 , do_probabilities = False):

    gs = GridSearchCV(
        estimator=model,
        param_grid=param_grid,
        cv=cv,
        n_jobs=-1,
        scoring=['accuracy'],
        verbose=0,
        refit = 'accuracy'
    )
    fitted_model = gs.fit(train_x, train_y)

    if do_probabilities:
      pred = fitted_model.predict_proba(test_x)
    else:
      pred = fitted_model.predict(test_x)

    return fitted_model, pred

""" Gridsearch for Keras deep learning model"""
keras_param_grid = {
              'batch_size':[128,256],
              'epochs' :              [100,150,200,300,400,500],
            #  'batch_size' :          [32, 128],
              'optimizer' :           ['Adam', 'Nadam','SGD'],
              'dropout_rate' :        [0.1,0.2, 0.3]
            #  'activation' :          ['relu', 'elu']
             }
Keras_model = tf.keras.wrappers.scikit_learn.KerasClassifier(build_fn=create_model,  verbose=False)
Keras_model._estimator_type = 'classifier'
Keras_model, pred = algorithm_pipeline(train_x, test_x, train_y, test_y, Keras_model, keras_param_grid,cv=5)

"""Saving Keras best parameters as pickle file"""
keras_best_pars = Keras_model.best_params_
pickle.dump(Keras_model.best_params_, open("keras_log_reg.pickle", "wb"))

print("Keras model parameters saved...")

""" Gridsearch for XGBoost model"""
xgb_model = XGBClassifier()
xgb_param_grid = {
    'n_estimators': [400, 700, 1000],
    'colsample_bytree': [0.7, 0.8],
    'max_depth': [15,20,25],
    'reg_alpha': [1.1, 1.2, 1.3],
    'reg_lambda': [1.1, 1.2, 1.3],
    'subsample': [0.7, 0.8, 0.9]
}
xgb_model, pred = algorithm_pipeline(train_x, test_x, train_y, test_y, xgb_model, xgb_param_grid,cv=5)

"""Saving XGBoost best parameters as pickle file"""
xgb_best_pars = xgb_model.best_params_
pickle.dump(xgb_model.best_params_, open("xgb_log_reg.pickle", "wb"))

print("XGB model parameters saved...")

""" Grid search for RFC model"""
rfc_model = RandomForestClassifier()
rfc_param_grid = {
'n_estimators': [400, 700, 1000],
    'max_depth': [15,20,25],
    'max_leaf_nodes': [50, 100, 200]
}
rfc_model, pred = algorithm_pipeline(train_x, test_x, train_y, test_y, rfc_model,
                                 rfc_param_grid,cv=5)
"""Saving RFC best parameters as pickle file"""
rfc_best_pars = rfc_model.best_params_
pickle.dump(rfc_model.best_params_, open("RFC_log_reg.pickle", "wb"))

print("RFC model parameters saved...")
print("############# GridSearch finished, Voting Started #############")

""" Ensemble voting classifier"""
eclf = VotingClassifier(
    estimators=[('Keras', Keras_model),
                ('XGB', xgb_model),
                ('RFC', rfc_model)],
                voting= 'soft',
                flatten_transform=False)

eclf.fit(train_x, train_y)

print("Keras Best score", Keras_model.best_score_)
print("Keras Best Params" , Keras_model.best_params_)
print("XGboost Best score" , np.sqrt(xgb_model.best_score_))
print("Xgboost Best params" , xgb_model.best_params_)
print("RFC Best score" , rfc_model.best_score_)
print("RFC Best params" , rfc_model.best_params_)
print("Best Estimator",)

print('5-fold cross validation:\n')

for clf in (Keras_model, xgb_model, rfc_model, eclf):
    y_pred = clf.predict(test_x)
    print("Model after voting ",clf.__class__.__name__, accuracy_score(test_y, y_pred))

end_time = time.time()
print("############### Gradient search and voting script end time ###############",end_time)

delta = end_time-start_time
print("############### Time taken for gridsearch and voting ###############",delta)


# curl -X POST 'https://api-free.deepl.com/v2/translate' \
# 	-H 'Authorization: DeepL-Auth-Key [yourAuthKey]' \
# 	-d 'text=Hello%2C%20world!' \
# 	-d 'target_lang=DE'
#
import requests

DEEPL_DOMAIN = "https://api-free.deepl.com"
DEEPL_VERSION = "v2"
DEEPL_TOKEN = "37009457-c483-0947-1d70-823a6f80e4c2:fx"

DEEPL_URL = f"{DEEPL_DOMAIN}/{DEEPL_VERSION}"

session = requests.session()

def __get(path, params=None):
    resp = session.get(
        f"{DEEPL_URL}/{path}",
        params=params,
        headers={'Authorization': 'DeepL-Auth-Key {}'.format(DEEPL_TOKEN)}
    )
    return resp

def translate(to_translate, target_lang, source_lang=None):
    """
    Deppl documentation see https://www.deepl.com/docs-api/translate-text/
    :param to_translate:
    :param target_lang:
    :param source_lang:
    :return:
    """
    params = {'text': to_translate, 'target_lang': target_lang}
    if source_lang:
        params['source_lang'] = source_lang
    resp = __get(path='translate', params=params)
    if resp.status_code == 200:
        return resp.json()

def translate_text(text, target_lang, source_lang=None):
    deeple_json = translate(text, target_lang=target_lang, source_lang=source_lang)
    translated = None
    if deeple_json:
        translations = deeple_json.get('translations', [])
        translated = ','.join(t.get('text') for t in translations)
    return translated or text


"""Tesis YURAKU de Christian Flores y Franklin Villavicencio 2019"""

"""
    librerias importadas
    forms: libreria propia de django para crear formularios
    Planta: importa el modelo llamado Planta.
"""
from django import forms
from gestionplantas.models import Planta

"""
    Clase GuardarPlantaForm
    Clase creada para generar el formulario de Planta basado en los
    campos que tiene el modelo Planta
        Parametros
        :param forms.ModelForm: Modelo basico propio de Django.

    Subclase Meta
        Clase creada para pasarle los atributos del moledo Comentario al
        nuevo Formulario.
            Atributos:
                model : moldelo que tengra el fomulario (en esta caso sera del modelo Planta)
                fields : campos que tendra el formulario (en este caso sera del modelo Planta)
                labels : mensajes que tendra en cada campo del formulario
                widgets : estilos que tendran cada campo.
"""
class GuardarPlantaForm(forms.ModelForm):
    class Meta:
        model = Planta
        fields = ['nombre_planta',
                  'nombre_comun',
                  'nombre_cientifico',
                  'reino',
                  'lugar_adaptacion',
                  'lugar_proviene',
                  'como_ingerir',
                  'uso',
                  'dosis',
                  'tipo',
                  'clase',
                  'orden',
                  'familia',
                  'genero',
                  'especie',
                  'imagen_planta',]
        labels = {'nombre_planta':'Nombre de la Planta:',
                  'nombre_comun':'Nombre Común:',
                  'nombre_cientifico': 'Nombre Cientifico:',
                  'reino': 'Reino:',
                  'lugar_adaptacion': 'Lugar de Adaptacion:',
                  'lugar_proviene': 'Lugar de donde proviene:',
                  'como_ingerir':'Como ingerir',
                  'uso':'Uso',
                  'dosis': 'Dosis:',
                  'tipo': 'Tipo:',
                  'clase': 'Clase:',
                  'orden': 'Orden:',
                  'familia': 'Familia:',
                  'genero': 'Genero:',
                  'especie': 'Especie:',}
        widgets = {'nombre_planta':forms.TextInput(attrs={'class':'form-control','placeholder': 'Ejemplo: Floripondio'}),
                   'nombre_comun':forms.TextInput(attrs={'class':'form-control','placeholder': 'Ejemplo: Guanto'}),
                   'nombre_cientifico': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: Es para fines educativos'}),
                   'reino': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: Plantae'}),
                   'lugar_adaptacion': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: Todo el mundo'}),
                   'lugar_proviene': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: Todo el mundo'}),
                   'uso': forms.Textarea(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: Sedante para dormir'}),
                   'como_ingerir': forms.Textarea(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: Se debe hacer infusión'}),
                   'dosis': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: cada noche durante 1 semana'}),
                   'tipo': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: Magnoliophyta.'}),
                   'clase': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: Dicotyledons'}),
                   'orden': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: Dicotyledons'}),
                   'familia': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: Solanaceae'}),
                   'genero': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: Brugmansia'}),
                   'especie': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Ejemplo: Arbustiva'}),}


from abc import ABC, abstractmethod
from functools import partial
from typing import Tuple

import jax
import jax.lax as lax
import jax.nn as nn
import jax.numpy as jnp
import jax.scipy as jsp

from jax.tree_util import register_pytree_node, register_pytree_node_class

def gradient_descent(loss, x0, step_size, tol=1e-3, maxiter=100):
    """TODO: add step size..."""

    loss_i = loss(x0)
    _lgrad = jax.grad(loss)

    def _cond_f(state):
        loss_imo, loss_i, iter_i, x_i = state
        diff_check = jnp.fabs(loss_i - loss_imo) > tol
        iter_check = iter_i < maxiter
        return jnp.all(jnp.array([diff_check, iter_check]))

    def _body_f(state):
        loss_imt, loss_imo, iter_imo, x_imo = state

        b = _lgrad(x_imo)

        d_i = -step_size * b
        x_i = x_imo + d_i
        loss_i = loss(x_i)

        return (loss_imo, loss_i, iter_imo + 1, x_i)

    state = (10000, loss_i, 0, x0)
    state = lax.while_loop(_cond_f, _body_f, state)

    return state

def newton_cg(loss, x0, step_size, tol=1e-3, maxiter=100):
    """TODO: add step size..."""

    loss_i = loss(x0)
    _lgrad = jax.grad(loss)

    def _cond_f(state):
        loss_imo, loss_i, iter_i, x_i = state
        diff_check = jnp.fabs(loss_i - loss_imo) > tol
        iter_check = iter_i < maxiter
        return jnp.all(jnp.array([diff_check, iter_check]))

    def _body_f(state):
        loss_imt, loss_imo, iter_imo, x_imo = state

        b = _lgrad(x_imo)

        # lets define matrix vector product over the hessian
        # but without having to explicitly compute hessian...
        # we want to compute inv(H(x_imo)) @ grad(x_imo)
        def _matvec(d):
            return _hvp(_lgrad, x_imo, d)

        d_i, _ = jsp.sparse.linalg.cg(_matvec, -b)
        x_i = x_imo + d_i
        loss_i = loss(x_i)

        return (loss_imo, loss_i, iter_imo + 1, x_i)

    state = (10000, loss_i, 0, x0)
    state = lax.while_loop(_cond_f, _body_f, state)

    return state

@register_pytree_node_class
class AbstractRegressionFunc(ABC):
    """Abstract class that lets us pass around a function
    into JIT compatible calls
    """

    @abstractmethod
    def __call__(self, data, x) -> Tuple[Tuple[jnp.ndarray, jnp.ndarray], jnp.ndarray]:
        pass

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        register_pytree_node(cls, cls.tree_flatten, cls.tree_unflatten)

    def tree_flatten(self):
        children = ()
        aux = ()
        return (children, aux)

    @classmethod
    def tree_unflatten(cls, aux, children):
        return cls()

def _pad_variant(x: jnp.ndarray, covar: jnp.ndarray) -> jnp.ndarray:
    """Pad the genotype to include covariates"""
    X = jnp.hstack((x[:, jnp.newaxis], covar))
    return X

# OLS using QR decomp with variables (x, covar) and y
class OLSQR(AbstractRegressionFunc):
    def __call__(self, data, x):
        y, covar = data
        X = _pad_variant(x, covar)

        q_matrix, r_matrix = jnp.linalg.qr(X, mode="reduced")
        qty = q_matrix.T @ y
        beta_hat = jsp.linalg.solve_triangular(r_matrix, qty)
        df = q_matrix.shape[0] - q_matrix.shape[1]
        residual = y - q_matrix @ qty
        rss = jnp.sum(residual**2)
        sigma = jnp.sqrt(rss / df)
        se = (
            jnp.sqrt(
                jnp.diag(
                    jsp.linalg.cho_solve((r_matrix, False), jnp.eye(r_matrix.shape[0]))
                )
            )
            * sigma
        )
        t_scores = beta_hat / se
        # p_value = jnp.array(2 * stats.t.sf(abs(t_scores), df=df))
        log_p_value = jnp.log(2) + jsp.stats.norm.logcdf(-jnp.abs(t_scores))

        return data, jnp.array([beta_hat, se, t_scores, log_p_value]).T[0]

# OLS using jax built in least-squares function
class OLSJAX(AbstractRegressionFunc):
    def __call__(self, data, x):
        y, covar = data
        n = len(y)
        X = _pad_variant(x, covar)

        beta_hat, rss, rank, svals = jnp.linalg.lstsq(X, y)

        se = jnp.sqrt(rss / (n - rank)) / svals
        z_scores = beta_hat / se
        log_p_value = jnp.log(2) + jsp.stats.norm.logcdf(-jnp.abs(z_scores))

        return data, jnp.array([beta_hat, se, z_scores, log_p_value]).T[0]

def _hvp(g, primals, tangents):
    # hessian vector product
    return jax.jvp(g, (primals,), (tangents,))[1]

def _bern_negloglike(beta, y, X):
    # squash R => [0, 1]
    lin_pred = X @ beta

    # lets break this down...
    # prob_i = sigmoid(lin_pred_i)
    #
    # loglikelihood := sum_i y_i * log(prob_i) + (1 - y_i) * log(1 - prob_i)
    # log(prob_i) = log(sigmoid(lin_pred_i)) = log(1) - log(1 + e^(-lin_pred_i))
    #             = 0 - log(1 + e^(-lin_pred_i)) = -softplus(-lin_pred_i)
    # similarly, 1 - prob_i = 1 - sigmoid(lin_pred_i) = sigmoid(-lin_pred_i)
    # hence, log(1 - prob_i) = log(sigmoid(-lin_pred_i)) = 0 - log(1 + e^lin_pred_i)
    #                        = -softplus(lin_pred_i)
    # we drop the "-" in front of softplus to reflect neg log like
    return jnp.sum(nn.softplus(jnp.where(y, -lin_pred, lin_pred)))

class LogisticRegression(AbstractRegressionFunc):
    def __init__(self, tol=1e-3, step_size=1e-1, maxiter=100):
        self.tol = tol
        self.step_size = step_size
        self.maxiter = maxiter

    def __call__(self, data, x):

        y, covar = data
        X = _pad_variant(x, covar)

        # close over data to get 'simple' function
        _loss = partial(_bern_negloglike, y=y, X=X)

        # optimize neg loglikelihood
        optstate = newton_cg(
            _loss, jnp.zeros(X.shape[1]), self.step_size, tol=self.tol, maxiter=self.maxiter
        )

        # pull out results
        loss_imo, loss_i, iter_i, x_i = optstate
        beta_hat = x_i
        converged = jnp.all(
            jnp.array(
                [(jnp.fabs(loss_i - loss_imo) < self.tol), (iter_i < self.maxiter)]
            )
        )
        converged = (jnp.ones(X.shape[1]) * converged).astype(float)

        # hessian = fisher information matrix when using canonical link
        se = jnp.sqrt(jnp.diag(jnp.linalg.inv(jax.hessian(_loss)(beta_hat))))
        t_scores = beta_hat / se
        # p_value = jnp.array(2 * stats.t.sf(abs(t_scores), df=df))
        log_p_value = jnp.log(2) + jsp.stats.norm.logcdf(-jnp.abs(t_scores))

        return data, jnp.array([beta_hat, se, t_scores, log_p_value, converged]).T[0]

    def tree_flatten(self):
        children = (self.tol, self.step_size, self.maxiter)
        aux = ()
        return (children, aux)

    @classmethod
    def tree_unflatten(cls, aux, children):
        return cls(*children)


import time
import torch
import numpy as np
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import ReduceLROnPlateau

import scipy.sparse as sp

from .model import Teacher_Features , Teacher_Edge , Student
from sklearn.cluster import KMeans , SpectralClustering , AgglomerativeClustering , DBSCAN , OPTICS , Birch
from .accuracy import get_accuracy
from .utils import students_t_kernel_euclidean , student_t_kernel_cosine , generate_targer_distribution
from .PPR_Matrix.ppr import topk_ppr_matrix
from .losses import  link_prediction_objectif
import os
os.environ['CUDA_LAUNCH_BLOCKING'] = '1'
from tqdm import tqdm

class Train :
    def __init__(self , epochs ,  device  , num_nodes, input_dim , output_dim , hidden2 , nbr_clusters , beta_struct = 10 , beta_features = 10 , beta_student = 10 , teta = 0.5 ,dropout_rate=0.2 , lr=0.01 , weight_decay=0.0005 , clustering_method=KMeans):
        self.epochs = epochs
        self.device = device
        self.num_nodes = num_nodes
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.hidden2 = hidden2
        self.nbr_clusters = nbr_clusters
        self.dropout_rate = dropout_rate
        self.lr = lr
        self.weight_decay = weight_decay
        self.teta = teta

        self.feature_teacher = Teacher_Features(self.num_nodes , self.input_dim , self.output_dim , self.hidden2 , self.dropout_rate , self.device)
        self.edge_teacher = Teacher_Edge(self.num_nodes , self.input_dim , self.output_dim , self.hidden2 , self.dropout_rate , self.device)
        self.student = Student(self.num_nodes , self.input_dim , self.output_dim , self.hidden2 ,self.hidden2 , self.hidden2 ,self.dropout_rate , self.device)

        self.feature_teacher.to(self.device)
        self.edge_teacher.to(self.device)
        self.student.to(self.device)

        self.feat_teach_optimizer = optim.Adam(self.feature_teacher.parameters() , lr=self.lr , weight_decay=self.weight_decay)
        self.feat_scheduler = ReduceLROnPlateau(self.feat_teach_optimizer , mode='min' , factor=0.5 , patience=5 , verbose=True)
        self.beta_features = beta_features

        self.edge_teach_optimizer = optim.Adam(self.edge_teacher.parameters() , lr=self.lr , weight_decay=self.weight_decay)
        self.edge_scheduler = ReduceLROnPlateau(self.edge_teach_optimizer , mode='min' , factor=0.5 , patience=5 , verbose=True)
        self.beta_struct = beta_struct

        self.student_optimizer = optim.Adam(self.student.parameters() , lr=self.lr , weight_decay=self.weight_decay)
        self.student_scheduler = ReduceLROnPlateau(self.student_optimizer , mode='min' , factor=0.5 , patience=5 , verbose=True)
        self.beta_student = beta_student

        self.clustering_method = clustering_method

    """
    Pretrain the feeature teacher
    """

    def pretrain_feat_teacher(self , feat_epochs , data ) :
        loadcheck = input("Do you want to load a checkpoint ? (y/n) : ")
        if loadcheck == 'y' :
            self.load_checkpoint(model='feat_teacher')
            print("Feature teacher checkpoint loaded")
        else :
            print("Training from scratch")

        print("making the clustering layer")

        output = []
        for batch in tqdm(data  , total=len(data)):
            batch.to(self.device)
            X = batch.x.squeeze(1)
            pe_feat = batch.pe_feat
            with torch.no_grad() :
                feat_teacher_output , _ = self.feature_teacher(X , pe_feat)
                output.append(feat_teacher_output)
        all_outputs = torch.cat(output , dim=0)

        clustering = self.clustering_method(self.nbr_clusters , n_init="auto")
        cluster_ids = clustering.fit_predict(all_outputs.cpu().detach().numpy())
        self.feature_teacher.Cluster_Layer = torch.tensor(clustering.cluster_centers_).to(self.device)
        self.feature_teacher.Cluster_Layer.requires_grad = False
        print("Clustering layer made")

            # clear memory
        del X, pe_feat, feat_teacher_output , output , all_outputs
        torch.cuda.empty_cache()

        lowest_loss = np.inf

        for epoch in range(1 , 1+feat_epochs):
            print("starting epoch {}".format(epoch))
            all_outputs = []
            epoch_loss=0
            for batch in tqdm(data , desc="Epoch : {}".format(epoch) , total=len(data)):
                batch.to(self.device)
                X = batch.x.squeeze(1)

                pe_feat = batch.pe_feat

                feat_teacher_output , _ = self.feature_teacher(X, pe_feat)

                Q = students_t_kernel_euclidean(feat_teacher_output , self.feature_teacher.Cluster_Layer)
                P = generate_targer_distribution(Q)
                kl_loss = nn.KLDivLoss()(torch.log(Q) ,P.detach())

                mse_loss = 0
                if self.output_dim == self.input_dim :
                    mse_loss = nn.MSELoss()(feat_teacher_output , X)
                    with open("mse_loss.txt" , "a") as f :
                        f.write("Epoch : {} , Loss : {} \n".format(epoch , mse_loss.item()))
                        f.write("shape of the output : {} \n".format(feat_teacher_output.shape))
                        f.write("shape of the input : {} \n".format(X.shape))
                        f.write("shape of the pe_feat : {} \n".format(pe_feat.shape))
                        f.write("is their nan in the output : {} \n".format(torch.isnan(feat_teacher_output).any()))
                        f.write("is their nan in the input : {} \n".format(torch.isnan(X).any()))

                loss = self.beta_features*kl_loss + mse_loss

                self.feat_teach_optimizer.zero_grad()
                loss.backward()
                self.feat_teach_optimizer.step()
                epoch_loss += loss.item()

                feat_teacher_output = feat_teacher_output.squeeze(0).detach().cpu()
                all_outputs.append(feat_teacher_output)

                # clear memory
                del X, pe_feat, feat_teacher_output, Q, P, kl_loss, mse_loss, loss
                torch.cuda.empty_cache()
            self.feat_scheduler.step(epoch_loss)
            if epoch_loss < lowest_loss :
                lowest_loss = epoch_loss
                self.save_checkpoint(epoch , model='best_feat_teacher')
                print("Best feature teacher checkpoint saved at epoch {}".format(epoch))
            if epoch_loss > lowest_loss :
                patience += 1
            else :
                patience = 0
            if patience > 10 :
                print("Early stopping")
                break

            all_outputs = torch.cat(all_outputs , dim=0)
            sil_score, db_score, ch_score = get_accuracy(all_outputs , self.nbr_clusters)

            print("Epoch : {} , Loss : {}".format(epoch , epoch_loss))
            print("Silhouette score : {} , Davies Bouldin score : {} , Calinski Harabasz score : {}".format(sil_score , db_score , ch_score))
            if epoch % 10 == 0 :
                self.save_checkpoint(epoch , model='feat_teacher')
                print("Feature teacher checkpoint saved at epoch {}".format(epoch))

            """
    pretrain the edge teacher
    """

    def pretrain_edge_teacher(self , edge_epochs , data) :
        loadcheck = input("Do you want to load a checkpoint ? (y/n) : ")
        if loadcheck == 'y' :
            self.load_checkpoint(model='edge_teacher')
            print("edge teacher checkpoint loaded")
        else :
            print("Training from scratch")

        print("making the clustering layer")
        output = []
        for batch in tqdm(data  , total=len(data)) :
            batch.to(self.device)
            X = batch.x.squeeze(1)
            adj_aug = batch.adj_aug
            pe_feat = batch.pe_feat.to_dense()
            with torch.no_grad() :
                edge_teacher_output , _ = self.edge_teacher( adj_aug, pe_feat , X)
                output.append(edge_teacher_output.squeeze(0))
            del adj_aug , pe_feat , edge_teacher_output
        all_outputs = torch.cat(output , dim=0)

        clustering = self.clustering_method(self.nbr_clusters , n_init="auto")
        cluster_ids = clustering.fit_predict(all_outputs.cpu().detach().numpy())
        self.edge_teacher.Cluster_Layer = torch.tensor(clustering.cluster_centers_).to(self.device)
        self.edge_teacher.Cluster_Layer.requires_grad = False
        print("Clustering layer made")
        print("the shape of the clustering layer is : {}".format(self.edge_teacher.Cluster_Layer.shape))
        del output , all_outputs
        torch.cuda.empty_cache()

        self.edge_teacher.train()

        lowest_loss = np.inf

        for epoch in range(1 , 1+edge_epochs):
            print("starting epoch {}".format(epoch))
            epoch_loss=0
            all_outputs = []
            for batch in tqdm(data , desc="Epoch : {}".format(epoch) , total=len(data)):
                batch.to(self.device)
                X = batch.x.squeeze(1)
                adj_aug = batch.adj_aug
                pe_feat = batch.pe_feat.to_dense()

                edge_teacher_output , _ = self.edge_teacher( adj_aug, pe_feat , X)
                edge_teacher_output = edge_teacher_output.squeeze(0)

                Q = students_t_kernel_euclidean(edge_teacher_output , self.edge_teacher.Cluster_Layer)
                P = generate_targer_distribution(Q)

                kl_loss = nn.KLDivLoss()(torch.log(Q) ,P.detach())

                mse_loss = 0
                if self.output_dim == self.input_dim :
                    mse_loss = nn.MSELoss()(edge_teacher_output , X)
                    # print the mse loss in another file
                    with open("mse_loss.txt" , "a") as f :
                        f.write("Epoch : {} , Loss : {} \n".format(epoch , mse_loss.item()))
                        f.write("shape of the output : {} \n".format(edge_teacher_output.shape))
                        f.write("shape of the input : {} \n".format(X.shape))
                        f.write("shape of the pe_feat : {} \n".format(pe_feat.shape))
                        f.write("is their nan in the output : {} \n".format(torch.isnan(edge_teacher_output).any()))
                        f.write("is their nan in the input : {} \n".format(torch.isnan(X).any()))

                loss = self.beta_struct*kl_loss + mse_loss

                self.edge_teach_optimizer.zero_grad()
                loss.backward()
                self.edge_teach_optimizer.step()

                epoch_loss += loss.item()
                edge_teacher_output = edge_teacher_output.squeeze(0).detach().cpu()
                all_outputs.append(edge_teacher_output)

                # clear memory
                del adj_aug , pe_feat , edge_teacher_output, Q, P, kl_loss, mse_loss, loss
                torch.cuda.empty_cache()
            self.edge_scheduler.step(epoch_loss)
            if epoch_loss < lowest_loss :
                lowest_loss = epoch_loss
                self.save_checkpoint(epoch , model='best_edge_teacher')
                print("Best edge teacher checkpoint saved at epoch {}".format(epoch))
            if epoch_loss > lowest_loss :
                patience += 1
            else :
                patience = 0
            if patience > 10 :
                print("Early stopping")
                break

            all_outputs = torch.cat(all_outputs , dim=0)
            sil_score, db_score, ch_score = get_accuracy(all_outputs , self.nbr_clusters)

            print("Epoch : {} , Loss : {}".format(epoch , epoch_loss))
            print("Silhouette score : {} , Davies Bouldin score : {} , Calinski Harabasz score : {}".format(sil_score , db_score , ch_score))
            if epoch % 10 == 0 :
                self.save_checkpoint(epoch , model='edge_teacher')
                print("Edge teacher checkpoint saved at epoch {}".format(epoch))

    """
    given a feature teacher and an edge/structure teacher train the student
    """

    def train_student(self , student_epochs , data ):
        loadcheck = input("Do you want to load a checkpoint ? (y/n) : ")
        if loadcheck == 'y' :
            self.load_checkpoint(model='student')
            print("student checkpoint loaded")
        else :
            print("Training from scratch")
        print("making the clustering layer for the student model")

        output = []
        for batch in tqdm(data, total=len(data)):
            batch.to(self.device)
            X = batch.x.squeeze(1)
            adj = batch.adj
            adj_aug = batch.adj_aug
            with torch.no_grad() :
                student_output, _ , _ , _= self.student(X , adj_aug)
                output.append(student_output.squeeze(0))
        all_outputs = torch.cat(output , dim=0)

        clustering = self.clustering_method(self.nbr_clusters , n_init="auto")
        cluster_ids = clustering.fit_predict(all_outputs.cpu().detach().numpy())
        self.student.Cluster_Layer = torch.tensor(clustering.cluster_centers_).to(self.device)
        self.student.Cluster_Layer.requires_grad = False
        print("Clustering layer for student model made")

        del output , all_outputs
        torch.cuda.empty_cache()

        self.student.train()

        lowest_loss = np.inf

        for epoch in range(1 , 1+student_epochs):
            print("starting epoch {}".format(epoch))
            epoch_loss=0
            epoch_clustering_loss = 0
            epoch_link_prediction_loss = 0

            for batch in tqdm(data , desc="Epoch : {}".format(epoch) , total=len(data)):
                batch.to(self.device)
                X = batch.x.squeeze(1)
                adj = batch.adj
                adj_aug = batch.adj_aug
                pe_feat = batch.pe_feat
                pe_feat_dense = pe_feat.to_dense()

                with torch.no_grad() :
                    _ , middle_representation_edge = self.edge_teacher(adj_aug ,pe_feat_dense , X)
                    _ , middle_representation_feat = self.feature_teacher(X , pe_feat)

                student_output , middle_representation , link_predictions , teta = self.student(X , adj_aug)
                student_output = student_output.squeeze(0)
                link_prediction = link_predictions.squeeze(0)

                Q = students_t_kernel_euclidean(student_output , self.student.Cluster_Layer)
                P = generate_targer_distribution(Q)

                link_prediction_loss = link_prediction_objectif(link_prediction , batch.edge_index)

                kl_loss = nn.KLDivLoss()(torch.log(Q) ,P.detach())

                struct_loss , feat_loss = self.student.loss(middle_representation , middle_representation_feat , middle_representation_edge)

                clustering_loss = kl_loss + teta*struct_loss + (1-teta)*feat_loss

                mse_loss = 0
                if self.output_dim == self.input_dim :
                    mse_loss = nn.MSELoss()(student_output , X)

                loss =  10*link_prediction_loss + teta*struct_loss + (1-teta)*feat_loss

                with open("Student_Training_with_link_pred.txt" , "a") as f :
                    f.write("======================================== \n")
                    f.write("Epoch : {} , Loss : {} \n".format(epoch , link_prediction_loss.item()))
                    f.write("shape of the output : {} \n".format(student_output.shape))
                    f.write("shape of the input : {} \n".format(X.shape))
                    f.write("shape of the pe_feat : {} \n".format(pe_feat.shape))
                    f.write("is their nan in the output : {} \n".format(torch.isnan(student_output).any()))
                    f.write("is their nan in the input : {} \n".format(torch.isnan(X).any()))
                    f.write("is their nan in the pe_feat : {} \n".format(torch.isnan(pe_feat).any()))
                    f.write("is their nan in the pe_feat_dense : {} \n".format(torch.isnan(pe_feat_dense).any()))
                    f.write("is their nan in the Q : {} \n".format(torch.isnan(Q).any()))
                    f.write("is their nan in the P : {} \n".format(torch.isnan(P).any()))
                    f.write("is their nan in the kl_loss : {} \n".format(torch.isnan(kl_loss).any()))
                    f.write("is their nan in the struct_loss : {} \n".format(torch.isnan(struct_loss).any()))
                    f.write("is their nan in the feat_loss : {} \n".format(torch.isnan(feat_loss).any()))
                    f.write("is their nan in the clustering_loss : {} \n".format(torch.isnan(clustering_loss).any()))
                    f.write("is their nan in the loss : {} \n".format(torch.isnan(loss).any()))
                    f.write("the losses are : linkpred {} , mse {} , clustering {} , struct {} , feat {} \n".format(link_prediction_loss.item() , mse_loss.item() , clustering_loss.item() , struct_loss.item() , feat_loss.item()))
                self.student_optimizer.zero_grad()
                loss.backward()
                self.student_optimizer.step()
                epoch_loss += loss.item()
                epoch_clustering_loss += clustering_loss.item()
                epoch_link_prediction_loss += link_prediction_loss.item()

                # clear memory
                del X, adj, adj_aug, student_output, Q, P, kl_loss, struct_loss, feat_loss, loss , middle_representation , middle_representation_edge , middle_representation_feat  , clustering_loss , pe_feat , pe_feat_dense , link_prediction_loss , link_prediction
                torch.cuda.empty_cache()
            self.student_scheduler.step(epoch_loss)
            if epoch_loss < lowest_loss :
                lowest_loss = epoch_loss
                self.save_checkpoint(epoch , model='best_student')
                print("Best student checkpoint saved at epoch {}".format(epoch))
            if epoch_loss > lowest_loss :
                patience += 1
            else :
                patience = 0
            if patience > 10 :
                print("Early stopping")
                break

            print("Epoch : {} , Loss : {} , clustering_loss : {} , link_pred_loss : {}".format(epoch , epoch_loss , epoch_clustering_loss , epoch_link_prediction_loss))
            if epoch % 10 == 0 :
                self.save_checkpoint(epoch , model='student')
                print("Student model checkpoint saved at epoch {}".format(epoch))

    """
    Save checkpoint
    """

    def save_checkpoint(self , epoch :int , path = "/T2_GNN/save_checkpoint/" , model = 'student' ):
        if not os.path.exists(path):
            os.makedirs(path)

        if model == 'student':
            torch.save(self.student.state_dict() , path+'_student.pth')
        elif model == 'feat_teacher':
            torch.save(self.feature_teacher.state_dict() , path+'_feat_teacher.pth')
        elif model == 'edge_teacher':
            torch.save(self.edge_teacher.state_dict() , path+'_edge_teacher.pth')
        elif model == 'best_student':
            torch.save(self.student.state_dict() , path+'_best_student.pth')
        elif model == 'best_feat_teacher':
            torch.save(self.feature_teacher.state_dict() , path+'_best_feat_teacher.pth')
        elif model == 'best_edge_teacher':
            torch.save(self.edge_teacher.state_dict() , path+'_best_edge_teacher.pth')
        else :
            raise ValueError("Model must be student or feat_teacher or edge_teacher")

    """
    Load checkpoint
    """

    def load_checkpoint(self , path = "/T2_GNN/save_checkpoint/" , model = 'student'):
        if not os.path.exists(path):
            print("No checkpoint found")
            print("Training from scratch")
            return

        if model == 'student':
            self.student.load_state_dict(torch.load(path+'_best_student.pth'))
        elif model == 'feat_teacher':
            self.feature_teacher.load_state_dict(torch.load(path+'_best_feat_teacher.pth'))
        elif model == 'edge_teacher':
            self.edge_teacher.load_state_dict(torch.load(path+'_best_edge_teacher.pth'))
        else :
            raise ValueError("Model must be student or feat_teacher or edge_teacher")


from datetime import datetime,timedelta
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
import os,glob
#from scipy.ndimage import boxcarsmooth
#from scipy.ndimage import smooth_previous
from collections import Counter
import scipy.interpolate as interp
from scipy.optimize import curve_fit
from sklearn.datasets import make_regression
from sklearn.isotonic import IsotonicRegression

def date_key(a):
    b = datetime.strptime(a, '%d.%m.%Y').date()
    return b

def smooth_previous(series, days):
    # specialni zhlazovani: pro dany den se uvazuji prumerne hodnoty teplot z predchozich "days" dni.
    # duvod: ocekava se, ze vliv budou mit udalosti predchozi, ne budouci, proto klasicke (oboustranne)
    # zhlazovani nemusi byt reprezentativni
    new_series=np.zeros_like(series)
    for i in range(days,len(series)):
        new_series[i]=np.mean(series[i-days:i])
    return new_series

def boxcarsmooth(y, box_pts):
    box = np.ones(box_pts)/box_pts
    y_smooth = np.convolve(y, box, mode='same')
    return y_smooth

#mean temperature tct to dataframe
path_mt = '/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/meteodata/mean_temperature/'
mean_temp = [f for f in os.listdir(path_mt) if f.endswith('.txt')]
col_mt=['souid','date','tg','q_tg']
for i,item in enumerate(mean_temp):
        if i==0:
            mean_temp_data1=pd.read_csv(str(path_mt)+str(item), sep=",", names= col_mt, header=None)
        elif i==1:
            mean_temp_data2=pd.read_csv(str(path_mt)+str(item), sep=",", names= col_mt, header=None)
        elif i==2:
            mean_temp_data3=pd.read_csv(str(path_mt)+str(item), sep=",", names= col_mt, header=None)
        else:
            pass
#mean_temp_data1_cl=mean_temp_data1[mean_temp_data1['q_tg']!=9]
mean_temp_data1.loc[mean_temp_data1.q_tg == 9, 'tg'] = 0
#mean_temp_data2_cl=mean_temp_data2[mean_temp_data2['q_tg']!=9]
mean_temp_data2.loc[mean_temp_data2.q_tg == 9, 'tg'] = 0
#mean_temp_data3_cl=mean_temp_data3[mean_temp_data3['q_tg']!=9]
mean_temp_data3.loc[mean_temp_data3.q_tg == 9, 'tg'] = 0
mean_temp_data=pd.concat([mean_temp_data1, mean_temp_data2,mean_temp_data3],ignore_index=False).groupby(['date'],as_index=False).mean('tg')
#date and temperature to list
mt_date=list(mean_temp_data['date'])
mt_date = [int(item) for item in mt_date]
mt_tg=list(mean_temp_data['tg'])

#precipitation amount txt to dataframe
path_pa = '/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/meteodata/precipitation_amount/'
prec_amount = [f for f in os.listdir(path_pa) if f.endswith('.txt')]
col_pa=['souid','date','rr','q_rr']
for i,item in enumerate(prec_amount):
        if i==0:
            prec_amount_data1=pd.read_csv(str(path_pa)+str(item), sep=",", names= col_pa, header=None)
        elif i==1:
            prec_amount_data2=pd.read_csv(str(path_pa)+str(item), sep=",", names= col_pa, header=None)
        elif i==2:
            prec_amount_data3=pd.read_csv(str(path_pa)+str(item), sep=",", names= col_pa, header=None)
        else:
            pass
#prec_amount_data1_cl=prec_amount_data1[prec_amount_data1['q_rr']!=9]
prec_amount_data1.loc[prec_amount_data1.q_rr == 9, 'rr'] = 0
#prec_amount_data2_cl=prec_amount_data2[prec_amount_data2['q_rr']!=9]
prec_amount_data2.loc[prec_amount_data2.q_rr == 9, 'rr'] = 0
#prec_amount_data3_cl=prec_amount_data3[prec_amount_data3['q_rr']!=9]
prec_amount_data3.loc[prec_amount_data3.q_rr == 9, 'rr'] = 0
prec_amount_data=pd.concat([prec_amount_data1, prec_amount_data2,prec_amount_data3],ignore_index=False).groupby(['date'],as_index=False).mean('rr')
#date and precipitation amount to list
pa_date=list(prec_amount_data['date'])
pa_date = [int(item) for item in pa_date]
pa_rr=list(prec_amount_data['rr'])

#kindex

#BUDKOV
#filein='/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/kindex/k-3.txt'

#HURBANOVO
filein='/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/kindex_hurb_420nt/k_value/k-3.txt'

f = open(filein, 'r')
lines = f.readlines()
f.close()
x=[]
dates=[]
k=[]
for line in lines:
        p = line.split()
        x.append(float(p[0])) #poradie#
        dates.append(p[1])
        k.append(float(p[2])) #kindex
poradie = np.array(x)
kindex = np.array(k)
kindex_date_arr=[]
for i,item in enumerate(dates):
    kindex_date_arr.append(datetime.strptime(str(item), '%d.%m.%Y'))
#datetiem to string in format YYYYmmdd
kindex_date=[date_obj.strftime('%Y%m%d') for date_obj in kindex_date_arr]

#['09.07.2011', '10.08.2012', '08.07.2015']
peak_dates=[datetime(2011,7,9),datetime(2012,8,10),datetime(2015,7,8)]
peaks=[[datetime(2011,5,9),datetime(2011,9,9)],
       [datetime(2012,6,10),datetime(2012,10,10)],
       [datetime(2015,5,8),datetime(2015,9,8)]]

st_ind=[]
ed_ind=[]
mydates=[]
for j,peak in enumerate(peaks):
    mydates.append(pd.date_range(peak[0],peak[1]-timedelta(days=1),freq='d'))
    for i,item in enumerate(kindex_date_arr):
        if item ==peak[0]:
            st_ind.append(i)
        elif item==peak[1]:
            ed_ind.append(i)
    fig,(ax1) = plt.subplots(1,figsize=(8,6))
    ax1.plot(mydates[j],kindex[st_ind[j]:ed_ind[j]], 'k' ,label='k index')
    ax1.axvline(x=peak_dates[j],c='red',ls='--', lw=1)
    ax1.text(0.6, 0.8, str(peak_dates[j].date()), horizontalalignment='center', verticalalignment='center', transform=ax1.transAxes, c='red')
    ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
    ax1.tick_params(axis='x', rotation=30)
    ax1.legend(loc='best')
    #plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/plots/kindex_for_special_peaks'+str(peak_dates[j].date())+'.eps', format='PDF')
    #plt.show()
    plt.close()

#poruchy
file_datumy_poruch='/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/distributori/dataset-1-poruchy.txt'
f3=open(file_datumy_poruch, 'r')
lines3 = f3.readlines()
f3.close()

date_=[]
for line in lines3:
    p=line.split()
    date_.append(str(p[0]))# datum poruch

dist_dates=[]
for i in date_:
    dist_dates.append(date_key(i))
binss=pd.date_range(dist_dates[0],dist_dates[-1],freq='d')
binss_str=binss.strftime('%Y%m%d')

fail_date_arr=[]
for i,item in enumerate(date_):
    fail_date_arr.append(datetime.strptime(str(item), '%d.%m.%Y'))

#datetiem to string in format YYYYmmdd
fail_date=[date_obj.strftime('%Y%m%d') for date_obj in fail_date_arr]

#for K INDEX AND METEODATA
first_ind=[]
for i,item in enumerate(kindex_date):
    if item == str(pa_date[0]):
        print(i)
        first_ind=i

last_ind=[]
for i,item in enumerate(pa_date):
    if str(item) == (kindex_date[-1]):
        last_ind=i

#OREZANIE POLI
kindex_k=kindex[first_ind:]
mt_tg_k=mt_tg[:last_ind+1]
pa_rr_k=pa_rr[:last_ind+1]

#VYKRESLENIE GRAFOV
fig, ((ax1), (ax2),(ax3)) = plt.subplots(nrows=3, ncols=1, sharex=True, sharey=False,figsize=(10,8))
ax1.plot(kindex_k, label='k-index')
ax1.legend()
ax2.plot(mt_tg_k, label='priemerne teploty')
ax2.legend()
ax3.plot(pa_rr_k, label='uhrn zrazok')
ax3.legend()
#plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/plots/meteodata_vs_kindex.pdf', format="PDF")
#plt.show()
plt.close()

#FOR FAILURES AND METEODATA
strt_ind=[]
end_ind=[]
for i,item in enumerate(mt_date):
    if str(item) == (fail_date[0]):
        strt_ind = i
    elif str(item) == (fail_date[-1]):
        end_ind = i
    else:
        pass

#FOR FAILURES AND KINDEX
strt_ind_k=[]
end_ind_k=[]
for i,item in enumerate(kindex_date):
    if str(item) == (fail_date[0]):
        strt_ind_k = i
    elif str(item) == (fail_date[-1]):
        end_ind_k = i
    else:
        pass

#orezanie na rovnake indexy
mt_date=mt_date[strt_ind+2:end_ind+1]
mt_tg=mt_tg[strt_ind+2:end_ind+1]

pa_date=pa_date[strt_ind+2:end_ind+1]
pa_rr=pa_rr[strt_ind+2:end_ind+1]

k_date=kindex_date[strt_ind_k+2:end_ind_k+1]
k_val=kindex[strt_ind_k+2:end_ind_k+1]

#string date to datetime in order to do ordinal dates
mt_date_dt=[]
for i,item in enumerate(mt_date):
    mt_date_dt.append(datetime.strptime(str(item), '%Y%m%d'))
pa_date_dt=[]
for i,item in enumerate(pa_date):
    pa_date_dt.append(datetime.strptime(str(item), '%Y%m%d'))
k_date_dt=[]
for i,item in enumerate(k_date):
    k_date_dt.append(datetime.strptime(str(item), '%Y%m%d'))

#BINOVANIE DAT
ord_bins=[]
for i in range(1,len(binss)):
  ord_bins.append(datetime.toordinal(binss[i]))

ord_dist=[]
for i in range(1,len(dist_dates)):
  ord_dist.append(datetime.toordinal(dist_dates[i]))

X=np.histogram(ord_dist, ord_bins)

dat=(X[1])  #[:-1]
peaks=X[0]

D=[]
for i in range(1,len(dat)):
  D.append(datetime.fromordinal(dat[i]))

D1=D
Y1=peaks

D2=mt_date_dt
Y2=mt_tg

D3=pa_date_dt
Y3=pa_rr

D4=k_date_dt
Y4=k_val

# ##ulozenie dat do txt files
dat_mt = np.array([D2, Y2])
dat_mt = dat_mt.T
np.savetxt('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/meteodata/mean_temperature/mean_temp_.txt', dat_mt , delimiter='\t', fmt="%s")

dat_pa = np.array([D3, Y3])
dat_pa = dat_pa.T
np.savetxt('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/meteodata/precipitation_amount/prec_amount_.txt', dat_pa , delimiter='\t', fmt="%s")

# for window in [10,20,30,40,50,60,70,80,90,100]:
#     mean_temp_smooth=smooth_previous(np.asarray(Y2).astype('float'),window)
#     dat_mt = np.array([D2, mean_temp_smooth])
#     dat_mt = dat_mt.T

#     prec_amount_smooth=smooth_previous(np.asarray(Y3).astype('float'),window)
#     dat_pa = np.array([D3, prec_amount_smooth])
#     dat_pa = dat_pa.T

#     np.savetxt('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/meteodata/mean_temp_' + str(window) + '.txt', dat_mt , delimiter='\t', fmt="%s")
#     np.savetxt('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/meteodata/prec_amount_' + str(window) + '.txt', dat_pa , delimiter='\t', fmt="%s")

sigma=20
#print(min(smooth_previous(Y2,sigma)/10))

corr_coeff_k=np.corrcoef(boxcarsmooth(np.asarray(Y1).astype('float'),sigma),boxcarsmooth(Y4,sigma))[1][0]
corr_coeff_mt=np.corrcoef(boxcarsmooth(np.asarray(Y1).astype('float'),sigma),smooth_previous(Y2,sigma)/10)[1][0]
corr_coeff_pa=np.corrcoef(boxcarsmooth(np.asarray(Y1).astype('float'),sigma),smooth_previous(Y3,sigma))[1][0]

fig, ((ax1),(ax2),(ax3),(ax4)) = plt.subplots(nrows=4, ncols=1, sharex=True, sharey=False,figsize=(10,8))
ax1.set_title('Smoothing window '+str(sigma)+' days')
ax1.plot(D1, boxcarsmooth(np.asarray(Y1).astype('float'),sigma),'r',label='disturbances')
ax1.legend()
ax2.plot(D4, boxcarsmooth(Y4,sigma),'k',label='kindex')
ax2.legend()
ax2.text(0.85, 0.1, 'corr_coef = '+str(round(corr_coeff_k,4)), horizontalalignment='center', verticalalignment='center', transform=ax2.transAxes, c='k')
ax3.plot(D2, smooth_previous(Y2,sigma)/10,label='mean temperature')
ax3.legend()
ax3.text(0.85, -1.1, 'corr_coef = '+str(round(corr_coeff_mt,4)), horizontalalignment='center', verticalalignment='center', transform=ax2.transAxes,c='C0')
ax4.plot(D3, smooth_previous(Y3,sigma),'g',label='precipitation amount',)
ax4.legend()
ax4.text(0.85, -1.8, 'corr_coef = '+str(round(corr_coeff_pa,4)), horizontalalignment='center', verticalalignment='center', transform=ax2.transAxes, c='g')
plt.xlabel('dates')
plt.xticks(rotation=45, ha='right')
#BUDKOV
#plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/plots/prec_amount_mean_temp_dist.pdf', format='PDF')
#HURBANOVO
plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/kindex_hurb_420nT/plots/prec_amount_mean_temp_dist.pdf', format='PDF')
#plt.show()
plt.close()

####################################################################################################################################################
#FITOVANIE
MT=smooth_previous(Y2,sigma)/10
DIST=boxcarsmooth(np.asarray(Y1).astype('float'),sigma)

def polynom(x, a, b, c, d ):
    return a*x*x*x + b*x*x + c*x + d
    #return d + c * x + b * np.exp(a * x)

popt, _ = curve_fit(polynom, MT[::sigma], DIST[::sigma]) #kazdy n prvok kvoli zhladzovaniu sigmaa=n aby sme dostali nezlavisle hodnoty
a,b,c,d=popt
fit_eq=('y = %.10f * x^3 + %.10f * x^2 + %.10f * x + %.10f' % (a, b, c, d))
print(fit_eq)

#a = 0.00001
#b = 0.00047
#c = 0.00508
#d = 0.07031

plt.plot(MT[::sigma],DIST[::sigma], markersize=1,label='sigma='+str(sigma),linestyle='None', marker="o")
plt.xlabel('mean temperature [$^\circ$C]')
plt.ylabel('Daily anomaly rate (smoothed & binned)')
plt.legend(loc='best')
x_line = np.arange(min(MT[::sigma]), max(MT[::sigma]), 1)
# calculate the output for the range
y_line = polynom(x_line, a, b, c, d)
# create a line plot for the mapping function
plt.plot(x_line, y_line, '--', color = 'red')
#plt.text(0, 0.1, fit_eq, color = 'red')
#BUDKOV
#plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/plots/MT_DIST_function_boxcarsmooth_test.pdf', format='PDF')
#HURBANOVO
#plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/kindex_hurb_420nT/plots/MT_DIST_function_boxcarsmooth_test.pdf', format='PDF')
plt.show()
plt.close()

#rezidua a test
DIST_COMPT=[]
for i in MT[::sigma]:
    DIST_COMPT.append(polynom(i,a,b,c,d))

rezid=DIST[::sigma]-DIST_COMPT
plt.plot(MT[::sigma],rezid,'o',markersize=1)
plt.xlabel('mean temperature [$^\circ$C]')
plt.ylabel('Residual of disturbances')
#plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/plots/MT_DIST_rezid_boxcarsmooth.pdf', format='PDF')
#plt.show()
plt.close()

plt.hist(rezid, density=True, bins=10)  # density=False would make counts
plt.ylabel('Probability')
plt.xlabel('Residual disturbances')
#plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/plots/MT_DIST_rezid_HIST_boxcarsmooth.pdf', format='PDF')
#plt.show()
plt.close()

##########################################################################################################################################################################
# MODELOVE PORUCHY

#pocitam model pre nezhladene priemerne teploty
model_dist=[]
for i in MT:
    #model_dist.append(round(polynom(i,a,b,c,d)))
    model_dist.append(polynom(i,a,b,c,d))
np.savetxt('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/model_dist'+str(sigma)+'.txt', model_dist,fmt='%1.4f')

#zaporne hodnoty prahujem nulou
new_model_dist = []
for ind, item in enumerate(model_dist):
    if item <= 0:
        new_model_dist.append(0)
    else:
        new_model_dist.append(item)

#modelove poruchy bez teplotnej zavislosti
#rezid_dist = boxcarsmooth(np.asarray(Y1).astype('float'),sigma) - new_model_dist
#new_model_dist=[round(num) for num in new_model_dist]
rezid_dist = Y1 - new_model_dist

print(max(Y1),max(new_model_dist),min(Y1),min(new_model_dist))

# #len dalsie prahovanie nulou, nasobenie 100 aby sme mali cele cisla
new_rezid_dist = []
for ind, item in enumerate(rezid_dist):
    if item <= 0:
        new_rezid_dist.append(0)
    else:
        new_rezid_dist.append(round(item))

fig, ((ax1),(ax2),(ax3), (ax4)) = plt.subplots(4,figsize=(10,8))
ax1.plot(Y1, color='darkblue', label='original dist')
ax1.legend(loc='best')
ax2.plot(DIST, 'g', label='boxcarsmoothed dist')
ax2.legend(loc='best')
ax3.plot(new_model_dist,'r', label='modeled dist')
ax3.legend(loc='best')
ax4.plot(new_rezid_dist, color= 'purple', label='rezid dist')
ax4.legend(loc='best')
#plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/plots/boxcarsmooth_rezid.pdf', format='PDF')
#plt.show()
plt.close()

import time
new_D1=[]
for i in D1:
    new_D1.append(i.strftime("%d.%m.%Y"))

model_dist_dates=[]
for ind, item in enumerate(new_rezid_dist):
    if item > 0:
        model_dist_dates.extend( [new_D1[ind]] * int(item))

#np.savetxt('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/distributori/dataset-1-poruchy_rezid_boxcarsmooth.txt', model_dist_dates,fmt='%s')
np.savetxt('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/distributori/dataset-1-poruchy_rezid_test.txt', model_dist_dates,fmt='%s')

##########################################################################################################################################################################
#REZIDUA
model_dist_dt=[]
for i, item in enumerate(model_dist_dates):
    model_dist_dt.append((datetime.strptime(str(item), '%d.%m.%Y')))

#BINOVANIE DAT
model_ord_dist=[]
for i in range(1,len(model_dist_dt)):
  model_ord_dist.append(datetime.toordinal(model_dist_dt[i]))

model_X=np.histogram(model_ord_dist, ord_bins)

model_dat=(model_X[1])  #[:-1]
model_peaks=model_X[0]
model_Y=model_peaks

model_D=[]
for i in range(1,len(model_dat)):
  model_D.append(datetime.fromordinal(model_dat[i]))

rezid_dist_divided = [x  for x in new_rezid_dist]
rezid_model_seps =  boxcarsmooth(np.asarray(Y1).astype('float'),sigma) - new_model_dist  #rezid_dist_divided - boxcarsmooth(np.asarray(Y1).astype('float'),sigma)

#fig, ((ax1),(ax2),(ax3),(ax4),(ax5),(ax6),(ax7),(ax8)) = plt.subplots(nrows=8, ncols=1, sharex=True, sharey=False,figsize=(12,10))
fig, ((ax1),(ax2),(ax3),(ax4),(ax5),(ax6),(ax7),(ax8)) = plt.subplots(nrows=8, ncols=1, sharex=True, sharey=False,figsize=(12,10))

ax1.set_title('Smoothing window '+str(sigma)+' days')
ax1.plot(D1,Y1,'r',label='SEPS dist')
ax1.legend()
ax2.plot(D1, boxcarsmooth(np.asarray(Y1).astype('float'),sigma),'r',label='smoothed SEPS dist')
ax2.legend()
ax3.plot(model_D, boxcarsmooth(np.asarray(new_model_dist).astype('float'),sigma),'orange',label='modeled dist')
ax3.legend()
#ax4.plot(model_D,rezid_model_seps,'k',label='reziduum modeled & smoothed SEPS dist')
#ax4.legend()
#ax5.plot(model_D,boxcarsmooth(np.asarray(rezid_model_seps).astype('float'),sigma),'k',label='smoothed reziduum modeled & SEPS dist')
#ax5.legend()
ax4.plot(model_D,rezid_dist_divided,label='reziduum')
ax4.legend()
ax5.plot(model_D, boxcarsmooth(np.asarray(rezid_dist_divided).astype('float'),sigma),label='smoothed reziduum')
ax5.legend()

#ax7.xaxis.set_tick_params(labelbottom=True, size=2)
ax6.plot(D4, boxcarsmooth(Y4,sigma),'k',label='kindex')
ax6.legend()
#ax3.xaxis.set_tick_params(labelbottom=True, size=2)
#ax4.xaxis.set_tick_params(labelbottom=True, size=2)
ax7.plot(D2, MT,'m',label='mean temperature')
ax7.legend()
ax8.plot(D3, boxcarsmooth(Y3,sigma),'g',label='precipitation amount')
ax8.legend()
plt.xlabel('dates')
#plt.xticks(rotation=45, ha='right')
#BUDKOV
#plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/plots/mean_temp_modeled_dist_boxcarsmooth_FINAL_SEPS.pdf', format='PDF')
#HURBANOVO
plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/kindex_hurb_420nT/plots/mean_temp_modeled_dist_boxcarsmooth_FINAL_SEPS.pdf', format='PDF')
plt.show()
plt.close()

with open('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/Michal_data.txt','w') as f:
    lis=[np.array(D1),np.array(Y1),np.array(MT)]
    for x in zip(*lis):
        f.write("{0}\t{1}\t{2}\n".format(*x))
#MODELED
sigmas=range(1,200)
Corr_mt=[]
Corr_pa=[]
Corr_k=[]
for isigma in sigmas:
  Corr_mt.append((np.corrcoef(boxcarsmooth(np.asarray(model_Y).astype('float'),isigma),boxcarsmooth(np.asarray(Y2).astype('float'),isigma)))[0,1])
  Corr_pa.append((np.corrcoef(boxcarsmooth(np.asarray(model_Y).astype('float'),isigma),boxcarsmooth(np.asarray(Y3).astype('float'),isigma)))[0,1])
  Corr_k.append((np.corrcoef(boxcarsmooth(np.asarray(model_Y).astype('float'),isigma),boxcarsmooth(np.asarray(Y4).astype('float'),isigma)))[0,1])

fig,((ax1),(ax2),(ax3))=plt.subplots(nrows=3, ncols=1, sharex=True, sharey=False,figsize=(10,8))
ax1.plot(sigmas, Corr_k, 'k', label='k index')
ax1.legend()
ax1.set_xlabel('Smoothing window [days]')
ax1.set_ylabel('Correlation coefficient')
ax1.xaxis.set_tick_params(labelbottom=True, size=10)
ax2.plot(sigmas, Corr_mt, label='mean temperature')
ax2.legend()
ax2.set_xlabel('Smoothing window [days]')
ax2.set_ylabel('Correlation coefficient')
ax2.xaxis.set_tick_params(labelbottom=True, size=10)
ax3.plot(sigmas, Corr_pa, 'g', label='precipitation amount')
ax3.legend()
ax3.set_xlabel('Smoothing window [days]')
ax3.set_ylabel('Correlation coefficient')
#BUDKOV
#plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/plots/korelace_prec_amount_mean_temp_modeled_dist_boxcarsmooth_FINAL.pdf', format='PDF')
#HURBANOVO
#plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/kindex_hurb_420nT/plots/korelace_prec_amount_mean_temp_modeled_dist_boxcarsmooth_FINAL.pdf', format='PDF')
plt.show()
plt.close()

#ORIGINAL
sigmas=range(1,200)
Corr_mt=[]
Corr_pa=[]
Corr_k=[]
for isigma in sigmas:
  Corr_mt.append((np.corrcoef(boxcarsmooth(np.asarray(Y1).astype('float'),isigma),boxcarsmooth(np.asarray(Y2).astype('float'),isigma)))[0,1])
  Corr_pa.append((np.corrcoef(boxcarsmooth(np.asarray(Y1).astype('float'),isigma),boxcarsmooth(np.asarray(Y3).astype('float'),isigma)))[0,1])
  Corr_k.append((np.corrcoef(boxcarsmooth(np.asarray(Y1).astype('float'),isigma),boxcarsmooth(np.asarray(Y4).astype('float'),isigma)))[0,1])

fig,((ax1),(ax2),(ax3))=plt.subplots(nrows=3, ncols=1, sharex=True, sharey=False,figsize=(10,8))
ax1.plot(sigmas, Corr_k, 'k', label='k index')
ax1.legend()
ax1.set_xlabel('Smoothing window [days]')
ax1.set_ylabel('Correlation coefficient')
ax1.xaxis.set_tick_params(labelbottom=True, size=10)
ax2.plot(sigmas, Corr_mt, label='mean temperature')
ax2.legend()
ax2.set_xlabel('Smoothing window [days]')
ax2.set_ylabel('Correlation coefficient')
ax2.xaxis.set_tick_params(labelbottom=True, size=10)
ax3.plot(sigmas, Corr_pa, 'g', label='precipitation amount')
ax3.legend()
ax3.set_xlabel('Smoothing window [days]')
ax3.set_ylabel('Correlation coefficient')
#BUDKOV
#plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/plots/korelace_prec_amount_mean_temp_modeled_dist_boxcarsmooth_FINAL.pdf', format='PDF')
#HURBANOVO
plt.savefig('/Users/Taninka/Documents/skola_PhD/STATISTICAL_ANALYSIS/SEPS/data/kindex_hurb_420nT/plots/orig_korelace_prec_amount_mean_temp_modeled_dist_boxcarsmooth_FINAL.pdf', format='PDF')
plt.show()
plt.close()

#import code
#code.interact(local=locals())
print('finished')


import requests
import os
from dotenv import load_dotenv

load_dotenv()
API_KEY = os.getenv("MAPS_API_KEY")

# Define the location you want to search for
# address = '1600 Amphitheatre Parkway, Mountain View, CA'
print("Enter address (street, city, state):")
address = input()

# Build the API request URL
url = f'https://maps.googleapis.com/maps/api/geocode/json?address={address}&key={API_KEY}'

# Send the API request and parse the response
response = requests.get(url)
data = response.json()

# Extract the latitude and longitude from the response
lat = data['results'][0]['geometry']['location']['lat']
lng = data['results'][0]['geometry']['location']['lng']

# Print the latitude and longitude
# print(f"Latitude: {lat}")
# print(f"Longitude: {lng}")
print(f"{lat},{lng}")


import streamlit as st
from images import ImageVoteManager
from poem import PoemManager
import os
from PIL import Image

curr_dir = os.path.dirname(os.path.abspath(__file__))

st.set_page_config("Demo: Poem Image Viewer")
st.title("Poem Image Viewer")

image_vote_manager = ImageVoteManager(
    os.path.join(curr_dir, "../data/votes.tsv"),
    os.path.join(curr_dir, "../static/images"),
)
poem_manager = PoemManager(os.path.join(curr_dir, "../data/poems.tsv"))

poem_index = st.selectbox(
    "Select Poem",
    poem_manager._data.index,
    format_func=lambda x: f'{poem_manager._data.loc[x]["id"]} - {poem_manager._data.loc[x]["author"]} - {poem_manager._data.loc[x]["title"]}',
)

poem = poem_manager[poem_index]
prettify_content = poem.content.replace("，", "，\n").replace("。", "。\n")

st.subheader(poem.title)
st.caption(f"Author: {poem.author}")
st.caption(f"Dynasty: {poem.dynasty}")
st.text(prettify_content)

images = image_vote_manager.get_images_by_id(poem.id)
for prompt_name, df in images.groupby("prompt_name"):
    st.subheader(f"{prompt_name} Result")
    for i, row in df.iterrows():
        st.image(Image.open(row["image_file"]), caption=row["version"])


"""Special handler for modifier."""
from __future__ import annotations

from typing import TYPE_CHECKING

from ..strategy import VERSION_STRATEGIES_DICT, AwesomeVersionStrategy
from ..utils.regex import RE_MODIFIER

SEMVER_MODIFIER_MAP = {"dev": 0, "alpha": 1, "beta": 2, "rc": 3}

if TYPE_CHECKING:
    from awesomeversion import AwesomeVersion

def compare_handler_semver_modifier(
    version_a: AwesomeVersion,
    version_b: AwesomeVersion,
) -> bool | None:
    """Compare handler sections."""
    if AwesomeVersionStrategy.SEMVER not in (
        version_a.strategy,
        version_b.strategy,
    ) or (version_a.modifier_type is None or version_b.modifier_type is None):
        return None

    if version_a.modifier_type != version_b.modifier_type:
        mod_a = SEMVER_MODIFIER_MAP.get(version_a.modifier_type)
        mod_b = SEMVER_MODIFIER_MAP.get(version_b.modifier_type)
        if mod_a is not None and mod_b is not None:
            return mod_a > mod_b

    ver_a_modifier, ver_b_modifier = None, None

    semver_pattern = VERSION_STRATEGIES_DICT[AwesomeVersionStrategy.SEMVER].pattern

    semver_match = semver_pattern.match(version_a.string)
    if semver_match and len(semver_match.groups()) >= 4:
        modifier_match = RE_MODIFIER.match(semver_match.group(4))
        if modifier_match and len(modifier_match.groups()) >= 4:
            ver_a_modifier = modifier_match.group(4)

    semver_match = semver_pattern.match(version_b.string)
    if semver_match and len(semver_match.groups()) >= 4:
        modifier_match = RE_MODIFIER.match(semver_match.group(4))
        if modifier_match and len(modifier_match.groups()) >= 4:
            ver_b_modifier = modifier_match.group(4)

    if not ver_a_modifier or not ver_b_modifier:
        return True

    return int(ver_a_modifier) > int(ver_b_modifier)


import hydra
from comet_ml import Experiment

import torch.nn as nn
import torch.optim as optim

from sklearn.datasets import load_iris

import enchanter.tasks as tasks
import enchanter.addons.layers as layers

x, y = load_iris(return_X_y=True)
x = x.astype("float32")
y = y.astype("int64")

@hydra.main("config", "config.yaml")
def main(cfg):
    shapes = cfg.model.shapes
    opt_params = cfg.optimizer.params

    experiment = Experiment(log_code=False)
    experiment.set_code(filename=hydra.utils.to_absolute_path(__file__))
    experiment.add_tag("with_hydra")
    experiment.log_parameters({"hydra-cfg": [cfg]})
    model = layers.MLP(shapes)
    optimizer = optim.Adam(model.parameters(), **opt_params)
    runner = tasks.ClassificationRunner(
        model,
        optimizer=optimizer,
        criterion=nn.CrossEntropyLoss(),
        experiment=experiment
    )
    runner.fit(x, y, epochs=10, checkpoint_path="./checkpoints")
    runner.save()

if __name__ == '__main__':
    main()


import os
import argparse
import torch

from MSHGT.funcset.data import get_dataset, train_val_test_split
import torch.nn as nn
from torch_geometric.utils import degree
from MSHGT.funcset.utils import adj_to_coo
from MSHGT.funcset.draw import draw_loss, draw_acc, visualize_embedding
from MSHGT.model.ACM.mshgt import MSHGTModel
from sklearn.metrics import f1_score
import scipy.io as sio
from torch_geometric.data import HeteroData

device = torch.device('cuda' if torch.cuda.is_available() else "cpu")

def load_args():
    parser = argparse.ArgumentParser(description='MSHGT', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('--seed', type=int, default=52, help='random seed')
    parser.add_argument('--dataset', type=str, default='ACM', help='name of dataset')  # adjust
    parser.add_argument('--hidden-dim', type=int, default=64, help="hidden dimension of Transformer")  # adjust
    parser.add_argument('--dropout', type=float, default=0.4, help="dropout-rate")
    parser.add_argument('--epochs', type=int, default=300, help='number of epochs')
    parser.add_argument('--num-layers', type=int, default=1, help="number of transformer encoders")
    parser.add_argument('--heads', type=int, default=4, help="number of transformer multi-heads")
    parser.add_argument('--lr', type=float, default=0.01, help='initial learning rate')  # adjust
    parser.add_argument('--weight-decay', type=float, default=5e-4, help='weight decay')
    parser.add_argument('--use_lr_schedule', type=bool, default=False, help='whether use warmup?')  # adjust
    parser.add_argument('--convergence_epoch', type=int, default=250, help="number of epochs for warmup")  # adjust
    parser.add_argument('--use_early_stopping', type=bool, default=True,
                        help="whether to use early stopping")  # adjust
    parser.add_argument('--patience', type=int, default=200, help='val_dataset loss increases or is stable '
                                                                  'before the maximum iterations')  # adjust

    args = parser.parse_args()

    return args

def train(model, data, original_A, y, train_mask, deg, loss_fn, optimizer):
    model.train()
    loss_pe, out, embs = model(data, original_A, deg)
    loss_acc = loss_fn(out[train_mask], y[train_mask])
    l = loss_pe + loss_acc
    optimizer.zero_grad()
    l.backward()
    optimizer.step()

    pred = out.argmax(dim=1)
    marco_f1 = f1_score(y_true=y[train_mask].cpu().numpy(), y_pred=pred[train_mask].cpu().numpy(), average='macro')
    mirco_f1 = f1_score(y_true=y[train_mask].cpu().numpy(), y_pred=pred[train_mask].cpu().numpy(), average='micro')

    return l.cpu().detach().numpy(), marco_f1, mirco_f1

def validate(model, data, original_A, y, val_mask, deg, loss_fn):
    model.eval()
    with torch.no_grad():
        loss_pe, out, embs = model(data, original_A, deg)
        loss_acc = loss_fn(out[val_mask], y[val_mask])
        l = loss_pe + loss_acc
        pred = out.argmax(dim=1)
        marco_f1 = f1_score(y_true=y[val_mask].cpu().numpy(), y_pred=pred[val_mask].cpu().numpy(), average='macro')
        mirco_f1 = f1_score(y_true=y[val_mask].cpu().numpy(), y_pred=pred[val_mask].cpu().numpy(), average='micro')
    return l.cpu().detach().numpy(), marco_f1, mirco_f1

def test(model, data, original_A, y, test_mask, deg):
    model.eval()
    with torch.no_grad():
        loss_pe, out, embs = model(data, original_A, deg)
        pred = out.argmax(dim=1)
        marco_f1 = f1_score(y_true=y[test_mask].cpu().numpy(), y_pred=pred[test_mask].cpu().numpy(), average='macro')
        mirco_f1 = f1_score(y_true=y[test_mask].cpu().numpy(), y_pred=pred[test_mask].cpu().numpy(), average='micro')
    return marco_f1, mirco_f1, embs

def main():
    global args
    args = load_args()
    print(args)

    # set_random_seed(args.seed)
    path = 'ACM3025.mat'
    dataset = sio.loadmat(path)
    data = HeteroData()
    adj_ptp = torch.tensor(dataset['PTP'], dtype=torch.float32)
    data['PTP'].edge_index = adj_to_coo(adj_ptp)._indices()
    adj_plp = torch.tensor(dataset['PLP'], dtype=torch.float32)
    data['PLP'].edge_index = adj_to_coo(adj_plp)._indices()
    adj_pap = torch.tensor(dataset['PAP'], dtype=torch.float32)
    data['PAP'].edge_index = adj_to_coo(adj_pap)._indices()

    data['P'].x = torch.tensor(dataset['feature'], dtype=torch.float32)
    data['P'].y = torch.tensor(dataset['label'], dtype=torch.float32).nonzero()[:, 1]
    data['P'].train_idx = torch.tensor(dataset['train_idx'][0])
    data['P'].val_idx = torch.tensor(dataset['train_idx'][0])
    data['P'].test_idx = torch.tensor(dataset['train_idx'][0])
    print(data)

    num_nodes = adj_pap.shape[0]
    num_classes = len((data['P'].y).unique())
    in_dim = data['P'].x.shape[1]

    original_A = []
    original_A.append(adj_pap)
    original_A.append(adj_plp)
    # original_A.append(adj_ptp)

    # Calculate degree
    all_A = original_A[0]
    for i in range(1, 2):
        all_A += original_A[i]
    deg = degree(index=all_A.nonzero().t()[0], num_nodes=num_nodes)
    deg = deg.to(device)
    train_mask, val_mask, test_mask = train_val_test_split(num_nodes=num_nodes, y=data['P'].y, train_p=0.5,
                                                           val_p=0.25)
    # visualize_embedding(data['P'].x[test_mask], data['P'].y[test_mask], name='org_ACM')

    data = data.to(device)
    original_A = torch.cat(original_A, dim=0).view(-1, num_nodes, num_nodes)
    original_A = original_A.to(device)
    y = data['P'].y.to(device)
    model = MFHGTModel(num_nodes=num_nodes, in_dim=in_dim, hidden_dim=args.hidden_dim, out_dim=num_classes,
                       num_edge_types=2, heads=args.heads, num_layers_gnn=3,num_layers_gt=args.num_layers, dropout=args.dropout).to(device)

    optimizer = torch.optim.Adam(model.parameters(), lr=args.lr, weight_decay=args.weight_decay)

    lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer=optimizer, step_size=50, gamma=0.1, last_epoch=-1)

    loss_fn = nn.CrossEntropyLoss().to(device)

    save_path = 'models/' + args.dataset

    Train_Loss = []
    Train_macro_f1 = []
    Train_micro_f1 = []
    Val_Loss = []
    Val_macro_f1 = []
    Val_micro_f1 = []

    patience = args.patience
    count = 0
    max_val_acc = 0
    best_macro_f1 = 0
    best_micro_f1 = 0
    for i in range(args.epochs):
        train_loss, train_macro_f1, train_micro_f1 = train(model, data, original_A, y, train_mask, deg,
                                                           loss_fn,
                                                           optimizer)
        Train_Loss.append(train_loss)
        Train_macro_f1.append(train_macro_f1)
        Train_micro_f1.append(train_micro_f1)
        val_loss, val_macro_f1, val_micro_f1 = validate(model, data, original_A, y, val_mask, deg, loss_fn)
        Val_macro_f1.append(val_macro_f1)
        Val_micro_f1.append(val_micro_f1)
        Val_Loss.append(val_loss)
        test_macro_f1, test_micro_f1, _ = test(model, data, original_A, y, test_mask, deg)

        if i % 10 == 0:
            print(
                'Epoch {:03d}'.format(i),
                '|| train',
                'loss : {:.3f}'.format(train_loss),
                ', macro_f1 : {:.2f}%'.format(train_macro_f1 * 100),
                ', micro_f1 : {:.2f}%'.format(train_micro_f1 * 100),
                '|| val',
                'loss : {:.3f}'.format(val_loss),
                ', macro_f1 : {:.2f}%'.format(val_macro_f1 * 100),
                ', micro_f1 : {:.2f}%'.format(val_micro_f1 * 100),
                '|| test',
                ', macro_f1 : {:.2f}%'.format(test_macro_f1 * 100),
                ', micro_f1 : {:.2f}%'.format(test_micro_f1 * 100),
            )
        if i > args.convergence_epoch and args.use_lr_schedule:
            lr_scheduler.step()

        if args.use_early_stopping:
            if count <= patience:
                if max_val_acc >= Val_macro_f1[-1]:
                    if count == 0:
                        best_macro_f1 = test_macro_f1
                        best_micro_f1 = test_micro_f1
                        path = os.path.join(save_path, 'best_network_DBLP.pth')
                        torch.save(model.state_dict(), path)
                    count += 1
                else:
                    count = 0
                    max_val_acc = Val_macro_f1[-1]
            else:
                break

    _, _, out = test(model, data, original_A, y, test_mask, deg)
    # visualize_embedding(outputs=out[test_mask], labels=y[test_mask], name='ACM')

    draw_loss(Train_Loss, len(Train_Loss), args.dataset, 'Train')
    draw_acc(Train_macro_f1, len(Train_macro_f1), args.dataset, 'Train_macro_f1')
    draw_acc(Train_micro_f1, len(Train_micro_f1), args.dataset, 'Train_micro_f1')
    draw_loss(Val_Loss, len(Val_Loss), args.dataset, 'Val')
    draw_acc(Val_macro_f1, len(Val_macro_f1), args.dataset, 'Val_macro_f1')
    draw_acc(Val_micro_f1, len(Val_micro_f1), args.dataset, 'Val_micro_f1')
    print('test_macro_f1:{:.2f}'.format(best_macro_f1 * 100))
    print('test_micro_f1:{:.2f}'.format(best_micro_f1 * 100))

if __name__ == "__main__":
    main()


from tornado import httpserver, web, httpclient, ioloop
from tornado.options import options, define

import urllib
import json
import datetime
import time

PORT = 8000

from tornado.options import define, options
define("port",default=PORT,help="run on at %s" % PORT, type=int)

class Application(web.Application):
	def __init__(self):
		handlers = [
		(r'/',IndexHandler)
		]
		settings = dict(debug=True)
		super(Application,self).__init__(handlers,**settings)

class IndexHandler(web.RequestHandler):
	def get(self):

		query = self.get_argument('q')
		client = httpclient.HTTPClient()
		response = client.fetch("http://www.reddit.com/search.json?" + \
			urllib.urlencode({"q": query, "result_type": "recent", "rpp": 100}))
		body = json.loads(response.body)
		# import ipdb; ipdb.set_trace()
		result_count = len(body['data'])
		now = datetime.datetime.utcnow()
		raw_oldest_tweet_at = body['data']['children'][-1]['data']['created']
		# oldest_tweet_at = datetime.datetime.strptime(raw_oldest_tweet_at,
		# 	"%a, %d %b %Y %H:%M:%S +0000")
		# seconds_diff = time.mktime(now.timetuple()) - \
		# time.mktime(raw_oldest_tweet_at.timetuple())
		# tweets_per_second = float(result_count) / seconds_diff

		self.write("""

%s

%.02f

tweets per second

""" % (query, time.time() - raw_oldest_tweet_at))

if __name__ == "__main__":
	options.parse_command_line()
	httpserver.HTTPServer(Application()).listen(options.port)
	ioloop.IOLoop.instance().start()


from typing import List
from git import Head
from enum import Enum

class BranchStatus(Enum):
    Sync = 1
    NotSync = 2
    Behind = 4
    MergedAndDeleted = 5

class GitBranch:

    @staticmethod
    def branches_to_clean(base_branch, repo) -> List[Head]:
        return [
            branch
            for branch in repo.branches
            if (
                GitBranch.has_commit_in_base(base_branch, branch) and
                not GitBranch.is_base_remote(base_branch, branch, repo) and
                not GitBranch.is_current_branch(branch, repo)
            )
        ]

    @staticmethod
    def is_base_remote(base_branch, branch, repo):
        for remote in repo.remotes:
            name = f"{remote.name}/{branch.name}"
            if name == base_branch.name:
                return True
        return False

    @staticmethod
    def is_current_branch(branch, repo):
        return GitBranch.branch_name(repo.head) == branch.name

    @staticmethod
    def has_commit_in_base(base_branch, branch):
        commit = branch.commit
        tree = base_branch.commit
        for item in tree.traverse():
            if item.hexsha == commit.hexsha:
                return True

        return False

    @staticmethod
    def branch_name(branch):
        try:
            return branch.reference.name
        except:
            return "Detached Head"