From 2ec4ecd9b0b22b9c859e1f7ee956785455d0f4a9 Mon Sep 17 00:00:00 2001
From: yacinetouahria <medyacinetouahria@gmail.com>
Date: Sun, 29 Sep 2024 11:47:42 +0100
Subject: [PATCH] changing repository

---
 .gitignore                                   |   1 -
 H2HGCN/.gitignore                            |   1 -
 H2HGCN/__init__.py                           |   0
 H2HGCN/h2hgcn.py                             | 162 ---------
 H2HGCN/layers/CentroidDistance.py            |  56 ---
 H2HGCN/layers/__init__.py                    |   1 -
 H2HGCN/layers/layers.py                      |  24 --
 H2HGCN/manifolds/LorentzManifold.py          | 194 ----------
 H2HGCN/manifolds/StiefelManifold.py          |  41 ---
 H2HGCN/manifolds/__init__.py                 |   1 -
 H2HGCN/models/__init__.py                    |   0
 H2HGCN/models/base_models.py                 |  76 ----
 H2HGCN/models/decoders.py                    |  42 ---
 H2HGCN/models/encoders.py                    | 264 --------------
 H2HGCN/optimizers/__init__.py                |   1 -
 H2HGCN/optimizers/rsgd.py                    |  29 --
 H2HGCN/utils/__init__.py                     |   1 -
 H2HGCN/utils/data_utils.py                   | 102 ------
 H2HGCN/utils/eval_utils.py                   |  13 -
 H2HGCN/utils/math_utils.py                   |  69 ----
 H2HGCN/utils/pre_utils.py                    | 167 ---------
 H2HGCN/utils/train_utils.py                  |  52 ---
 HGCAE/.gitignore                             |   1 -
 HGCAE/__init__.py                            |   2 -
 HGCAE/hgcae.py                               | 230 ------------
 HGCAE/layers/__init__.py                     |   0
 HGCAE/layers/att_layers.py                   |  80 -----
 HGCAE/layers/hyp_layers.py                   | 232 ------------
 HGCAE/layers/layers.py                       |  68 ----
 HGCAE/manifolds/__init__.py                  |   7 -
 HGCAE/manifolds/base.py                      |  84 -----
 HGCAE/manifolds/euclidean.py                 |  66 ----
 HGCAE/manifolds/poincare.py                  | 136 -------
 HGCAE/models/__init__.py                     |   0
 HGCAE/models/base_models.py                  | 200 -----------
 HGCAE/models/decoders.py                     | 106 ------
 HGCAE/models/encoders.py                     |  65 ----
 HGCAE/optimizers/__init__.py                 |   2 -
 HGCAE/optimizers/radam.py                    | 175 ---------
 HGCAE/utils/__init__.py                      |   0
 HGCAE/utils/data_utils.py                    | 134 -------
 HGCAE/utils/eval_utils.py                    |  11 -
 HGCAE/utils/math_utils.py                    |  70 ----
 HGCAE/utils/train_utils.py                   | 225 ------------
 HGCN/.gitignore                              |   1 -
 HGCN/__init__.py                             |   2 -
 HGCN/hgcn.py                                 | 165 ---------
 HGCN/layers/__init__.py                      |   0
 HGCN/layers/att_layers.py                    | 144 --------
 HGCN/layers/hyp_layers.py                    | 158 ---------
 HGCN/layers/layers.py                        |  71 ----
 HGCN/manifolds/__init__.py                   |   4 -
 HGCN/manifolds/base.py                       |  88 -----
 HGCN/manifolds/euclidean.py                  |  67 ----
 HGCN/manifolds/hyperboloid.py                | 155 --------
 HGCN/manifolds/poincare.py                   | 145 --------
 HGCN/models/__init__.py                      |   0
 HGCN/models/base_models.py                   |  85 -----
 HGCN/models/decoders.py                      |  52 ---
 HGCN/models/encoders.py                      |  99 ------
 HGCN/optimizers/__init__.py                  |   2 -
 HGCN/optimizers/radam.py                     | 172 ---------
 HGCN/utils/__init__.py                       |   0
 HGCN/utils/data_utils.py                     |  87 -----
 HGCN/utils/eval_utils.py                     |  14 -
 HGCN/utils/math_utils.py                     |  69 ----
 HGCN/utils/train_utils.py                    |  47 ---
 HGNN/.gitignore                              |   1 -
 HGNN/__init__.py                             |   0
 HGNN/dataset/NodeClassificationDataset.py    | 160 ---------
 HGNN/dataset/__init__.py                     |   0
 HGNN/gnn/RiemannianGNN.py                    | 138 -------
 HGNN/gnn/__init__.py                         |   1 -
 HGNN/hgnn.py                                 |  70 ----
 HGNN/hyperbolic_module/CentroidDistance.py   |  54 ---
 HGNN/hyperbolic_module/PoincareDistance.py   |  38 --
 HGNN/hyperbolic_module/__init__.py           |   0
 HGNN/manifold/LorentzManifold.py             | 165 ---------
 HGNN/manifold/PoincareManifold.py            | 112 ------
 HGNN/manifold/__init__.py                    |   2 -
 HGNN/optimizer/__init__.py                   |   0
 HGNN/optimizer/ramsgrad.py                   |  74 ----
 HGNN/optimizer/rsgd.py                       |  43 ---
 HGNN/task/BaseTask.py                        |  43 ---
 HGNN/task/NodeClassification.py              |  44 ---
 HGNN/task/NodeClassificationTask.py          | 137 -------
 HGNN/task/__init__.py                        |   1 -
 HGNN/utils/EarlyStoppingCriterion.py         |  51 ---
 HGNN/utils/__init__.py                       |   3 -
 HGNN/utils/logger.py                         |  54 ---
 HGNN/utils/utils.py                          | 284 ---------------
 PVAE/__init__.py                             |   0
 PVAE/distributions/__init__.py               |   4 -
 PVAE/distributions/ars.py                    | 135 -------
 PVAE/distributions/hyperbolic_radius.py      | 295 ---------------
 PVAE/distributions/hyperspherical_uniform.py |  42 ---
 PVAE/distributions/riemannian_normal.py      |  49 ---
 PVAE/distributions/wrapped_normal.py         |  65 ----
 PVAE/manifolds/__init__.py                   |   4 -
 PVAE/manifolds/euclidean.py                  |  42 ---
 PVAE/manifolds/poincareball.py               |  84 -----
 PVAE/models/__init__.py                      |   2 -
 PVAE/models/architectures.py                 | 180 ----------
 PVAE/models/tabular.py                       |  36 --
 PVAE/models/vae.py                           |  63 ----
 PVAE/objectives.py                           |  46 ---
 PVAE/ops/__init__.py                         |   0
 PVAE/ops/manifold_layers.py                  |  90 -----
 PVAE/pvae.py                                 | 211 -----------
 PVAE/utils.py                                | 355 -------------------
 Poincare/__init__.py                         |   2 -
 Poincare/layers/__init__.py                  |   0
 Poincare/layers/layers.py                    |  43 ---
 Poincare/manifolds/__init__.py               |   3 -
 Poincare/manifolds/base.py                   |  88 -----
 Poincare/manifolds/euclidean.py              |  67 ----
 Poincare/manifolds/poincare.py               | 145 --------
 Poincare/models/__init__.py                  |   0
 Poincare/models/base_models.py               |  77 ----
 Poincare/models/decoders.py                  |  46 ---
 Poincare/models/encoders.py                  |  42 ---
 Poincare/optimizers/__init__.py              |   2 -
 Poincare/optimizers/radam.py                 | 172 ---------
 Poincare/poincare.py                         | 156 --------
 Poincare/utils/__init__.py                   |   0
 Poincare/utils/data_utils.py                 |  83 -----
 Poincare/utils/eval_utils.py                 |  14 -
 Poincare/utils/math_utils.py                 |  69 ----
 Poincare/utils/train_utils.py                |  38 --
 README.md                                    |  72 +---
 __init__.py                                  |  14 -
 anomaly_detection/__init__.py                |   5 -
 anomaly_detection/dbscan.py                  |   9 -
 anomaly_detection/isolation_forest.py        |  12 -
 anomaly_detection/kmeans.py                  |  12 -
 anomaly_detection/local_outlier_factor.py    |  10 -
 anomaly_detection/one_class_svm.py           |  11 -
 anomaly_detection/utils.py                   |  22 --
 classifiers/__init__.py                      |  19 -
 classifiers/adaboost.py                      |   5 -
 classifiers/decision_tree.py                 |   5 -
 classifiers/knn.py                           |   5 -
 classifiers/mlp.py                           |   7 -
 classifiers/naive_bayes.py                   |   5 -
 classifiers/random_forest.py                 |   5 -
 classifiers/svm.py                           |   6 -
 clusterers/__init__.py                       |   6 -
 clusterers/ahc.py                            |   7 -
 clusterers/dbscan.py                         |  13 -
 clusterers/fuzzy_c_mean.py                   |   9 -
 clusterers/gaussian_mixture.py               |   7 -
 clusterers/kmeans.py                         |  11 -
 clusterers/mean_shift.py                     |  10 -
 clusterers/utils.py                          |  22 --
 datasets/.gitignore                          |   3 -
 datasets/__init__.py                         |   0
 datasets/datasets.py                         | 299 ----------------
 datasets/outlier_datasets.py                 | 314 ----------------
 datasets/repetition_datasets.py              | 308 ----------------
 datasets/utils.py                            |  32 --
 requirements.txt                             | Bin 1106 -> 0 bytes
 161 files changed, 2 insertions(+), 10306 deletions(-)
 delete mode 100644 .gitignore
 delete mode 100644 H2HGCN/.gitignore
 delete mode 100644 H2HGCN/__init__.py
 delete mode 100644 H2HGCN/h2hgcn.py
 delete mode 100644 H2HGCN/layers/CentroidDistance.py
 delete mode 100644 H2HGCN/layers/__init__.py
 delete mode 100644 H2HGCN/layers/layers.py
 delete mode 100644 H2HGCN/manifolds/LorentzManifold.py
 delete mode 100644 H2HGCN/manifolds/StiefelManifold.py
 delete mode 100644 H2HGCN/manifolds/__init__.py
 delete mode 100644 H2HGCN/models/__init__.py
 delete mode 100644 H2HGCN/models/base_models.py
 delete mode 100644 H2HGCN/models/decoders.py
 delete mode 100644 H2HGCN/models/encoders.py
 delete mode 100644 H2HGCN/optimizers/__init__.py
 delete mode 100644 H2HGCN/optimizers/rsgd.py
 delete mode 100644 H2HGCN/utils/__init__.py
 delete mode 100644 H2HGCN/utils/data_utils.py
 delete mode 100644 H2HGCN/utils/eval_utils.py
 delete mode 100644 H2HGCN/utils/math_utils.py
 delete mode 100644 H2HGCN/utils/pre_utils.py
 delete mode 100644 H2HGCN/utils/train_utils.py
 delete mode 100644 HGCAE/.gitignore
 delete mode 100644 HGCAE/__init__.py
 delete mode 100644 HGCAE/hgcae.py
 delete mode 100644 HGCAE/layers/__init__.py
 delete mode 100644 HGCAE/layers/att_layers.py
 delete mode 100644 HGCAE/layers/hyp_layers.py
 delete mode 100644 HGCAE/layers/layers.py
 delete mode 100644 HGCAE/manifolds/__init__.py
 delete mode 100644 HGCAE/manifolds/base.py
 delete mode 100644 HGCAE/manifolds/euclidean.py
 delete mode 100644 HGCAE/manifolds/poincare.py
 delete mode 100644 HGCAE/models/__init__.py
 delete mode 100644 HGCAE/models/base_models.py
 delete mode 100644 HGCAE/models/decoders.py
 delete mode 100644 HGCAE/models/encoders.py
 delete mode 100644 HGCAE/optimizers/__init__.py
 delete mode 100644 HGCAE/optimizers/radam.py
 delete mode 100644 HGCAE/utils/__init__.py
 delete mode 100644 HGCAE/utils/data_utils.py
 delete mode 100644 HGCAE/utils/eval_utils.py
 delete mode 100644 HGCAE/utils/math_utils.py
 delete mode 100644 HGCAE/utils/train_utils.py
 delete mode 100644 HGCN/.gitignore
 delete mode 100644 HGCN/__init__.py
 delete mode 100644 HGCN/hgcn.py
 delete mode 100644 HGCN/layers/__init__.py
 delete mode 100644 HGCN/layers/att_layers.py
 delete mode 100644 HGCN/layers/hyp_layers.py
 delete mode 100644 HGCN/layers/layers.py
 delete mode 100644 HGCN/manifolds/__init__.py
 delete mode 100644 HGCN/manifolds/base.py
 delete mode 100644 HGCN/manifolds/euclidean.py
 delete mode 100644 HGCN/manifolds/hyperboloid.py
 delete mode 100644 HGCN/manifolds/poincare.py
 delete mode 100644 HGCN/models/__init__.py
 delete mode 100644 HGCN/models/base_models.py
 delete mode 100644 HGCN/models/decoders.py
 delete mode 100644 HGCN/models/encoders.py
 delete mode 100644 HGCN/optimizers/__init__.py
 delete mode 100644 HGCN/optimizers/radam.py
 delete mode 100644 HGCN/utils/__init__.py
 delete mode 100644 HGCN/utils/data_utils.py
 delete mode 100644 HGCN/utils/eval_utils.py
 delete mode 100644 HGCN/utils/math_utils.py
 delete mode 100644 HGCN/utils/train_utils.py
 delete mode 100644 HGNN/.gitignore
 delete mode 100644 HGNN/__init__.py
 delete mode 100644 HGNN/dataset/NodeClassificationDataset.py
 delete mode 100644 HGNN/dataset/__init__.py
 delete mode 100644 HGNN/gnn/RiemannianGNN.py
 delete mode 100644 HGNN/gnn/__init__.py
 delete mode 100644 HGNN/hgnn.py
 delete mode 100644 HGNN/hyperbolic_module/CentroidDistance.py
 delete mode 100644 HGNN/hyperbolic_module/PoincareDistance.py
 delete mode 100644 HGNN/hyperbolic_module/__init__.py
 delete mode 100644 HGNN/manifold/LorentzManifold.py
 delete mode 100644 HGNN/manifold/PoincareManifold.py
 delete mode 100644 HGNN/manifold/__init__.py
 delete mode 100644 HGNN/optimizer/__init__.py
 delete mode 100644 HGNN/optimizer/ramsgrad.py
 delete mode 100644 HGNN/optimizer/rsgd.py
 delete mode 100644 HGNN/task/BaseTask.py
 delete mode 100644 HGNN/task/NodeClassification.py
 delete mode 100644 HGNN/task/NodeClassificationTask.py
 delete mode 100644 HGNN/task/__init__.py
 delete mode 100644 HGNN/utils/EarlyStoppingCriterion.py
 delete mode 100644 HGNN/utils/__init__.py
 delete mode 100644 HGNN/utils/logger.py
 delete mode 100644 HGNN/utils/utils.py
 delete mode 100644 PVAE/__init__.py
 delete mode 100644 PVAE/distributions/__init__.py
 delete mode 100644 PVAE/distributions/ars.py
 delete mode 100644 PVAE/distributions/hyperbolic_radius.py
 delete mode 100644 PVAE/distributions/hyperspherical_uniform.py
 delete mode 100644 PVAE/distributions/riemannian_normal.py
 delete mode 100644 PVAE/distributions/wrapped_normal.py
 delete mode 100644 PVAE/manifolds/__init__.py
 delete mode 100644 PVAE/manifolds/euclidean.py
 delete mode 100644 PVAE/manifolds/poincareball.py
 delete mode 100644 PVAE/models/__init__.py
 delete mode 100644 PVAE/models/architectures.py
 delete mode 100644 PVAE/models/tabular.py
 delete mode 100644 PVAE/models/vae.py
 delete mode 100644 PVAE/objectives.py
 delete mode 100644 PVAE/ops/__init__.py
 delete mode 100644 PVAE/ops/manifold_layers.py
 delete mode 100644 PVAE/pvae.py
 delete mode 100644 PVAE/utils.py
 delete mode 100644 Poincare/__init__.py
 delete mode 100644 Poincare/layers/__init__.py
 delete mode 100644 Poincare/layers/layers.py
 delete mode 100644 Poincare/manifolds/__init__.py
 delete mode 100644 Poincare/manifolds/base.py
 delete mode 100644 Poincare/manifolds/euclidean.py
 delete mode 100644 Poincare/manifolds/poincare.py
 delete mode 100644 Poincare/models/__init__.py
 delete mode 100644 Poincare/models/base_models.py
 delete mode 100644 Poincare/models/decoders.py
 delete mode 100644 Poincare/models/encoders.py
 delete mode 100644 Poincare/optimizers/__init__.py
 delete mode 100644 Poincare/optimizers/radam.py
 delete mode 100644 Poincare/poincare.py
 delete mode 100644 Poincare/utils/__init__.py
 delete mode 100644 Poincare/utils/data_utils.py
 delete mode 100644 Poincare/utils/eval_utils.py
 delete mode 100644 Poincare/utils/math_utils.py
 delete mode 100644 Poincare/utils/train_utils.py
 delete mode 100644 __init__.py
 delete mode 100644 anomaly_detection/__init__.py
 delete mode 100644 anomaly_detection/dbscan.py
 delete mode 100644 anomaly_detection/isolation_forest.py
 delete mode 100644 anomaly_detection/kmeans.py
 delete mode 100644 anomaly_detection/local_outlier_factor.py
 delete mode 100644 anomaly_detection/one_class_svm.py
 delete mode 100644 anomaly_detection/utils.py
 delete mode 100644 classifiers/__init__.py
 delete mode 100644 classifiers/adaboost.py
 delete mode 100644 classifiers/decision_tree.py
 delete mode 100644 classifiers/knn.py
 delete mode 100644 classifiers/mlp.py
 delete mode 100644 classifiers/naive_bayes.py
 delete mode 100644 classifiers/random_forest.py
 delete mode 100644 classifiers/svm.py
 delete mode 100644 clusterers/__init__.py
 delete mode 100644 clusterers/ahc.py
 delete mode 100644 clusterers/dbscan.py
 delete mode 100644 clusterers/fuzzy_c_mean.py
 delete mode 100644 clusterers/gaussian_mixture.py
 delete mode 100644 clusterers/kmeans.py
 delete mode 100644 clusterers/mean_shift.py
 delete mode 100644 clusterers/utils.py
 delete mode 100644 datasets/.gitignore
 delete mode 100644 datasets/__init__.py
 delete mode 100644 datasets/datasets.py
 delete mode 100644 datasets/outlier_datasets.py
 delete mode 100644 datasets/repetition_datasets.py
 delete mode 100644 datasets/utils.py
 delete mode 100644 requirements.txt

diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index c18dd8d..0000000
--- a/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-__pycache__/
diff --git a/H2HGCN/.gitignore b/H2HGCN/.gitignore
deleted file mode 100644
index ba0430d..0000000
--- a/H2HGCN/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-__pycache__/
\ No newline at end of file
diff --git a/H2HGCN/__init__.py b/H2HGCN/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/H2HGCN/h2hgcn.py b/H2HGCN/h2hgcn.py
deleted file mode 100644
index 4d92fa9..0000000
--- a/H2HGCN/h2hgcn.py
+++ /dev/null
@@ -1,162 +0,0 @@
-from __future__ import division
-from __future__ import print_function
-import logging
-import os
-import time
-import numpy as np
-import torch
-from Ghypeddings.H2HGCN.models.base_models import NCModel
-from Ghypeddings.H2HGCN.utils.data_utils import process_data
-from Ghypeddings.H2HGCN.utils.train_utils import format_metrics, create_args
-from Ghypeddings.H2HGCN.utils.pre_utils import *
-import warnings
-warnings.filterwarnings('ignore')
-
-class H2HGCN:
-    def __init__(self,
-                adj,
-                features,
-                labels,
-                dim,
-                c=None,
-                num_layers=2,
-                bias=True,
-                act='leaky_relu',
-                select_manifold='lorentz',
-                num_centroid=10,
-                lr_stie=0.009,
-                stie_vars=[],
-                stiefel_optimizer='rsgd',
-                eucl_vars=[],
-                grad_clip=None,
-                optimizer='Adam',
-                weight_decay=0.01,
-                lr=0.01,
-                lr_scheduler='step',
-                lr_gamma=0.5,
-                step_lr_gamma=0.1,
-                step_lr_reduce_freq=500,
-                proj_init='xavier',
-                tie_weight=True,
-                cuda=0,
-                epochs=50,
-                min_epochs=50,
-                patience=None,
-                seed=42,
-                log_freq=1,
-                eval_freq=1,
-                val_prop=0.15,
-                test_prop=0.15,
-                double_precision=0,
-                dropout=0.1,
-                normalize_adj=False,
-                normalize_feats=True
-                ):
-        
-        self.args = create_args(dim,c,num_layers,bias,act,select_manifold,num_centroid,lr_stie,stie_vars,stiefel_optimizer,eucl_vars,grad_clip,optimizer,weight_decay,lr,lr_scheduler,lr_gamma,step_lr_gamma,step_lr_reduce_freq,proj_init,tie_weight,cuda,epochs,min_epochs,patience,seed,log_freq,eval_freq,val_prop,test_prop,double_precision,dropout,normalize_adj,normalize_feats)
-        
-        self.args.n_nodes = adj.shape[0]
-        self.args.feat_dim = features.shape[1]
-        self.args.n_classes = len(np.unique(labels))
-        self.data = process_data(self.args,adj,features,labels)
-
-        if int(self.args.double_precision):
-            torch.set_default_dtype(torch.float64)
-
-        self.args.device = 'cuda:' + str(self.args.cuda) if int(self.args.cuda) >= 0 else 'cpu'
-        self.args.patience = self.args.epochs if not self.args.patience else  int(self.args.patience)
-        self.model = NCModel(self.args)
-        self.optimizer, self.lr_scheduler, self.stiefel_optimizer, self.stiefel_lr_scheduler = set_up_optimizer_scheduler(True, self.args, self.model, self.args.lr, self.args.lr_stie)
-        
-        if self.args.cuda is not None and int(self.args.cuda) >= 0 :
-            os.environ['CUDA_VISIBLE_DEVICES'] = str(self.args.cuda)
-            self.model = self.model.to(self.args.device)
-            for x, val in self.data.items():
-                if torch.is_tensor(self.data[x]):
-                    self.data[x] = self.data[x].to(self.args.device)
-        self.best_emb = None
-
-
-    def fit(self):
-        logging.getLogger().setLevel(logging.INFO)
-        logging.info(f'Using: {self.args.device}')
-        tot_params = sum([np.prod(p.size()) for p in self.model.parameters()])
-        logging.info(f"Total number of parameters: {tot_params}")
-        
-        t_total = time.time()
-        counter = 0
-        best_val_metrics = self.model.init_metric_dict()
-
-        best_losses = []
-        real_losses = []
-        train_losses = []
-
-        for epoch in range(self.args.epochs):       
-            t = time.time()
-            self.model.train()
-            self.optimizer.zero_grad()
-            self.stiefel_optimizer.zero_grad()
-            embeddings = self.model.encode(self.data['features'], self.data['hgnn_adj'], self.data['hgnn_weight']) 
-            train_metrics = self.model.compute_metrics(embeddings, self.data, 'train')
-            train_metrics['loss'].backward()
-            if self.args.grad_clip is not None:
-                max_norm = float(self.args.grad_clip)
-                all_params = list(self.model.parameters())
-                for param in all_params:
-                    torch.nn.utils.clip_grad_norm_(param, max_norm)
-            self.optimizer.step()
-            self.stiefel_optimizer.step()
-            self.lr_scheduler.step()
-            self.stiefel_lr_scheduler.step()
-
-            train_losses.append(train_metrics['loss'].item())
-            if(len(best_losses) == 0):
-                best_losses.append(train_losses[0])
-            elif (best_losses[-1] > train_losses[-1]):
-                best_losses.append(train_losses[-1])
-            else:
-                best_losses.append(best_losses[-1])
-
-            if (epoch + 1) % self.args.log_freq == 0:
-                logging.info(" ".join(['Epoch: {:04d}'.format(epoch + 1),
-                                    'lr: {:04f}, stie_lr: {:04f}'.format(self.lr_scheduler.get_lr()[0], self.stiefel_lr_scheduler.get_lr()[0]),
-                                    format_metrics(train_metrics, 'train'),
-                                    'time: {:.4f}s'.format(time.time() - t)
-                                    ]))
-                
-            if (epoch + 1) % self.args.eval_freq == 0:
-                self.model.eval()
-                embeddings = self.model.encode(self.data['features'], self.data['hgnn_adj'], self.data['hgnn_weight'])
-                val_metrics = self.model.compute_metrics(embeddings, self.data, 'val')
-                real_losses.append(val_metrics['loss'].item())
-                if (epoch + 1) % self.args.log_freq == 0:
-                    logging.info(" ".join(['Epoch: {:04d}'.format(epoch + 1), format_metrics(val_metrics, 'val')]))
-                if self.model.has_improved(best_val_metrics, val_metrics):
-                    self.best_emb = embeddings
-                    best_val_metrics = val_metrics
-                    counter = 0
-                else:
-                    counter += 1
-                    if counter == self.args.patience and epoch > self.args.min_epochs:
-                        logging.info("Early stopping")
-                        break
-
-        logging.info("Training Finished!")
-        logging.info("Total time elapsed: {:.4f}s".format(time.time() - t_total))
-        return {'val':real_losses,'best':best_losses,'train':train_losses},best_val_metrics['acc'],best_val_metrics['f1'],best_val_metrics['recall'],best_val_metrics['precision'],best_val_metrics['roc_auc'],time.time() - t_total
-
-    def predict(self):
-        self.model.eval()
-        embeddings = self.model.encode(self.data['features'], self.data['hgnn_adj'], self.data['hgnn_weight'])
-        val_metrics = self.model.compute_metrics(embeddings, self.data, 'test')
-        logging.info(" ".join([format_metrics(val_metrics, 'test')]))
-        return val_metrics['loss'].item(),val_metrics['acc'],val_metrics['f1'],val_metrics['recall'],val_metrics['precision'],val_metrics['roc_auc']
-    
-    def save_embeddings(self):
-        #tb_embeddings_euc = self.model.manifold.log_map_zero(self.best_emb)
-        for_classification_hyp = np.hstack((self.best_emb.cpu().detach().numpy(),self.data['labels'].cpu().reshape(-1,1)))
-        #for_classification_euc = np.hstack((tb_embeddings_euc.cpu().detach().numpy(),self.data['labels'].cpu().reshape(-1,1)))
-        hyp_file_path = os.path.join(os.getcwd(),'h2hgcn_embeddings_hyp.csv')
-        #euc_file_path = os.path.join(os.getcwd(),'h2hgcn_embeddings_euc.csv')
-        np.savetxt(hyp_file_path, for_classification_hyp, delimiter=',')
-        #np.savetxt(euc_file_path, for_classification_euc, delimiter=',')
diff --git a/H2HGCN/layers/CentroidDistance.py b/H2HGCN/layers/CentroidDistance.py
deleted file mode 100644
index 5464474..0000000
--- a/H2HGCN/layers/CentroidDistance.py
+++ /dev/null
@@ -1,56 +0,0 @@
-import torch as th
-import torch.nn as nn
-import torch.nn.functional as F
-from Ghypeddings.H2HGCN.utils import *
-
-class CentroidDistance(nn.Module):
-    """
-    Implement a model that calculates the pairwise distances between node representations
-    and centroids
-    """
-    def __init__(self, args, logger, manifold):
-        super(CentroidDistance, self).__init__()
-        self.args = args
-        self.logger = logger
-        self.manifold = manifold
-        self.debug = False
-
-        # centroid embedding
-        self.centroid_embedding = nn.Embedding(
-            args.num_centroid, args.dim,
-            sparse=False,
-            scale_grad_by_freq=False,
-        )
-        nn_init(self.centroid_embedding, self.args.proj_init)
-        args.eucl_vars.append(self.centroid_embedding)
-
-    def forward(self, node_repr, mask):
-        """
-        Args:
-            node_repr: [node_num, dim] 
-            mask: [node_num, 1] 1 denote real node, 0 padded node
-        return:
-            graph_centroid_dist: [1, num_centroid]
-            node_centroid_dist: [1, node_num, num_centroid]
-        """
-        node_num = node_repr.size(0)
-
-        # broadcast and reshape node_repr to [node_num * num_centroid, dim]
-        node_repr =  node_repr.unsqueeze(1).expand(
-                                                -1,
-                                                self.args.num_centroid,
-                                                -1).contiguous().view(-1, self.args.dim)
-
-        # broadcast and reshape centroid embeddings to [node_num * num_centroid, dim]
-        centroid_repr = self.manifold.exp_map_zero(self.centroid_embedding(th.arange(self.args.num_centroid).cuda().to(self.args.device)))
-        centroid_repr = centroid_repr.unsqueeze(0).expand(
-                                                node_num,
-                                                -1,
-                                                -1).contiguous().view(-1, self.args.dim) 
-        # get distance
-        node_centroid_dist = self.manifold.distance(node_repr, centroid_repr) 
-        node_centroid_dist = node_centroid_dist.view(1, node_num, self.args.num_centroid) 
-        # average pooling over nodes
-        graph_centroid_dist = th.sum(node_centroid_dist, dim=1) / th.sum(mask)
-        return graph_centroid_dist, node_centroid_dist
-
diff --git a/H2HGCN/layers/__init__.py b/H2HGCN/layers/__init__.py
deleted file mode 100644
index 8b13789..0000000
--- a/H2HGCN/layers/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/H2HGCN/layers/layers.py b/H2HGCN/layers/layers.py
deleted file mode 100644
index 48d5c1f..0000000
--- a/H2HGCN/layers/layers.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import math
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-from torch.nn.modules.module import Module
-from torch.nn.parameter import Parameter
-
-class Linear(Module):
-    """
-    Simple Linear layer with dropout.
-    """
-
-    def __init__(self, args, in_features, out_features, dropout, act, use_bias):
-        super(Linear, self).__init__()
-        self.dropout = dropout
-        self.linear = nn.Linear(in_features, out_features, use_bias)
-        self.act = act
-        args.eucl_vars.append(self.linear)
-
-    def forward(self, x):
-        hidden = self.linear.forward(x)
-        hidden = F.dropout(hidden, self.dropout, training=self.training)
-        out = self.act(hidden)
-        return out
\ No newline at end of file
diff --git a/H2HGCN/manifolds/LorentzManifold.py b/H2HGCN/manifolds/LorentzManifold.py
deleted file mode 100644
index 1ae351c..0000000
--- a/H2HGCN/manifolds/LorentzManifold.py
+++ /dev/null
@@ -1,194 +0,0 @@
-"""Lorentz manifold."""
-import torch
-import torch as th
-import torch.nn as nn
-import numpy as np
-from torch.autograd import Function, Variable
-import torch
-from Ghypeddings.H2HGCN.utils import *
-from Ghypeddings.H2HGCN.utils.pre_utils import *
-from Ghypeddings.H2HGCN.manifolds import *
-from Ghypeddings.H2HGCN.utils.math_utils import arcosh, cosh, sinh 
-
-_eps = 1e-10
-
-class LorentzManifold:
-
-    def __init__(self, args, eps=1e-3, norm_clip=1, max_norm=1e3):
-        self.args = args
-        self.eps = eps
-        self.norm_clip = norm_clip
-        self.max_norm = max_norm
-
-    def minkowski_dot(self, x, y, keepdim=True):
-        res = torch.sum(x * y, dim=-1) - 2 * x[..., 0] * y[..., 0]
-        if keepdim:
-            res = res.view(res.shape + (1,))
-        return res
-
-
-    def sqdist(self, x, y, c):
-        K = 1. / c
-        prod = self.minkowski_dot(x, y)
-        eps = {torch.float32: 1e-7, torch.float64: 1e-15}
-        theta = torch.clamp(-prod / K, min=1.0 + eps[x.dtype])
-        sqdist = K * arcosh(theta) ** 2
-        return torch.clamp(sqdist, max=50.0)
-
-
-    @staticmethod
-    def ldot(u, v, keepdim=False):
-        """
-        Lorentzian Scalar Product
-        Args:
-            u: [batch_size, d + 1]
-            v: [batch_size, d + 1]
-        Return:
-            keepdim: False [batch_size]
-            keepdim: True  [batch_size, 1]
-        """
-        d = u.size(1) - 1
-        uv = u * v
-        uv = th.cat((-uv.narrow(1, 0, 1), uv.narrow(1, 1, d)), dim=1) 
-        return th.sum(uv, dim=1, keepdim=keepdim)
-
-    def from_lorentz_to_poincare(self, x):
-        """
-        Args:
-            u: [batch_size, d + 1]
-        """
-        d = x.size(-1) - 1
-        return x.narrow(-1, 1, d) / (x.narrow(-1, 0, 1) + 1)
-
-    def from_poincare_to_lorentz(self, x):
-        """
-        Args:
-            u: [batch_size, d]
-        """
-        x_norm_square = th_dot(x, x)
-        return th.cat((1 + x_norm_square, 2 * x), dim=1) / (1 - x_norm_square + self.eps)
-
-    def distance(self, u, v):
-        d = -LorentzDot.apply(u, v)
-        dis = Acosh.apply(d, self.eps)
-        return dis
-
-    def normalize(self, w):
-        """
-        Normalize vector such that it is located on the Lorentz
-        Args:
-            w: [batch_size, d + 1]
-        """
-        d = w.size(-1) - 1
-        narrowed = w.narrow(-1, 1, d)
-        if self.max_norm:
-            narrowed = th.renorm(narrowed.view(-1, d), 2, 0, self.max_norm)
-        first = 1 + th.sum(th.pow(narrowed, 2), dim=-1, keepdim=True)
-        first = th.sqrt(first)
-        tmp = th.cat((first, narrowed), dim=1)
-        return tmp
-
-    def init_embed(self, embed, irange=1e-2):
-        embed.weight.data.uniform_(-irange, irange)
-        embed.weight.data.copy_(self.normalize(embed.weight.data))
-
-    def rgrad(self, p, d_p):
-        """Riemannian gradient for Lorentz"""
-        u = d_p
-        x = p
-        u.narrow(-1, 0, 1).mul_(-1)
-        u.addcmul_(self.ldot(x, u, keepdim=True).expand_as(x), x)
-        return d_p
-
-    def exp_map_zero(self, v):
-        zeros = th.zeros_like(v)
-        zeros[:, 0] = 1
-        return self.exp_map_x(zeros, v)
-
-    def exp_map_x(self, p, d_p, d_p_normalize=True, p_normalize=True):
-        if d_p_normalize:
-            d_p = self.normalize_tan(p, d_p)
-
-        ldv = self.ldot(d_p, d_p, keepdim=True)
-        nd_p = th.sqrt(th.clamp(ldv + self.eps, _eps))
-
-        t = th.clamp(nd_p, max=self.norm_clip)
-        newp = (th.cosh(t) * p) + (th.sinh(t) * d_p / nd_p)
-
-        if p_normalize:
-            newp = self.normalize(newp)
-        return newp
-
-    def normalize_tan(self, x_all, v_all):
-        d = v_all.size(1) - 1
-        x = x_all.narrow(1, 1, d)
-        xv = th.sum(x * v_all.narrow(1, 1, d), dim=1, keepdim=True)
-        tmp = 1 + th.sum(th.pow(x_all.narrow(1, 1, d), 2), dim=1, keepdim=True)
-        tmp = th.sqrt(tmp)
-        return th.cat((xv / tmp, v_all.narrow(1, 1, d)), dim=1)
-
-    def log_map_zero(self, y, i=-1):
-        zeros = th.zeros_like(y)
-        zeros[:, 0] = 1
-        return self.log_map_x(zeros, y)
-
-    def log_map_x(self, x, y, normalize=False):
-        """Logarithmic map on the Lorentz Manifold"""
-        xy = self.ldot(x, y).unsqueeze(-1)
-        tmp = th.sqrt(th.clamp(xy * xy - 1 + self.eps, _eps))
-        v = Acosh.apply(-xy, self.eps) / (
-            tmp
-        ) * th.addcmul(y, xy, x)
-        if normalize:
-            result = self.normalize_tan(x, v)
-        else:
-            result = v
-        return result
-
-    def parallel_transport(self, x, y, v):
-        """Parallel transport for Lorentz"""
-        v_ = v
-        x_ = x
-        y_ = y
-
-        xy = self.ldot(x_, y_, keepdim=True).expand_as(x_)
-        vy = self.ldot(v_, y_, keepdim=True).expand_as(x_)
-        vnew = v_ + vy / (1 - xy) * (x_ + y_)
-        return vnew
-
-    def metric_tensor(self, x, u, v):
-        return self.ldot(u, v, keepdim=True)
-
-
-
-class LorentzDot(Function):
-    @staticmethod
-    def forward(ctx, u, v):
-        ctx.save_for_backward(u, v)
-        return LorentzManifold.ldot(u, v)
-
-    @staticmethod
-    def backward(ctx, g):
-        u, v = ctx.saved_tensors
-        g = g.unsqueeze(-1).expand_as(u).clone()
-        g.narrow(-1, 0, 1).mul_(-1)
-        return g * v, g * u
-
-class Acosh(Function):
-    @staticmethod
-    def forward(ctx, x, eps): 
-        z = th.sqrt(th.clamp(x * x - 1 + eps, _eps))
-        ctx.save_for_backward(z)
-        ctx.eps = eps
-        xz = x + z
-        tmp = th.log(xz)
-        return tmp
-
-    @staticmethod
-    def backward(ctx, g):
-        z, = ctx.saved_tensors
-        z = th.clamp(z, min=ctx.eps)
-        z = g / z
-        return z, None
-
-
diff --git a/H2HGCN/manifolds/StiefelManifold.py b/H2HGCN/manifolds/StiefelManifold.py
deleted file mode 100644
index f42b62f..0000000
--- a/H2HGCN/manifolds/StiefelManifold.py
+++ /dev/null
@@ -1,41 +0,0 @@
-import torch as th
-import torch.nn as nn
-import numpy as np
-from torch.autograd import Function, Variable
-from Ghypeddings.clusterers.utils import *
-
-_eps = 1e-10
-
-class StiefelManifold:
-
-    def __init__(self, args, logger, eps=1e-3, norm_clip=1, max_norm=1e3):
-        self.args = args
-        self.logger = logger
-        self.eps = eps
-        self.norm_clip = norm_clip
-        self.max_norm = max_norm
-
-    def normalize(self, w):
-        return w
-
-    def init_embed(self, embed, irange=1e-2):
-        embed.weight.data.uniform_(-irange, irange)
-        embed.weight.data.copy_(self.normalize(embed.weight.data))
-
-    def symmetric(self, A):
-        return 0.5 * (A + A.t())
-
-    def rgrad(self, A, B):
-        out = B - A.mm(self.symmetric(A.transpose(0,1).mm(B)))
-        return out
-
-    def exp_map_x(self, A, ref):
-        data = A + ref
-        Q, R = data.qr()
-        # To avoid (any possible) negative values in the output matrix, we multiply the negative values by -1
-        sign = (R.diag().sign() + 0.5).sign().diag()
-        out = Q.mm(sign)
-        return out
-
-
-
diff --git a/H2HGCN/manifolds/__init__.py b/H2HGCN/manifolds/__init__.py
deleted file mode 100644
index 99a7356..0000000
--- a/H2HGCN/manifolds/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from Ghypeddings.H2HGCN.manifolds.LorentzManifold import LorentzManifold
\ No newline at end of file
diff --git a/H2HGCN/models/__init__.py b/H2HGCN/models/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/H2HGCN/models/base_models.py b/H2HGCN/models/base_models.py
deleted file mode 100644
index a0a235c..0000000
--- a/H2HGCN/models/base_models.py
+++ /dev/null
@@ -1,76 +0,0 @@
-import numpy as np
-from sklearn.metrics import roc_auc_score, average_precision_score
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-import Ghypeddings.H2HGCN.models.encoders as encoders
-from Ghypeddings.H2HGCN.models.encoders import H2HGCN
-from Ghypeddings.H2HGCN.models.decoders import model2decoder
-from Ghypeddings.H2HGCN.utils.eval_utils import acc_f1
-from Ghypeddings.H2HGCN.manifolds import LorentzManifold
-
- 
-class BaseModel(nn.Module):
-    """
-    Base model for graph embedding tasks.
-    """
-
-    def __init__(self, args):
-        super(BaseModel, self).__init__()
-        self.c = torch.Tensor([1.]).cuda().to(args.device)
-        args.manifold = self.manifold = LorentzManifold(args)
-        args.feat_dim = args.feat_dim + 1
-        # add 1 for Lorentz as the degree of freedom is d - 1 with d dimensions
-        args.dim = args.dim + 1
-        self.nnodes = args.n_nodes
-        self.encoder = H2HGCN(args, 1)
-
-    def encode(self, x, hgnn_adj, hgnn_weight):
-        h = self.encoder.encode(x, hgnn_adj, hgnn_weight)
-        return h
-
-    def compute_metrics(self, embeddings, data, split):
-        raise NotImplementedError
-
-    def init_metric_dict(self):
-        raise NotImplementedError
-
-    def has_improved(self, m1, m2):
-        raise NotImplementedError
-
-
-class NCModel(BaseModel):
-    """
-    Base model for node classification task.
-    """
-
-    def __init__(self, args):
-        super(NCModel, self).__init__(args)
-        self.decoder = model2decoder(self.c, args)
-        if args.n_classes > 2:
-            self.f1_average = 'micro'
-        else:
-            self.f1_average = 'binary'
-        
-        self.weights = torch.Tensor([1.] * args.n_classes)
-        if not args.cuda == -1:
-            self.weights = self.weights.to(args.device)
-
-    def decode(self, h, adj, idx):
-        output = self.decoder.decode(h, adj)
-        return F.log_softmax(output[idx], dim=1)
-
-
-    def compute_metrics(self, embeddings, data, split):
-        idx = data[f'idx_{split}']
-        output = self.decode(embeddings, data['adj_train_norm'], idx)
-        loss = F.nll_loss(output, data['labels'][idx], self.weights)
-        acc, f1 , recall,precision,roc_auc = acc_f1(output, data['labels'][idx], average=self.f1_average)
-        metrics = {'loss': loss, 'acc': acc, 'f1': f1 , 'recall':recall,'precision':precision,'roc_auc':roc_auc}
-        return metrics
-
-    def init_metric_dict(self):
-        return {'acc': -1, 'f1': -1}
-
-    def has_improved(self, m1, m2):
-        return m1["f1"] < m2["f1"]
\ No newline at end of file
diff --git a/H2HGCN/models/decoders.py b/H2HGCN/models/decoders.py
deleted file mode 100644
index 55d4be5..0000000
--- a/H2HGCN/models/decoders.py
+++ /dev/null
@@ -1,42 +0,0 @@
-"""Graph decoders."""
-import torch.nn as nn
-import torch.nn.functional as F
-from Ghypeddings.H2HGCN.layers.layers import Linear
-
-class Decoder(nn.Module):
-    """
-    Decoder abstract class for node classification tasks.
-    """
-
-    def __init__(self, c):
-        super(Decoder, self).__init__()
-        self.c = c
-
-    def decode(self, x, adj):
-        if self.decode_adj:
-            input = (x, adj)
-            probs, _ = self.cls.forward(input)
-        else:
-            probs = self.cls.forward(x)
-        return probs
-
-
-class MyDecoder(Decoder):
-    """
-    Decoder abstract class for node classification tasks.
-    """
-
-    def __init__(self, c, args):
-        super(MyDecoder, self).__init__(c)
-        self.input_dim = args.num_centroid
-        self.output_dim = args.n_classes
-        act = lambda x: x
-        self.cls = Linear(args, self.input_dim, self.output_dim, args.dropout, act, args.bias)
-        self.decode_adj = False
-
-    def decode(self, x, adj):
-        h = x
-        return super(MyDecoder, self).decode(h, adj)
-
-model2decoder = MyDecoder
-
diff --git a/H2HGCN/models/encoders.py b/H2HGCN/models/encoders.py
deleted file mode 100644
index e5ab931..0000000
--- a/H2HGCN/models/encoders.py
+++ /dev/null
@@ -1,264 +0,0 @@
-import numpy as np
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-import Ghypeddings.H2HGCN.utils.math_utils as pmath
-import torch as th
-from Ghypeddings.H2HGCN.utils import *
-from Ghypeddings.H2HGCN.utils import pre_utils
-from Ghypeddings.H2HGCN.utils.pre_utils import *
-from Ghypeddings.H2HGCN.manifolds import *
-from Ghypeddings.H2HGCN.layers.CentroidDistance import CentroidDistance
-
-
-class H2HGCN(nn.Module):
-
-    def __init__(self, args, logger):
-        super(H2HGCN, self).__init__()
-        self.debug = False
-        self.args = args
-        self.logger = logger
-        self.set_up_params()
-        self.activation = nn.SELU()
-        fd = args.feat_dim - 1
-        self.linear = nn.Linear(
-                int(fd), int(args.dim),
-        )
-        nn_init(self.linear, self.args.proj_init)
-        self.args.eucl_vars.append(self.linear)	
-
-        self.distance = CentroidDistance(args, logger, args.manifold)
-
-
-    def create_params(self):
-        """
-        create the GNN params for a specific msg type
-        """
-        msg_weight = []
-        layer = self.args.num_layers if not self.args.tie_weight else 1
-        for iii in range(layer):
-            M = th.zeros([self.args.dim-1, self.args.dim-1], requires_grad=True)
-            init_weight(M, 'orthogonal')
-            M = nn.Parameter(M)
-            self.args.stie_vars.append(M)
-            msg_weight.append(M)
-        return nn.ParameterList(msg_weight)
-
-    def set_up_params(self):
-        """
-        set up the params for all message types
-        """
-        self.type_of_msg = 1
-
-        for i in range(0, self.type_of_msg):
-            setattr(self, "msg_%d_weight" % i, self.create_params())
-
-    def apply_activation(self, node_repr):
-        """
-        apply non-linearity for different manifolds
-        """
-        if self.args.select_manifold == "poincare":
-            return self.activation(node_repr)
-        elif self.args.select_manifold == "lorentz":
-            return self.args.manifold.from_poincare_to_lorentz(
-                self.activation(self.args.manifold.from_lorentz_to_poincare(node_repr))
-            )
-
-    def split_graph_by_negative_edge(self, adj_mat, weight):
-        """
-        Split the graph according to positive and negative edges.
-        """
-        mask = weight > 0
-        neg_mask = weight < 0
-
-        pos_adj_mat = adj_mat * mask.long()
-        neg_adj_mat = adj_mat * neg_mask.long()
-        pos_weight = weight * mask.float()
-        neg_weight = -weight * neg_mask.float()
-        return pos_adj_mat, pos_weight, neg_adj_mat, neg_weight
-
-    def split_graph_by_type(self, adj_mat, weight):
-        """
-        split the graph according to edge type for multi-relational datasets
-        """
-        multi_relation_adj_mat = []
-        multi_relation_weight = []
-        for relation in range(1, self.args.edge_type):
-            mask = (weight.int() == relation)
-            multi_relation_adj_mat.append(adj_mat * mask.long())
-            multi_relation_weight.append(mask.float())
-        return multi_relation_adj_mat, multi_relation_weight
-
-    def split_input(self, adj_mat, weight):
-        return [adj_mat], [weight]
-
-    def p2k(self, x, c):
-        denom = 1 + c * x.pow(2).sum(-1, keepdim=True)
-        return 2 * x / denom
-
-    def k2p(self, x, c):
-        denom = 1 + torch.sqrt(1 - c * x.pow(2).sum(-1, keepdim=True))
-        return x / denom
-
-    def lorenz_factor(self, x, *, c=1.0, dim=-1, keepdim=False):
-        """
-            Calculate Lorenz factors
-        """
-        x_norm = x.pow(2).sum(dim=dim, keepdim=keepdim)
-        x_norm = torch.clamp(x_norm, 0, 0.9)
-        tmp = 1 / torch.sqrt(1 - c * x_norm)
-        return tmp
-     
-    def from_lorentz_to_poincare(self, x):
-        """
-        Args:
-            u: [batch_size, d + 1]
-        """
-        d = x.size(-1) - 1
-        return x.narrow(-1, 1, d) / (x.narrow(-1, 0, 1) + 1)
-
-    def h2p(self, x):
-        return self.from_lorentz_to_poincare(x)
-
-    def from_poincare_to_lorentz(self, x, eps=1e-3):
-        """
-        Args:
-            u: [batch_size, d]
-        """
-        x_norm_square = x.pow(2).sum(-1, keepdim=True)
-        tmp = th.cat((1 + x_norm_square, 2 * x), dim=1)
-        tmp = tmp / (1 - x_norm_square)
-        return  tmp
-
-    def p2h(self, x):
-        return  self.from_poincare_to_lorentz(x)
-
-    def p2k(self, x, c=1.0):
-        denom = 1 + c * x.pow(2).sum(-1, keepdim=True)
-        return 2 * x / denom
-
-    def k2p(self, x, c=1.0):
-        denom = 1 + torch.sqrt(1 - c * x.pow(2).sum(-1, keepdim=True))
-        return x / denom
-
-    def h2k(self, x):
-        tmp = x.narrow(-1, 1, x.size(-1)-1) / x.narrow(-1, 0, 1)
-        return tmp
-        
-    def k2h(self, x):
-        x_norm_square = x.pow(2).sum(-1, keepdim=True)
-        x_norm_square = torch.clamp(x_norm_square, max=0.9)
-        tmp = torch.ones((x.size(0),1)).cuda().to(self.args.device)
-        tmp1 = th.cat((tmp, x), dim=1)
-        tmp2 = 1.0 / torch.sqrt(1.0 - x_norm_square)
-        tmp3 = (tmp1 * tmp2)
-        return tmp3 
-
-
-    def hyperbolic_mean(self, y, node_num, max_neighbor, real_node_num, weight, dim=0, c=1.0, ):
-        '''
-        y [node_num * max_neighbor, dim]
-        '''
-        x = y[0:real_node_num*max_neighbor, :]
-        weight_tmp = weight.view(-1,1)[0:real_node_num*max_neighbor, :]
-        x = self.h2k(x)
-        
-        lamb = self.lorenz_factor(x, c=c, keepdim=True)
-        lamb = lamb  * weight_tmp 
-        lamb = lamb.view(real_node_num, max_neighbor, -1)
-
-        x = x.view(real_node_num, max_neighbor, -1) 
-        k_mean = (torch.sum(lamb * x, dim=1, keepdim=True) / (torch.sum(lamb, dim=1, keepdim=True))).squeeze()
-        h_mean = self.k2h(k_mean)
-
-        virtual_mean = torch.cat((torch.tensor([[1.0]]), torch.zeros(1,y.size(-1)-1)), 1).cuda().to(self.args.device)
-        tmp = virtual_mean.repeat(node_num-real_node_num, 1)
-
-        mean = torch.cat((h_mean, tmp), 0)
-        return mean	
-
-    def test_lor(self, A):
-        tmp1 = (A[:,0] * A[:,0]).view(-1)
-        tmp2 = A[:,1:]
-        tmp2 = th.diag(tmp2.mm(tmp2.transpose(0,1)))
-        return (tmp1 - tmp2)
-
-    def retrieve_params(self, weight, step):
-        """
-        Args:
-            weight: a list of weights
-            step: a certain layer
-        """
-        layer_weight = th.cat((th.zeros((self.args.dim-1, 1)).cuda().to(self.args.device), weight[step]), dim=1)
-        tmp = th.zeros((1, self.args.dim)).cuda().to(self.args.device)
-        tmp[0,0] = 1
-        layer_weight = th.cat((tmp, layer_weight), dim=0)
-        return layer_weight
-
-    def aggregate_msg(self, node_repr, adj_mat, weight, layer_weight, mask):
-        """
-        message passing for a specific message type.
-        """
-        node_num, max_neighbor = adj_mat.shape[0], adj_mat.shape[1] 
-        combined_msg = node_repr.clone()
-
-        tmp = self.test_lor(node_repr)
-        msg = th.mm(node_repr, layer_weight) * mask
-        real_node_num = (mask>0).sum()
-        
-        # select out the neighbors of each node
-        neighbors = th.index_select(msg, 0, adj_mat.view(-1))
-        combined_msg = self.hyperbolic_mean(neighbors, node_num, max_neighbor, real_node_num, weight)
-        return combined_msg 
-
-    def get_combined_msg(self, step, node_repr, adj_mat, weight, mask):
-        """
-        perform message passing in the tangent space of x'
-        """
-        gnn_layer = 0 if self.args.tie_weight else step
-        combined_msg = None
-        for relation in range(0, self.type_of_msg):
-            layer_weight = self.retrieve_params(getattr(self, "msg_%d_weight" % relation), gnn_layer)
-            aggregated_msg = self.aggregate_msg(node_repr,
-                                                adj_mat[relation],
-                                                weight[relation],
-                                                layer_weight, mask)
-            combined_msg = aggregated_msg if combined_msg is None else (combined_msg + aggregated_msg)
-        return combined_msg
-
-
-    def encode(self, node_repr, adj_list, weight):
-        node_repr = self.activation(self.linear(node_repr))
-        adj_list, weight = self.split_input(adj_list, weight)
-        
-        mask = torch.ones((node_repr.size(0),1)).cuda().to(self.args.device)
-        node_repr = self.args.manifold.exp_map_zero(node_repr)
-
-        for step in range(self.args.num_layers):
-            node_repr = node_repr * mask
-            tmp = node_repr
-            combined_msg = self.get_combined_msg(step, node_repr, adj_list, weight, mask)
-            combined_msg = (combined_msg) * mask
-            node_repr = combined_msg * mask
-            node_repr = self.apply_activation(node_repr) * mask
-            real_node_num = (mask>0).sum()
-            node_repr = self.args.manifold.normalize(node_repr)
-        _, node_centroid_sim = self.distance(node_repr, mask) 
-        return node_centroid_sim.squeeze()
-
-class Encoder(nn.Module):
-    """
-    Encoder abstract class.
-    """
-
-    def __init__(self, c):
-        super(Encoder, self).__init__()
-        self.c = c
-
-    def encode(self, x, adj):
-        if self.encode_graph:
-            input = (x, adj)
-            output, _ = self.layers.forward(input)
-        else:
-            output = self.layers.forward(x)
-        return output
diff --git a/H2HGCN/optimizers/__init__.py b/H2HGCN/optimizers/__init__.py
deleted file mode 100644
index 23027ab..0000000
--- a/H2HGCN/optimizers/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from torch.optim import Adam
diff --git a/H2HGCN/optimizers/rsgd.py b/H2HGCN/optimizers/rsgd.py
deleted file mode 100644
index 968b974..0000000
--- a/H2HGCN/optimizers/rsgd.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import torch as th
-from torch.optim.optimizer import Optimizer, required
-from Ghypeddings.H2HGCN.utils import *
-import os
-import math
-
-class RiemannianSGD(Optimizer):
-    """Riemannian stochastic gradient descent.
-    """
-    def __init__(self, args, params, lr):
-        defaults = dict(lr=lr)
-        self.args = args
-        super(RiemannianSGD, self).__init__(params, defaults)
-
-    def step(self, lr=None):
-        """
-        Performs a single optimization step.
-        """
-        loss = None
-        for group in self.param_groups:
-            for p in group['params']:
-                if p.grad is None:
-                    continue
-                d_p = p.grad.data
-                d_p = self.args.manifold.rgrad(p, d_p)
-                if lr is None:
-                    lr = group['lr']
-                p.data = self.args.manifold.exp_map_x(p, -lr * d_p)
-        return loss
diff --git a/H2HGCN/utils/__init__.py b/H2HGCN/utils/__init__.py
deleted file mode 100644
index 7c3b514..0000000
--- a/H2HGCN/utils/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from Ghypeddings.H2HGCN.utils.pre_utils import *
\ No newline at end of file
diff --git a/H2HGCN/utils/data_utils.py b/H2HGCN/utils/data_utils.py
deleted file mode 100644
index f726ddf..0000000
--- a/H2HGCN/utils/data_utils.py
+++ /dev/null
@@ -1,102 +0,0 @@
-"""Data utils functions for pre-processing and data loading."""
-import os
-import pickle as pkl
-import sys
-import networkx as nx
-import numpy as np
-import scipy.sparse as sp
-import torch
-from Ghypeddings.H2HGCN.utils.pre_utils import *
-
-def convert_hgnn_adj(adj):
-    hgnn_adj = [[i] for i in range(adj.shape[0])]
-    hgnn_weight = [[1] for i in range(adj.shape[0])]
-    for i in range(adj.shape[0]):
-        for j in range(adj.shape[1]):
-            if adj[i,j] == 1:
-                hgnn_adj[i].append(j)
-                hgnn_weight[i].append(1)
-
-    max_len = max([len(i) for i in hgnn_adj])
-    normalize_weight(hgnn_adj, hgnn_weight)
- 
-    hgnn_adj = pad_sequence(hgnn_adj, max_len)
-    hgnn_weight = pad_sequence(hgnn_weight, max_len)
-    hgnn_adj = np.array(hgnn_adj)
-    hgnn_weight = np.array(hgnn_weight)
-    return torch.from_numpy(hgnn_adj).cuda(), torch.from_numpy(hgnn_weight).cuda().float()
-
-
-def process_data(args,adj,features,labels):
-    data = process_data_nc(args,adj,features,labels)
-    data['adj_train_norm'], data['features'] = process(
-            data['adj_train'], data['features'], args.normalize_adj, args.normalize_feats
-    )
-    return data
-
-
-def process(adj, features, normalize_adj, normalize_feats):
-    if sp.isspmatrix(features):
-        features = np.array(features.todense())
-    if normalize_feats:
-        features = normalize(features)
-    features = torch.Tensor(features)
-    if normalize_adj:
-        adj = normalize(adj)
-    adj = sparse_mx_to_torch_sparse_tensor(adj)
-    return adj, features
-
-def normalize(mx):
-    """Row-normalize sparse matrix."""
-    rowsum = np.array(mx.sum(1))
-    r_inv = np.power(rowsum, -1).flatten()
-    r_inv[np.isinf(r_inv)] = 0.
-    r_mat_inv = sp.diags(r_inv)
-    mx = r_mat_inv.dot(mx)
-    return mx
-
-def sparse_mx_to_torch_sparse_tensor(sparse_mx):
-    """Convert a scipy sparse matrix to a torch sparse tensor."""
-    sparse_mx = sparse_mx.tocoo()
-    indices = torch.from_numpy(
-            np.vstack((sparse_mx.row, sparse_mx.col)).astype(np.int64)
-    )
-    values = torch.Tensor(sparse_mx.data)
-    shape = torch.Size(sparse_mx.shape)
-    return torch.sparse.FloatTensor(indices, values, shape)
-
-def augment(adj, features, normalize_feats=True):
-    deg = np.squeeze(np.sum(adj, axis=0).astype(int))
-    deg[deg > 5] = 5
-    deg_onehot = torch.tensor(np.eye(6)[deg], dtype=torch.float).squeeze()
-    const_f = torch.ones(features.size(0), 1)
-    features = torch.cat((features, deg_onehot, const_f), dim=1)
-    return features
-
-def split_data(labels, val_prop, test_prop, seed):
-    np.random.seed(seed)
-    nb_nodes = labels.shape[0]
-    all_idx = np.arange(nb_nodes)
-    pos_idx = labels.nonzero()[0]
-    neg_idx = (1. - labels).nonzero()[0]
-    np.random.shuffle(pos_idx)
-    np.random.shuffle(neg_idx)
-    pos_idx = pos_idx.tolist()
-    neg_idx = neg_idx.tolist()
-    nb_pos_neg = min(len(pos_idx), len(neg_idx))
-    nb_val = round(val_prop * nb_pos_neg)
-    nb_test = round(test_prop * nb_pos_neg)
-    idx_val_pos, idx_test_pos, idx_train_pos = pos_idx[:nb_val], pos_idx[nb_val:nb_val + nb_test], pos_idx[
-                                                                                                   nb_val + nb_test:]
-    idx_val_neg, idx_test_neg, idx_train_neg = neg_idx[:nb_val], neg_idx[nb_val:nb_val + nb_test], neg_idx[
-                                                                                                   nb_val + nb_test:]
-    return idx_val_pos + idx_val_neg, idx_test_pos + idx_test_neg, idx_train_pos + idx_train_neg
-
-
-def process_data_nc(args,adj,features,labels):
-    adj = sp.csr_matrix(adj)
-    hgnn_adj, hgnn_weight = convert_hgnn_adj(adj.todense())
-    idx_val, idx_test, idx_train = split_data(labels, args.val_prop, args.test_prop, seed=args.seed)
-    labels = torch.LongTensor(labels)
-    data = {'adj_train': adj, 'features': features, 'labels': labels, 'idx_train': idx_train, 'idx_val': idx_val, 'idx_test': idx_test, 'hgnn_adj': hgnn_adj, 'hgnn_weight': hgnn_weight}
-    return data
\ No newline at end of file
diff --git a/H2HGCN/utils/eval_utils.py b/H2HGCN/utils/eval_utils.py
deleted file mode 100644
index 4a17797..0000000
--- a/H2HGCN/utils/eval_utils.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from sklearn.metrics import accuracy_score, f1_score, recall_score,precision_score,roc_auc_score
- 
-def acc_f1(output, labels, average='binary'):
-    preds = output.max(1)[1].type_as(labels)
-    if preds.is_cuda:
-        preds = preds.cpu()
-        labels = labels.cpu()
-    accuracy = accuracy_score(labels,preds)
-    f1 = f1_score(labels,preds , average=average)
-    recall = recall_score(labels,preds)
-    precision = precision_score(labels,preds )
-    roc_auc = roc_auc_score(labels,preds)
-    return accuracy, f1 , recall,precision, roc_auc
\ No newline at end of file
diff --git a/H2HGCN/utils/math_utils.py b/H2HGCN/utils/math_utils.py
deleted file mode 100644
index 9cf278e..0000000
--- a/H2HGCN/utils/math_utils.py
+++ /dev/null
@@ -1,69 +0,0 @@
-"""Math utils functions."""
-
-import torch
-
-
-def cosh(x, clamp=15):
-    return x.clamp(-clamp, clamp).cosh()
-
-
-def sinh(x, clamp=15):
-    return x.clamp(-clamp, clamp).sinh()
-
-
-def tanh(x, clamp=15):
-    return x.clamp(-clamp, clamp).tanh()
-
-
-def arcosh(x):
-    return Arcosh.apply(x)
-
-
-def arsinh(x):
-    return Arsinh.apply(x)
-
-
-def artanh(x):
-    return Artanh.apply(x)
-
-
-class Artanh(torch.autograd.Function):
-    @staticmethod
-    def forward(ctx, x):
-        x = x.clamp(-1 + 1e-15, 1 - 1e-15)
-        ctx.save_for_backward(x)
-        z = x.double()
-        return (torch.log_(1 + z).sub_(torch.log_(1 - z))).mul_(0.5).to(x.dtype)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        input, = ctx.saved_tensors
-        return grad_output / (1 - input ** 2)
-
-
-class Arsinh(torch.autograd.Function):
-    @staticmethod
-    def forward(ctx, x):
-        ctx.save_for_backward(x)
-        z = x.double()
-        return (z + torch.sqrt_(1 + z.pow(2))).clamp_min_(1e-15).log_().to(x.dtype)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        input, = ctx.saved_tensors
-        return grad_output / (1 + input ** 2) ** 0.5
-
-
-class Arcosh(torch.autograd.Function):
-    @staticmethod
-    def forward(ctx, x):
-        x = x.clamp(min=1.0 + 1e-15)
-        ctx.save_for_backward(x)
-        z = x.double()
-        return (z + torch.sqrt_(z.pow(2) - 1)).clamp_min_(1e-15).log_().to(x.dtype)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        input, = ctx.saved_tensors
-        return grad_output / (input ** 2 - 1) ** 0.5
-
diff --git a/H2HGCN/utils/pre_utils.py b/H2HGCN/utils/pre_utils.py
deleted file mode 100644
index 283e730..0000000
--- a/H2HGCN/utils/pre_utils.py
+++ /dev/null
@@ -1,167 +0,0 @@
-from collections import defaultdict
-import os
-import pickle
-import json
-import torch.nn as nn
-import torch as th
-import torch.optim as optim
-import numpy as np
-import random
-from Ghypeddings.H2HGCN.optimizers.rsgd import RiemannianSGD
-import math
-import subprocess
-import random
-
-def set_seed(seed):
-    """
-    Set the random seed
-    """
-    random.seed(seed)
-    np.random.seed(seed)
-    th.manual_seed(seed)
-    th.cuda.manual_seed(seed)
-    th.cuda.manual_seed_all(seed)
-
-def th_dot(x, y, keepdim=True):
-    return th.sum(x * y, dim=1, keepdim=keepdim)
-
-def pad_sequence(data_list, maxlen, value=0):
-    return [row + [value] * (maxlen - len(row)) for row in data_list]
-
-def normalize_weight(adj_mat, weight):
-    degree = [1 / math.sqrt(sum(np.abs(w))) for w in weight]
-    for dst in range(len(adj_mat)):
-        for src_idx in range(len(adj_mat[dst])):
-            src = adj_mat[dst][src_idx]
-            weight[dst][src_idx] = degree[dst] * weight[dst][src_idx] * degree[src]
-
-def nn_init(nn_module, method='orthogonal'):
-    """
-    Initialize a Sequential or Module object
-    Args:
-        nn_module: Sequential or Module
-        method: initialization method
-    """
-    if method == 'none':
-        return
-    for param_name, _ in nn_module.named_parameters():
-        if isinstance(nn_module, nn.Sequential):
-            # for a Sequential object, the param_name contains both id and param name
-            i, name = param_name.split('.', 1)
-            param = getattr(nn_module[int(i)], name)
-        else:
-            param = getattr(nn_module, param_name)
-        if param_name.find('weight') > -1:
-            init_weight(param, method)
-        elif param_name.find('bias') > -1:
-            nn.init.uniform_(param, -1e-4, 1e-4)
-
-def get_params(params_list, vars_list):
-    """
-    Add parameters in vars_list to param_list
-    """
-    for i in vars_list:
-        if issubclass(i.__class__, nn.Module):
-            params_list.extend(list(i.parameters()))
-        elif issubclass(i.__class__, nn.Parameter):
-            params_list.append(i)
-        else:
-            print("Encounter unknown objects")
-            exit(1)
-
-def categorize_params(args):
-    """
-    Categorize parameters into hyperbolic ones and euclidean ones
-    """
-    stiefel_params, euclidean_params = [], []
-    get_params(euclidean_params, args.eucl_vars)
-    get_params(stiefel_params, args.stie_vars)
-    return stiefel_params, euclidean_params
-
-def get_activation(args):
-    if args.activation == 'leaky_relu':
-        return nn.LeakyReLU(args.leaky_relu)
-    elif args.activation == 'rrelu':
-        return nn.RReLU()
-    elif args.activation == 'relu':
-        return nn.ReLU()
-    elif args.activation == 'elu':
-        return nn.ELU()
-    elif args.activation == 'prelu':
-        return nn.PReLU()
-    elif args.activation == 'selu':
-        return nn.SELU()
-
-def init_weight(weight, method):
-    """
-    Initialize parameters
-    Args:
-        weight: a Parameter object
-        method: initialization method 
-    """
-    if method == 'orthogonal':
-        nn.init.orthogonal_(weight)
-    elif method == 'xavier':
-        nn.init.xavier_uniform_(weight)
-    elif method == 'kaiming':
-        nn.init.kaiming_uniform_(weight)
-    elif method == 'none':
-        pass
-    else:
-        raise Exception('Unknown init method')
-
-
-def get_stiefel_optimizer(args, params, lr_stie):
-    if args.stiefel_optimizer == 'rsgd':
-        optimizer = RiemannianSGD(
-            args,
-            params,
-            lr=lr_stie,
-        )
-    elif args.stiefel_optimizer == 'ramsgrad':
-        optimizer = RiemannianAMSGrad(
-            args,
-            params,
-            lr=lr_stie,
-        )
-    else:
-        print("unsupported hyper optimizer")
-        exit(1)        
-    return optimizer
-
-def get_lr_scheduler(args, optimizer):
-    if args.lr_scheduler == 'exponential':
-        return optim.lr_scheduler.ExponentialLR(optimizer, gamma=args.lr_gamma)
-    elif args.lr_scheduler == 'cosine':
-        return optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=30, eta_min=0)
-    elif args.lr_scheduler == 'cycle':
-        return optim.lr_scheduler.CyclicLR(optimizer, 0, max_lr=args.lr, step_size_up=20, cycle_momentum=False)
-    elif args.lr_scheduler == 'step':
-        return optim.lr_scheduler.StepLR(
-        optimizer,
-        step_size=int(args.step_lr_reduce_freq),
-        gamma=float(args.step_lr_gamma)
-    )
-    elif args.lr_scheduler == 'none':
-        return NoneScheduler()
-
-def get_optimizer(args, params, lr):
-    if args.optimizer == 'sgd':
-        optimizer = optim.SGD(params, lr=lr, weight_decay=args.weight_decay)
-    elif args.optimizer == 'Adam':
-        optimizer = optim.Adam(params, lr=lr, weight_decay=args.weight_decay)
-    elif args.optimizer == 'amsgrad':
-        optimizer = optim.Adam(params, lr=lr, amsgrad=True, weight_decay=args.weight_decay)
-    return optimizer
-
-def set_up_optimizer_scheduler(hyperbolic, args, model, lr, lr_stie, pprint=True):
-    stiefel_params, euclidean_params = categorize_params(args)
-    #assert(len(list(model.parameters())) == len(stiefel_params) + len(euclidean_params))
-    optimizer = get_optimizer(args, euclidean_params, lr)
-    lr_scheduler = get_lr_scheduler(args, optimizer)
-    if len(stiefel_params) > 0:
-        stiefel_optimizer = get_stiefel_optimizer(args, stiefel_params, lr_stie)
-        stiefel_lr_scheduler = get_lr_scheduler(args, stiefel_optimizer)
-    else:
-        stiefel_optimizer, stiefel_lr_scheduler = None, None
-    return optimizer, lr_scheduler, stiefel_optimizer, stiefel_lr_scheduler
\ No newline at end of file
diff --git a/H2HGCN/utils/train_utils.py b/H2HGCN/utils/train_utils.py
deleted file mode 100644
index 71781f9..0000000
--- a/H2HGCN/utils/train_utils.py
+++ /dev/null
@@ -1,52 +0,0 @@
-import os
-import numpy as np
-import torch
-import torch.nn.functional as F
-import torch.nn.modules.loss
-import argparse
-
-
-def format_metrics(metrics, split):
-    """Format metric in metric dict for logging."""
-    return " ".join(
-            ["{}_{}: {:.4f}".format(split, metric_name, metric_val) for metric_name, metric_val in metrics.items()])
-
-
-def create_args(*args):
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--dim', type=int, default=args[0])
-    parser.add_argument('--c', type=int, default=args[1])
-    parser.add_argument('--num_layers', type=int, default=args[2])
-    parser.add_argument('--bias', type=bool, default=args[3])
-    parser.add_argument('--act', type=str, default=args[4])
-    parser.add_argument('--select_manifold', type=str, default=args[5])
-    parser.add_argument('--num_centroid', type=int, default=args[6])
-    parser.add_argument('--lr_stie', type=float, default=args[7])
-    parser.add_argument('--stie_vars', nargs='+', default=args[8])
-    parser.add_argument('--stiefel_optimizer', type=str, default=args[9])
-    parser.add_argument('--eucl_vars', nargs='+', default=args[10])
-    parser.add_argument('--grad_clip', type=float, default=args[11])
-    parser.add_argument('--optimizer', type=str, default=args[12])
-    parser.add_argument('--weight_decay', type=float, default=args[13])
-    parser.add_argument('--lr', type=float, default=args[14])
-    parser.add_argument('--lr_scheduler', type=str, default=args[15])
-    parser.add_argument('--lr_gamma', type=float, default=args[16])
-    parser.add_argument('--step_lr_gamma', type=float, default=args[17])
-    parser.add_argument('--step_lr_reduce_freq', type=int, default=args[18])
-    parser.add_argument('--proj_init', type=str, default=args[19])
-    parser.add_argument('--tie_weight', type=bool, default=args[20])
-    parser.add_argument('--cuda', type=int, default=args[21])
-    parser.add_argument('--epochs', type=int, default=args[22])
-    parser.add_argument('--min_epochs', type=int, default=args[23])
-    parser.add_argument('--patience', type=int, default=args[24])
-    parser.add_argument('--seed', type=int, default=args[25])
-    parser.add_argument('--log_freq', type=int, default=args[26])
-    parser.add_argument('--eval_freq', type=int, default=args[27])
-    parser.add_argument('--val_prop', type=float, default=args[28])
-    parser.add_argument('--test_prop', type=float, default=args[29])
-    parser.add_argument('--double_precision', type=int, default=args[30])
-    parser.add_argument('--dropout', type=float, default=args[31])
-    parser.add_argument('--normalize_adj', type=bool, default=args[32])
-    parser.add_argument('--normalize_feats', type=bool, default=args[33])
-    flags, unknown = parser.parse_known_args()
-    return flags
\ No newline at end of file
diff --git a/HGCAE/.gitignore b/HGCAE/.gitignore
deleted file mode 100644
index bee8a64..0000000
--- a/HGCAE/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-__pycache__
diff --git a/HGCAE/__init__.py b/HGCAE/__init__.py
deleted file mode 100644
index bfa83a0..0000000
--- a/HGCAE/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from __future__ import print_function
-from __future__ import division
diff --git a/HGCAE/hgcae.py b/HGCAE/hgcae.py
deleted file mode 100644
index 614885f..0000000
--- a/HGCAE/hgcae.py
+++ /dev/null
@@ -1,230 +0,0 @@
-from Ghypeddings.HGCAE.models.base_models import LPModel
-import logging
-import torch
-import numpy as np
-import os
-import time
-from Ghypeddings.HGCAE.utils.train_utils import get_dir_name, format_metrics
-from Ghypeddings.HGCAE.utils.data_utils import process_data
-from Ghypeddings.HGCAE.utils.train_utils import create_args , get_classifier ,get_clustering_algorithm,get_anomaly_detection_algorithm
-import Ghypeddings.HGCAE.optimizers as optimizers
-from Ghypeddings.HGCAE.utils.data_utils import sparse_mx_to_torch_sparse_tensor
-
-from Ghypeddings.classifiers import calculate_metrics
-
-class HGCAE(object):
-    def __init__(self, 
-                adj,
-                features,
-                labels,
-                dim,
-                hidden_dim,
-                c=None,
-                num_layers=2,
-                bias=True,
-                act='relu',
-                grad_clip=None,
-                optimizer='RiemannianAdam',
-                weight_decay=0.01,
-                lr=0.001,
-                gamma=0.5,
-                lr_reduce_freq=500,
-                cuda=0,
-                epochs=50,
-                min_epochs=50,
-                patience=None,
-                seed=42,
-                log_freq=1,
-                eval_freq=1,
-                val_prop=0.0002,
-                test_prop=0.3,
-                double_precision=0,
-                dropout=0.1,
-                lambda_rec=1.0,
-                lambda_lp=1.0,
-                num_dec_layers=2,
-                use_att= True,
-                att_type= 'sparse_adjmask_dist',
-                att_logit='tanh',
-                beta = 0.2,
-                classifier=None,
-                clusterer = None,
-                normalize_adj=False,
-                normalize_feats=True,
-                anomaly_detector=None
-                ):
-        
-        self.args = create_args(dim,hidden_dim,c,num_layers,bias,act,grad_clip,optimizer,weight_decay,lr,gamma,lr_reduce_freq,cuda,epochs,min_epochs,patience,seed,log_freq,eval_freq,val_prop,test_prop,double_precision,dropout,lambda_rec,lambda_lp,num_dec_layers,use_att,att_type,att_logit,beta,classifier,clusterer,normalize_adj,normalize_feats,anomaly_detector)
-        self.cls = None
-
-        self.args.n_nodes = adj.shape[0]
-        self.args.feat_dim = features.shape[1]
-        self.args.n_classes = len(np.unique(labels))
-        self.data = process_data(self.args,adj,features,labels)
-
-        if(self.args.c == None):
-            self.args.c_trainable = 1
-            self.args.c = 1.0
-        
-        np.random.seed(self.args.seed)
-        torch.manual_seed(self.args.seed)
-
-        if int(self.args.double_precision):
-            torch.set_default_dtype(torch.float64)
-        if int(self.args.cuda) >= 0:
-            torch.cuda.manual_seed(self.args.seed)
-
-        self.args.device = 'cuda:' + str(self.args.cuda) if int(self.args.cuda) >= 0 else 'cpu'
-        self.args.patience = self.args.epochs if not self.args.patience else  int(self.args.patience)
-
-        if not self.args.lr_reduce_freq:
-            self.args.lr_reduce_freq = self.args.epochs
-
-        self.args.nb_false_edges = len(self.data['train_edges_false'])
-        self.args.nb_edges = len(self.data['train_edges'])
-        st0 = np.random.get_state()
-        self.args.np_seed = st0
-        np.random.set_state(self.args.np_seed)
-
-        for x, val in self.data.items():
-            if 'adj' in x:
-                self.data[x] = sparse_mx_to_torch_sparse_tensor(self.data[x])
-
-        self.model = LPModel(self.args)
-
-        if self.args.cuda is not None and int(self.args.cuda) >= 0 :
-            os.environ['CUDA_VISIBLE_DEVICES'] = str(self.args.cuda)
-            self.model = self.model.to(self.args.device)
-            for x, val in self.data.items():
-                if torch.is_tensor(self.data[x]):
-                    self.data[x] = self.data[x].to(self.args.device)
-
-        self.adj_train_enc = self.data['adj_train_enc']
-        self.optimizer = getattr(optimizers, self.args.optimizer)(params=self.model.parameters(), lr=self.args.lr,
-                                                        weight_decay=self.args.weight_decay)
-        self.lr_scheduler = torch.optim.lr_scheduler.StepLR(
-            self.optimizer,
-            step_size=int(self.args.lr_reduce_freq),
-            gamma=float(self.args.gamma)
-        )
-
-        self.best_emb = None
-
-
-
-    def fit(self):
-
-        logging.getLogger().setLevel(logging.INFO)
-        logging.info(f'Using: {self.args.device}')
-        logging.info(str(self.model))
-        tot_params = sum([np.prod(p.size()) for p in self.model.parameters()])
-        logging.info(f"Total number of parameters: {tot_params}")
-
-        t_total = time.time()
-        counter = 0
-        best_val_metrics = self.model.init_metric_dict()
-
-        best_losses = []
-        train_losses = []
-        val_losses = []
-
-        for epoch in range(self.args.epochs):
-            t = time.time()
-            self.model.train()
-            self.optimizer.zero_grad()
-            embeddings = self.model.encode(self.data['features'], self.adj_train_enc)
-            train_metrics = self.model.compute_metrics(embeddings, self.data, 'train', epoch)
-            print(train_metrics)
-            train_metrics['loss'].backward()
-            if self.args.grad_clip is not None:
-                max_norm = float(self.args.grad_clip)
-                all_params = list(self.model.parameters())
-                for param in all_params:
-                    torch.nn.utils.clip_grad_norm_(param, max_norm)
-            self.optimizer.step()
-            self.lr_scheduler.step()
-
-            train_losses.append(train_metrics['loss'].item())
-            if(len(best_losses) == 0):
-                best_losses.append(train_losses[0])
-            elif (best_losses[-1] > train_losses[-1]):
-                best_losses.append(train_losses[-1])
-            else:
-                best_losses.append(best_losses[-1])
-
-            with torch.no_grad():
-                if (epoch + 1) % self.args.log_freq == 0:
-                    logging.info(" ".join(['Epoch: {:04d}'.format(epoch + 1),
-                                           'lr: {}'.format(self.lr_scheduler.get_lr()[0]),
-                                           format_metrics(train_metrics, 'train'),
-                                           'time: {:.4f}s'.format(time.time() - t)
-                                           ]))
-                    
-                if (epoch + 1) % self.args.eval_freq == 0:
-                    self.model.eval()
-                    embeddings = self.model.encode(self.data['features'], self.adj_train_enc)
-                    #val_metrics = self.model.compute_metrics(embeddings, self.data, 'val')
-                    # val_losses.append(val_metrics['loss'].item())
-                    # if (epoch + 1) % self.args.log_freq == 0:
-                    #     logging.info(" ".join(['Epoch: {:04d}'.format(epoch + 1), format_metrics(val_metrics, 'val')]))
-                    # if self.model.has_improved(best_val_metrics, val_metrics):
-                    #     self.best_emb = embeddings
-                    #     best_val_metrics = val_metrics
-                    #     counter = 0
-                    # else:
-                    #     counter += 1
-                    #     if counter == self.args.patience and epoch > self.args.min_epochs:
-                    #         logging.info("Early stopping")
-                    #         break
-
-        logging.info("Training Finished!")
-        logging.info("Total time elapsed: {:.4f}s".format(time.time() - t_total))
-
-        # train_idx = np.unique(self.data['train_edges'][:,0].cpu().detach().numpy())
-        # val_idx = np.unique(self.data['val_edges'][:,0].cpu().detach().numpy())
-        # idx = np.unique(np.concatenate((train_idx,val_idx)))
-        # X = self.model.manifold.logmap0(self.best_emb[idx],self.model.encoder.curvatures[-1]).cpu().detach().numpy()
-        # y = self.data['labels'].reshape(-1,1)[idx]
-
-        # if(self.args.classifier):
-        #     self.cls = get_classifier(self.args, X,y)
-        #     acc,f1,recall,precision,roc_auc = calculate_metrics(self.cls,X,y)
-        # elif self.args.clusterer:
-        #     y = y.reshape(-1,)
-        #     acc,f1,recall,precision,roc_auc = get_clustering_algorithm(self.args.clusterer,X,y)[6:]
-        # elif self.args.anomaly_detector:
-        #     y = y.reshape(-1,)
-        #     acc,f1,recall,precision,roc_auc = get_anomaly_detection_algorithm(self.args.anomaly_detector,X,y)[6:]
-        
-        # return {'train':train_losses,'best':best_losses,'val':val_losses},acc,f1,recall,precision,roc_auc , time.time() - t_total
-        return {'train':train_losses,'best':best_losses,'val':val_losses}, time.time() - t_total
-
-    def predict(self):
-        self.model.eval()
-        test_idx = np.unique(self.data['test_edges'][:,0].cpu().detach().numpy())
-        embeddings = self.model.encode(self.data['features'], self.adj_train_enc)
-        val_metrics = self.model.compute_metrics(embeddings, self.data, 'test')
-        data = self.model.manifold.logmap0(embeddings[test_idx],self.model.encoder.curvatures[-1]).cpu().detach().numpy()
-        labels = self.data['labels'].reshape(-1,1)[test_idx]
-        if self.args.classifier:
-            acc,f1,recall,precision,roc_auc = calculate_metrics(self.cls,data,labels)
-        elif self.args.clusterer:
-            labels = labels.reshape(-1,)
-            acc,f1,recall,precision,roc_auc = get_clustering_algorithm(self.args.clusterer,data,labels)[6:]
-        elif self.args.anomaly_detector:
-            labels = labels.reshape(-1,)
-            acc,f1,recall,precision,roc_auc = get_anomaly_detection_algorithm(self.args.anomaly_detector,data,labels)[6:]
-        self.tb_embeddings = embeddings
-        return val_metrics['loss'].item(),acc,f1,recall,precision,roc_auc
-
-                    
-    def save_embeddings(self,directory):
-        self.model.eval()
-        embeddings = self.model.encode(self.data['features'], self.adj_train_enc)
-        tb_embeddings_euc = self.model.manifold.logmap0(embeddings,self.model.encoder.curvatures[-1])
-        for_classification_hyp = np.hstack((embeddings.cpu().detach().numpy(),self.data['labels'].reshape(-1,1)))
-        for_classification_euc = np.hstack((tb_embeddings_euc.cpu().detach().numpy(),self.data['labels'].reshape(-1,1)))
-        hyp_file_path = os.path.join(directory,'hgcae_embeddings_hyp.csv')
-        euc_file_path = os.path.join(directory,'hgcae_embeddings_euc.csv')
-        np.savetxt(hyp_file_path, for_classification_hyp, delimiter=',')
-        np.savetxt(euc_file_path, for_classification_euc, delimiter=',')
\ No newline at end of file
diff --git a/HGCAE/layers/__init__.py b/HGCAE/layers/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/HGCAE/layers/att_layers.py b/HGCAE/layers/att_layers.py
deleted file mode 100644
index e99964c..0000000
--- a/HGCAE/layers/att_layers.py
+++ /dev/null
@@ -1,80 +0,0 @@
-"""Attention layers (some modules are copied from https://github.com/Diego999/pyGAT.)"""
-import numpy as np
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-
-def HypAggAtt(in_features, manifold, dropout, act=None, att_type=None, att_logit=None, beta=0):
-    att_logit = get_att_logit(att_logit, att_type)
-    return GeometricAwareHypAggAtt(in_features, manifold, dropout, lambda x: x, att_logit=att_logit, beta=beta)
-
-class GeometricAwareHypAggAtt(nn.Module):
-    def __init__(self, in_features, manifold, dropout, act, att_logit=torch.tanh, beta=0.):
-        super(GeometricAwareHypAggAtt, self).__init__()
-        self.dropout = dropout
-        self.att_logit=att_logit
-        self.special_spmm = SpecialSpmm()
-
-
-        self.m = manifold
-        self.beta = nn.Parameter(torch.Tensor([1e-6]))
-        self.con = nn.Parameter(torch.Tensor([1e-6]))
-        self.act = act
-        self.in_features = in_features
-
-    def forward (self, x, adj, c=1):
-        n = x.size(0)
-        edge = adj._indices()
-
-        assert not torch.isnan(self.beta).any()
-        edge_h = self.beta * self.m.sqdist(x[edge[0, :], :], x[edge[1, :], :], c) + self.con
-
-        self.edge_h = edge_h
-        assert not torch.isnan(edge_h).any()
-        edge_e = self.att_logit(edge_h)
-        self.edge_e = edge_e
-        ones = torch.ones(size=(n, 1))
-        if x.is_cuda:
-            ones = ones.to(x.device)
-        e_rowsum = self.special_spmm(edge, abs(edge_e), torch.Size([n, n]), ones) + 1e-10
-
-        return edge_e, e_rowsum
-
-class SpecialSpmmFunction(torch.autograd.Function):
-    """Special function for only sparse region backpropataion layer."""
-    # generate sparse matrix from `indicex, values, shape` and matmul with b
-    # Previously, `AXW` computing did not need bp to `A`.
-    # To trian attention of `A`, now bp through sparse matrix needed.
-    @staticmethod
-    def forward(ctx, indices, values, shape, b):
-        assert indices.requires_grad == False
-        a = torch.sparse_coo_tensor(indices, values, shape, device=b.device) # make sparse matrix shaped of `NxN` 
-        ctx.save_for_backward(a, b) # save sparse matrix for bp
-        ctx.N = shape[0] # number of nodes
-        return torch.matmul(a, b)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        assert not torch.isnan(grad_output).any()
-
-        # grad_output : Nxd  gradient
-        # a : NxN adj(attention) matrix, b: Nxd node feature
-        a, b = ctx.saved_tensors
-        grad_values = grad_b = None
-        if ctx.needs_input_grad[1]:
-            grad_a_dense = grad_output.matmul(b.t())
-            edge_idx = a._indices()[0, :] * ctx.N + a._indices()[1, :] # flattening (x,y) --> nx + y
-            grad_values = grad_a_dense.view(-1)[edge_idx]
-        if ctx.needs_input_grad[3]:
-            grad_b = a.t().matmul(grad_output)
-        return None, grad_values, None, grad_b
-
-
-class SpecialSpmm(nn.Module):
-    def forward(self, indices, values, shape, b):
-        return SpecialSpmmFunction.apply(indices, values, shape, b)
-
-def get_att_logit(att_logit, att_type):
-    if att_logit:
-        att_logit = getattr(torch, att_logit)
-    return att_logit
diff --git a/HGCAE/layers/hyp_layers.py b/HGCAE/layers/hyp_layers.py
deleted file mode 100644
index c19b241..0000000
--- a/HGCAE/layers/hyp_layers.py
+++ /dev/null
@@ -1,232 +0,0 @@
-"""
-Hyperbolic layers.
-Major codes of hyperbolic layers are from HGCN
-"""
-import math
-
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-import torch.nn.init as init
-from torch.nn.modules.module import Module
-from torch.nn.parameter import Parameter
-
-from Ghypeddings.HGCAE.layers.att_layers import HypAggAtt, SpecialSpmm
-
-
-def get_dim_act_curv(args):
-    """
-    Helper function to get dimension and activation at every layer.
-    :param args:
-    :return:
-    """
-    if not args.act:
-        act = lambda x: x
-    else:
-        act = getattr(F, args.act)
-    acts = [act] * (args.num_layers - 1)
-
-    dims = [args.feat_dim]
-    # Check layer_num and hdden_dim match
-    if args.num_layers > 1:
-        hidden_dim = [args.hidden_dim for _ in range(args.num_layers -1)]
-        if args.num_layers != len(hidden_dim) + 1:
-            raise RuntimeError('Check dimension hidden:{}, num_layers:{}'.format(args.hidden_dim, args.num_layers) )
-        dims = dims + hidden_dim
-
-    dims += [args.dim]
-    acts += [act]
-    n_curvatures = args.num_layers
-    if args.c_trainable == 1: # NOTE : changed from # if args.c is None:
-        # create list of trainable curvature parameters
-        curvatures = [nn.Parameter(torch.Tensor([args.c]).to(args.device)) for _ in range(n_curvatures)]
-    else:
-        # fixed curvature
-        curvatures = [torch.tensor([args.c]) for _ in range(n_curvatures)]
-        if not args.cuda == -1:
-            curvatures = [curv.to(args.device) for curv in curvatures]
-    return dims, acts, curvatures
-
-
-
-class HNNLayer(nn.Module):
-    """
-    Hyperbolic neural networks layer.
-    """
-
-    def __init__(self, manifold, in_features, out_features, c_in, c_out, dropout, act, use_bias):
-        super(HNNLayer, self).__init__()
-        self.linear = HypLinear(manifold, in_features, out_features, c_in, dropout, use_bias)
-        self.hyp_act = HypAct(manifold, c_in, c_out, act)
-
-    def forward(self, x):
-        h = self.linear.forward(x)
-        h = self.hyp_act.forward(h)
-        return h
-
-
-class HyperbolicGraphConvolution(nn.Module):
-    """
-    Hyperbolic graph convolution layer.
-    """
-
-    def __init__(self, manifold, in_features, out_features, c_in, c_out, dropout, act, use_bias, use_att,
-            att_type='sparse_adjmask_dist', att_logit=torch.exp, beta=0., decode=False):
-        super(HyperbolicGraphConvolution, self).__init__()
-        self.linear = HypLinear(manifold, in_features, out_features, c_in, dropout, use_bias)
-        self.agg = HypAgg(manifold, c_in, use_att, out_features, dropout, att_type=att_type, att_logit=att_logit, beta=beta, decode=decode)
-        self.hyp_act = HypAct(manifold, c_in, c_out, act)
-        self.decode = decode
-
-    def forward(self, input):
-        x, adj = input
-        assert not torch.isnan(self.hyp_act.c_in).any()
-        self.hyp_act.c_in.data = torch.clamp_min(self.hyp_act.c_in,1e-12)
-        if self.hyp_act.c_out:
-            assert not torch.isnan(self.hyp_act.c_out).any()
-            self.hyp_act.c_out.data = torch.clamp_min(self.hyp_act.c_out,1e-12)
-        assert not torch.isnan(x).any()
-        h = self.linear.forward(x)
-        assert not torch.isnan(h).any()
-        h = self.agg.forward(h, adj, prev_x=x)
-        assert not torch.isnan(h).any()
-        h = self.hyp_act.forward(h)
-        assert not torch.isnan(h).any()
-        output = h, adj
-        return output
-
-
-class HypLinear(nn.Module):
-    """
-    Hyperbolic linear layer.
-    """
-
-    def __init__(self, manifold, in_features, out_features, c, dropout, use_bias):
-        super(HypLinear, self).__init__()
-        self.manifold = manifold
-        self.in_features = in_features
-        self.out_features = out_features
-        self.c = c
-        self.dropout = dropout
-        self.use_bias = use_bias
-        # self.bias = nn.Parameter(torch.Tensor(out_features))
-        self.bias = nn.Parameter(torch.Tensor(1, out_features))
-        self.weight = nn.Parameter(torch.Tensor(out_features, in_features))
-        self.reset_parameters()
-
-    def reset_parameters(self):
-        init.xavier_uniform_(self.weight, gain=math.sqrt(2))
-        init.constant_(self.bias, 0)
-
-    def forward(self, x):
-        drop_weight = F.dropout(self.weight, self.dropout, training=self.training)
-        mv = self.manifold.mobius_matvec(drop_weight, x, self.c)
-        res = self.manifold.proj(mv, self.c)
-        if self.use_bias: 
-            bias = self.bias
-            hyp_bias = self.manifold.expmap0(bias, self.c)
-            hyp_bias = self.manifold.proj(hyp_bias, self.c)
-            res = self.manifold.mobius_add(res, hyp_bias, c=self.c)
-            res = self.manifold.proj(res, self.c)
-        return res
-
-    def extra_repr(self):
-        return 'in_features={}, out_features={}, c={}'.format(
-                self.in_features, self.out_features, self.c
-        )
-
-
-class HypAgg(Module):
-    """
-    Hyperbolic aggregation layer.
-    """
-
-    def __init__(self, manifold, c, use_att, in_features, dropout, att_type='sparse_adjmask_dist', att_logit=None, beta=0, decode=False):
-        super(HypAgg, self).__init__()
-        self.manifold = manifold
-        self.c = c
-        self.use_att = use_att
-
-        self.in_features = in_features
-        self.dropout = dropout
-        if use_att:
-            self.att = HypAggAtt(in_features, manifold, dropout, act=None, att_type=att_type, att_logit=att_logit, beta=beta)
-            self.att_type = att_type
-
-            self.special_spmm = SpecialSpmm()
-        self.decode = decode
-
-    def forward(self, x, adj, prev_x=None):
-
-        if self.use_att:
-            dist = 'dist' in self.att_type
-            if dist:
-                if 'sparse' in self.att_type:
-                    if self.decode:
-                        # NOTE : AGG(prev_x)
-                        edge_e, e_rowsum = self.att(prev_x, adj, self.c) # SparseAtt
-                    else:
-                        # NOTE : AGG(x)
-                        edge_e, e_rowsum = self.att(x, adj, self.c) # SparseAtt
-                    self.edge_e = edge_e
-                    self.e_rowsum = e_rowsum
-                    ## SparseAtt
-                    x_tangent = self.manifold.logmap0(x, c=self.c)
-                    N = x.size()[0]
-                    edge = adj._indices()
-                    support_t = self.special_spmm(edge, edge_e, torch.Size([N, N]), x_tangent) 
-                    assert not torch.isnan(support_t).any()
-                    support_t = support_t.div(e_rowsum)
-                    assert not torch.isnan(support_t).any()
-                    output = self.manifold.proj(self.manifold.expmap0(support_t, c=self.c), c=self.c)
-                else:
-                    adj = self.att(x, adj, self.c) # DenseAtt
-                    x_tangent = self.manifold.logmap0(x, c=self.c)
-                    support_t = torch.spmm(adj, x_tangent)
-                    output = self.manifold.proj(self.manifold.expmap0(support_t, c=self.c), c=self.c)
-            else:
-                ## MLP attention
-                x_tangent = self.manifold.logmap0(x, c=self.c)
-                adj = self.att(x_tangent, adj)
-                support_t = torch.spmm(adj, x_tangent)
-                output = self.manifold.proj(self.manifold.expmap0(support_t, c=self.c), c=self.c)
-        else:
-            x_tangent = self.manifold.logmap0(x, c=self.c)
-            support_t = torch.spmm(adj, x_tangent)
-            output = self.manifold.proj(self.manifold.expmap0(support_t, c=self.c), c=self.c)
-
-        return output
-
-    def extra_repr(self):
-        return 'c={}, use_att={}, decode={}'.format(
-                self.c, self.use_att, self.decode
-        )
-
-
-class HypAct(Module):
-    """
-    Hyperbolic activation layer.
-    """
-
-    def __init__(self, manifold, c_in, c_out, act):
-        super(HypAct, self).__init__()
-        self.manifold = manifold
-        self.c_in = c_in
-        self.c_out = c_out
-        self.act = act
-
-    def forward(self, x):
-        if self.manifold.name == 'PoincareBall':
-            if self.c_out:
-                xt = self.manifold.activation(x, self.act, self.c_in, self.c_out)
-                return xt
-            else:
-                xt = self.manifold.logmap0(x, c=self.c_in)
-                return xt
-        else:
-            NotImplementedError("not implemented")
-
-    def extra_repr(self):
-        return 'Manifold={},\n c_in={},\n act={},\n c_out={}'.format(
-                self.manifold.name, self.c_in, self.act.__name__, self.c_out
-        )
diff --git a/HGCAE/layers/layers.py b/HGCAE/layers/layers.py
deleted file mode 100644
index d17b37d..0000000
--- a/HGCAE/layers/layers.py
+++ /dev/null
@@ -1,68 +0,0 @@
-"""Euclidean layers."""
-import math
-
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-from torch.nn.modules.module import Module
-from torch.nn.parameter import Parameter
-
-
-def get_dim_act(args):
-    """
-    Helper function to get dimension and activation at every layer.
-    :param args:
-    :return:
-    """
-    if not args.act:
-        act = lambda x: x
-    else:
-        act = getattr(F, args.act)
-    acts = [act] * (args.num_layers - 1)
-
-    dims = [args.feat_dim]
-    if args.num_layers > 1:
-        # Check layer_num and hdden_dim match
-        hidden_dim = [int(h) for h in args.hidden_dim.split(',')]
-        if args.num_layers != len(hidden_dim) + 1:
-            raise RuntimeError('Check dimension hidden:{}, num_laysers:{}'.format(args.hidden_dim, args.num_layers) )
-        dims = dims + hidden_dim
-
-    dims += [args.dim]
-    acts += [act]
-    return dims, acts
-
-
-class Linear(Module):
-    """
-    Simple Linear layer with dropout.
-    """
-
-    def __init__(self, in_features, out_features, dropout, act, use_bias):
-        super(Linear, self).__init__()
-        self.dropout = dropout
-        self.linear = nn.Linear(in_features, out_features, use_bias)
-        self.act = act
-
-    def forward(self, x):
-        hidden = self.linear.forward(x)
-        hidden = F.dropout(hidden, self.dropout, training=self.training)
-        out = self.act(hidden)
-        return out
-
-'''
-InnerProductDecdoer implemntation from:
-https://github.com/zfjsail/gae-pytorch/blob/master/gae/model.py
-'''
-class InnerProductDecoder(nn.Module):
-    """Decoder for using inner product for prediction."""
-
-    def __init__(self, dropout=0, act=torch.sigmoid):
-        super(InnerProductDecoder, self).__init__()
-        self.dropout = dropout
-        self.act = act
-
-    def forward(self, emb_in, emb_out):
-        cos_dist = emb_in * emb_out
-        probs = self.act(cos_dist.sum(1))
-        return probs
diff --git a/HGCAE/manifolds/__init__.py b/HGCAE/manifolds/__init__.py
deleted file mode 100644
index ed1d717..0000000
--- a/HGCAE/manifolds/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-'''
-Major codes of hyperbolic layers are from HGCN
-Refer Lorentz implementation from HGCN if you need.
-'''
-from Ghypeddings.HGCAE.manifolds.base import ManifoldParameter
-from Ghypeddings.HGCAE.manifolds.euclidean import Euclidean
-from Ghypeddings.HGCAE.manifolds.poincare import PoincareBall
diff --git a/HGCAE/manifolds/base.py b/HGCAE/manifolds/base.py
deleted file mode 100644
index 805edd6..0000000
--- a/HGCAE/manifolds/base.py
+++ /dev/null
@@ -1,84 +0,0 @@
-'''
-Major codes of hyperbolic layers are from HGCN
-'''
-from torch.nn import Parameter
-
-class Manifold(object):
-    """
-    Abstract class to define operations on a manifold.
-    """
-
-    def __init__(self):
-        super().__init__()
-        self.eps = 10e-8
-
-    def sqdist(self, p1, p2, c):
-        """Squared distance between pairs of points."""
-        raise NotImplementedError
-
-    def egrad2rgrad(self, p, dp, c):
-        """Converts Euclidean Gradient to Riemannian Gradients."""
-        raise NotImplementedError
-
-    def proj(self, p, c):
-        """Projects point p on the manifold."""
-        raise NotImplementedError
-
-    def proj_tan(self, u, p, c):
-        """Projects u on the tangent space of p."""
-        raise NotImplementedError
-
-    def proj_tan0(self, u, c):
-        """Projects u on the tangent space of the origin."""
-        raise NotImplementedError
-
-    def expmap(self, u, p, c):
-        """Exponential map of u at point p."""
-        raise NotImplementedError
-
-    def logmap(self, p1, p2, c):
-        """Logarithmic map of point p1 at point p2."""
-        raise NotImplementedError
-
-    def expmap0(self, u, c):
-        """Exponential map of u at the origin."""
-        raise NotImplementedError
-
-    def logmap0(self, p, c):
-        """Logarithmic map of point p at the origin."""
-        raise NotImplementedError
-
-    def mobius_add(self, x, y, c, dim=-1):
-        """Adds points x and y."""
-        raise NotImplementedError
-
-    def mobius_matvec(self, m, x, c):
-        """Performs hyperboic martrix-vector multiplication."""
-        raise NotImplementedError
-
-    def init_weights(self, w, c, irange=1e-5):
-        """Initializes random weigths on the manifold."""
-        raise NotImplementedError
-
-    def inner(self, p, c, u, v=None):
-        """Inner product for tangent vectors at point x."""
-        raise NotImplementedError
-
-    def ptransp(self, x, y, u, c):
-        """Parallel transport of u from x to y."""
-        raise NotImplementedError
-
-
-class ManifoldParameter(Parameter):
-    """
-    Subclass of torch.nn.Parameter for Riemannian optimization.
-    """
-    def __new__(cls, data, requires_grad, manifold, c):
-        return Parameter.__new__(cls, data, requires_grad)
-
-    def __init__(self, data, requires_grad, manifold, c):
-        self.c = c
-        self.manifold = manifold
-
-    def __repr__(self):
-        return '{} Parameter containing:\n'.format(self.manifold.name) + super(Parameter, self).__repr__()
diff --git a/HGCAE/manifolds/euclidean.py b/HGCAE/manifolds/euclidean.py
deleted file mode 100644
index c102023..0000000
--- a/HGCAE/manifolds/euclidean.py
+++ /dev/null
@@ -1,66 +0,0 @@
-'''
-Major codes of hyperbolic layers are from HGCN
-'''
-import torch
-from Ghypeddings.HGCAE.manifolds.base import Manifold
-
-
-class Euclidean(Manifold):
-    """
-    Euclidean Manifold class.
-    """
-
-    def __init__(self):
-        super(Euclidean, self).__init__()
-        self.name = 'Euclidean'
-
-    def normalize(self, p):
-        dim = p.size(-1)
-        p_norm = torch.renorm(p, 2, 0, 1.)
-        return p_norm
-
-    def sqdist(self, p1, p2, c):
-        return (p1 - p2).pow(2).sum(dim=-1)
-
-    def egrad2rgrad(self, p, dp, c):
-        return dp
-
-    def proj(self, p, c):
-        return p
-
-    def proj_tan(self, u, p, c):
-        return u
-
-    def proj_tan0(self, u, c):
-        return u
-
-    def expmap(self, u, p, c):
-        return p + u
-
-    def logmap(self, p1, p2, c):
-        return p2 - p1
-
-    def expmap0(self, u, c):
-        return u
-
-    def logmap0(self, p, c):
-        return p
-
-    def mobius_add(self, x, y, c, dim=-1):
-        return x + y
-
-    def mobius_matvec(self, m, x, c):
-        mx = x @ m.transpose(-1, -2)
-        return mx
-
-    def init_weights(self, w, c, irange=1e-5):
-        w.data.uniform_(-irange, irange)
-        return w
-
-    def inner(self, p, c, u, v=None, keepdim=False):
-        if v is None:
-            v = u
-        return (u * v).sum(dim=-1, keepdim=keepdim)
-
-    def ptransp(self, x, y, v, c):
-        return v
diff --git a/HGCAE/manifolds/poincare.py b/HGCAE/manifolds/poincare.py
deleted file mode 100644
index df06e38..0000000
--- a/HGCAE/manifolds/poincare.py
+++ /dev/null
@@ -1,136 +0,0 @@
-'''
-Major codes of hyperbolic layers are from HGCN
-'''
-import torch
-from Ghypeddings.HGCAE.manifolds.base import Manifold
-from torch.autograd import Function
-from Ghypeddings.HGCAE.utils.math_utils import artanh, tanh
-
-
-class PoincareBall(Manifold):
-    """
-    PoicareBall Manifold class.
-
-    We use the following convention: x0^2 + x1^2 + ... + xd^2 < 1 / c
-
-    Note that 1/sqrt(c) is the Poincare ball radius.
-
-    """
-
-    def __init__(self, ):
-        super(PoincareBall, self).__init__()
-        self.name = 'PoincareBall'
-        self.min_norm = 1e-15
-        self.eps = {torch.float32: 4e-3, torch.float64: 1e-5}
-
-    def sqdist(self, p1, p2, c):
-        sqrt_c = c ** 0.5
-        dist_c = artanh(
-            sqrt_c * self.mobius_add(-p1, p2, c, dim=-1).norm(dim=-1, p=2, keepdim=False)
-        )
-        dist = dist_c * 2 / sqrt_c
-        return dist ** 2
-
-    def _lambda_x(self, x, c):
-        x_sqnorm = torch.sum(x.data.pow(2), dim=-1, keepdim=True)
-        return 2 / (1. - c * x_sqnorm).clamp_min(self.min_norm)
-
-    def egrad2rgrad(self, p, dp, c):
-        lambda_p = self._lambda_x(p, c)
-        dp /= lambda_p.pow(2)
-        return dp
-
-    def proj(self, x, c):
-        norm = torch.clamp_min(x.norm(dim=-1, keepdim=True, p=2), self.min_norm)
-        maxnorm = (1 - self.eps[x.dtype]) / (c ** 0.5)
-        cond = norm > maxnorm
-        projected = x / norm * maxnorm
-        return torch.where(cond, projected, x)
-
-    def proj_tan(self, u, p, c):
-        return u
-
-    def proj_tan0(self, u, c):
-        return u
-
-    def expmap(self, u, p, c):
-        sqrt_c = c ** 0.5
-        u_norm = u.norm(dim=-1, p=2, keepdim=True).clamp_min(self.min_norm)
-        second_term = (
-                tanh(sqrt_c / 2 * self._lambda_x(p, c) * u_norm)
-                * u
-                / (sqrt_c * u_norm)
-        )
-        gamma_1 = self.mobius_add(p, second_term, c)
-        return gamma_1
-
-    def logmap(self, p1, p2, c):
-        sub = self.mobius_add(-p1, p2, c)
-        sub_norm = sub.norm(dim=-1, p=2, keepdim=True).clamp_min(self.min_norm)
-        lam = self._lambda_x(p1, c)
-        sqrt_c = c ** 0.5
-        return 2 / sqrt_c / lam * artanh(sqrt_c * sub_norm) * sub / sub_norm
-
-    def expmap0(self, u, c):
-        sqrt_c = c ** 0.5
-        u_norm = torch.clamp_min(u.norm(dim=-1, p=2, keepdim=True), self.min_norm)
-        gamma_1 = tanh(sqrt_c * u_norm) * u / (sqrt_c * u_norm)
-        return gamma_1
-
-    def logmap0(self, p, c):
-        sqrt_c = c ** 0.5
-        p_norm = p.norm(dim=-1, p=2, keepdim=True).clamp_min(self.min_norm)
-        scale = 1. / sqrt_c * artanh(sqrt_c * p_norm) / p_norm
-        return scale * p
-
-    def mobius_add(self, x, y, c, dim=-1):
-        x2 = x.pow(2).sum(dim=dim, keepdim=True)
-        y2 = y.pow(2).sum(dim=dim, keepdim=True)
-        xy = (x * y).sum(dim=dim, keepdim=True)
-        num = (1 + 2 * c * xy + c * y2) * x + (1 - c * x2) * y
-        denom = 1 + 2 * c * xy + c ** 2 * x2 * y2
-        return num / denom.clamp_min(self.min_norm)
-
-    def mobius_matvec(self, m, x, c):
-        sqrt_c = c ** 0.5
-        x_norm = x.norm(dim=-1, keepdim=True, p=2).clamp_min(self.min_norm)
-        mx = x @ m.transpose(-1, -2)
-        mx_norm = mx.norm(dim=-1, keepdim=True, p=2).clamp_min(self.min_norm)
-        res_c = tanh(mx_norm / x_norm * artanh(sqrt_c * x_norm)) * mx / (mx_norm * sqrt_c)
-        cond = (mx == 0).prod(-1, keepdim=True, dtype=torch.uint8)
-        res_0 = torch.zeros(1, dtype=res_c.dtype, device=res_c.device)
-        res = torch.where(cond, res_0, res_c)
-        return res
-
-    def init_weights(self, w, c, irange=1e-5):
-        w.data.uniform_(-irange, irange)
-        return w
-
-    def _gyration(self, u, v, w, c, dim: int = -1):
-        u2 = u.pow(2).sum(dim=dim, keepdim=True)
-        v2 = v.pow(2).sum(dim=dim, keepdim=True)
-        uv = (u * v).sum(dim=dim, keepdim=True)
-        uw = (u * w).sum(dim=dim, keepdim=True)
-        vw = (v * w).sum(dim=dim, keepdim=True)
-        c2 = c ** 2
-        a = -c2 * uw * v2 + c * vw + 2 * c2 * uv * vw
-        b = -c2 * vw * u2 - c * uw
-        d = 1 + 2 * c * uv + c2 * u2 * v2
-        return w + 2 * (a * u + b * v) / d.clamp_min(self.min_norm)
-
-    def inner(self, x, c, u, v=None, keepdim=False, dim=-1):
-        if v is None:
-            v = u
-        lambda_x = self._lambda_x(x, c)
-        return lambda_x ** 2 * (u * v).sum(dim=dim, keepdim=keepdim)
-
-    def ptransp(self, x, y, u, c):
-        lambda_x = self._lambda_x(x, c)
-        lambda_y = self._lambda_x(y, c)
-        return self._gyration(y, -x, u, c) * lambda_x / lambda_y
-
-    def activation(self, x, act, c_in, c_out):
-        x_act = act(x)
-        x_prev = self.logmap0(x_act, c_in)
-        x_next = self.expmap0(x_prev, c_out)
-        return x_next
diff --git a/HGCAE/models/__init__.py b/HGCAE/models/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/HGCAE/models/base_models.py b/HGCAE/models/base_models.py
deleted file mode 100644
index 7d10fd9..0000000
--- a/HGCAE/models/base_models.py
+++ /dev/null
@@ -1,200 +0,0 @@
-import Ghypeddings.HGCAE.models.encoders as encoders
-import torch
-import numpy as np
-import torch.nn as nn
-import torch.nn.functional as F
-from Ghypeddings.HGCAE.models.decoders import model2decoder
-from Ghypeddings.HGCAE.layers.layers import  InnerProductDecoder
-from sklearn.metrics import roc_auc_score, average_precision_score
-from Ghypeddings.HGCAE.utils.eval_utils import acc_f1
-from sklearn import cluster
-from sklearn.metrics import accuracy_score, normalized_mutual_info_score, adjusted_rand_score
-import Ghypeddings.HGCAE.manifolds as manifolds
-import Ghypeddings.HGCAE.models.encoders as encoders
-
-class BaseModel(nn.Module):
-    """
-    Base model for graph embedding tasks.
-    """
-
-    def __init__(self, args):
-        super(BaseModel, self).__init__()
-        self.manifold_name = "PoincareBall"
-        if args.c is not None:
-            self.c = torch.tensor([args.c])
-            if not args.cuda == -1:
-                self.c = self.c.to(args.device)
-        else:
-            self.c = nn.Parameter(torch.Tensor([1.]))
-        self.manifold = getattr(manifolds, self.manifold_name)()
-        self.nnodes = args.n_nodes
-        self.n_classes = args.n_classes
-        self.encoder = getattr(encoders, "HGCAE")(self.c, args)
-        self.num_layers=args.num_layers
-
-        # Embedding c
-        self.hyperbolic_embedding = True if args.use_att else False
-        self.decoder_type = 'InnerProductDecoder'
-        self.dc = InnerProductDecoder(dropout=0, act=torch.sigmoid)
-
-
-    def encode(self, x, adj):
-        h = self.encoder.encode(x, adj)
-        return h
-
-    def pred_link_score(self, h, idx):  # for LP,REC 
-        emb_in = h[idx[:, 0], :]
-        emb_out = h[idx[:, 1], :]
-        probs = self.dc.forward(emb_in, emb_out)
-
-        return probs
-
-    def decode(self, h, adj, idx): # REC
-        output = self.decoder.decode(h, adj)
-        return output
-
-
-    def eval_cluster(self, embeddings, data, split):
-        if self.hyperbolic_embedding:
-            emb_c = self.encoder.layers[-1].hyp_act.c_out
-            embeddings = self.manifold.logmap0(embeddings.to(emb_c.device), c=emb_c).cpu()
-
-        idx = data[f'idx_{split}']
-        n_classes = self.n_classes
-
-        embeddings_to_cluster = embeddings[idx].detach().cpu().numpy()
-        # gt_label = data['labels'][idx].cpu().numpy()
-        gt_label = data['labels']
-
-        kmeans = cluster.KMeans(n_clusters=n_classes, algorithm='auto')
-        kmeans.fit(embeddings_to_cluster)
-        pred_label = kmeans.fit_predict(embeddings_to_cluster)
-
-        from munkres import Munkres
-        def best_map(L1,L2):
-            #L1 should be the groundtruth labels and L2 should be the clustering labels we got
-            Label1 = np.unique(L1)
-            nClass1 = len(Label1)
-            Label2 = np.unique(L2)
-            nClass2 = len(Label2)
-            nClass = np.maximum(nClass1,nClass2)
-            G = np.zeros((nClass,nClass))
-            for i in range(nClass1):
-                ind_cla1 = L1 == Label1[i]
-                ind_cla1 = ind_cla1.astype(float)
-                for j in range(nClass2):
-                    ind_cla2 = L2 == Label2[j]
-                    ind_cla2 = ind_cla2.astype(float)
-                    G[i,j] = np.sum(ind_cla2 * ind_cla1)
-            m = Munkres()
-            index = m.compute(-G.T)
-            index = np.array(index)
-            c = index[:,1]
-            newL2 = np.zeros(L2.shape)
-            for i in range(nClass2):
-                newL2[L2 == Label2[i]] = Label1[c[i]]
-            return newL2
-
-
-        def err_rate(gt_s, s):
-            c_x = best_map(gt_s, s)
-            err_x = np.sum(gt_s[:] !=c_x[:])
-            missrate = err_x.astype(float) / (gt_s.shape[0])
-            return missrate
-
-
-        acc = 1-err_rate(gt_label, pred_label)
-        # acc = accuracy_score(gt_label, pred_label)
-        nmi = normalized_mutual_info_score(gt_label, pred_label, average_method='arithmetic')
-        ari = adjusted_rand_score(gt_label, pred_label)
-    
-        metrics = { 'cluster_acc': acc, 'nmi': nmi, 'ari': ari}
-        return metrics, pred_label
-
-
-    def compute_metrics(self, embeddings, data, split, epoch=None):
-        raise NotImplementedError
-
-    def init_metric_dict(self):
-        raise NotImplementedError
-
-    def has_improved(self, m1, m2):
-        raise NotImplementedError
-
-class LPModel(BaseModel):
-    """
-    Base model for link prediction task.
-    """
-
-    def __init__(self, args):
-        super(LPModel, self).__init__(args)
-        self.nb_false_edges = args.nb_false_edges
-        self.positive_edge_samplig = True
-        if self.positive_edge_samplig:
-            self.nb_edges = min(args.nb_edges, 5000) # NOTE : be-aware too dense edges
-        else:
-            self.nb_edges = args.nb_edges
-
-        if args.lambda_rec > 0:
-            self.num_dec_layers = args.num_dec_layers
-            self.lambda_rec = args.lambda_rec
-            c = self.encoder.curvatures if hasattr(self.encoder, 'curvatures') else args.c ### handle HNN
-            self.decoder = model2decoder(c, args, 'rec')
-        else:
-            self.lambda_rec = 0
-            
-        if args.lambda_lp > 0:
-            self.lambda_lp = args.lambda_lp
-        else:
-            self.lambda_lp = 0
-
-    def compute_metrics(self, embeddings, data, split, epoch=None):
-        if split == 'train':
-            num_true_edges = data[f'{split}_edges'].shape[0]
-            if self.positive_edge_samplig and num_true_edges > self.nb_edges:
-                edges_true = data[f'{split}_edges'][np.random.randint(0, num_true_edges, self.nb_edges)]
-            else:
-                edges_true = data[f'{split}_edges']
-            edges_false = data[f'{split}_edges_false'][np.random.randint(0, self.nb_false_edges, self.nb_edges)]
-        else:
-            edges_true = data[f'{split}_edges']
-            edges_false = data[f'{split}_edges_false']
-
-        pos_scores = self.pred_link_score(embeddings, edges_true)
-        neg_scores = self.pred_link_score(embeddings, edges_false)
-        assert not torch.isnan(pos_scores).any()
-        assert not torch.isnan(neg_scores).any()
-        loss = F.binary_cross_entropy(pos_scores, torch.ones_like(pos_scores))
-        loss += F.binary_cross_entropy(neg_scores, torch.zeros_like(neg_scores))
-        if pos_scores.is_cuda:
-            pos_scores = pos_scores.cpu()
-            neg_scores = neg_scores.cpu()
-        labels = [1] * pos_scores.shape[0] + [0] * neg_scores.shape[0]
-        preds = list(pos_scores.data.numpy()) + list(neg_scores.data.numpy())
-        roc = roc_auc_score(labels, preds)
-        ap = average_precision_score(labels, preds)
-        metrics = {'loss': loss, 'roc': roc, 'ap': ap}
-
-        assert not torch.isnan(loss).any()
-        if self.lambda_rec:
-            idx = data['idx_all']
-            recon = self.decode(embeddings, data['adj_train_dec'], idx) ## NOTE : adj
-            assert not torch.isnan(recon).any()
-            if self.num_dec_layers == self.num_layers:
-                target = data['features'][idx]
-            elif self.num_dec_layers == self.num_layers - 1: 
-                target = self.encoder.features[0].detach()[idx]
-            else:
-                raise RuntimeError('num_dec_layers only support 1,2')
-            loss_rec = self.lambda_rec * torch.nn.functional.mse_loss(recon[idx], target , reduction='mean')
-            assert not torch.isnan(loss_rec).any()
-            loss_lp = loss * self.lambda_lp
-            metrics.update({'loss': loss_lp + loss_rec, 'loss_rec': loss_rec, 'loss_lp': loss_lp})
-
-        return metrics
-
-    def init_metric_dict(self):
-        return {'roc': -1, 'ap': -1}
-
-    def has_improved(self, m1, m2):
-        return 0.5 * (m1['roc'] + m1['ap']) < 0.5 * (m2['roc'] + m2['ap'])
diff --git a/HGCAE/models/decoders.py b/HGCAE/models/decoders.py
deleted file mode 100644
index 72c4694..0000000
--- a/HGCAE/models/decoders.py
+++ /dev/null
@@ -1,106 +0,0 @@
-"""Graph decoders."""
-import Ghypeddings.HGCAE.manifolds as manifolds
-import torch.nn as nn
-import torch.nn.functional as F
-
-
-import torch
-
-
-class Decoder(nn.Module):
-    """
-    Decoder abstract class
-    """
-
-    def __init__(self, c):
-        super(Decoder, self).__init__()
-        self.c = c
-
-    def classify(self, x, adj):
-        '''
-        output
-        - nc : probs 
-        - rec : input_feat
-        '''
-        if self.decode_adj:
-            input = (x, adj)
-            output, _ = self.classifier.forward(input)
-        else:
-            output = self.classifier.forward(x)
-        return output
-
-
-    def decode(self, x, adj):
-        '''
-        output
-        - nc : probs 
-        - rec : input_feat
-        '''
-        if self.decode_adj:
-            input = (x, adj)
-            output, _ = self.decoder.forward(input)
-        else:
-            output = self.decoder.forward(x)
-        return output
-
-
-
-import Ghypeddings.HGCAE.layers.hyp_layers as hyp_layers
-class HGCAEDecoder(Decoder):
-    """
-    Decoder for HGCAE
-    """
-
-    def __init__(self, c, args, task):
-        super(HGCAEDecoder, self).__init__(c)
-        self.manifold = getattr(manifolds, 'PoincareBall')()
-    
-        assert args.num_layers > 0
-
-        dims, acts, _ = hyp_layers.get_dim_act_curv(args)
-        dims = dims[::-1]
-        acts = acts[::-1][:-1] + [lambda x: x] # Last layer without act
-        self.curvatures = self.c[::-1]
-
-        encdec_share_curvature = False
-        if not encdec_share_curvature and args.num_layers == args.num_dec_layers: # do not share and enc-dec mirror-shape
-            num_c = len(self.curvatures)
-            self.curvatures = self.curvatures[:1] 
-            if args.c_trainable == 1:
-                self.curvatures += [nn.Parameter(torch.Tensor([args.c]).to(args.device))] * (num_c - 1)
-            else:
-                self.curvatures += [torch.tensor([args.c])] * (num_c - 1)
-                if not args.cuda == -1:
-                    self.curvatures = [curv.to(args.device) for curv in self.curvatures]
-
-
-        self.curvatures = self.curvatures[:-1] + [None]
-
-
-        hgc_layers = []
-        num_dec_layers = args.num_dec_layers
-        for i in range(num_dec_layers):
-            c_in, c_out = self.curvatures[i], self.curvatures[i + 1]
-            in_dim, out_dim = dims[i], dims[i + 1]
-            act = acts[i]
-            hgc_layers.append(
-                hyp_layers.HyperbolicGraphConvolution(
-                        self.manifold, in_dim, out_dim, c_in, c_out, args.dropout, act, args.bias, args.use_att,
-                        att_type=args.att_type, att_logit=args.att_logit, beta=args.beta, decode=True
-                )
-            )
-
-        self.decoder = nn.Sequential(*hgc_layers)
-        self.decode_adj = True
-
-    # NOTE : self.c is fixed, not trainable
-    def classify(self, x, adj):
-        h = self.manifold.logmap0(x, c=self.c)
-        return super(HGCAEDecoder, self).classify(h, adj)
-    
-    def decode(self, x, adj):
-        output = super(HGCAEDecoder, self).decode(x, adj)
-        return output
-
-model2decoder = HGCAEDecoder
-
diff --git a/HGCAE/models/encoders.py b/HGCAE/models/encoders.py
deleted file mode 100644
index e4b0a74..0000000
--- a/HGCAE/models/encoders.py
+++ /dev/null
@@ -1,65 +0,0 @@
-"""Graph encoders."""
-import Ghypeddings.HGCAE.manifolds as manifolds
-import Ghypeddings.HGCAE.layers.hyp_layers as hyp_layers
-import torch
-import torch.nn as nn
-
-
-class Encoder(nn.Module):
-    """
-    Encoder abstract class.
-    """
-
-    def __init__(self, c, use_cnn=None):
-        super(Encoder, self).__init__()
-        self.c = c
-
-    def encode(self, x, adj):
-        self.features = []
-        if self.encode_graph:
-            input = (x, adj)
-            xx = input
-            for i in range(len(self.layers)):
-                out = self.layers[i].forward(xx)
-                self.features.append(out[0])
-                xx = out
-            output , _ = xx
-        else:
-            output = self.layers.forward(x)
-        return output
-
-class HGCAE(Encoder):
-    """
-    Hyperbolic Graph Convolutional Auto-Encoders.
-    """
-
-    def __init__(self, c, args): #, use_cnn
-        super(HGCAE, self).__init__(c, use_cnn=True)
-        self.manifold = getattr(manifolds, "PoincareBall")()
-        assert args.num_layers > 0 
-        dims, acts, self.curvatures = hyp_layers.get_dim_act_curv(args)
-        if args.c_trainable == 1: 
-            self.curvatures.append(nn.Parameter(torch.Tensor([args.c]).to(args.device)))
-        else:
-            self.curvatures.append(torch.tensor([args.c]).to(args.device)) 
-        hgc_layers = []
-        for i in range(len(dims) - 1):
-            c_in, c_out = self.curvatures[i], self.curvatures[i + 1]
-            in_dim, out_dim = dims[i], dims[i + 1]
-            act = acts[i]
-
-            hgc_layers.append(
-                    hyp_layers.HyperbolicGraphConvolution(
-                            self.manifold, in_dim, out_dim, c_in, c_out, args.dropout, act, args.bias, args.use_att,
-                            att_type=args.att_type, att_logit=args.att_logit, beta=args.beta
-                    )
-            )
-        self.layers = nn.Sequential(*hgc_layers)
-        self.encode_graph = True
-
-    def encode(self, x, adj):
-        self.curvatures[0] = torch.clamp_min(self.curvatures[0],min=1e-12)
-        x_hyp = self.manifold.proj(
-                self.manifold.expmap0(self.manifold.proj_tan0(x, self.curvatures[0]), c=self.curvatures[0]),
-                c=self.curvatures[0])
-        return super(HGCAE, self).encode(x_hyp, adj)
diff --git a/HGCAE/optimizers/__init__.py b/HGCAE/optimizers/__init__.py
deleted file mode 100644
index a1198f3..0000000
--- a/HGCAE/optimizers/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from torch.optim import Adam
-from Ghypeddings.HGCAE.optimizers.radam import RiemannianAdam
diff --git a/HGCAE/optimizers/radam.py b/HGCAE/optimizers/radam.py
deleted file mode 100644
index b48cb6f..0000000
--- a/HGCAE/optimizers/radam.py
+++ /dev/null
@@ -1,175 +0,0 @@
-"""Riemannian adam optimizer geoopt implementation (https://github.com/geoopt/)."""
-import torch.optim
-from Ghypeddings.HGCAE.manifolds import Euclidean,ManifoldParameter
-
-_default_manifold = Euclidean()
-
-
-class OptimMixin(object):
-    def __init__(self, *args, stabilize=None, **kwargs):
-        self._stabilize = stabilize
-        super().__init__(*args, **kwargs)
-
-    def stabilize_group(self, group):
-        pass
-
-    def stabilize(self):
-        """Stabilize parameters if they are off-manifold due to numerical reasons
-        """
-        for group in self.param_groups:
-            self.stabilize_group(group)
-
-
-def copy_or_set_(dest, source):
-    """
-    A workaround to respect strides of :code:`dest` when copying :code:`source`
-    (https://github.com/geoopt/geoopt/issues/70)
-    Parameters
-    ----------
-    dest : torch.Tensor
-        Destination tensor where to store new data
-    source : torch.Tensor
-        Source data to put in the new tensor
-    Returns
-    -------
-    dest
-        torch.Tensor, modified inplace
-    """
-    if dest.stride() != source.stride():
-        return dest.copy_(source)
-    else:
-        return dest.set_(source)
-
-
-class RiemannianAdam(OptimMixin, torch.optim.Adam):
-    r"""Riemannian Adam with the same API as :class:`torch.optim.Adam`
-    Parameters
-    ----------
-    params : iterable
-        iterable of parameters to optimize or dicts defining
-        parameter groups
-    lr : float (optional)
-        learning rate (default: 1e-3)
-    betas : Tuple[float, float] (optional)
-        coefficients used for computing
-        running averages of gradient and its square (default: (0.9, 0.999))
-    eps : float (optional)
-        term added to the denominator to improve
-        numerical stability (default: 1e-8)
-    weight_decay : float (optional)
-        weight decay (L2 penalty) (default: 0)
-    amsgrad : bool (optional)
-        whether to use the AMSGrad variant of this
-        algorithm from the paper `On the Convergence of Adam and Beyond`_
-        (default: False)
-    Other Parameters
-    ----------------
-    stabilize : int
-        Stabilize parameters if they are off-manifold due to numerical
-        reasons every ``stabilize`` steps (default: ``None`` -- no stabilize)
-    .. _On the Convergence of Adam and Beyond:
-        https://openreview.net/forum?id=ryQu7f-RZ
-    """
-
-    def step(self, closure=None):
-        """Performs a single optimization step.
-        Arguments
-        ---------
-        closure : callable (optional)
-            A closure that reevaluates the model
-            and returns the loss.
-        """
-        loss = None
-        if closure is not None:
-            loss = closure()
-        with torch.no_grad():
-            for group in self.param_groups:
-                if "step" not in group:
-                    group["step"] = 0
-                betas = group["betas"]
-                weight_decay = group["weight_decay"]
-                eps = group["eps"]
-                learning_rate = group["lr"]
-                amsgrad = group["amsgrad"]
-                for point in group["params"]:
-                    grad = point.grad
-                    if grad is None:
-                        continue
-
-                    if isinstance(point, (ManifoldParameter)):
-                        manifold = point.manifold
-                        c = point.c
-                    else:
-                        manifold = _default_manifold
-                        c = None
-                    if grad.is_sparse:
-                        raise RuntimeError(
-                                "Riemannian Adam does not support sparse gradients yet (PR is welcome)"
-                        )
-
-                    state = self.state[point]
-
-                    # State initialization
-                    if len(state) == 0:
-                        state["step"] = 0
-                        # Exponential moving average of gradient values
-                        state["exp_avg"] = torch.zeros_like(point)
-                        # Exponential moving average of squared gradient values
-                        state["exp_avg_sq"] = torch.zeros_like(point)
-                        if amsgrad:
-                            # Maintains max of all exp. moving avg. of sq. grad. values
-                            state["max_exp_avg_sq"] = torch.zeros_like(point)
-                    # make local variables for easy access
-                    exp_avg = state["exp_avg"]
-                    exp_avg_sq = state["exp_avg_sq"]
-                    # actual step
-                    grad.add_(weight_decay, point)
-                    grad = manifold.egrad2rgrad(point, grad, c)
-
-                    exp_avg.mul_(betas[0]).add_(1 - betas[0], grad)
-                    exp_avg_sq.mul_(betas[1]).add_(
-                            1 - betas[1], manifold.inner(point, c, grad, keepdim=True)
-                    )
-                    if amsgrad:
-                        max_exp_avg_sq = state["max_exp_avg_sq"]
-                        # Maintains the maximum of all 2nd moment running avg. till now
-                        torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq)
-                        # Use the max. for normalizing running avg. of gradient
-                        denom = max_exp_avg_sq.sqrt().add_(eps)
-                    else:
-                        denom = exp_avg_sq.sqrt().add_(eps)
-                    group["step"] += 1
-                    bias_correction1 = 1 - betas[0] ** group["step"]
-                    bias_correction2 = 1 - betas[1] ** group["step"]
-                    step_size = (
-                        learning_rate * bias_correction2 ** 0.5 / bias_correction1
-                    )
-
-                    # copy the state, we need it for retraction
-                    # get the direction for ascend
-                    direction = exp_avg / denom
-                    # transport the exponential averaging to the new point
-                    new_point = manifold.proj(manifold.expmap(-step_size * direction, point, c), c)
-                    exp_avg_new = manifold.ptransp(point, new_point, exp_avg, c)
-                    # use copy only for user facing point
-                    copy_or_set_(point, new_point)
-                    exp_avg.set_(exp_avg_new)
-
-                    group["step"] += 1
-                if self._stabilize is not None and group["step"] % self._stabilize == 0:
-                    self.stabilize_group(group)
-        return loss
-
-    @torch.no_grad()
-    def stabilize_group(self, group):
-        for p in group["params"]:
-            if not isinstance(p, ManifoldParameter):
-                continue
-            state = self.state[p]
-            if not state:  # due to None grads
-                continue
-            manifold = p.manifold
-            c = p.c
-            exp_avg = state["exp_avg"]
-            copy_or_set_(p, manifold.proj(p, c))
-            exp_avg.set_(manifold.proj_tan(exp_avg, u, c))
diff --git a/HGCAE/utils/__init__.py b/HGCAE/utils/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/HGCAE/utils/data_utils.py b/HGCAE/utils/data_utils.py
deleted file mode 100644
index 8739c8a..0000000
--- a/HGCAE/utils/data_utils.py
+++ /dev/null
@@ -1,134 +0,0 @@
-"""Data utils functions for pre-processing and data loading."""
-import os
-import pickle as pkl
-import sys
-
-import networkx as nx
-import numpy as np
-import scipy.sparse as sp
-import torch
-
-from scipy import sparse
-import logging
-
-import pandas as pd
-
-def process_data(args, adj , features, labels):
-    ## Load data
-    data = {'adj_train': sp.csr_matrix(adj), 'features': features, 'labels': labels}
-    adj = data['adj_train']
-
-    ## TAKES a lot of time
-
-    adj_train, train_edges, train_edges_false, val_edges, val_edges_false, test_edges, test_edges_false = mask_edges(
-                adj, args.val_prop, args.test_prop, args.seed
-        )
-
-    ## TAKES a lot of time
-    data['adj_train'] = adj_train
-    data['train_edges'], data['train_edges_false'] = train_edges, train_edges_false
-    if args.val_prop + args.test_prop > 0:
-        data['val_edges'], data['val_edges_false'] = val_edges, val_edges_false
-        data['test_edges'], data['test_edges_false'] = test_edges, test_edges_false
-    all_info=""
-
-    ## Adj matrix
-    adj = data['adj_train']
-    data['adj_train_enc'], data['features'] = process(
-            data['adj_train'], data['features'], args.normalize_adj, args.normalize_feats
-    )
-
-    if args.lambda_rec:
-        data['adj_train_dec'] = rowwise_normalizing(data['adj_train'])
-
-    adj_2hop = get_adj_2hop(adj)
-    data['adj_train_enc_2hop'] = symmetric_laplacian_smoothing(adj_2hop)
-
-    # NOTE : Re-adjust labels
-    # Some data omit `0` class, thus n_classes are wrong with `max(labels)+1`
-    args.n_classes = int(data['labels'].max() + 1)
-
-    data['idx_all'] =  range(data['features'].shape[0])
-    data_info = "Dataset {} Loaded : dimensions are adj:{}, edges:{}, features:{}, labels:{}\n".format(
-            'ddos2019', data['adj_train'].shape, data['adj_train'].sum(), data['features'].shape, data['labels'].shape)
-    data['info'] = data_info
-    return data
-
-def process(adj, features, normalize_adj, normalize_feats):
-    if sp.isspmatrix(features):
-        features = np.array(features.todense())
-    if normalize_feats:
-        features = normalize(features)
-    features = torch.Tensor(features)
-    if normalize_adj:
-        adj = normalize(adj + sp.eye(adj.shape[0]))
-    return adj, features
-
-def get_adj_2hop(adj):
-    adj_self = adj + sp.eye(adj.shape[0])
-    adj_2hop = adj_self.dot(adj_self)
-    adj_2hop.data = np.clip(adj_2hop.data, 0, 1)
-    adj_2hop = adj_2hop - sp.eye(adj.shape[0]) - adj
-    return adj_2hop
-
-def normalize(mx):
-    """Row-normalize sparse matrix."""
-    rowsum = np.array(mx.sum(1))
-    r_inv = np.power(rowsum, -1).flatten()
-    r_inv[np.isinf(r_inv)] = 0.
-    r_mat_inv = sp.diags(r_inv)
-    mx = r_mat_inv.dot(mx)
-    return mx
-
-def symmetric_laplacian_smoothing(adj):
-    """Symmetrically normalize adjacency matrix."""
-    adj = adj + sp.eye(adj.shape[0])  # self-loop
-
-    adj = sp.coo_matrix(adj)
-    rowsum = np.array(adj.sum(1))
-    d_inv_sqrt = np.power(rowsum, -0.5).flatten()
-    d_inv_sqrt[np.isinf(d_inv_sqrt)] = 0.
-    d_mat_inv_sqrt = sp.diags(d_inv_sqrt)
-    return adj.dot(d_mat_inv_sqrt).transpose().dot(d_mat_inv_sqrt).tocoo()
-
-def rowwise_normalizing(adj):
-    """Row-wise normalize adjacency matrix."""
-    adj = adj + sp.eye(adj.shape[0])  # self-loop
-    adj = sp.coo_matrix(adj)
-    rowsum = np.array(adj.sum(1))
-    d_inv = np.power(rowsum, -1.0).flatten()
-    d_inv[np.isinf(d_inv)] = 0.
-    d_mat_inv = sp.diags(d_inv)
-    return adj.dot(d_mat_inv).transpose().tocoo()
-
-def sparse_mx_to_torch_sparse_tensor(sparse_mx):
-    """Convert a scipy sparse matrix to a torch sparse tensor."""
-    sparse_mx = sparse_mx.tocoo()
-    indices = torch.from_numpy(
-            np.vstack((sparse_mx.row, sparse_mx.col)).astype(np.int64)
-    )
-    values = torch.Tensor(sparse_mx.data)
-    shape = torch.Size(sparse_mx.shape)
-    return torch.sparse.FloatTensor(indices, values, shape)
-
-def mask_edges(adj, val_prop, test_prop, seed):
-    np.random.seed(seed)  # get tp edges
-    x, y = sp.triu(adj).nonzero()
-    pos_edges = np.array(list(zip(x, y)))
-    np.random.shuffle(pos_edges)
-    # get tn edges
-    x, y = sp.triu(sp.csr_matrix(1. - adj.toarray())).nonzero()   #  LONG
-    neg_edges = np.array(list(zip(x, y)))   #  EVEN LONGER
-    np.random.shuffle(neg_edges)  # ALSO LONG
-
-    m_pos = len(pos_edges)
-    n_val = int(m_pos * val_prop)
-    n_test = int(m_pos * test_prop)
-    val_edges, test_edges, train_edges = pos_edges[:n_val], pos_edges[n_val:n_test + n_val], pos_edges[n_test + n_val:]
-    val_edges_false, test_edges_false = neg_edges[:n_val], neg_edges[n_val:n_test + n_val]
-    train_edges_false = np.concatenate([neg_edges, val_edges, test_edges], axis=0)
-    adj_train = sp.csr_matrix((np.ones(train_edges.shape[0]), (train_edges[:, 0], train_edges[:, 1])), shape=adj.shape)
-    adj_train = adj_train + adj_train.T
-    return adj_train, torch.LongTensor(train_edges), torch.LongTensor(train_edges_false), torch.LongTensor(val_edges), \
-           torch.LongTensor(val_edges_false), torch.LongTensor(test_edges), torch.LongTensor(
-            test_edges_false)  
diff --git a/HGCAE/utils/eval_utils.py b/HGCAE/utils/eval_utils.py
deleted file mode 100644
index e2793a6..0000000
--- a/HGCAE/utils/eval_utils.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from sklearn.metrics import average_precision_score, accuracy_score, f1_score
-
-def acc_f1(output, labels, average='binary'):
-    preds = output.max(1)[1].type_as(labels)
-    if preds.is_cuda:
-        preds = preds.cpu()
-        labels = labels.cpu()
-    accuracy = accuracy_score(labels,preds)
-    f1 = f1_score(labels,preds, average=average)
-    return accuracy, f1
-
diff --git a/HGCAE/utils/math_utils.py b/HGCAE/utils/math_utils.py
deleted file mode 100644
index 56a0de2..0000000
--- a/HGCAE/utils/math_utils.py
+++ /dev/null
@@ -1,70 +0,0 @@
-'''
-Code from HGCN (https://github.com/HazyResearch/hgcn/blob/master/utils/math_utils.py)
-'''
-import torch
-
-
-def cosh(x, clamp=15):
-    return x.clamp(-clamp, clamp).cosh()
-
-
-def sinh(x, clamp=15):
-    return x.clamp(-clamp, clamp).sinh()
-
-
-def tanh(x, clamp=15):
-    return x.clamp(-clamp, clamp).tanh()
-
-
-def arcosh(x):
-    return Arcosh.apply(x)
-
-
-def arsinh(x):
-    return Arsinh.apply(x)
-
-
-def artanh(x):
-    return Artanh.apply(x)
-
-
-class Artanh(torch.autograd.Function):
-    @staticmethod
-    def forward(ctx, x):
-        x = x.clamp(-1 + 1e-15, 1 - 1e-15)
-        ctx.save_for_backward(x)
-        z = x.double()
-        return (torch.log_(1 + z).sub_(torch.log_(1 - z))).mul_(0.5).to(x.dtype)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        input, = ctx.saved_tensors
-        return grad_output / (1 - input ** 2)
-
-
-class Arsinh(torch.autograd.Function):
-    @staticmethod
-    def forward(ctx, x):
-        ctx.save_for_backward(x)
-        z = x.double()
-        return (z + torch.sqrt_(1 + z.pow(2))).clamp_min_(1e-15).log_().to(x.dtype)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        input, = ctx.saved_tensors
-        return grad_output / (1 + input ** 2) ** 0.5
-
-
-class Arcosh(torch.autograd.Function):
-    @staticmethod
-    def forward(ctx, x):
-        x = x.clamp(min=1 + 1e-7)
-        ctx.save_for_backward(x)
-        z = x.double()
-        return (z + torch.sqrt_(z.pow(2) - 1)).clamp_min_(1e-15).log_().to(x.dtype)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        input, = ctx.saved_tensors
-        return grad_output / (input ** 2 - 1) ** 0.5
-
diff --git a/HGCAE/utils/train_utils.py b/HGCAE/utils/train_utils.py
deleted file mode 100644
index 42026c4..0000000
--- a/HGCAE/utils/train_utils.py
+++ /dev/null
@@ -1,225 +0,0 @@
-import os
-import sys
-
-import numpy as np
-import torch
-import torch.nn.functional as F
-import torch.nn.modules.loss
-import argparse
-
-def format_metrics(metrics, split):
-    """Format metric in metric dict for logging."""
-    return " ".join(
-            ["{}_{}: {:.8f}".format(split, metric_name, metric_val) for metric_name, metric_val in metrics.items()])
-
-def get_dir_name(models_dir):
-    """Gets a directory to save the model.
-
-    If the directory already exists, then append a new integer to the end of
-    it. This method is useful so that we don't overwrite existing models
-    when launching new jobs.
-
-    Args:
-        models_dir: The directory where all the models are.
-
-    Returns:
-        The name of a new directory to save the training logs and model weights.
-    """
-    if not os.path.exists(models_dir):
-        save_dir = os.path.join(models_dir, '0')
-        os.makedirs(save_dir)
-    else:
-        existing_dirs = np.array(
-                [
-                    d
-                    for d in os.listdir(models_dir)
-                    if os.path.isdir(os.path.join(models_dir, d))
-                    ]
-        ).astype(np.int)
-        if len(existing_dirs) > 0:
-            dir_id = str(existing_dirs.max() + 1)
-        else:
-            dir_id = "1"
-        save_dir = os.path.join(models_dir, dir_id)
-        os.makedirs(save_dir)
-    return save_dir
-
-
-def add_flags_from_config(parser, config_dict):
-    """
-    Adds a flag (and default value) to an ArgumentParser for each parameter in a config
-    """
-
-    def OrNone(default):
-        def func(x):
-            # Convert "none" to proper None object
-            if x.lower() == "none":
-                return None
-            # If default is None (and x is not None), return x without conversion as str
-            elif default is None:
-                return str(x)
-            # Otherwise, default has non-None type; convert x to that type
-            else:
-                return type(default)(x)
-
-        return func
-
-    for param in config_dict:
-        default, description = config_dict[param]
-        try:
-            if isinstance(default, dict):
-                parser = add_flags_from_config(parser, default)
-            elif isinstance(default, list):
-                if len(default) > 0:
-                    # pass a list as argument
-                    parser.add_argument(
-                            f"--{param}",
-                            action="append",
-                            type=type(default[0]),
-                            default=default,
-                            help=description
-                    )
-                else:
-                    pass
-                    parser.add_argument(f"--{param}", action="append", default=default, help=description)
-            else:
-                pass
-                parser.add_argument(f"--{param}", type=OrNone(default), default=default, help=description)
-        except argparse.ArgumentError:
-            print(
-                f"Could not add flag for param {param} because it was already present."
-            )
-    return parser
-
-
-
-import subprocess
-def check_gpustats(columns=None):
-    query = r'nvidia-smi --query-gpu=%s --format=csv,noheader' % ','.join(columns)
-    smi_output = subprocess.check_output(query, shell=True).decode().strip()
-
-    gpustats = []
-    for line in smi_output.split('\n'):
-        if not line:
-            continue
-        gpustat = line.split(',')
-        gpustats.append({k: v.strip() for k, v in zip(columns, gpustat)})
-
-    return gpustats
-
-
-def assign_gpus(num_gpu, memory_threshold=1000):    # (MiB)
-    os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
-
-    columns = ['index', 'memory.used']
-    gpustats = {i['index']: i['memory.used'] for i in check_gpustats(columns)}
-
-
-
-    available_gpus = []
-    for gpu in sorted(gpustats.keys()):
-        if int(gpustats.get(gpu).split(' ')[0]) < memory_threshold:
-            available_gpus.append(gpu)
-
-    if len(available_gpus) < num_gpu:
-        raise MemoryError('{} GPUs requested, but only {} available'.format(num_gpu, len(available_gpus)))
-
-    gpus_to_assign = available_gpus[:num_gpu]
-    # os.environ['CUDA_VISIBLE_DEVICES'] = ','.join(gpus_to_assign)
-    return gpus_to_assign
-
-
-
-def create_args(*args):
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--dim', type=int, default=args[0])
-    parser.add_argument('--hidden_dim', type=int, default=args[1])
-    parser.add_argument('--c', type=int, default=args[2])
-    parser.add_argument('--num_layers', type=int, default=args[3])
-    parser.add_argument('--bias', type=bool, default=args[4])
-    parser.add_argument('--act', type=str, default=args[5])
-    parser.add_argument('--grad_clip', type=float, default=args[6])
-    parser.add_argument('--optimizer', type=str, default=args[7])
-    parser.add_argument('--weight_decay', type=float, default=args[8])
-    parser.add_argument('--lr', type=float, default=args[9])
-    parser.add_argument('--gamma', type=float, default=args[10])
-    parser.add_argument('--lr_reduce_freq', type=int, default=args[11])
-    parser.add_argument('--cuda', type=int, default=args[12])
-    parser.add_argument('--epochs', type=int, default=args[13])
-    parser.add_argument('--min_epochs', type=int, default=args[14])
-    parser.add_argument('--patience', type=int, default=args[15])
-    parser.add_argument('--seed', type=int, default=args[16])
-    parser.add_argument('--log_freq', type=int, default=args[17])
-    parser.add_argument('--eval_freq', type=int, default=args[18])
-    parser.add_argument('--val_prop', type=float, default=args[19])
-    parser.add_argument('--test_prop', type=float, default=args[20])
-    parser.add_argument('--double_precision', type=int, default=args[21])
-    parser.add_argument('--dropout', type=float, default=args[22])
-    parser.add_argument('--lambda_rec', type=float, default=args[23])
-    parser.add_argument('--lambda_lp', type=float, default=args[24])
-    parser.add_argument('--num_dec_layers', type=int, default=args[25])
-    parser.add_argument('--use_att', type=bool, default=args[26])
-    parser.add_argument('--att_type', type=str, default=args[27])
-    parser.add_argument('--att_logit', type=str, default=args[28])
-    parser.add_argument('--beta', type=float, default=args[29])
-    parser.add_argument('--classifier', type=str, default=args[30])
-    parser.add_argument('--clusterer', type=str, default=args[31])
-    parser.add_argument('--normalize_adj', type=bool, default=args[32])
-    parser.add_argument('--normalize_feats', type=bool, default=args[33])
-    parser.add_argument('--anomaly_detector', type=str, default=args[34])
-    flags, unknown = parser.parse_known_args()
-    return flags
-
-
-
-from Ghypeddings.classifiers import *
-def get_classifier(args,X,y):
-    if(args.classifier == 'svm'):
-        return SVM(X,y)
-    elif(args.classifier == 'mlp'):
-        return mlp(X,y,1,10,seed=args.seed)
-    elif(args.classifier == 'decision tree'):
-        return decision_tree(X,y)
-    elif(args.classifier == 'random forest'):
-        return random_forest(X,y,args.seed)
-    elif(args.classifier == 'adaboost'):
-        return adaboost(X,y,args.seed)
-    elif(args.classifier == 'knn'):
-        return KNN(X,y)
-    elif(args.classifier == 'naive bayes'):
-        return naive_bayes(X,y)
-    else:
-        raise NotImplementedError
-    
-from Ghypeddings.clusterers import *
-def get_clustering_algorithm(clusterer,X,y):
-    if(clusterer == 'agglomerative_clustering'):
-        return agglomerative_clustering(X,y)
-    elif(clusterer == 'dbscan'):
-        return dbscan(X,y)
-    elif(clusterer == 'fuzzy_c_mean'):
-        return fuzzy_c_mean(X,y)
-    elif(clusterer == 'gaussian_mixture'):
-        return gaussian_mixture(X,y)
-    elif(clusterer == 'kmeans'):
-        return kmeans(X,y)
-    elif(clusterer == 'mean_shift'):
-        return mean_shift(X,y)
-    else:
-        raise NotImplementedError
-    
-
-from Ghypeddings.anomaly_detection import *
-def get_anomaly_detection_algorithm(algorithm,X,y):
-    if(algorithm == 'isolation_forest'):
-        return isolation_forest(X,y)
-    elif(algorithm == 'one_class_svm'):
-        return one_class_svm(X,y)
-    elif(algorithm == 'dbscan'):
-        return dbscan(X,y)
-    elif(algorithm == 'kmeans'):
-        return kmeans(X,y)
-    elif(algorithm == 'local_outlier_factor'):
-        return local_outlier_factor(X,y)
-    else:
-        raise NotImplementedError
\ No newline at end of file
diff --git a/HGCN/.gitignore b/HGCN/.gitignore
deleted file mode 100644
index ba0430d..0000000
--- a/HGCN/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-__pycache__/
\ No newline at end of file
diff --git a/HGCN/__init__.py b/HGCN/__init__.py
deleted file mode 100644
index bfa83a0..0000000
--- a/HGCN/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from __future__ import print_function
-from __future__ import division
diff --git a/HGCN/hgcn.py b/HGCN/hgcn.py
deleted file mode 100644
index 84c735f..0000000
--- a/HGCN/hgcn.py
+++ /dev/null
@@ -1,165 +0,0 @@
-from __future__ import division
-from __future__ import print_function
-
-import logging
-import os
-import time
-
-import numpy as np
-import Ghypeddings.HGCN.optimizers as optimizers
-import torch
-from Ghypeddings.HGCN.models.base_models import NCModel
-from Ghypeddings.HGCN.utils.data_utils import process_data
-from Ghypeddings.HGCN.utils.train_utils import format_metrics
-from Ghypeddings.HGCN.utils.train_utils import create_args
-import warnings
-warnings.filterwarnings('ignore')
-
-
-class HGCN:
-    def __init__(self,
-                adj,
-                features,
-                labels,
-                dim,
-                c=None,
-                num_layers=2,
-                bias=True,
-                act='relu',
-                select_manifold='Euclidean', #Euclidean , Hyperboloid
-                grad_clip=1.0,
-                optimizer='Adam', #Adam , RiemannianAdam
-                weight_decay=0.01,
-                lr=0.1, #0.009
-                gamma=0.5,
-                lr_reduce_freq=200,
-                cuda=0,
-                epochs=50,
-                min_epochs=50,
-                patience=None,
-                seed=42,
-                log_freq=1,
-                eval_freq=1,
-                val_prop=0.15,
-                test_prop=0.15,
-                double_precision=0,
-                dropout=0.1,
-                use_att= True,
-                alpha=0.5,
-                local_agg = False,
-                normalize_adj=False,
-                normalize_feats=True
-                ):
-        
-        self.args = create_args(dim,c,num_layers,bias,act,select_manifold,grad_clip,optimizer,weight_decay,lr,gamma,lr_reduce_freq,cuda,epochs,min_epochs,patience,seed,log_freq,eval_freq,val_prop,test_prop,double_precision,dropout,use_att,alpha,local_agg,normalize_adj,normalize_feats)
-        self.args.n_nodes = adj.shape[0]
-        self.args.feat_dim = features.shape[1]
-        self.args.n_classes = len(np.unique(labels))
-        self.data = process_data(self.args,adj,features,labels)
-
-        np.random.seed(self.args.seed)
-        torch.manual_seed(self.args.seed)
-        if int(self.args.double_precision):
-            torch.set_default_dtype(torch.float64)
-        if int(self.args.cuda) >= 0:
-            torch.cuda.manual_seed(self.args.seed)
-        self.args.device = 'cuda:' + str(self.args.cuda) if int(self.args.cuda) >= 0 else 'cpu'
-        self.args.patience = self.args.epochs if not self.args.patience else  int(self.args.patience)
-        if not self.args.lr_reduce_freq:
-            self.args.lr_reduce_freq = self.args.epochs
-        self.model = NCModel(self.args)
-        self.optimizer = getattr(optimizers, self.args.optimizer)(params=self.model.parameters(), lr=self.args.lr,weight_decay=self.args.weight_decay)
-        self.lr_scheduler = torch.optim.lr_scheduler.StepLR(
-            self.optimizer,
-            step_size=int(self.args.lr_reduce_freq),
-            gamma=float(self.args.gamma)
-        )
-        if self.args.cuda is not None and int(self.args.cuda) >= 0 :
-            os.environ['CUDA_VISIBLE_DEVICES'] = str(self.args.cuda)
-            self.model = self.model.to(self.args.device)
-            for x, val in self.data.items():
-                if torch.is_tensor(self.data[x]):
-                    self.data[x] = self.data[x].to(self.args.device)
-        self.best_emb = None
-
-    def fit(self):
-        logging.getLogger().setLevel(logging.INFO)
-        logging.info(f'Using: {self.args.device}')
-        logging.info(str(self.model))
-        tot_params = sum([np.prod(p.size()) for p in self.model.parameters()])
-        logging.info(f"Total number of parameters: {tot_params}")
-
-        t_total = time.time()
-        counter = 0
-        best_val_metrics = self.model.init_metric_dict()
-
-        best_losses = []
-        train_losses = []
-        val_losses = []
-
-        for epoch in range(self.args.epochs):
-            t = time.time()
-            self.model.train()
-            self.optimizer.zero_grad()
-            embeddings = self.model.encode(self.data['features'], self.data['adj_train_norm'])
-            train_metrics = self.model.compute_metrics(embeddings, self.data, 'train')
-            train_metrics['loss'].backward()
-            if self.args.grad_clip is not None:
-                max_norm = float(self.args.grad_clip)
-                all_params = list(self.model.parameters())
-                for param in all_params:
-                    torch.nn.utils.clip_grad_norm_(param, max_norm)
-            self.optimizer.step()
-            self.lr_scheduler.step()
-
-            train_losses.append(train_metrics['loss'].item())
-            if(len(best_losses) == 0):
-                best_losses.append(train_losses[0])
-            elif (best_losses[-1] > train_losses[-1]):
-                best_losses.append(train_losses[-1])
-            else:
-                best_losses.append(best_losses[-1])
-
-            if (epoch + 1) % self.args.log_freq == 0:
-                logging.info(" ".join(['Epoch: {:04d}'.format(epoch + 1),
-                                    'lr: {}'.format(self.lr_scheduler.get_lr()[0]),
-                                    format_metrics(train_metrics, 'train'),
-                                    'time: {:.4f}s'.format(time.time() - t)
-                                    ]))
-                
-            if (epoch + 1) % self.args.eval_freq == 0:
-                self.model.eval()
-                embeddings = self.model.encode(self.data['features'], self.data['adj_train_norm'])
-                val_metrics = self.model.compute_metrics(embeddings, self.data, 'val')
-                val_losses.append(val_metrics['loss'].item())
-                if (epoch + 1) % self.args.log_freq == 0:
-                    logging.info(" ".join(['Epoch: {:04d}'.format(epoch + 1), format_metrics(val_metrics, 'val')]))
-                if self.model.has_improved(best_val_metrics, val_metrics):
-                    self.best_emb = embeddings
-                    best_val_metrics = val_metrics
-                    counter = 0
-                else:
-                    counter += 1
-                    if counter == self.args.patience and epoch > self.args.min_epochs:
-                        logging.info("Early stopping")
-                        break
-
-        logging.info("Training Finished!")
-        logging.info("Total time elapsed: {:.4f}s".format(time.time() - t_total))
-        return {'train':train_losses,'best':best_losses,'val':val_losses},best_val_metrics['acc'],best_val_metrics['f1'],best_val_metrics['recall'],best_val_metrics['precision'],best_val_metrics['roc_auc'],time.time() - t_total
-
-    def predict(self):
-        self.model.eval()
-        embeddings = self.model.encode(self.data['features'], self.data['adj_train_norm'])
-        val_metrics = self.model.compute_metrics(embeddings, self.data, 'test')
-        return val_metrics['loss'].item(),val_metrics['acc'],val_metrics['f1'],val_metrics['recall'],val_metrics['precision'],val_metrics['roc_auc']
-
-    def save_embeddings(self):
-        c = self.model.decoder.c
-        tb_embeddings_euc = self.manifold.proj_tan0(self.model.manifold.logmap0(self.best_emb,c),c)
-        for_classification_hyp = np.hstack((self.best_emb.cpu().detach().numpy(),self.data['labels'].cpu().reshape(-1,1)))
-        for_classification_euc = np.hstack((tb_embeddings_euc.cpu().detach().numpy(),self.data['labels'].cpu().reshape(-1,1)))
-        hyp_file_path = os.path.join(os.getcwd(),'hgcn_embeddings_hyp.csv')
-        euc_file_path = os.path.join(os.getcwd(),'hgcn_embeddings_euc.csv')
-        np.savetxt(hyp_file_path, for_classification_hyp, delimiter=',')
-        np.savetxt(euc_file_path, for_classification_euc, delimiter=',')
\ No newline at end of file
diff --git a/HGCN/layers/__init__.py b/HGCN/layers/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/HGCN/layers/att_layers.py b/HGCN/layers/att_layers.py
deleted file mode 100644
index 8414d8d..0000000
--- a/HGCN/layers/att_layers.py
+++ /dev/null
@@ -1,144 +0,0 @@
-"""Attention layers (some modules are copied from https://github.com/Diego999/pyGAT."""
-import numpy as np
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-
-
-class DenseAtt(nn.Module):
-    def __init__(self, in_features, dropout):
-        super(DenseAtt, self).__init__()
-        self.dropout = dropout
-        self.linear = nn.Linear(2 * in_features, 1, bias=True)
-        self.in_features = in_features
-
-    def forward (self, x, adj):
-        n = x.size(0)
-        # n x 1 x d
-        x_left = torch.unsqueeze(x, 1)
-        x_left = x_left.expand(-1, n, -1)
-        # 1 x n x d
-        x_right = torch.unsqueeze(x, 0)
-        x_right = x_right.expand(n, -1, -1)
-
-        x_cat = torch.cat((x_left, x_right), dim=2)
-        att_adj = self.linear(x_cat).squeeze()
-        att_adj = F.sigmoid(att_adj)
-        att_adj = torch.mul(adj.to_dense(), att_adj)
-        return att_adj
-
-
-class SpecialSpmmFunction(torch.autograd.Function):
-    """Special function for only sparse region backpropataion layer."""
-
-    @staticmethod
-    def forward(ctx, indices, values, shape, b):
-        assert indices.requires_grad == False
-        a = torch.sparse_coo_tensor(indices, values, shape)
-        ctx.save_for_backward(a, b)
-        ctx.N = shape[0]
-        return torch.matmul(a, b)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        a, b = ctx.saved_tensors
-        grad_values = grad_b = None
-        if ctx.needs_input_grad[1]:
-            grad_a_dense = grad_output.matmul(b.t())
-            edge_idx = a._indices()[0, :] * ctx.N + a._indices()[1, :]
-            grad_values = grad_a_dense.view(-1)[edge_idx]
-        if ctx.needs_input_grad[3]:
-            grad_b = a.t().matmul(grad_output)
-        return None, grad_values, None, grad_b
-
-
-class SpecialSpmm(nn.Module):
-    def forward(self, indices, values, shape, b):
-        return SpecialSpmmFunction.apply(indices, values, shape, b)
-
-
-class SpGraphAttentionLayer(nn.Module):
-    """
-    Sparse version GAT layer, similar to https://arxiv.org/abs/1710.10903
-    """
-
-    def __init__(self, in_features, out_features, dropout, alpha, activation):
-        super(SpGraphAttentionLayer, self).__init__()
-        self.in_features = in_features
-        self.out_features = out_features
-        self.alpha = alpha
-
-        self.W = nn.Parameter(torch.zeros(size=(in_features, out_features)))
-        nn.init.xavier_normal_(self.W.data, gain=1.414)
-
-        self.a = nn.Parameter(torch.zeros(size=(1, 2 * out_features)))
-        nn.init.xavier_normal_(self.a.data, gain=1.414)
-
-        self.dropout = nn.Dropout(dropout)
-        self.leakyrelu = nn.LeakyReLU(self.alpha)
-        self.special_spmm = SpecialSpmm()
-        self.act = activation
-
-    def forward(self, input, adj):
-        N = input.size()[0]
-        edge = adj._indices()
-
-        h = torch.mm(input, self.W)
-        # h: N x out
-        assert not torch.isnan(h).any()
-
-        # Self-attention on the nodes - Shared attention mechanism
-        edge_h = torch.cat((h[edge[0, :], :], h[edge[1, :], :]), dim=1).t()
-        # edge: 2*D x E
-
-        edge_e = torch.exp(-self.leakyrelu(self.a.mm(edge_h).squeeze()))
-        assert not torch.isnan(edge_e).any()
-        # edge_e: E
-
-        ones = torch.ones(size=(N, 1))
-        if h.is_cuda:
-            ones = ones.cuda()
-        e_rowsum = self.special_spmm(edge, edge_e, torch.Size([N, N]), ones)
-        # e_rowsum: N x 1
-
-        edge_e = self.dropout(edge_e)
-        # edge_e: E
-
-        h_prime = self.special_spmm(edge, edge_e, torch.Size([N, N]), h)
-        assert not torch.isnan(h_prime).any()
-        # h_prime: N x out
-
-        h_prime = h_prime.div(e_rowsum)
-        # h_prime: N x out
-        assert not torch.isnan(h_prime).any()
-        return self.act(h_prime)
-
-    def __repr__(self):
-        return self.__class__.__name__ + ' (' + str(self.in_features) + ' -> ' + str(self.out_features) + ')'
-
-
-class GraphAttentionLayer(nn.Module):
-    def __init__(self, input_dim, output_dim, dropout, activation, alpha, nheads, concat):
-        """Sparse version of GAT."""
-        super(GraphAttentionLayer, self).__init__()
-        self.dropout = dropout
-        self.output_dim = output_dim
-        self.attentions = [SpGraphAttentionLayer(input_dim,
-                                                 output_dim,
-                                                 dropout=dropout,
-                                                 alpha=alpha,
-                                                 activation=activation) for _ in range(nheads)]
-        self.concat = concat
-        for i, attention in enumerate(self.attentions):
-            self.add_module('attention_{}'.format(i), attention)
-
-    def forward(self, input):
-        x, adj = input
-        x = F.dropout(x, self.dropout, training=self.training)
-        if self.concat:
-            h = torch.cat([att(x, adj) for att in self.attentions], dim=1)
-        else:
-            h_cat = torch.cat([att(x, adj).view((-1, self.output_dim, 1)) for att in self.attentions], dim=2)
-            h = torch.mean(h_cat, dim=2)
-        h = F.dropout(h, self.dropout, training=self.training)
-        return (h, adj)
diff --git a/HGCN/layers/hyp_layers.py b/HGCN/layers/hyp_layers.py
deleted file mode 100644
index 0913411..0000000
--- a/HGCN/layers/hyp_layers.py
+++ /dev/null
@@ -1,158 +0,0 @@
-"""Hyperbolic layers."""
-import math
-
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-import torch.nn.init as init
-from torch.nn.modules.module import Module
-
-from Ghypeddings.HGCN.layers.att_layers import DenseAtt
-
-
-def get_dim_act_curv(args):
-    """
-    Helper function to get dimension and activation at every layer.
-    :param args:
-    :return:
-    """
-    if not args.act:
-        act = lambda x: x
-    else:
-        act = getattr(F, args.act)
-    acts = [act] * (args.num_layers - 1)
-    dims = [args.feat_dim] + ([args.dim] * (args.num_layers - 1))
-    n_curvatures = args.num_layers - 1
-    if args.c is None:
-        # create list of trainable curvature parameters
-        curvatures = [nn.Parameter(torch.Tensor([1.])) for _ in range(n_curvatures)]
-    else:
-        # fixed curvature
-        curvatures = [torch.tensor([args.c]) for _ in range(n_curvatures)]
-        if not args.cuda == -1:
-            curvatures = [curv.to(args.device) for curv in curvatures]
-    return dims, acts, curvatures
-
-
-class HyperbolicGraphConvolution(nn.Module):
-    """
-    Hyperbolic graph convolution layer.
-    """
-
-    def __init__(self, manifold, in_features, out_features, c_in, c_out, dropout, act, use_bias, use_att, local_agg):
-        super(HyperbolicGraphConvolution, self).__init__()
-        self.linear = HypLinear(manifold, in_features, out_features, c_in, dropout, use_bias)
-        self.agg = HypAgg(manifold, c_in, out_features, dropout, use_att, local_agg)
-        self.hyp_act = HypAct(manifold, c_in, c_out, act)
-
-    def forward(self, input):
-        x, adj = input
-        h = self.linear.forward(x)
-        h = self.agg.forward(h, adj)
-        h = self.hyp_act.forward(h)
-        output = h, adj
-        return output
-
-
-class HypLinear(nn.Module):
-    """
-    Hyperbolic linear layer.
-    """
-
-    def __init__(self, manifold, in_features, out_features, c, dropout, use_bias):
-        super(HypLinear, self).__init__()
-        self.manifold = manifold
-        self.in_features = in_features
-        self.out_features = out_features
-        self.c = c
-        self.dropout = dropout
-        self.use_bias = use_bias
-        self.bias = nn.Parameter(torch.Tensor(out_features))
-        self.weight = nn.Parameter(torch.Tensor(out_features, in_features))
-        self.reset_parameters()
-
-    def reset_parameters(self):
-        init.xavier_uniform_(self.weight, gain=math.sqrt(2))
-        init.constant_(self.bias, 0)
-
-    def forward(self, x):
-        drop_weight = F.dropout(self.weight, self.dropout, training=self.training)
-        mv = self.manifold.mobius_matvec(drop_weight, x, self.c)
-        res = self.manifold.proj(mv, self.c)
-        if self.use_bias:
-            bias = self.manifold.proj_tan0(self.bias.view(1, -1), self.c)
-            hyp_bias = self.manifold.expmap0(bias, self.c)
-            hyp_bias = self.manifold.proj(hyp_bias, self.c)
-            res = self.manifold.mobius_add(res, hyp_bias, c=self.c)
-            res = self.manifold.proj(res, self.c)
-        return res
-
-    def extra_repr(self):
-        return 'in_features={}, out_features={}, c={}'.format(
-            self.in_features, self.out_features, self.c
-        )
-
-
-class HypAgg(Module):
-    """
-    Hyperbolic aggregation layer.
-    """
-
-    def __init__(self, manifold, c, in_features, dropout, use_att, local_agg):
-        super(HypAgg, self).__init__()
-        self.manifold = manifold
-        self.c = c
-
-        self.in_features = in_features
-        self.dropout = dropout
-        self.local_agg = local_agg
-        self.use_att = use_att
-        if self.use_att:
-            self.att = DenseAtt(in_features, dropout)
-
-    def forward(self, x, adj):
-        x_tangent = self.manifold.logmap0(x, c=self.c)
-        if self.use_att:
-            if self.local_agg:
-                x_local_tangent = []
-                for i in range(x.size(0)):
-                    x_local_tangent.append(self.manifold.logmap(x[i], x, c=self.c))
-                x_local_tangent = torch.stack(x_local_tangent, dim=0)
-                adj_att = self.att(x_tangent, adj)
-                att_rep = adj_att.unsqueeze(-1) * x_local_tangent
-                support_t = torch.sum(adj_att.unsqueeze(-1) * x_local_tangent, dim=1)
-                output = self.manifold.proj(self.manifold.expmap(x, support_t, c=self.c), c=self.c)
-                return output
-            else:
-                adj_att = self.att(x_tangent, adj)
-                support_t = torch.matmul(adj_att, x_tangent)
-        else:
-            support_t = torch.spmm(adj, x_tangent)
-        output = self.manifold.proj(self.manifold.expmap0(support_t, c=self.c), c=self.c)
-        return output
-
-    def extra_repr(self):
-        return 'c={}'.format(self.c)
-
-
-class HypAct(Module):
-    """
-    Hyperbolic activation layer.
-    """
-
-    def __init__(self, manifold, c_in, c_out, act):
-        super(HypAct, self).__init__()
-        self.manifold = manifold
-        self.c_in = c_in
-        self.c_out = c_out
-        self.act = act
-
-    def forward(self, x):
-        xt = self.act(self.manifold.logmap0(x, c=self.c_in))
-        xt = self.manifold.proj_tan0(xt, c=self.c_out)
-        return self.manifold.proj(self.manifold.expmap0(xt, c=self.c_out), c=self.c_out)
-
-    def extra_repr(self):
-        return 'c_in={}, c_out={}'.format(
-            self.c_in, self.c_out
-        )
diff --git a/HGCN/layers/layers.py b/HGCN/layers/layers.py
deleted file mode 100644
index c2eeb70..0000000
--- a/HGCN/layers/layers.py
+++ /dev/null
@@ -1,71 +0,0 @@
-"""Euclidean layers."""
-import math
-
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-from torch.nn.modules.module import Module
-from torch.nn.parameter import Parameter
-
-class Linear(Module):
-    """
-    Simple Linear layer with dropout.
-    """
-
-    def __init__(self, in_features, out_features, dropout, act, use_bias):
-        super(Linear, self).__init__()
-        self.dropout = dropout
-        self.linear = nn.Linear(in_features, out_features, use_bias)
-        self.act = act
-
-    def forward(self, x):
-        hidden = self.linear.forward(x)
-        hidden = F.dropout(hidden, self.dropout, training=self.training)
-        out = self.act(hidden)
-        return out
-
-
-
-def get_dim_act(args):
-    """
-    Helper function to get dimension and activation at every layer.
-    :param args:
-    :return:
-    """
-    if not args.act:
-        act = lambda x: x
-    else:
-        act = getattr(F, args.act)
-    acts = [act] * (args.num_layers - 1)
-    dims = [args.feat_dim] + ([args.dim] * (args.num_layers - 1))
-    return dims, acts
-
-
-class GraphConvolution(Module):
-    """
-    Simple GCN layer.
-    """
-
-    def __init__(self, in_features, out_features, dropout, act, use_bias):
-        super(GraphConvolution, self).__init__()
-        self.dropout = dropout
-        self.linear = nn.Linear(in_features, out_features, use_bias)
-        self.act = act
-        self.in_features = in_features
-        self.out_features = out_features
-
-    def forward(self, input):
-        x, adj = input
-        hidden = self.linear.forward(x)
-        hidden = F.dropout(hidden, self.dropout, training=self.training)
-        if adj.is_sparse:
-            support = torch.spmm(adj, hidden)
-        else:
-            support = torch.mm(adj, hidden)
-        output = self.act(support), adj
-        return output
-
-    def extra_repr(self):
-        return 'input_dim={}, output_dim={}'.format(
-                self.in_features, self.out_features
-        )
diff --git a/HGCN/manifolds/__init__.py b/HGCN/manifolds/__init__.py
deleted file mode 100644
index bd4b8d8..0000000
--- a/HGCN/manifolds/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from Ghypeddings.HGCN.manifolds.base import ManifoldParameter
-from Ghypeddings.HGCN.manifolds.hyperboloid import Hyperboloid
-from Ghypeddings.HGCN.manifolds.euclidean import Euclidean
-from Ghypeddings.HGCN.manifolds.poincare import PoincareBall
diff --git a/HGCN/manifolds/base.py b/HGCN/manifolds/base.py
deleted file mode 100644
index 925d4a6..0000000
--- a/HGCN/manifolds/base.py
+++ /dev/null
@@ -1,88 +0,0 @@
-"""Base manifold."""
-
-from torch.nn import Parameter
-
-
-class Manifold(object):
-    """
-    Abstract class to define operations on a manifold.
-    """
-
-    def __init__(self):
-        super().__init__()
-        self.eps = 10e-8
-
-    def sqdist(self, p1, p2, c):
-        """Squared distance between pairs of points."""
-        raise NotImplementedError
-
-    def egrad2rgrad(self, p, dp, c):
-        """Converts Euclidean Gradient to Riemannian Gradients."""
-        raise NotImplementedError
-
-    def proj(self, p, c):
-        """Projects point p on the manifold."""
-        raise NotImplementedError
-
-    def proj_tan(self, u, p, c):
-        """Projects u on the tangent space of p."""
-        raise NotImplementedError
-
-    def proj_tan0(self, u, c):
-        """Projects u on the tangent space of the origin."""
-        raise NotImplementedError
-
-    def expmap(self, u, p, c):
-        """Exponential map of u at point p."""
-        raise NotImplementedError
-
-    def logmap(self, p1, p2, c):
-        """Logarithmic map of point p1 at point p2."""
-        raise NotImplementedError
-
-    def expmap0(self, u, c):
-        """Exponential map of u at the origin."""
-        raise NotImplementedError
-
-    def logmap0(self, p, c):
-        """Logarithmic map of point p at the origin."""
-        raise NotImplementedError
-
-    def mobius_add(self, x, y, c, dim=-1):
-        """Adds points x and y."""
-        raise NotImplementedError
-
-    def mobius_matvec(self, m, x, c):
-        """Performs hyperboic martrix-vector multiplication."""
-        raise NotImplementedError
-
-    def init_weights(self, w, c, irange=1e-5):
-        """Initializes random weigths on the manifold."""
-        raise NotImplementedError
-
-    def inner(self, p, c, u, v=None, keepdim=False):
-        """Inner product for tangent vectors at point x."""
-        raise NotImplementedError
-
-    def ptransp(self, x, y, u, c):
-        """Parallel transport of u from x to y."""
-        raise NotImplementedError
-
-    def ptransp0(self, x, u, c):
-        """Parallel transport of u from the origin to y."""
-        raise NotImplementedError
-
-
-class ManifoldParameter(Parameter):
-    """
-    Subclass of torch.nn.Parameter for Riemannian optimization.
-    """
-    def __new__(cls, data, requires_grad, manifold, c):
-        return Parameter.__new__(cls, data, requires_grad)
-
-    def __init__(self, data, requires_grad, manifold, c):
-        self.c = c
-        self.manifold = manifold
-
-    def __repr__(self):
-        return '{} Parameter containing:\n'.format(self.manifold.name) + super(Parameter, self).__repr__()
diff --git a/HGCN/manifolds/euclidean.py b/HGCN/manifolds/euclidean.py
deleted file mode 100644
index 4ec5e38..0000000
--- a/HGCN/manifolds/euclidean.py
+++ /dev/null
@@ -1,67 +0,0 @@
-"""Euclidean manifold."""
-
-from Ghypeddings.HGCN.manifolds.base import Manifold
-
-
-class Euclidean(Manifold):
-    """
-    Euclidean Manifold class.
-    """
-
-    def __init__(self):
-        super(Euclidean, self).__init__()
-        self.name = 'Euclidean'
-
-    def normalize(self, p):
-        dim = p.size(-1)
-        p.view(-1, dim).renorm_(2, 0, 1.)
-        return p
-
-    def sqdist(self, p1, p2, c):
-        return (p1 - p2).pow(2).sum(dim=-1)
-
-    def egrad2rgrad(self, p, dp, c):
-        return dp
-
-    def proj(self, p, c):
-        return p
-
-    def proj_tan(self, u, p, c):
-        return u
-
-    def proj_tan0(self, u, c):
-        return u
-
-    def expmap(self, u, p, c):
-        return p + u
-
-    def logmap(self, p1, p2, c):
-        return p2 - p1
-
-    def expmap0(self, u, c):
-        return u
-
-    def logmap0(self, p, c):
-        return p
-
-    def mobius_add(self, x, y, c, dim=-1):
-        return x + y
-
-    def mobius_matvec(self, m, x, c):
-        mx = x @ m.transpose(-1, -2)
-        return mx
-
-    def init_weights(self, w, c, irange=1e-5):
-        w.data.uniform_(-irange, irange)
-        return w
-
-    def inner(self, p, c, u, v=None, keepdim=False):
-        if v is None:
-            v = u
-        return (u * v).sum(dim=-1, keepdim=keepdim)
-
-    def ptransp(self, x, y, v, c):
-        return v
-
-    def ptransp0(self, x, v, c):
-        return x + v
diff --git a/HGCN/manifolds/hyperboloid.py b/HGCN/manifolds/hyperboloid.py
deleted file mode 100644
index d014700..0000000
--- a/HGCN/manifolds/hyperboloid.py
+++ /dev/null
@@ -1,155 +0,0 @@
-"""Hyperboloid manifold."""
-
-import torch
-
-from Ghypeddings.HGCN.manifolds.base import Manifold
-from Ghypeddings.HGCN.utils.math_utils import arcosh, cosh, sinh 
-
-
-class Hyperboloid(Manifold):
-    """
-    Hyperboloid manifold class.
-
-    We use the following convention: -x0^2 + x1^2 + ... + xd^2 = -K
-
-    c = 1 / K is the hyperbolic curvature. 
-    """
-
-    def __init__(self):
-        super(Hyperboloid, self).__init__()
-        self.name = 'Hyperboloid'
-        self.eps = {torch.float32: 1e-7, torch.float64: 1e-15}
-        self.min_norm = 1e-15
-        self.max_norm = 1e6
-
-    def minkowski_dot(self, x, y, keepdim=True):
-        res = torch.sum(x * y, dim=-1) - 2 * x[..., 0] * y[..., 0]
-        if keepdim:
-            res = res.view(res.shape + (1,))
-        return res
-
-    def minkowski_norm(self, u, keepdim=True):
-        dot = self.minkowski_dot(u, u, keepdim=keepdim)
-        return torch.sqrt(torch.clamp(dot, min=self.eps[u.dtype]))
-
-    def sqdist(self, x, y, c):
-        K = 1. / c
-        prod = self.minkowski_dot(x, y)
-        theta = torch.clamp(-prod / K, min=1.0 + self.eps[x.dtype])
-        sqdist = K * arcosh(theta) ** 2
-        # clamp distance to avoid nans in Fermi-Dirac decoder
-        return torch.clamp(sqdist, max=50.0)
-
-    def proj(self, x, c):
-        K = 1. / c
-        d = x.size(-1) - 1
-        y = x.narrow(-1, 1, d)
-        y_sqnorm = torch.norm(y, p=2, dim=1, keepdim=True) ** 2 
-        mask = torch.ones_like(x)
-        mask[:, 0] = 0
-        vals = torch.zeros_like(x)
-        vals[:, 0:1] = torch.sqrt(torch.clamp(K + y_sqnorm, min=self.eps[x.dtype]))
-        return vals + mask * x
-
-    def proj_tan(self, u, x, c):
-        K = 1. / c
-        d = x.size(-1) - 1
-        ux = torch.sum(x.narrow(-1, 1, d) * u.narrow(-1, 1, d), dim=1, keepdim=True)
-        mask = torch.ones_like(u)
-        mask[:, 0] = 0
-        vals = torch.zeros_like(u)
-        if(len(x.size()) == 1):
-            x = x.unsqueeze(0)
-        vals[:, 0:1] = ux / torch.clamp(x[:, 0:1], min=self.eps[x.dtype])
-        return vals + mask * u
-
-    def proj_tan0(self, u, c):
-        narrowed = u.narrow(-1, 0, 1)
-        vals = torch.zeros_like(u)
-        vals[:, 0:1] = narrowed
-        return u - vals
-
-    def expmap(self, u, x, c):
-        K = 1. / c
-        sqrtK = K ** 0.5
-        normu = self.minkowski_norm(u)
-        normu = torch.clamp(normu, max=self.max_norm)
-        theta = normu / sqrtK
-        theta = torch.clamp(theta, min=self.min_norm)
-        result = cosh(theta) * x + sinh(theta) * u / theta
-        return self.proj(result, c)
-        
-    def logmap(self, x, y, c):
-        K = 1. / c
-        xy = torch.clamp(self.minkowski_dot(x, y) + K, max=-self.eps[x.dtype]) - K
-        u = y + xy * x * c
-        normu = self.minkowski_norm(u)
-        normu = torch.clamp(normu, min=self.min_norm)
-        dist = self.sqdist(x, y, c) ** 0.5
-        result = dist * u / normu
-        return self.proj_tan(result, x, c)
-
-    def expmap0(self, u, c):
-        K = 1. / c
-        sqrtK = K ** 0.5
-        d = u.size(-1) - 1
-        x = u.narrow(-1, 1, d).view(-1, d)
-        x_norm = torch.norm(x, p=2, dim=1, keepdim=True)
-        x_norm = torch.clamp(x_norm, min=self.min_norm)
-        theta = x_norm / sqrtK
-        res = torch.ones_like(u)
-        res[:, 0:1] = sqrtK * cosh(theta)
-        res[:, 1:] = sqrtK * sinh(theta) * x / x_norm
-        return self.proj(res, c)
-
-    def logmap0(self, x, c):
-        K = 1. / c
-        sqrtK = K ** 0.5
-        d = x.size(-1) - 1
-        y = x.narrow(-1, 1, d).view(-1, d)
-        y_norm = torch.norm(y, p=2, dim=1, keepdim=True)
-        y_norm = torch.clamp(y_norm, min=self.min_norm)
-        res = torch.zeros_like(x)
-        theta = torch.clamp(x[:, 0:1] / sqrtK, min=1.0 + self.eps[x.dtype])
-        res[:, 1:] = sqrtK * arcosh(theta) * y / y_norm
-        return res
-
-    def mobius_add(self, x, y, c):
-        u = self.logmap0(y, c)
-        v = self.ptransp0(x, u, c)
-        return self.expmap(v, x, c)
-
-    def mobius_matvec(self, m, x, c):
-        u = self.logmap0(x, c)
-        mu = u @ m.transpose(-1, -2)
-        return self.expmap0(mu, c)
-
-    def ptransp(self, x, y, u, c):
-        logxy = self.logmap(x, y, c)
-        logyx = self.logmap(y, x, c)
-        sqdist = torch.clamp(self.sqdist(x, y, c), min=self.min_norm)
-        alpha = self.minkowski_dot(logxy, u) / sqdist
-        res = u - alpha * (logxy + logyx)
-        return self.proj_tan(res, y, c)
-
-    def ptransp0(self, x, u, c):
-        K = 1. / c
-        sqrtK = K ** 0.5
-        x0 = x.narrow(-1, 0, 1)
-        d = x.size(-1) - 1
-        y = x.narrow(-1, 1, d)
-        y_norm = torch.clamp(torch.norm(y, p=2, dim=1, keepdim=True), min=self.min_norm)
-        y_normalized = y / y_norm
-        v = torch.ones_like(x)
-        v[:, 0:1] = - y_norm 
-        v[:, 1:] = (sqrtK - x0) * y_normalized
-        alpha = torch.sum(y_normalized * u[:, 1:], dim=1, keepdim=True) / sqrtK
-        res = u - alpha * v
-        return self.proj_tan(res, x, c)
-
-    def to_poincare(self, x, c):
-        K = 1. / c
-        sqrtK = K ** 0.5
-        d = x.size(-1) - 1
-        return sqrtK * x.narrow(-1, 1, d) / (x[:, 0:1] + sqrtK)
-
diff --git a/HGCN/manifolds/poincare.py b/HGCN/manifolds/poincare.py
deleted file mode 100644
index 601b580..0000000
--- a/HGCN/manifolds/poincare.py
+++ /dev/null
@@ -1,145 +0,0 @@
-"""Poincare ball manifold."""
-
-import torch
-
-from Ghypeddings.HGCN.manifolds.base import Manifold
-from Ghypeddings.HGCN.utils.math_utils import artanh, tanh
-
-
-class PoincareBall(Manifold):
-    """
-    PoicareBall Manifold class.
-
-    We use the following convention: x0^2 + x1^2 + ... + xd^2 < 1 / c
-
-    Note that 1/sqrt(c) is the Poincare ball radius.
-
-    """
-
-    def __init__(self, ):
-        super(PoincareBall, self).__init__()
-        self.name = 'PoincareBall'
-        self.min_norm = 1e-15
-        self.eps = {torch.float32: 4e-3, torch.float64: 1e-5}
-
-    def sqdist(self, p1, p2, c):
-        sqrt_c = c ** 0.5
-        dist_c = artanh(
-            sqrt_c * self.mobius_add(-p1, p2, c, dim=-1).norm(dim=-1, p=2, keepdim=False)
-        )
-        dist = dist_c * 2 / sqrt_c
-        return dist ** 2
-
-    def _lambda_x(self, x, c):
-        x_sqnorm = torch.sum(x.data.pow(2), dim=-1, keepdim=True)
-        return 2 / (1. - c * x_sqnorm).clamp_min(self.min_norm)
-
-    def egrad2rgrad(self, p, dp, c):
-        lambda_p = self._lambda_x(p, c)
-        dp /= lambda_p.pow(2)
-        return dp
-
-    def proj(self, x, c):
-        norm = torch.clamp_min(x.norm(dim=-1, keepdim=True, p=2), self.min_norm)
-        maxnorm = (1 - self.eps[x.dtype]) / (c ** 0.5)
-        cond = norm > maxnorm
-        projected = x / norm * maxnorm
-        return torch.where(cond, projected, x)
-
-    def proj_tan(self, u, p, c):
-        return u
-
-    def proj_tan0(self, u, c):
-        return u
-
-    def expmap(self, u, p, c):
-        sqrt_c = c ** 0.5
-        u_norm = u.norm(dim=-1, p=2, keepdim=True).clamp_min(self.min_norm)
-        second_term = (
-                tanh(sqrt_c / 2 * self._lambda_x(p, c) * u_norm)
-                * u
-                / (sqrt_c * u_norm)
-        )
-        gamma_1 = self.mobius_add(p, second_term, c)
-        return gamma_1
-
-    def logmap(self, p1, p2, c):
-        sub = self.mobius_add(-p1, p2, c)
-        sub_norm = sub.norm(dim=-1, p=2, keepdim=True).clamp_min(self.min_norm)
-        lam = self._lambda_x(p1, c)
-        sqrt_c = c ** 0.5
-        return 2 / sqrt_c / lam * artanh(sqrt_c * sub_norm) * sub / sub_norm
-
-    def expmap0(self, u, c):
-        sqrt_c = c ** 0.5
-        u_norm = torch.clamp_min(u.norm(dim=-1, p=2, keepdim=True), self.min_norm)
-        gamma_1 = tanh(sqrt_c * u_norm) * u / (sqrt_c * u_norm)
-        return gamma_1
-
-    def logmap0(self, p, c):
-        sqrt_c = c ** 0.5
-        p_norm = p.norm(dim=-1, p=2, keepdim=True).clamp_min(self.min_norm)
-        scale = 1. / sqrt_c * artanh(sqrt_c * p_norm) / p_norm
-        return scale * p
-
-    def mobius_add(self, x, y, c, dim=-1):
-        x2 = x.pow(2).sum(dim=dim, keepdim=True)
-        y2 = y.pow(2).sum(dim=dim, keepdim=True)
-        xy = (x * y).sum(dim=dim, keepdim=True)
-        num = (1 + 2 * c * xy + c * y2) * x + (1 - c * x2) * y
-        denom = 1 + 2 * c * xy + c ** 2 * x2 * y2
-        return num / denom.clamp_min(self.min_norm)
-
-    def mobius_matvec(self, m, x, c):
-        sqrt_c = c ** 0.5
-        x_norm = x.norm(dim=-1, keepdim=True, p=2).clamp_min(self.min_norm)
-        mx = x @ m.transpose(-1, -2)
-        mx_norm = mx.norm(dim=-1, keepdim=True, p=2).clamp_min(self.min_norm)
-        res_c = tanh(mx_norm / x_norm * artanh(sqrt_c * x_norm)) * mx / (mx_norm * sqrt_c)
-        cond = (mx == 0).prod(-1, keepdim=True, dtype=torch.uint8)
-        res_0 = torch.zeros(1, dtype=res_c.dtype, device=res_c.device)
-        res = torch.where(cond, res_0, res_c)
-        return res
-
-    def init_weights(self, w, c, irange=1e-5):
-        w.data.uniform_(-irange, irange)
-        return w
-
-    def _gyration(self, u, v, w, c, dim: int = -1):
-        u2 = u.pow(2).sum(dim=dim, keepdim=True)
-        v2 = v.pow(2).sum(dim=dim, keepdim=True)
-        uv = (u * v).sum(dim=dim, keepdim=True)
-        uw = (u * w).sum(dim=dim, keepdim=True)
-        vw = (v * w).sum(dim=dim, keepdim=True)
-        c2 = c ** 2
-        a = -c2 * uw * v2 + c * vw + 2 * c2 * uv * vw
-        b = -c2 * vw * u2 - c * uw
-        d = 1 + 2 * c * uv + c2 * u2 * v2
-        return w + 2 * (a * u + b * v) / d.clamp_min(self.min_norm)
-
-    def inner(self, x, c, u, v=None, keepdim=False):
-        if v is None:
-            v = u
-        lambda_x = self._lambda_x(x, c)
-        return lambda_x ** 2 * (u * v).sum(dim=-1, keepdim=keepdim)
-
-    def ptransp(self, x, y, u, c):
-        lambda_x = self._lambda_x(x, c)
-        lambda_y = self._lambda_x(y, c)
-        return self._gyration(y, -x, u, c) * lambda_x / lambda_y
-
-    def ptransp_(self, x, y, u, c):
-        lambda_x = self._lambda_x(x, c)
-        lambda_y = self._lambda_x(y, c)
-        return self._gyration(y, -x, u, c) * lambda_x / lambda_y
-
-    def ptransp0(self, x, u, c):
-        lambda_x = self._lambda_x(x, c)
-        return 2 * u / lambda_x.clamp_min(self.min_norm)
-
-    def to_hyperboloid(self, x, c):
-        K = 1./ c
-        sqrtK = K ** 0.5
-        sqnorm = torch.norm(x, p=2, dim=1, keepdim=True) ** 2
-        return sqrtK * torch.cat([K + sqnorm, 2 * sqrtK * x], dim=1) / (K - sqnorm)
-
diff --git a/HGCN/models/__init__.py b/HGCN/models/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/HGCN/models/base_models.py b/HGCN/models/base_models.py
deleted file mode 100644
index 00f5628..0000000
--- a/HGCN/models/base_models.py
+++ /dev/null
@@ -1,85 +0,0 @@
-"""Base model class."""
-
-import numpy as np
-from sklearn.metrics import roc_auc_score, average_precision_score
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-
-import Ghypeddings.HGCN.manifolds as manifolds
-import Ghypeddings.HGCN.models.encoders as encoders
-from Ghypeddings.HGCN.models.decoders import model2decoder
-from Ghypeddings.HGCN.utils.eval_utils import acc_f1
-
-
-class BaseModel(nn.Module):
-    """
-    Base model for graph embedding tasks.
-    """
-
-    def __init__(self, args):
-        super(BaseModel, self).__init__()
-        self.manifold_name = args.select_manifold
-        if args.c is not None:
-            self.c = torch.tensor([args.c])
-            if not args.cuda == -1:
-                self.c = self.c.to(args.device)
-        else:
-            self.c = nn.Parameter(torch.Tensor([1.]))
-        self.manifold = getattr(manifolds, self.manifold_name)()
-        if self.manifold.name == 'Hyperboloid':
-            args.feat_dim = args.feat_dim + 1
-        self.nnodes = args.n_nodes
-        self.encoder = getattr(encoders, args.model)(self.c, args)
-
-    def encode(self, x, adj):
-        if self.manifold.name == 'Hyperboloid':
-            o = torch.zeros_like(x)
-            x = torch.cat([o[:, 0:1], x], dim=1)
-        h = self.encoder.encode(x, adj)
-        return h
-
-    def compute_metrics(self, embeddings, data, split):
-        raise NotImplementedError
-
-    def init_metric_dict(self):
-        raise NotImplementedError
-
-    def has_improved(self, m1, m2):
-        raise NotImplementedError
-
-
-class NCModel(BaseModel):
-    """
-    Base model for node classification task.
-    """
-
-    def __init__(self, args):
-        super(NCModel, self).__init__(args)
-        self.decoder = model2decoder(self.c, args)
-        if args.n_classes > 2:
-            self.f1_average = 'micro'
-        else:
-            self.f1_average = 'binary'
-        
-        self.weights = torch.Tensor([1.] * args.n_classes)
-        if not args.cuda == -1:
-            self.weights = self.weights.to(args.device)
-
-    def decode(self, h, adj, idx):
-        output = self.decoder.decode(h, adj)
-        return F.log_softmax(output[idx], dim=1)
-
-    def compute_metrics(self, embeddings, data, split):
-        idx = data[f'idx_{split}']
-        output = self.decode(embeddings, data['adj_train_norm'], idx)
-        loss = F.nll_loss(output, data['labels'][idx], self.weights)
-        acc, f1,recall,precision,roc_auc = acc_f1(output, data['labels'][idx], average=self.f1_average)
-        metrics = {'loss': loss, 'acc': acc, 'f1': f1,'recall':recall,'precision':precision,'roc_auc':roc_auc}
-        return metrics
-
-    def init_metric_dict(self):
-        return {'acc': -1, 'f1': -1}
-
-    def has_improved(self, m1, m2):
-        return m1["f1"] < m2["f1"]
diff --git a/HGCN/models/decoders.py b/HGCN/models/decoders.py
deleted file mode 100644
index f20046b..0000000
--- a/HGCN/models/decoders.py
+++ /dev/null
@@ -1,52 +0,0 @@
-"""Graph decoders."""
-import Ghypeddings.HGCN.manifolds as manifolds
-import torch.nn as nn
-import torch.nn.functional as F
-
-from Ghypeddings.HGCN.layers.layers import Linear
-
-
-class Decoder(nn.Module):
-    """
-    Decoder abstract class for node classification tasks.
-    """
-
-    def __init__(self, c):
-        super(Decoder, self).__init__()
-        self.c = c
-
-    def decode(self, x, adj):
-        if self.decode_adj:
-            input = (x, adj)
-            probs, _ = self.cls.forward(input)
-        else:
-            probs = self.cls.forward(x)
-        return probs
-
-
-class LinearDecoder(Decoder):
-    """
-    MLP Decoder for Hyperbolic/Euclidean node classification models.
-    """
-
-    def __init__(self, c, args):
-        super(LinearDecoder, self).__init__(c)
-        self.manifold = getattr(manifolds, args.select_manifold)()
-        self.input_dim = args.dim
-        self.output_dim = args.n_classes
-        self.bias = args.bias
-        self.cls = Linear(self.input_dim, self.output_dim, args.dropout, lambda x: x, self.bias)
-        self.decode_adj = False
-
-    def decode(self, x, adj):
-        h = self.manifold.proj_tan0(self.manifold.logmap0(x, c=self.c), c=self.c)
-        return super(LinearDecoder, self).decode(h, adj)
-
-    def extra_repr(self):
-        return 'in_features={}, out_features={}, bias={}, c={}'.format(
-                self.input_dim, self.output_dim, self.bias, self.c
-        )
-
-
-model2decoder = LinearDecoder
-
diff --git a/HGCN/models/encoders.py b/HGCN/models/encoders.py
deleted file mode 100644
index c82c611..0000000
--- a/HGCN/models/encoders.py
+++ /dev/null
@@ -1,99 +0,0 @@
-"""Graph encoders."""
-
-import numpy as np
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-
-import Ghypeddings.HGCN.manifolds as manifolds
-import Ghypeddings.HGCN.layers.hyp_layers as hyp_layers
-import Ghypeddings.HGCN.utils.math_utils as pmath
-
-from Ghypeddings.HGCN.layers.layers import GraphConvolution, Linear, get_dim_act
-from Ghypeddings.HGCN.layers.att_layers import GraphAttentionLayer
-
-class Encoder(nn.Module):
-    """
-    Encoder abstract class.
-    """
-
-    def __init__(self, c):
-        super(Encoder, self).__init__()
-        self.c = c
-
-    def encode(self, x, adj):
-        if self.encode_graph:
-            input = (x, adj)
-            output, _ = self.layers.forward(input)
-        else:
-            output = self.layers.forward(x)
-        return output
-
-class GCN(Encoder):
-    """
-    Graph Convolution Networks.
-    """
-
-    def __init__(self, c, args):
-        super(GCN, self).__init__(c)
-        assert args.num_layers > 0
-        dims, acts = get_dim_act(args)
-        gc_layers = []
-        for i in range(len(dims) - 1):
-            in_dim, out_dim = dims[i], dims[i + 1]
-            act = acts[i]
-            gc_layers.append(GraphConvolution(in_dim, out_dim, args.dropout, act, args.bias))
-        self.layers = nn.Sequential(*gc_layers)
-        self.encode_graph = True
-
-class GAT(Encoder):
-    """
-    Graph Attention Networks.
-    """
-
-    def __init__(self, c, args):
-        super(GAT, self).__init__(c)
-        assert args.num_layers > 0
-        dims, acts = get_dim_act(args)
-        gat_layers = []
-        for i in range(len(dims) - 1):
-            in_dim, out_dim = dims[i], dims[i + 1]
-            act = acts[i]
-            assert dims[i + 1] % args.n_heads == 0
-            out_dim = dims[i + 1] // args.n_heads
-            concat = True
-            gat_layers.append(
-                    GraphAttentionLayer(in_dim, out_dim, args.dropout, act, args.alpha, args.n_heads, concat))
-        self.layers = nn.Sequential(*gat_layers)
-        self.encode_graph = True
-
-
-class HGCN(Encoder):
-    """
-    Hyperbolic-GCN.
-    """
-
-    def __init__(self, c, args):
-        super(HGCN, self).__init__(c)
-        self.manifold = getattr(manifolds, args.select_manifold)()
-        assert args.num_layers > 1
-        dims, acts, self.curvatures = hyp_layers.get_dim_act_curv(args)
-        self.curvatures.append(self.c)
-        hgc_layers = []
-        for i in range(len(dims) - 1):
-            c_in, c_out = self.curvatures[i], self.curvatures[i + 1]
-            in_dim, out_dim = dims[i], dims[i + 1]
-            act = acts[i]
-            hgc_layers.append(
-                    hyp_layers.HyperbolicGraphConvolution(
-                            self.manifold, in_dim, out_dim, c_in, c_out, args.dropout, act, args.bias, args.use_att, args.local_agg
-                    )
-            )
-        self.layers = nn.Sequential(*hgc_layers)
-        self.encode_graph = True
-
-    def encode(self, x, adj):
-        x_tan = self.manifold.proj_tan0(x, self.curvatures[0])
-        x_hyp = self.manifold.expmap0(x_tan, c=self.curvatures[0])
-        x_hyp = self.manifold.proj(x_hyp, c=self.curvatures[0])
-        return super(HGCN, self).encode(x_hyp, adj)
diff --git a/HGCN/optimizers/__init__.py b/HGCN/optimizers/__init__.py
deleted file mode 100644
index 411e319..0000000
--- a/HGCN/optimizers/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from torch.optim import Adam
-from Ghypeddings.HGCN.optimizers.radam import RiemannianAdam
diff --git a/HGCN/optimizers/radam.py b/HGCN/optimizers/radam.py
deleted file mode 100644
index c703393..0000000
--- a/HGCN/optimizers/radam.py
+++ /dev/null
@@ -1,172 +0,0 @@
-"""Riemannian adam optimizer geoopt implementation (https://github.com/geoopt/)."""
-import torch.optim
-from Ghypeddings.HGCN.manifolds import Euclidean, ManifoldParameter
-
-_default_manifold = Euclidean()
-
-class OptimMixin(object):
-    def __init__(self, *args, stabilize=None, **kwargs):
-        self._stabilize = stabilize
-        super().__init__(*args, **kwargs)
-
-    def stabilize_group(self, group):
-        pass
-
-    def stabilize(self):
-        """Stabilize parameters if they are off-manifold due to numerical reasons
-        """
-        for group in self.param_groups:
-            self.stabilize_group(group)
-
-
-def copy_or_set_(dest, source):
-    """
-    A workaround to respect strides of :code:`dest` when copying :code:`source`
-    (https://github.com/geoopt/geoopt/issues/70)
-    Parameters
-    ----------
-    dest : torch.Tensor
-        Destination tensor where to store new data
-    source : torch.Tensor
-        Source data to put in the new tensor
-    Returns
-    -------
-    dest
-        torch.Tensor, modified inplace
-    """
-    if dest.stride() != source.stride():
-        return dest.copy_(source)
-    else:
-        return dest.set_(source)
-
-
-class RiemannianAdam(OptimMixin, torch.optim.Adam):
-    r"""Riemannian Adam with the same API as :class:`torch.optim.Adam`
-    Parameters
-    ----------
-    params : iterable
-        iterable of parameters to optimize or dicts defining
-        parameter groups
-    lr : float (optional)
-        learning rate (default: 1e-3)
-    betas : Tuple[float, float] (optional)
-        coefficients used for computing
-        running averages of gradient and its square (default: (0.9, 0.999))
-    eps : float (optional)
-        term added to the denominator to improve
-        numerical stability (default: 1e-8)
-    weight_decay : float (optional)
-        weight decay (L2 penalty) (default: 0)
-    amsgrad : bool (optional)
-        whether to use the AMSGrad variant of this
-        algorithm from the paper `On the Convergence of Adam and Beyond`_
-        (default: False)
-    Other Parameters
-    ----------------
-    stabilize : int
-        Stabilize parameters if they are off-manifold due to numerical
-        reasons every ``stabilize`` steps (default: ``None`` -- no stabilize)
-    .. _On the Convergence of Adam and Beyond:
-        https://openreview.net/forum?id=ryQu7f-RZ
-    """
-
-    def step(self, closure=None):
-        """Performs a single optimization step.
-        Arguments
-        ---------
-        closure : callable (optional)
-            A closure that reevaluates the model
-            and returns the loss.
-        """
-        loss = None
-        if closure is not None:
-            loss = closure()
-        with torch.no_grad():
-            for group in self.param_groups:
-                if "step" not in group:
-                    group["step"] = 0
-                betas = group["betas"]
-                weight_decay = group["weight_decay"]
-                eps = group["eps"]
-                learning_rate = group["lr"]
-                amsgrad = group["amsgrad"]
-                for point in group["params"]:
-                    grad = point.grad
-                    if grad is None:
-                        continue
-                    if isinstance(point, (ManifoldParameter)):
-                        manifold = point.manifold
-                        c = point.c
-                    else:
-                        manifold = _default_manifold
-                        c = None
-                    if grad.is_sparse:
-                        raise RuntimeError(
-                                "Riemannian Adam does not support sparse gradients yet (PR is welcome)"
-                        )
-
-                    state = self.state[point]
-
-                    # State initialization
-                    if len(state) == 0:
-                        state["step"] = 0
-                        # Exponential moving average of gradient values
-                        state["exp_avg"] = torch.zeros_like(point)
-                        # Exponential moving average of squared gradient values
-                        state["exp_avg_sq"] = torch.zeros_like(point)
-                        if amsgrad:
-                            # Maintains max of all exp. moving avg. of sq. grad. values
-                            state["max_exp_avg_sq"] = torch.zeros_like(point)
-                    # make local variables for easy access
-                    exp_avg = state["exp_avg"]
-                    exp_avg_sq = state["exp_avg_sq"]
-                    # actual step
-                    grad.add_(weight_decay, point)
-                    grad = manifold.egrad2rgrad(point, grad, c)
-                    exp_avg.mul_(betas[0]).add_(1 - betas[0], grad)
-                    exp_avg_sq.mul_(betas[1]).add_(
-                            1 - betas[1], manifold.inner(point, c, grad, keepdim=True)
-                    )
-                    if amsgrad:
-                        max_exp_avg_sq = state["max_exp_avg_sq"]
-                        # Maintains the maximum of all 2nd moment running avg. till now
-                        torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq)
-                        # Use the max. for normalizing running avg. of gradient
-                        denom = max_exp_avg_sq.sqrt().add_(eps)
-                    else:
-                        denom = exp_avg_sq.sqrt().add_(eps)
-                    group["step"] += 1
-                    bias_correction1 = 1 - betas[0] ** group["step"]
-                    bias_correction2 = 1 - betas[1] ** group["step"]
-                    step_size = (
-                        learning_rate * bias_correction2 ** 0.5 / bias_correction1
-                    )
-
-                    # copy the state, we need it for retraction
-                    # get the direction for ascend
-                    direction = exp_avg / denom
-                    # transport the exponential averaging to the new point
-                    new_point = manifold.proj(manifold.expmap(-step_size * direction, point, c), c)
-                    exp_avg_new = manifold.ptransp(point, new_point, exp_avg, c)
-                    # use copy only for user facing point
-                    copy_or_set_(point, new_point)
-                    exp_avg.set_(exp_avg_new)
-
-                    group["step"] += 1
-                if self._stabilize is not None and group["step"] % self._stabilize == 0:
-                    self.stabilize_group(group)
-        return loss
-
-    @torch.no_grad()
-    def stabilize_group(self, group):
-        for p in group["params"]:
-            if not isinstance(p, ManifoldParameter):
-                continue
-            state = self.state[p]
-            if not state:  # due to None grads
-                continue
-            manifold = p.manifold
-            c = p.c
-            exp_avg = state["exp_avg"]
-            copy_or_set_(p, manifold.proj(p, c))
-            exp_avg.set_(manifold.proj_tan(exp_avg, u, c))
diff --git a/HGCN/utils/__init__.py b/HGCN/utils/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/HGCN/utils/data_utils.py b/HGCN/utils/data_utils.py
deleted file mode 100644
index 5169f98..0000000
--- a/HGCN/utils/data_utils.py
+++ /dev/null
@@ -1,87 +0,0 @@
-"""Data utils functions for pre-processing and data loading."""
-import os
-import pickle as pkl
-import sys
-
-import networkx as nx
-import numpy as np
-import scipy.sparse as sp
-import torch
-import pandas as pd
-
-from sklearn.preprocessing import MinMaxScaler
-
-
-def process_data(args, adj,features,labels):
-    data = process_data_nc(args,adj,features,labels)
-    data['adj_train_norm'], data['features'] = process(
-            data['adj_train'], data['features'],args.normalize_adj,args.normalize_feats
-    )
-    return data
-
-
-def process(adj, features, normalize_adj, normalize_feats):
-    if sp.isspmatrix(features):
-        features = np.array(features.todense())
-    if normalize_feats:
-        features = normalize(features)
-    features = torch.Tensor(features)
-    if normalize_adj:
-        adj = normalize(adj + sp.eye(adj.shape[0]))
-    adj = sparse_mx_to_torch_sparse_tensor(adj)
-    return adj, features
-
-
-def normalize(mx):
-    """Row-normalize sparse matrix."""
-    rowsum = np.array(mx.sum(1))
-    r_inv = np.power(rowsum, -1).flatten()
-    r_inv[np.isinf(r_inv)] = 0.
-    r_mat_inv = sp.diags(r_inv)
-    mx = r_mat_inv.dot(mx)
-    return mx
-
-
-def sparse_mx_to_torch_sparse_tensor(sparse_mx):
-    """Convert a scipy sparse matrix to a torch sparse tensor."""
-    sparse_mx = sparse_mx.tocoo()
-    indices = torch.from_numpy(
-            np.vstack((sparse_mx.row, sparse_mx.col)).astype(np.int64)
-    )
-    values = torch.Tensor(sparse_mx.data)
-    shape = torch.Size(sparse_mx.shape)
-    return torch.sparse.FloatTensor(indices, values, shape)
-
-
-def augment(adj, features, normalize_feats=True):
-    deg = np.squeeze(np.sum(adj, axis=0).astype(int))
-    deg[deg > 5] = 5
-    deg_onehot = torch.tensor(np.eye(6)[deg], dtype=torch.float).squeeze()
-    const_f = torch.ones(features.size(0), 1)
-    features = torch.cat((features, deg_onehot, const_f), dim=1)
-    return features
-
-
-def split_data(labels, val_prop, test_prop, seed):
-    np.random.seed(seed)
-    pos_idx = labels.nonzero()[0]
-    neg_idx = (1. - labels).nonzero()[0]
-    np.random.shuffle(pos_idx)
-    np.random.shuffle(neg_idx)
-    pos_idx = pos_idx.tolist()
-    neg_idx = neg_idx.tolist()
-    nb_pos_neg = min(len(pos_idx), len(neg_idx))
-    nb_val = round(val_prop * nb_pos_neg)
-    nb_test = round(test_prop * nb_pos_neg)
-    idx_val_pos, idx_test_pos, idx_train_pos = pos_idx[:nb_val], pos_idx[nb_val:nb_val + nb_test], pos_idx[
-                                                                                                   nb_val + nb_test:]
-    idx_val_neg, idx_test_neg, idx_train_neg = neg_idx[:nb_val], neg_idx[nb_val:nb_val + nb_test], neg_idx[
-                                                                                                   nb_val + nb_test:]
-    return idx_val_pos + idx_val_neg, idx_test_pos + idx_test_neg, idx_train_pos + idx_train_neg
-
-
-def process_data_nc(args,adj,features,labels):
-    idx_val, idx_test, idx_train = split_data(labels, args.val_prop, args.test_prop, seed=args.seed)
-    labels = torch.LongTensor(labels)
-    data = {'adj_train': sp.csr_matrix(adj), 'features': features, 'labels': labels, 'idx_train': idx_train, 'idx_val': idx_val, 'idx_test': idx_test}
-    return data
\ No newline at end of file
diff --git a/HGCN/utils/eval_utils.py b/HGCN/utils/eval_utils.py
deleted file mode 100644
index 840a48b..0000000
--- a/HGCN/utils/eval_utils.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from sklearn.metrics import accuracy_score, f1_score, recall_score,precision_score,roc_auc_score
-
-def acc_f1(output, labels, average='binary'):
-    preds = output.max(1)[1].type_as(labels)
-    if preds.is_cuda:
-        preds = preds.cpu()
-        labels = labels.cpu()
-    accuracy = accuracy_score(labels, preds)
-    recall = recall_score(labels, preds)
-    precision = precision_score(labels, preds)
-    roc_auc = roc_auc_score(labels,preds )
-    f1 = f1_score(labels, preds, average=average)
-    return accuracy, f1 , recall,precision,roc_auc
-
diff --git a/HGCN/utils/math_utils.py b/HGCN/utils/math_utils.py
deleted file mode 100644
index 9cf278e..0000000
--- a/HGCN/utils/math_utils.py
+++ /dev/null
@@ -1,69 +0,0 @@
-"""Math utils functions."""
-
-import torch
-
-
-def cosh(x, clamp=15):
-    return x.clamp(-clamp, clamp).cosh()
-
-
-def sinh(x, clamp=15):
-    return x.clamp(-clamp, clamp).sinh()
-
-
-def tanh(x, clamp=15):
-    return x.clamp(-clamp, clamp).tanh()
-
-
-def arcosh(x):
-    return Arcosh.apply(x)
-
-
-def arsinh(x):
-    return Arsinh.apply(x)
-
-
-def artanh(x):
-    return Artanh.apply(x)
-
-
-class Artanh(torch.autograd.Function):
-    @staticmethod
-    def forward(ctx, x):
-        x = x.clamp(-1 + 1e-15, 1 - 1e-15)
-        ctx.save_for_backward(x)
-        z = x.double()
-        return (torch.log_(1 + z).sub_(torch.log_(1 - z))).mul_(0.5).to(x.dtype)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        input, = ctx.saved_tensors
-        return grad_output / (1 - input ** 2)
-
-
-class Arsinh(torch.autograd.Function):
-    @staticmethod
-    def forward(ctx, x):
-        ctx.save_for_backward(x)
-        z = x.double()
-        return (z + torch.sqrt_(1 + z.pow(2))).clamp_min_(1e-15).log_().to(x.dtype)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        input, = ctx.saved_tensors
-        return grad_output / (1 + input ** 2) ** 0.5
-
-
-class Arcosh(torch.autograd.Function):
-    @staticmethod
-    def forward(ctx, x):
-        x = x.clamp(min=1.0 + 1e-15)
-        ctx.save_for_backward(x)
-        z = x.double()
-        return (z + torch.sqrt_(z.pow(2) - 1)).clamp_min_(1e-15).log_().to(x.dtype)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        input, = ctx.saved_tensors
-        return grad_output / (input ** 2 - 1) ** 0.5
-
diff --git a/HGCN/utils/train_utils.py b/HGCN/utils/train_utils.py
deleted file mode 100644
index 296451e..0000000
--- a/HGCN/utils/train_utils.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import os
-
-import numpy as np
-import torch
-import torch.nn.functional as F
-import torch.nn.modules.loss
-import argparse
-
-def format_metrics(metrics, split):
-    """Format metric in metric dict for logging."""
-    return " ".join(
-            ["{}_{}: {:.4f}".format(split, metric_name, metric_val) for metric_name, metric_val in metrics.items()])
-
-def create_args(*args):
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--dim', type=int, default=args[0])
-    parser.add_argument('--c', type=int, default=args[1])
-    parser.add_argument('--num_layers', type=int, default=args[2])
-    parser.add_argument('--bias', type=bool, default=args[3])
-    parser.add_argument('--act', type=str, default=args[4])
-    parser.add_argument('--select_manifold', type=str, default=args[5])
-    parser.add_argument('--grad_clip', type=float, default=args[6])
-    parser.add_argument('--optimizer', type=str, default=args[7])
-    parser.add_argument('--weight_decay', type=float, default=args[8])
-    parser.add_argument('--lr', type=float, default=args[9])
-    parser.add_argument('--gamma', type=float, default=args[10])
-    parser.add_argument('--lr_reduce_freq', type=int, default=args[11])
-    parser.add_argument('--cuda', type=int, default=args[12])
-    parser.add_argument('--epochs', type=int, default=args[13])
-    parser.add_argument('--min_epochs', type=int, default=args[14])
-    parser.add_argument('--patience', type=int, default=args[15])
-    parser.add_argument('--seed', type=int, default=args[16])
-    parser.add_argument('--log_freq', type=int, default=args[17])
-    parser.add_argument('--eval_freq', type=int, default=args[18])
-    parser.add_argument('--val_prop', type=float, default=args[19])
-    parser.add_argument('--test_prop', type=float, default=args[20])
-    parser.add_argument('--double_precision', type=int, default=args[21])
-    parser.add_argument('--dropout', type=float, default=args[22])
-    parser.add_argument('--use_att', type=bool, default=args[23])
-    parser.add_argument('--alpha', type=float, default=args[24])
-    parser.add_argument('--local_agg', type=bool, default=args[25])
-    parser.add_argument('--normalize_adj', type=bool, default=args[26])
-    parser.add_argument('--normalize_feats', type=bool, default=args[27])
-    parser.add_argument('--model', type=str, default='GAT') #GCN, GAT,HGCN
-    parser.add_argument('--n_heads', type=int, default=1) #GCN, GAT,HGCN
-    flags, unknown = parser.parse_known_args()
-    return flags
\ No newline at end of file
diff --git a/HGNN/.gitignore b/HGNN/.gitignore
deleted file mode 100644
index ba0430d..0000000
--- a/HGNN/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-__pycache__/
\ No newline at end of file
diff --git a/HGNN/__init__.py b/HGNN/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/HGNN/dataset/NodeClassificationDataset.py b/HGNN/dataset/NodeClassificationDataset.py
deleted file mode 100644
index ef6a3c8..0000000
--- a/HGNN/dataset/NodeClassificationDataset.py
+++ /dev/null
@@ -1,160 +0,0 @@
-import numpy as np
-import pickle as pkl
-import networkx as nx
-import scipy.sparse as sp
-from scipy.sparse import save_npz, load_npz
-from scipy.sparse.linalg import eigsh
-import sys
-from torch.utils.data import Dataset, DataLoader
-from Ghypeddings.HGNN.utils import *
-import pandas as pd
-from sklearn.preprocessing import MinMaxScaler
-
-def parse_index_file(filename):
-    """Parse index file."""
-    index = []
-    for line in open(filename):
-        index.append(int(line.strip()))
-    return index
-
-def sample_mask(idx, l):
-    """Create mask."""
-    mask = np.zeros(l)
-    mask[idx] = 1
-    return np.array(mask, dtype=np.bool_)
-
-def preprocess_features(features):
-    """Row-normalize feature matrix and convert to tuple representation"""
-    rowsum = np.array(features.sum(1)).astype(float)
-    r_inv = np.power(rowsum, -1).flatten()
-    r_inv[np.isinf(r_inv)] = 0
-    r_mat_inv = sp.diags(r_inv)
-    features = r_mat_inv.dot(features)
-    return features
-
-class NodeClassificationDataset(Dataset):
-    """
-    Extend the Dataset class for graph datasets
-    """
-    def __init__(self, args, logger,adj,features,labels):
-        self.args = args
-        self.process_data(adj,features,labels)
-
-    def _filling_adjacency_numpy(self,data, N, source_ip_index, destination_ip_index):
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-            
-        source_ips = data[:, source_ip_index]
-        destination_ips = data[:, destination_ip_index]
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips) | (destination_ips[:, np.newaxis] == destination_ips))
-        adjacency[mask] = True
-        adjacency = adjacency - np.eye(N)
-        return adjacency
-    
-    def compact_adjacency(self,adj):
-        max_neighbors = int(np.max(np.sum(adj, axis=1)))
-        shape = (adj.shape[0],max_neighbors)
-        c_adj = np.zeros(shape)
-        c_adj[:,:] = -1
-        indices , neighbors = np.where(adj == 1)
-
-        j=-1
-        l = indices[0]
-        for i,k in zip(indices,neighbors):
-            if i == l:
-                j+=1
-            else:
-                l=i
-                j=0
-            c_adj[i,j]=int(k)
-        return c_adj
-    
-    def compact_weight_matrix(self,c_adj):
-        return np.where(c_adj >= 0, 1, 0)
-    
-    def one_hot_labels(self,y):
-        array  = np.zeros((len(y),2))
-        for i,j in zip(range(len(y)),y):
-            if j:
-                array[i,1]=1
-            else:
-                array[i,0]=1
-
-        return array
-    
-    def split_data(self,labels, test_prop,val_prop):
-        np.random.seed(self.args.seed)
-        #nb_nodes = labels.shape[0]
-        #all_idx = np.arange(nb_nodes)
-        # pos_idx = labels.nonzero()[0]
-        # neg_idx = (1. - labels).nonzero()[0]
-        pos_idx = labels[:,1].nonzero()[0]
-        neg_idx = labels[:,0].nonzero()[0]
-        np.random.shuffle(pos_idx)
-        np.random.shuffle(neg_idx)
-        pos_idx = pos_idx.tolist()
-        neg_idx = neg_idx.tolist()
-        nb_pos_neg = min(len(pos_idx), len(neg_idx))
-        nb_val = round(val_prop * nb_pos_neg)
-        nb_test = round(test_prop * nb_pos_neg)
-        idx_val_pos, idx_test_pos, idx_train_pos = pos_idx[:nb_val], pos_idx[nb_val:nb_val + nb_test], pos_idx[
-                                                                                                    nb_val + nb_test:]
-        idx_val_neg, idx_test_neg, idx_train_neg = neg_idx[:nb_val], neg_idx[nb_val:nb_val + nb_test], neg_idx[
-                                                                                                    nb_val + nb_test:]
-        return idx_val_pos + idx_val_neg, idx_test_pos + idx_test_neg, idx_train_pos + idx_train_neg
-    
-    def process_data(self, adj,features,labels):
-            
-        adj = self.compact_adjacency(adj)
-        weight = self.compact_weight_matrix(adj)
-        adj[adj == -1] = 0
-
-        labels = self.one_hot_labels(labels)
-
-        idx_test, idx_train, idx_val = self.split_data(labels,self.args.test_prop,self.args.val_prop)
-
-        train_mask = sample_mask(idx_train, labels.shape[0])
-        val_mask = sample_mask(idx_val, labels.shape[0])
-        test_mask = sample_mask(idx_test, labels.shape[0])
-
-        y_train = np.zeros(labels.shape)
-        y_val = np.zeros(labels.shape)
-        y_test = np.zeros(labels.shape)
-        y_train[train_mask, :] = labels[train_mask, :]
-        y_val[val_mask, :] = labels[val_mask, :]
-        y_test[test_mask, :] = labels[test_mask, :]
-
-        self.adj = adj
-        self.weight = weight
-
-        self.features = preprocess_features(features) if self.args.normalize_feats else features
-        self.features = features
-        assert np.isnan(features).any()== False
-        self.y_train = y_train
-        self.y_val = y_val
-        self.y_test = y_test
-        self.train_mask = train_mask.astype(int)
-        self.val_mask = val_mask.astype(int)
-        self.test_mask = test_mask.astype(int)
-        self.args.node_num = self.features.shape[0]
-        self.args.input_dim = self.features.shape[1]
-        self.args.num_class = y_train.shape[1]
-    
-
-    def __len__(self):
-        return 1
-
-    def __getitem__(self, idx):
-        return  {
-                  'adj': self.adj,
-                  'weight': self.weight,
-                  'features': self.features,
-                  'y_train' : self.y_train,
-                  'y_val' : self.y_val,
-                  'y_test' : self.y_test,
-                  'train_mask' : self.train_mask,
-                  'val_mask' : self.val_mask,
-                  'test_mask' : self.test_mask,
-                }
diff --git a/HGNN/dataset/__init__.py b/HGNN/dataset/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/HGNN/gnn/RiemannianGNN.py b/HGNN/gnn/RiemannianGNN.py
deleted file mode 100644
index 5e89f0a..0000000
--- a/HGNN/gnn/RiemannianGNN.py
+++ /dev/null
@@ -1,138 +0,0 @@
-import torch as th
-import torch.nn as nn
-import torch.nn.functional as F
-from Ghypeddings.HGNN.utils import *
-
-class RiemannianGNN(nn.Module):
-
-	def __init__(self, args, logger, manifold):
-		super(RiemannianGNN, self).__init__()
-		self.args = args
-		self.logger = logger
-		self.manifold = manifold
-		self.set_up_params()
-		self.activation = get_activation(self.args)
-		self.dropout = nn.Dropout(self.args.dropout)
-
-	def create_params(self):
-		"""
-		create the GNN params for a specific msg type
-		"""
-		msg_weight = []
-		layer = self.args.num_layers if not self.args.tie_weight else 1
-		for _ in range(layer):
-			# weight in euclidean space
-			if self.args.select_manifold == 'poincare':
-				M = th.zeros([self.args.dim, self.args.dim], requires_grad=True)
-			elif self.args.select_manifold == 'lorentz': # one degree of freedom less
-				M = th.zeros([self.args.dim, self.args.dim - 1], requires_grad=True)
-			init_weight(M, self.args.proj_init)
-			M = nn.Parameter(M)
-			self.args.eucl_vars.append(M)
-			msg_weight.append(M)
-		return nn.ParameterList(msg_weight)
-
-	def set_up_params(self):
-		"""
-		set up the params for all message types
-		"""
-		self.type_of_msg = 1
-
-		for i in range(0, self.type_of_msg):
-			setattr(self, "msg_%d_weight" % i, self.create_params())
-
-
-	def retrieve_params(self, weight, step):
-		"""
-		Args:
-			weight: a list of weights
-			step: a certain layer
-		"""
-		if self.args.select_manifold == 'poincare':
-			layer_weight = weight[step]
-		elif self.args.select_manifold == 'lorentz': # Ensure valid tangent vectors for (1, 0, ...)
-			layer_weight = th.cat((th.zeros((self.args.dim, 1)).cuda(), weight[step]), dim=1)
-		return layer_weight
-
-	def apply_activation(self, node_repr):
-		"""
-		apply non-linearity for different manifolds
-		"""
-		if self.args.select_manifold == "poincare":
-			return self.activation(node_repr)
-		elif self.args.select_manifold == "lorentz":
-			return self.manifold.from_poincare_to_lorentz(
-				self.activation(self.manifold.from_lorentz_to_poincare(node_repr))
-			)
-
-	def split_graph_by_negative_edge(self, adj_mat, weight):
-		"""
-		Split the graph according to positive and negative edges.
-		"""
-		mask = weight > 0
-		neg_mask = weight < 0
-
-		pos_adj_mat = adj_mat * mask.long()
-		neg_adj_mat = adj_mat * neg_mask.long()
-		pos_weight = weight * mask.float()
-		neg_weight = -weight * neg_mask.float()
-		return pos_adj_mat, pos_weight, neg_adj_mat, neg_weight
-
-	def split_graph_by_type(self, adj_mat, weight):
-		"""
-		split the graph according to edge type for multi-relational datasets
-		"""
-		multi_relation_adj_mat = []
-		multi_relation_weight = []
-		for relation in range(1, self.args.edge_type):
-			mask = (weight.int() == relation)
-			multi_relation_adj_mat.append(adj_mat * mask.long())
-			multi_relation_weight.append(mask.float())
-		return multi_relation_adj_mat, multi_relation_weight
-
-	def split_input(self, adj_mat, weight):
-		"""
-		Split the adjacency matrix and weight matrix for multi-relational datasets
-		and datasets with enhanced inverse edges, e.g. Ethereum.
-		"""
-		return [adj_mat], [weight]
-
-	def aggregate_msg(self, node_repr, adj_mat, weight, layer_weight, mask):
-		"""
-		message passing for a specific message type.
-		"""
-		node_num, max_neighbor = adj_mat.size(0), adj_mat.size(1)
-		msg = th.mm(node_repr, layer_weight) * mask
-		# select out the neighbors of each node
-		neighbors = th.index_select(msg, 0, adj_mat.view(-1)) # [node_num * max_neighbor, embed_size]
-		neighbors = neighbors.view(node_num, max_neighbor, -1)
-		# weighted sum of the neighbors' representations
-		neighbors = weight.unsqueeze(2) * neighbors # [node_num, max_neighbor, embed_size]
-		combined_msg = th.sum(neighbors, dim=1)  # [node_num, embed_size]
-		return combined_msg
-
-	def get_combined_msg(self, step, node_repr, adj_mat, weight, mask):
-		"""
-		perform message passing in the tangent space of x'
-		"""
-		# use the first layer only if tying weights
-		gnn_layer = 0 if self.args.tie_weight else step
-		combined_msg = None
-		for relation in range(0, self.type_of_msg):
-			layer_weight = self.retrieve_params(getattr(self, "msg_%d_weight" % relation), gnn_layer)
-			aggregated_msg = self.aggregate_msg(node_repr,
-												adj_mat[relation],
-												weight[relation],
-												layer_weight, mask)
-			combined_msg = aggregated_msg if combined_msg is None else (combined_msg + aggregated_msg)
-		return combined_msg
-
-	def forward(self, node_repr, adj_list, weight, mask):
-		adj_list, weight = self.split_input(adj_list, weight)
-		for step in range(self.args.num_layers):
-			node_repr = self.manifold.log_map_zero(node_repr) * mask if step > 0 else node_repr * mask
-			combined_msg = self.get_combined_msg(step, node_repr, adj_list, weight, mask)
-			combined_msg = self.dropout(combined_msg) * mask
-			node_repr = self.manifold.exp_map_zero(combined_msg) * mask
-			node_repr = self.apply_activation(node_repr) * mask
-		return node_repr
diff --git a/HGNN/gnn/__init__.py b/HGNN/gnn/__init__.py
deleted file mode 100644
index 6c53e88..0000000
--- a/HGNN/gnn/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from Ghypeddings.HGNN.gnn.RiemannianGNN import RiemannianGNN
diff --git a/HGNN/hgnn.py b/HGNN/hgnn.py
deleted file mode 100644
index d8702de..0000000
--- a/HGNN/hgnn.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from Ghypeddings.HGNN.task import *
-from Ghypeddings.HGNN.utils import *
-from Ghypeddings.HGNN.manifold import *
-from Ghypeddings.HGNN.gnn import RiemannianGNN
-
-class HGNN:
-    def __init__(self,
-                adj,
-                features,
-                labels,
-                dim,
-                c=None,
-                num_layers=2,
-                bias=True,
-                act='leaky_relu',
-                alpha=0.2,
-                select_manifold='poincare',
-                num_centroid=100,
-                eucl_vars=[],
-                hyp_vars=[],
-                grad_clip=1.0,
-                optimizer='sgd',
-                weight_decay=0.01,
-                lr=0.01,
-                lr_scheduler='cosine',
-                lr_gamma=0.5,
-                lr_hyperbolic=0.01,
-                hyper_optimizer='ramsgrad',
-                proj_init='xavier',
-                tie_weight=True,
-                epochs=50,
-                patience=100,
-                seed=42,
-                log_freq=1,
-                eval_freq=1,
-                val_prop=0.15,
-                test_prop=0.15,
-                double_precision=0,
-                dropout=0.01,
-                normalize_adj=False,
-                normalize_feats=True):
-        
-        self.args = create_args(dim,c,num_layers,bias,act,alpha,select_manifold,num_centroid,eucl_vars,hyp_vars,grad_clip,optimizer,weight_decay,lr,lr_scheduler,lr_gamma,lr_hyperbolic,hyper_optimizer,proj_init,tie_weight,epochs,patience,seed,log_freq,eval_freq,val_prop,test_prop,double_precision,dropout,normalize_adj,normalize_feats)
-        
-        set_seed(self.args.seed)
-        self.logger = create_logger()
-        if self.args.select_manifold == 'lorentz':
-                    self.args.dim += 1
-        if self.args.select_manifold == 'lorentz':
-            self.manifold= LorentzManifold(self.args, self.logger)
-        elif self.args.select_manifold == 'poincare':
-            self.manifold= PoincareManifold(self.args,self.logger)
-        rgnn = RiemannianGNN(self.args, self.logger, self.manifold)
-        self.gnn = NodeClassificationTask(self.args, self.logger, rgnn, self.manifold, adj,features,labels)
-    
-    def fit(self):
-        return self.gnn.run_gnn()
-
-    def predict(self):
-        return self.gnn.evaluate(self.gnn.loader, 'test', self.gnn.model, self.gnn.loss_function)
-
-    def save_embeddings(self):
-        labels = np.argmax(th.squeeze(self.gnn.labels).numpy(),axis=1)
-        #tb_embeddings_euc = self.gnn.manifold.log_map_zero(self.gnn.early_stop.best_emb)
-        for_classification_hyp = np.hstack((self.gnn.early_stop.best_emb.cpu().detach().numpy(),labels.reshape(-1,1)))
-        #for_classification_euc = np.hstack((tb_embeddings_euc.cpu().detach().numpy(),labels.reshape(-1,1)))
-        hyp_file_path = os.path.join(os.getcwd(),'hgnn_embeddings_hyp.csv')
-        #euc_file_path = os.path.join(os.getcwd(),'hgnn_embeddings_euc.csv')
-        np.savetxt(hyp_file_path, for_classification_hyp, delimiter=',')
-        #np.savetxt(euc_file_path, for_classification_euc, delimiter=',')
\ No newline at end of file
diff --git a/HGNN/hyperbolic_module/CentroidDistance.py b/HGNN/hyperbolic_module/CentroidDistance.py
deleted file mode 100644
index 9d868cb..0000000
--- a/HGNN/hyperbolic_module/CentroidDistance.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import torch as th
-import torch.nn as nn
-import torch.nn.functional as F
-from Ghypeddings.HGNN.utils import *
-
-class CentroidDistance(nn.Module):
-	"""
-	Implement a model that calculates the pairwise distances between node representations
-	and centroids
-	"""
-	def __init__(self, args, logger, manifold):
-		super(CentroidDistance, self).__init__()
-		self.args = args
-		self.logger = logger
-		self.manifold = manifold
-
-		# centroid embedding
-		self.centroid_embedding = nn.Embedding(
-			args.num_centroid, args.dim,
-			sparse=False,
-			scale_grad_by_freq=False,
-		)
-		self.manifold.init_embed(self.centroid_embedding)
-		args.hyp_vars.append(self.centroid_embedding)
-
-	def forward(self, node_repr, mask):
-		"""
-		Args:
-			node_repr: [node_num, embed_size]
-			mask: [node_num, 1] 1 denote real node, 0 padded node
-		return:
-			graph_centroid_dist: [1, num_centroid]
-			node_centroid_dist: [1, node_num, num_centroid]
-		"""
-		node_num = node_repr.size(0)
-
-		# broadcast and reshape node_repr to [node_num * num_centroid, embed_size]
-		node_repr =  node_repr.unsqueeze(1).expand(
-												-1,
-												self.args.num_centroid,
-												-1).contiguous().view(-1, self.args.dim)
-
-		# broadcast and reshape centroid embeddings to [node_num * num_centroid, embed_size]
-		centroid_repr = self.centroid_embedding(th.arange(self.args.num_centroid).cuda())
-		centroid_repr = centroid_repr.unsqueeze(0).expand(
-												node_num,
-												-1,
-												-1).contiguous().view(-1, self.args.dim)
-		# get distance
-		node_centroid_dist = self.manifold.distance(node_repr, centroid_repr)
-		node_centroid_dist = node_centroid_dist.view(1, node_num, self.args.num_centroid) * mask
-		# average pooling over nodes
-		graph_centroid_dist = th.sum(node_centroid_dist, dim=1) / th.sum(mask)
-		return graph_centroid_dist, node_centroid_dist
diff --git a/HGNN/hyperbolic_module/PoincareDistance.py b/HGNN/hyperbolic_module/PoincareDistance.py
deleted file mode 100644
index 4bc4234..0000000
--- a/HGNN/hyperbolic_module/PoincareDistance.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import torch as th
-from torch.autograd import Function
-import torch.nn as nn
-import numpy as np
-from torch.autograd import Function, Variable
-
-class PoincareDistance(Function):
-    @staticmethod
-    def grad(x, v, sqnormx, sqnormv, sqdist, eps):
-        alpha = (1 - sqnormx)
-        beta = (1 - sqnormv)
-        z = 1 + 2 * sqdist / (alpha * beta)
-        a = ((sqnormv - 2 * th.sum(x * v, dim=-1) + 1) / th.pow(alpha, 2))\
-            .unsqueeze(-1).expand_as(x)
-        a = a * x - v / alpha.unsqueeze(-1).expand_as(v)
-        z = th.sqrt(th.pow(z, 2) - 1)
-        z = th.clamp(z * beta, min=eps).unsqueeze(-1)
-        return 4 * a / z.expand_as(x)
-
-    @staticmethod
-    def forward(ctx, u, v, eps):
-        squnorm = th.clamp(th.sum(u * u, dim=-1), 0, 1 - eps)
-        sqvnorm = th.clamp(th.sum(v * v, dim=-1), 0, 1 - eps)
-        sqdist = th.sum(th.pow(u - v, 2), dim=-1)
-        ctx.eps = eps
-        ctx.save_for_backward(u, v, squnorm, sqvnorm, sqdist)
-        x = sqdist / ((1 - squnorm) * (1 - sqvnorm)) * 2 + 1
-        # arcosh
-        z = th.sqrt(th.pow(x, 2) - 1)
-        return th.log(x + z)
-
-    @staticmethod
-    def backward(ctx, g):
-        u, v, squnorm, sqvnorm, sqdist = ctx.saved_tensors
-        g = g.unsqueeze(-1)
-        gu = PoincareDistance.grad(u, v, squnorm, sqvnorm, sqdist, ctx.eps)
-        gv = PoincareDistance.grad(v, u, sqvnorm, squnorm, sqdist, ctx.eps)
-        return g.expand_as(gu) * gu, g.expand_as(gv) * gv, None
diff --git a/HGNN/hyperbolic_module/__init__.py b/HGNN/hyperbolic_module/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/HGNN/manifold/LorentzManifold.py b/HGNN/manifold/LorentzManifold.py
deleted file mode 100644
index c6e9bbc..0000000
--- a/HGNN/manifold/LorentzManifold.py
+++ /dev/null
@@ -1,165 +0,0 @@
-import torch as th
-import torch.nn as nn
-import numpy as np
-from torch.autograd import Function, Variable
-from Ghypeddings.HGNN.utils import *
-
-_eps = 1e-10
-
-class LorentzManifold:
-
-    def __init__(self, args, logger, eps=1e-3, norm_clip=1, max_norm=1e3):
-        self.args = args
-        self.logger = logger
-        self.eps = eps
-        self.norm_clip = norm_clip
-        self.max_norm = max_norm
-
-    @staticmethod
-    def ldot(u, v, keepdim=False):
-        """
-        Lorentzian Scalar Product
-        Args:
-            u: [batch_size, d + 1]
-            v: [batch_size, d + 1]
-        Return:
-            keepdim: False [batch_size]
-            keepdim: True  [batch_size, 1]
-        """
-        d = u.size(1) - 1
-        uv = u * v
-        uv = th.cat((-uv.narrow(1, 0, 1), uv.narrow(1, 1, d)), dim=1)
-        return th.sum(uv, dim=1, keepdim=keepdim)
-
-    def from_lorentz_to_poincare(self, x):
-        """
-        Args:
-            u: [batch_size, d + 1]
-        """
-        d = x.size(-1) - 1
-        return x.narrow(-1, 1, d) / (x.narrow(-1, 0, 1) + 1)
-
-    def from_poincare_to_lorentz(self, x):
-        """
-        Args:
-            u: [batch_size, d]
-        """
-        x_norm_square = th_dot(x, x)
-        return th.cat((1 + x_norm_square, 2 * x), dim=1) / (1 - x_norm_square + self.eps)
-
-    def distance(self, u, v):
-        d = -LorentzDot.apply(u, v)
-        return Acosh.apply(d, self.eps)
-
-    def normalize(self, w):
-        """
-        Normalize vector such that it is located on the hyperboloid
-        Args:
-            w: [batch_size, d + 1]
-        """
-        d = w.size(-1) - 1
-        narrowed = w.narrow(-1, 1, d)
-        if self.max_norm:
-            narrowed = th.renorm(narrowed.view(-1, d), 2, 0, self.max_norm)
-        first = 1 + th.sum(th.pow(narrowed, 2), dim=-1, keepdim=True)
-        first = th.sqrt(first)
-        return th.cat((first, narrowed), dim=1)
-
-    def init_embed(self, embed, irange=1e-2):
-        embed.weight.data.uniform_(-irange, irange)
-        embed.weight.data.copy_(self.normalize(embed.weight.data))
-
-    def rgrad(self, p, d_p):
-        """Riemannian gradient for hyperboloid"""
-        u = d_p
-        x = p
-        u.narrow(-1, 0, 1).mul_(-1)
-        u.addcmul_(self.ldot(x, u, keepdim=True).expand_as(x), x)
-        return d_p
-
-    def exp_map_zero(self, v):
-        zeros = th.zeros_like(v)
-        zeros[:, 0] = 1
-        return self.exp_map_x(zeros, v)
-
-    def exp_map_x(self, p, d_p, d_p_normalize=True, p_normalize=True):
-        if d_p_normalize:
-            d_p = self.normalize_tan(p, d_p)
-
-        ldv = self.ldot(d_p, d_p, keepdim=True)
-        nd_p = th.sqrt(th.clamp(ldv + self.eps, _eps))
-
-        t = th.clamp(nd_p, max=self.norm_clip)
-        newp = (th.cosh(t) * p) + (th.sinh(t) * d_p / nd_p)
-
-        if p_normalize:
-            newp = self.normalize(newp)
-        return newp
-
-    def normalize_tan(self, x_all, v_all):
-        d = v_all.size(1) - 1
-        x = x_all.narrow(1, 1, d)
-        xv = th.sum(x * v_all.narrow(1, 1, d), dim=1, keepdim=True)
-        tmp = 1 + th.sum(th.pow(x_all.narrow(1, 1, d), 2), dim=1, keepdim=True)
-        tmp = th.sqrt(tmp)
-        return th.cat((xv / tmp, v_all.narrow(1, 1, d)), dim=1)
-
-    def log_map_zero(self, y, i=-1):
-        zeros = th.zeros_like(y)
-        zeros[:, 0] = 1
-        return self.log_map_x(zeros, y)
-
-    def log_map_x(self, x, y, normalize=False):
-        """Logarithmic map on the Lorentz Manifold"""
-        xy = self.ldot(x, y).unsqueeze(-1)
-        tmp = th.sqrt(th.clamp(xy * xy - 1 + self.eps, _eps))
-        v = Acosh.apply(-xy, self.eps) / (
-            tmp
-        ) * th.addcmul(y, xy, x)
-        if normalize:
-            result = self.normalize_tan(x, v)
-        else:
-            result = v
-        return result
-
-    def parallel_transport(self, x, y, v):
-        """Parallel transport for hyperboloid"""
-        v_ = v
-        x_ = x
-        y_ = y
-
-        xy = self.ldot(x_, y_, keepdim=True).expand_as(x_)
-        vy = self.ldot(v_, y_, keepdim=True).expand_as(x_)
-        vnew = v_ + vy / (1 - xy) * (x_ + y_)
-        return vnew
-
-    def metric_tensor(self, x, u, v):
-        return self.ldot(u, v, keepdim=True)
-
-class LorentzDot(Function):
-    @staticmethod
-    def forward(ctx, u, v):
-        ctx.save_for_backward(u, v)
-        return LorentzManifold.ldot(u, v)
-
-    @staticmethod
-    def backward(ctx, g):
-        u, v = ctx.saved_tensors
-        g = g.unsqueeze(-1).expand_as(u).clone()
-        g.narrow(-1, 0, 1).mul_(-1)
-        return g * v, g * u
-
-class Acosh(Function):
-    @staticmethod
-    def forward(ctx, x, eps):
-        z = th.sqrt(th.clamp(x * x - 1 + eps, _eps))
-        ctx.save_for_backward(z)
-        ctx.eps = eps
-        return th.log(x + z)
-
-    @staticmethod
-    def backward(ctx, g):
-        z, = ctx.saved_tensors
-        z = th.clamp(z, min=ctx.eps)
-        z = g / z
-        return z, None
diff --git a/HGNN/manifold/PoincareManifold.py b/HGNN/manifold/PoincareManifold.py
deleted file mode 100644
index 0a3c97c..0000000
--- a/HGNN/manifold/PoincareManifold.py
+++ /dev/null
@@ -1,112 +0,0 @@
-import torch as th
-import torch.nn as nn
-import numpy as np
-from torch.autograd import Function, Variable
-from Ghypeddings.HGNN.hyperbolic_module.PoincareDistance import PoincareDistance
-from Ghypeddings.HGNN.utils import *
-
-class PoincareManifold:
-
-    def __init__(self, args, logger, EPS=1e-5, PROJ_EPS=1e-5):
-        self.args = args
-        self.logger = logger
-        self.EPS = EPS
-        self.PROJ_EPS = PROJ_EPS
-        self.tanh = nn.Tanh()
-
-    def normalize(self, x):
-        return clip_by_norm(x, (1. - self.PROJ_EPS))
-
-    def init_embed(self, embed, irange=1e-2):
-        embed.weight.data.uniform_(-irange, irange)
-        embed.weight.data.copy_(self.normalize(embed.weight.data))
-
-    def mob_add(self, u, v):
-        """
-        Add two vectors in hyperbolic space
-        """
-        v = v + self.EPS
-        th_dot_u_v = 2. * th_dot(u, v)
-        th_norm_u_sq = th_dot(u, u)
-        th_norm_v_sq = th_dot(v, v)
-        denominator = 1. + th_dot_u_v + th_norm_v_sq * th_norm_u_sq
-        result = (1. + th_dot_u_v + th_norm_v_sq) / (denominator + self.EPS) * u + \
-                 (1. - th_norm_u_sq) / (denominator + self.EPS) * v
-        return self.normalize(result)
-
-    def distance(self, u, v):
-        return PoincareDistance.apply(u, v, 1e-5)
-
-    def lambda_x(self, x):
-        """
-        A conformal factor
-        """
-        return 2. / (1 - th_dot(x, x))
-
-    def log_map_zero(self, y):
-        diff = y + self.EPS
-        norm_diff = th_norm(diff)
-        return 1. / th_atanh(norm_diff, self.EPS) / norm_diff * diff
-
-    def log_map_x(self, x, y):
-        diff = self.mob_add(-x, y) + self.EPS
-        norm_diff = th_norm(diff)
-        lam = self.lambda_x(x)
-        return (( 2. / lam) * th_atanh(norm_diff, self.EPS) / norm_diff) * diff
-
-    def metric_tensor(self, x, u, v):
-        """
-        The metric tensor in hyperbolic space.
-        In-place operations for saving memory. (do not use this function in forward calls)
-        """
-        u_dot_v = th_dot(u, v)
-        lambda_x = self.lambda_x(x)
-        lambda_x *= lambda_x
-        lambda_x *= u_dot_v
-        return lambda_x
-
-    def exp_map_zero(self, v):
-        """
-        Exp map from tangent space of zero to hyperbolic space
-        Args:
-            v: [batch_size, *] in tangent space
-        """
-        v = v + self.EPS
-        norm_v = th_norm(v) # [batch_size, 1]
-        result = self.tanh(norm_v) / (norm_v) * v
-        return self.normalize(result)
-
-    def exp_map_x(self, x, v):
-        """
-        Exp map from tangent space of x to hyperbolic space
-        """
-        v = v + self.EPS # Perturbe v to avoid dealing with v = 0
-        norm_v = th_norm(v)
-        second_term = (self.tanh(self.lambda_x(x) * norm_v / 2) / norm_v) * v
-        return self.normalize(self.mob_add(x, second_term))
-
-    def gyr(self, u, v, w):
-        u_norm = th_dot(u, u)
-        v_norm = th_dot(v, v)
-        u_dot_w = th_dot(u, w)
-        v_dot_w = th_dot(v, w)
-        u_dot_v = th_dot(u, v)
-        A = - u_dot_w * v_norm + v_dot_w + 2 * u_dot_v * v_dot_w
-        B = - v_dot_w * u_norm - u_dot_w
-        D = 1 + 2 * u_dot_v + u_norm * v_norm
-        return w + 2 * (A * u + B * v) / (D + self.EPS)
-
-    def parallel_transport(self, src, dst, v):
-        return self.lambda_x(src) / th.clamp(self.lambda_x(dst), min=self.EPS) * self.gyr(dst, -src, v)
-
-    def rgrad(self, p, d_p):
-        """
-        Function to compute Riemannian gradient from the
-        Euclidean gradient in the Poincare ball.
-        Args:
-            p (Tensor): Current point in the ball
-            d_p (Tensor): Euclidean gradient at p
-        """
-        p_sqnorm = th.sum(p.data ** 2, dim=-1, keepdim=True)
-        d_p = d_p * ((1 - p_sqnorm) ** 2 / 4.0).expand_as(d_p)
-        return d_p
diff --git a/HGNN/manifold/__init__.py b/HGNN/manifold/__init__.py
deleted file mode 100644
index ada909b..0000000
--- a/HGNN/manifold/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from Ghypeddings.HGNN.manifold.PoincareManifold import *
-from Ghypeddings.HGNN.manifold.LorentzManifold import *
diff --git a/HGNN/optimizer/__init__.py b/HGNN/optimizer/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/HGNN/optimizer/ramsgrad.py b/HGNN/optimizer/ramsgrad.py
deleted file mode 100644
index c51d3d7..0000000
--- a/HGNN/optimizer/ramsgrad.py
+++ /dev/null
@@ -1,74 +0,0 @@
-"""
-Implement a AMSGrad: https://openreview.net/pdf?id=r1eiqi09K7
-"""
-import torch as th
-from torch.optim.optimizer import Optimizer, required
-import os
-import math
-import numpy as np
-
-class RiemannianAMSGrad(Optimizer):
-    """
-    Riemannian AMS gradient descent.
-    Args:
-        params (iterable): iterable of parameters to optimize or dicts defining
-            parameter groups
-        lr (float): learning rate
-    """
-
-    def __init__(self, args, manifold,params, lr, betas=(0.9, 0.99), eps=1e-8):
-        self.args = args
-        self.manifold = manifold
-        defaults = dict(lr=lr, betas=betas, eps=eps)
-        super(RiemannianAMSGrad, self).__init__(params, defaults)
-
-    def step(self, lr=None):
-        """Performs a single optimization step.
-        Arguments:
-            lr (float, optional): learning rate for the current update.
-        """
-        loss = None
-        with th.no_grad():
-            for group in self.param_groups:
-                for p in group['params']:
-                    if p.grad is None:
-                        continue
-                    grad = p.grad.data
-                    grad = self.manifold.rgrad(p, grad)
-                    if lr is None:
-                        lr = group['lr']
-
-                    state = self.state[p]
-
-                    # State initialization
-                    if len(state) == 0:
-                        state['step'] = 0
-                        state['tau'] = th.zeros_like(p.data)
-                        # Exponential moving average of gradient values
-                        state['exp_avg'] = th.zeros_like(p.data)
-                        # Exponential moving average of squared gradient values
-                        state['exp_avg_sq'] = th.zeros_like(p.data)
-                        # Maintains max of all exp. moving avg. of sq. grad. values
-                        state['max_exp_avg_sq'] = th.zeros_like(p.data)
-
-                    exp_avg, exp_avg_sq, tau, max_exp_avg_sq = \
-                    			state['exp_avg'], state['exp_avg_sq'], state['tau'], state['max_exp_avg_sq']
-
-                    beta1, beta2 = group['betas']
-
-                    state['step'] += 1
-
-                    # Decay the first and second moment running average coefficient
-                    exp_avg.data = beta1 * tau + (1 - beta1) * grad
-                    exp_avg_sq.mul_(beta2).add_(1 - beta2, self.manifold.metric_tensor(p, grad, grad))
-                    th.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq)
-                    # Use the max. for normalizing running avg. of gradient
-                    denom = max_exp_avg_sq.sqrt().clamp_(min=group['eps'])
-
-                    step_size = group['lr']
-
-                    p_original = p.clone()
-                    before_proj = self.manifold.exp_map_x(p, (-step_size * exp_avg).div_(denom))
-                    p.data = self.manifold.normalize(before_proj)
-                    tau.data = self.manifold.parallel_transport(p_original, p, exp_avg)
-            return loss
diff --git a/HGNN/optimizer/rsgd.py b/HGNN/optimizer/rsgd.py
deleted file mode 100644
index 14da1fe..0000000
--- a/HGNN/optimizer/rsgd.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import torch as th
-from torch.optim.optimizer import Optimizer, required
-from Ghypeddings.HGNN.utils import *
-import os
-import math
-
-class RiemannianSGD(Optimizer):
-    """Riemannian stochastic gradient descent.
-    Args:
-        params (iterable): iterable of parameters to optimize or dicts defining
-            parameter groups
-        rgrad (Function): Function to compute the Riemannian gradient from
-            an Euclidean gradient
-        retraction (Function): Function to update the parameters via a
-            retraction of the Riemannian gradient
-        lr (float): learning rate
-    """
-
-    def __init__(self, args, params, lr):
-        defaults = dict(lr=lr)
-        self.args = args
-        super(RiemannianSGD, self).__init__(params, defaults)
-
-    def step(self, lr=None):
-        """
-        Performs a single optimization step.
-        Arguments:
-            lr (float, optional): learning rate for the current update.
-        """
-        loss = None
-
-        for group in self.param_groups:
-            for p in group['params']:
-                if p.grad is None:
-                    continue
-                d_p = p.grad.data
-                d_p = self.args.manifold.rgrad(p, d_p)
-                if lr is None:
-                    lr = group['lr']
-                p.data = self.args.manifold.normalize(
-                            self.args.manifold.exp_map_x(p, -lr * d_p)
-                         )
-        return loss
diff --git a/HGNN/task/BaseTask.py b/HGNN/task/BaseTask.py
deleted file mode 100644
index 2486800..0000000
--- a/HGNN/task/BaseTask.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import numpy as np
-from Ghypeddings.HGNN.utils import *
-import torch as th
-import torch.nn as nn
-from torch.utils.data import Dataset, DataLoader
-import torch.optim as optim
-import torch.distributed as dist
-from torch.utils.data.distributed import DistributedSampler
-
-class BaseTask(object):
-	"""
-	A base class that supports loading datasets, early stop and reporting statistics
-	"""
-	def __init__(self, args, logger, criterion='max'):
-		"""
-		criterion: min/max
-		"""
-		self.args = args
-		self.logger = logger
-		self.early_stop = EarlyStoppingCriterion(self.args.patience, criterion)
-
-	def reset_epoch_stats(self, epoch, prefix):
-		"""
-		prefix: train/dev/test
-		"""
-		self.epoch_stats = {
-			'prefix': prefix,
-			'epoch': epoch,
-			'loss': 0,
-			'num_correct': 0,
-			'num_total': 0,
-		}
-
-	def update_epoch_stats(self, loss, score, label, is_regression=False):
-		with th.no_grad():
-			self.epoch_stats['loss'] += loss.item()
-			self.epoch_stats['num_total'] += label.size(0)
-			if not is_regression:
-				self.epoch_stats['num_correct'] += th.sum(th.eq(th.argmax(score, dim=1), label)).item()
-	
-	def report_best(self):
-		self.logger.info("best val %.6f" 
-			% (self.early_stop.best_dev_score))
diff --git a/HGNN/task/NodeClassification.py b/HGNN/task/NodeClassification.py
deleted file mode 100644
index 9ef8150..0000000
--- a/HGNN/task/NodeClassification.py
+++ /dev/null
@@ -1,44 +0,0 @@
-import torch as th
-import torch.nn as nn
-import torch.nn.functional as F
-from Ghypeddings.HGNN.utils import * 
-from Ghypeddings.HGNN.hyperbolic_module.CentroidDistance import CentroidDistance
-
-class NodeClassification(nn.Module):
-
-	def __init__(self, args, logger, rgnn, manifold):
-		super(NodeClassification, self).__init__()
-		self.args = args
-		self.logger = logger
-		self.manifold = manifold
-		self.c = nn.Parameter(th.Tensor([1.]))
-
-		self.feature_linear = nn.Linear(self.args.input_dim,
-										self.args.dim
-							  )
-		nn_init(self.feature_linear, self.args.proj_init)
-		self.args.eucl_vars.append(self.feature_linear)			
-
-		self.distance = CentroidDistance(args, logger, manifold)
-
-		self.rgnn = rgnn
-		self.output_linear = nn.Linear(self.args.num_centroid,
-										self.args.num_class
-							  )
-		nn_init(self.output_linear, self.args.proj_init)
-		self.args.eucl_vars.append(self.output_linear)
-
-		self.log_softmax = nn.LogSoftmax(dim=1)
-		self.activation = get_activation(self.args)
-
-	def forward(self, adj, weight, features):
-
-		adj, weight, features = adj.squeeze(0), weight.squeeze(0), features.squeeze(0)
-		node_repr = self.activation(self.feature_linear(features))
-		assert th.isnan(node_repr).any().item() == False
-		mask = th.ones((self.args.node_num, 1)).cuda() # [node_num, 1]
-		node_repr = self.rgnn(node_repr, adj, weight, mask) # [node_num, embed_size]
-
-		_, node_centroid_sim = self.distance(node_repr, mask) # [1, node_num, num_centroid]
-		class_logit = self.output_linear(node_centroid_sim.squeeze())
-		return self.log_softmax(class_logit) , node_repr
\ No newline at end of file
diff --git a/HGNN/task/NodeClassificationTask.py b/HGNN/task/NodeClassificationTask.py
deleted file mode 100644
index 7eeca46..0000000
--- a/HGNN/task/NodeClassificationTask.py
+++ /dev/null
@@ -1,137 +0,0 @@
-import torch as th
-import torch.nn as nn
-import torch.nn.functional as F
-from Ghypeddings.HGNN.utils import * 
-from torch.utils.data import DataLoader
-import torch.optim as optim
-from Ghypeddings.HGNN.task.BaseTask import BaseTask
-import numpy as np
-from Ghypeddings.HGNN.dataset.NodeClassificationDataset import NodeClassificationDataset
-from Ghypeddings.HGNN.task.NodeClassification import NodeClassification
-import time
-from sklearn.metrics import roc_auc_score,accuracy_score,f1_score,precision_score,recall_score
-
-def cross_entropy(log_prob, label, mask):
-	label, mask = label.squeeze(), mask.squeeze()
-	negative_log_prob = -th.sum(label * log_prob, dim=1)
-	return th.sum(mask * negative_log_prob, dim=0) / th.sum(mask)
-
-def get_accuracy(label, log_prob, mask):
-	lab = label.clone()
-	lab = lab.squeeze()
-	mask_copy = mask.clone().cpu().numpy()[0].astype(np.bool_)
-	pred_class = th.argmax(log_prob, dim=1).cpu().numpy()[mask_copy]
-	real_class = th.argmax(lab, dim=1).cpu().numpy()[mask_copy]
-	acc= accuracy_score(y_true=real_class,y_pred=pred_class)
-	f1= f1_score(y_true=real_class,y_pred=pred_class)
-	recall= recall_score(y_true=real_class,y_pred=pred_class)
-	precision= precision_score(y_true=real_class,y_pred=pred_class)
-	print(np.sum(real_class) , np.sum(pred_class))
-	roc_auc = roc_auc_score(real_class,pred_class)	
-	return acc,f1,recall,precision,roc_auc
-
-class NodeClassificationTask(BaseTask):
-
-	def __init__(self, args, logger, rgnn, manifold,adj,features,labels):
-		super(NodeClassificationTask, self).__init__(args, logger, criterion='max')
-		self.args = args
-		self.logger = logger
-		self.manifold = manifold
-		self.hyperbolic = True
-		self.rgnn = rgnn
-		self.loader = self.process_data(adj,features,labels)
-		self.model = NodeClassification(self.args, self.logger, self.rgnn, self.manifold).cuda()
-		self.loss_function = cross_entropy
-
-	def forward(self, model, sample, loss_function):
-		scores , embeddings = model(
-					sample['adj'].cuda().long(),
-			        sample['weight'].cuda().float(),
-			        sample['features'].cuda().float(),
-					)
-		loss = loss_function(scores,
-						 sample['y_train'].cuda().float(), 
-						 sample['train_mask'].cuda().float())
-		return scores, loss , embeddings
-
-	def run_gnn(self):
-		loader = self.loader
-		model = self.model
-		loss_function = self.loss_function
-		
-		self.args.manifold = self.manifold
-		optimizer, lr_scheduler, hyperbolic_optimizer, hyperbolic_lr_scheduler = \
-								set_up_optimizer_scheduler(self.hyperbolic, self.args, model,self.manifold)
-		self.labels = None
-		
-		best_losses = []
-		train_losses = []
-		val_losses = []
-
-		t_total = time.time()
-		for epoch in range(self.args.epochs):
-			model.train()
-			for i, sample in enumerate(loader):
-				model.zero_grad()
-				scores, loss , embeddings = self.forward(model, sample, loss_function)
-				loss.backward()
-				if self.args.grad_clip > 0.0:
-					th.nn.utils.clip_grad_norm_(model.parameters(), self.args.grad_clip)
-				optimizer.step()
-				if self.hyperbolic and len(self.args.hyp_vars) != 0:
-					hyperbolic_optimizer.step()
-				self.labels = sample['y_train']
-				accuracy,f1,recall,precision,roc_auc = get_accuracy(
-									sample['y_train'].cuda().float(), 
-									scores, 
-									sample['train_mask'].cuda().float())
-			
-				train_losses.append(loss.item())
-				if(len(best_losses) == 0):
-					best_losses.append(train_losses[0])
-				elif (best_losses[-1] > train_losses[-1]):
-					best_losses.append(train_losses[-1])
-				else:
-					best_losses.append(best_losses[-1])
-
-				if (epoch + 1) % self.args.log_freq == 0:
-					self.logger.info("%s epoch %d: accuracy %.4f f1 %.4f recall %.4f precision %.4f roc_auc %.4f loss: %.4f \n" % (
-						'train', 
-						epoch, 
-						accuracy,f1,recall,precision,roc_auc,loss.item()))
-					
-				dev_loss, accuracy ,f1,recall,precision,roc_auc  = self.evaluate(loader, 'val', model, loss_function)
-				val_losses.append(dev_loss)
-				lr_scheduler.step()
-
-				if self.hyperbolic and len(self.args.hyp_vars) != 0:
-					hyperbolic_lr_scheduler.step()
-				if not self.early_stop.step(dev_loss, epoch , embeddings):		
-					break
-
-		self.logger.info("Training Finished!")
-		self.logger.info("Total time elapsed: {:.4f}s".format(time.time() - t_total))
-
-		return {'train':train_losses,'best':best_losses,'val':val_losses}, accuracy,f1,recall,precision,roc_auc,time.time() - t_total
-			
-	def evaluate(self, data_loader, prefix, model, loss_function):
-		model.eval()
-		with th.no_grad():
-			for i, sample in enumerate(data_loader):
-				scores, loss , _ = self.forward(model, sample, loss_function)
-				if prefix == 'val':
-					accuracy,f1,recall,precision,roc_auc = get_accuracy(
-									sample['y_val'].cuda().float(), 
-									scores, 
-									sample['val_mask'].cuda().float())
-				elif prefix == 'test':
-					accuracy,f1,recall,precision,roc_auc = get_accuracy(
-									sample['y_test'].cuda().float(), 
-									scores, 
-									sample['test_mask'].cuda().float())
-				
-		return loss.item(), accuracy,f1,recall,precision,roc_auc
-
-	def process_data(self,adj,features,labels):
-		dataset = NodeClassificationDataset(self.args, self.logger,adj,features,labels)
-		return DataLoader(dataset, batch_size=1, shuffle=False, num_workers=0)
diff --git a/HGNN/task/__init__.py b/HGNN/task/__init__.py
deleted file mode 100644
index e4bd573..0000000
--- a/HGNN/task/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from Ghypeddings.HGNN.task.NodeClassificationTask import *
\ No newline at end of file
diff --git a/HGNN/utils/EarlyStoppingCriterion.py b/HGNN/utils/EarlyStoppingCriterion.py
deleted file mode 100644
index 7e57381..0000000
--- a/HGNN/utils/EarlyStoppingCriterion.py
+++ /dev/null
@@ -1,51 +0,0 @@
-class EarlyStoppingCriterion(object):
-    """
-    Arguments:
-        patience (int): The maximum number of epochs with no improvement before early stopping should take place
-        mode (str, can only be 'max' or 'min'): To take the maximum or minimum of the score for optimization
-        min_delta (float, optional): Minimum change in the score to qualify as an improvement (default: 0.0)
-    """
-
-    def __init__(self, patience, mode, min_delta=0.0):
-        assert patience >= 0
-        assert mode in {'min', 'max'}
-        assert min_delta >= 0.0
-        self.patience = patience
-        self.mode = mode
-        self.min_delta = min_delta
-
-        self._count = 0
-        self.best_dev_score = None
-        self.best_epoch = None
-        self.is_improved = None
-        self.best_emb = None
-
-    def step(self, cur_dev_score, epoch , embeddings):
-        """
-        Checks if training should be continued given the current score.
-
-        Arguments:
-            cur_dev_score (float): the current development score
-            cur_test_score (float): the current test score
-        Output:
-            bool: if training should be continued
-        """
-        if self.best_dev_score is None:
-            self.best_dev_score = cur_dev_score
-            self.best_epoch = epoch
-            self.best_emb = embeddings
-            return True
-        else:
-            if self.mode == 'max':
-                self.is_improved = (cur_dev_score > self.best_dev_score + self.min_delta)
-            else:
-                self.is_improved = (cur_dev_score < self.best_dev_score - self.min_delta)
-
-            if self.is_improved:
-                self._count = 0
-                self.best_dev_score = cur_dev_score
-                self.best_epoch = epoch
-                self.best_emb = embeddings
-            else:
-                self._count += 1
-            return self._count <= self.patience
diff --git a/HGNN/utils/__init__.py b/HGNN/utils/__init__.py
deleted file mode 100644
index b3da1a9..0000000
--- a/HGNN/utils/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from Ghypeddings.HGNN.utils.utils import *
-from Ghypeddings.HGNN.utils.EarlyStoppingCriterion import EarlyStoppingCriterion
-from Ghypeddings.HGNN.utils.logger import *
diff --git a/HGNN/utils/logger.py b/HGNN/utils/logger.py
deleted file mode 100644
index 6f55e77..0000000
--- a/HGNN/utils/logger.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import logging
-import time
-from datetime import timedelta
-from Ghypeddings.HGNN.utils import make_dir
-
-class LogFormatter():
-
-    def __init__(self):
-        self.start_time = time.time()
-
-    def format(self, record):
-        elapsed_seconds = round(record.created - self.start_time)
-
-        prefix = "%s - %s - %s" % (
-            record.levelname,
-            time.strftime('%x %X'),
-            timedelta(seconds=elapsed_seconds)
-        )
-        message = record.getMessage()
-        message = message.replace('\n', '\n' + ' ' * (len(prefix) + 3))
-        return "%s - %s" % (prefix, message)
-
-def create_logger():
-    """
-    Create a logger.
-    """
-    #make_dir('log')
-    # create log formatter
-    log_formatter = LogFormatter()
-
-    # create file handler and set level to debug
-    # file_handler = logging.FileHandler(filepath, "a")
-    # file_handler.setLevel(logging.DEBUG)
-    # file_handler.setFormatter(log_formatter)
-
-    # create console handler and set level to info
-    console_handler = logging.StreamHandler()
-    console_handler.setLevel(logging.INFO)
-    console_handler.setFormatter(log_formatter)
-
-    # create logger and set level to debug
-    logger = logging.getLogger()
-    logger.handlers = []
-    logger.setLevel(logging.DEBUG)
-    logger.propagate = False
-    #logger.addHandler(file_handler)
-    logger.addHandler(console_handler)
-
-    # reset logger elapsed time
-    def reset_time():
-        log_formatter.start_time = time.time()
-    logger.reset_time = reset_time
-
-    return logger
diff --git a/HGNN/utils/utils.py b/HGNN/utils/utils.py
deleted file mode 100644
index cae6a57..0000000
--- a/HGNN/utils/utils.py
+++ /dev/null
@@ -1,284 +0,0 @@
-from collections import defaultdict
-import os
-import pickle
-import json
-import torch.nn as nn
-import torch as th
-import torch.optim as optim
-import numpy as np
-import random
-from Ghypeddings.HGNN.optimizer.ramsgrad import RiemannianAMSGrad
-from Ghypeddings.HGNN.optimizer.rsgd import RiemannianSGD
-import math
-import subprocess
-import argparse
-
-def str2bool(v):
-    return v.lower() == "true"
-
-def make_dir(path):
-    if not os.path.exists(path):
-        try:
-            os.mkdir(path)
-        except:
-            pass
-
-def pickle_dump(file_name, content):
-    with open(file_name, 'wb') as out_file:        
-        pickle.dump(content, out_file, pickle.HIGHEST_PROTOCOL)
-        
-def pickle_load(file_name):
-    with open(file_name, 'rb') as f:
-        return pickle.load(f)
-
-def init_weight(weight, method):
-    """
-    Initialize parameters
-    Args:
-        weight: a Parameter object
-        method: initialization method 
-    """
-    if method == 'orthogonal':
-        nn.init.orthogonal_(weight)
-    elif method == 'xavier':
-        nn.init.xavier_uniform_(weight)
-    elif method == 'kaiming':
-        nn.init.kaiming_uniform_(weight)
-    elif method == 'none':
-        pass
-    else:
-        raise Exception('Unknown init method')
-
-
-def nn_init(nn_module, method='orthogonal'):
-    """
-    Initialize a Sequential or Module object
-    Args:
-        nn_module: Sequential or Module
-        method: initialization method
-    """
-    if method == 'none':
-        return
-    for param_name, _ in nn_module.named_parameters():
-        if isinstance(nn_module, nn.Sequential):
-            # for a Sequential object, the param_name contains both id and param name
-            i, name = param_name.split('.', 1)
-            param = getattr(nn_module[int(i)], name)
-        else:
-            param = getattr(nn_module, param_name)
-        if param_name.find('weight') > -1:
-            init_weight(param, method)
-        elif param_name.find('bias') > -1:
-            nn.init.uniform_(param, -1e-4, 1e-4)
-
-class NoneScheduler:
-	def step(self):
-		pass
-
-def get_lr_scheduler(args, optimizer):
-	if args.lr_scheduler == 'exponential':
-		return optim.lr_scheduler.ExponentialLR(optimizer, gamma=args.lr_gamma)
-	elif args.lr_scheduler == 'cosine':
-		return optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=30, eta_min=0)
-	elif args.lr_scheduler == 'cycle':
-		return optim.lr_scheduler.CyclicLR(optimizer, 0, max_lr=args.lr, step_size_up=20, cycle_momentum=False)
-	elif args.lr_scheduler == 'none':
-		return NoneScheduler()
-
-def get_optimizer(args, params):
-	if args.optimizer == 'sgd':
-		optimizer = optim.SGD(params, lr=args.lr, weight_decay=args.weight_decay)
-	elif args.optimizer == 'adam':
-		optimizer = optim.Adam(params, lr=args.lr, weight_decay=args.weight_decay)
-	elif args.optimizer == 'amsgrad':
-		optimizer = optim.Adam(params, lr=args.lr, amsgrad=True, weight_decay=args.weight_decay)
-	return optimizer
-
-def get_hyperbolic_optimizer(args, manifold,params):
-    if args.hyper_optimizer == 'rsgd':
-        optimizer = RiemannianSGD(
-            args,
-            params,
-            lr=args.lr_hyperbolic,
-        )
-    elif args.hyper_optimizer == 'ramsgrad':
-        optimizer = RiemannianAMSGrad(
-            args,
-			manifold,
-            params,
-            lr=args.lr_hyperbolic,
-        )
-    else:
-        print("unsupported hyper optimizer")
-        exit(1)        
-    return optimizer
-
-def set_seed(seed):
-    """
-    Set the random seed
-    """
-    random.seed(seed)
-    np.random.seed(seed)
-    th.manual_seed(seed)
-    th.cuda.manual_seed(seed)
-    th.cuda.manual_seed_all(seed)
-
-def pad_sequence(data_list, maxlen, value=0):
-	return [row + [value] * (maxlen - len(row)) for row in data_list]
-
-def normalize_weight(adj_mat, weight):
-	degree = [1 / math.sqrt(sum(np.abs(w))) for w in weight]
-	for dst in range(len(adj_mat)):
-		for src_idx in range(len(adj_mat[dst])):
-			src = adj_mat[dst][src_idx]
-			weight[dst][src_idx] = degree[dst] * weight[dst][src_idx] * degree[src]
-
-def set_up_distributed_training_multi_gpu(args): 
-    #args.device_id = args.local_rank
-    args.device_id = 0
-    th.cuda.set_device(args.device_id)
-    args.distributed_rank = args.device_id
-    th.distributed.init_process_group(backend='nccl',
-                                         init_method='env://')
-
-def save_model_weights(args, model, path):
-	"""
-	save model weights out to file
-	"""
-	if args.distributed_rank == 0:
-		make_dir(path)
-		th.save(model.state_dict(), os.path.join(path, args.name))
-
-def load_model_weights(model, path):
-	"""
-	load saved weights
-	"""
-	model.load_state_dict(th.load(path))
-
-def th_atanh(x, EPS):
-	values = th.min(x, th.Tensor([1.0 - EPS]).cuda())
-	return 0.5 * (th.log(1 + values + EPS) - th.log(1 - values + EPS))
-	
-def th_norm(x, dim=1):
-	"""
-	Args
-		x: [batch size, dim]
-	Output:	
-		[batch size, 1]
-	"""
-	if(len(x.shape) == 1):
-		x = x.unsqueeze(0)
-	return th.norm(x, 2, dim, keepdim=True)
-
-def th_dot(x, y, keepdim=True):
-	tmp = x*y
-	if(len(tmp.shape) == 1):
-		tmp = tmp.unsqueeze(0) 
-	return th.sum(tmp, dim=1, keepdim=keepdim)
-
-def clip_by_norm(x, clip_norm):
-	return th.renorm(x, 2, 0, clip_norm)
-
-def get_params(params_list, vars_list):
-	"""
-	Add parameters in vars_list to param_list
-	"""
-	for i in vars_list:
-		if issubclass(i.__class__, nn.Module):
-			params_list.extend(list(i.parameters()))
-		elif issubclass(i.__class__, nn.Parameter):
-			params_list.append(i)
-		else:
-			print("Encounter unknown objects")
-			exit(1)
-
-def categorize_params(args):
-	"""
-	Categorize parameters into hyperbolic ones and euclidean ones
-	"""
-	hyperbolic_params, euclidean_params = [], []
-	get_params(euclidean_params, args.eucl_vars)
-	get_params(hyperbolic_params, args.hyp_vars)
-	return hyperbolic_params, euclidean_params
-
-def get_activation(args):
-	if args.act == 'leaky_relu':
-		return nn.LeakyReLU(args.alpha)
-	elif args.act == 'rrelu':
-		return nn.RReLU()
-	elif args.act == 'relu':
-		return nn.ReLU()
-	elif args.act == 'elu':
-		return nn.ELU()
-	elif args.act == 'prelu':
-		return nn.PReLU()
-	elif args.act == 'selu':
-		return nn.SELU()
-
-def set_up_optimizer_scheduler(hyperbolic, args, model , manifold):
-	if hyperbolic:
-		hyperbolic_params, euclidean_params = categorize_params(args)
-		#assert(len(list(model.parameters())) == len(hyperbolic_params) + len(euclidean_params))
-		optimizer = get_optimizer(args, euclidean_params)
-		lr_scheduler = get_lr_scheduler(args, optimizer)
-		if len(hyperbolic_params) > 0:
-			hyperbolic_optimizer = get_hyperbolic_optimizer(args,manifold, hyperbolic_params)
-			hyperbolic_lr_scheduler = get_lr_scheduler(args, hyperbolic_optimizer)
-		else:
-			hyperbolic_optimizer, hyperbolic_lr_scheduler = None, None
-		return optimizer, lr_scheduler, hyperbolic_optimizer, hyperbolic_lr_scheduler
-	else:
-		optimizer = get_optimizer(args, model.parameters())
-		lr_scheduler = get_lr_scheduler(args, optimizer)
-		return optimizer, lr_scheduler, None, None
-
-# reimplement clamp functions to avoid killing gradient during backpropagation
-def clamp_max(x, max_value):
-	t = th.clamp(max_value - x.detach(), max=0)
-	return x + t
-
-def clamp_min(x, min_value):
-	t = th.clamp(min_value - x.detach(), min=0)
-	return x + t
-
-def one_hot_vec(length, pos):
-	vec = [0] * length
-	vec[pos] = 1
-	return vec
-
-
-def create_args(*args):
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--dim', type=int, default=args[0])
-    parser.add_argument('--c', type=int, default=args[1])
-    parser.add_argument('--num_layers', type=int, default=args[2])
-    parser.add_argument('--bias', type=bool, default=args[3])
-    parser.add_argument('--act', type=str, default=args[4])
-    parser.add_argument('--alpha', type=float, default=args[5])
-    parser.add_argument('--select_manifold', type=str, default=args[6])
-    parser.add_argument('--num_centroid', type=int, default=args[7])
-    parser.add_argument('--eucl_vars', nargs='+', default=args[8])
-    parser.add_argument('--hyp_vars', nargs='+', default=args[9])
-    parser.add_argument('--grad_clip', type=float, default=args[10])
-    parser.add_argument('--optimizer', type=str, default=args[11])
-    parser.add_argument('--weight_decay', type=float, default=args[12])
-    parser.add_argument('--lr', type=float, default=args[13])
-    parser.add_argument('--lr_scheduler', type=str, default=args[14])
-    parser.add_argument('--lr_gamma', type=float, default=args[15])
-    parser.add_argument('--lr_hyperbolic', type=float, default=args[16])
-    parser.add_argument('--hyper_optimizer', type=str, default=args[17])
-    parser.add_argument('--proj_init', type=str, default=args[18])
-    parser.add_argument('--tie_weight', type=bool, default=args[19])
-    parser.add_argument('--epochs', type=int, default=args[20])
-    parser.add_argument('--patience', type=int, default=args[21])
-    parser.add_argument('--seed', type=int, default=args[22])
-    parser.add_argument('--log_freq', type=int, default=args[23])
-    parser.add_argument('--eval_freq', type=int, default=args[24])
-    parser.add_argument('--val_prop', type=float, default=args[25])
-    parser.add_argument('--test_prop', type=float, default=args[26])
-    parser.add_argument('--double_precision', type=int, default=args[27])
-    parser.add_argument('--dropout', type=float, default=args[28])
-    parser.add_argument('--normalize_adj', type=bool, default=args[29])
-    parser.add_argument('--normalize_feats', type=bool, default=args[30])
-    flags, unknown = parser.parse_known_args()
-    return flags
\ No newline at end of file
diff --git a/PVAE/__init__.py b/PVAE/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/PVAE/distributions/__init__.py b/PVAE/distributions/__init__.py
deleted file mode 100644
index 360ae4e..0000000
--- a/PVAE/distributions/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from Ghypeddings.PVAE.distributions.riemannian_normal import RiemannianNormal
-from Ghypeddings.PVAE.distributions.hyperbolic_radius import HyperbolicRadius
-from Ghypeddings.PVAE.distributions.wrapped_normal import WrappedNormal
-from Ghypeddings.PVAE.distributions.hyperspherical_uniform import HypersphericalUniform
diff --git a/PVAE/distributions/ars.py b/PVAE/distributions/ars.py
deleted file mode 100644
index cdd7e72..0000000
--- a/PVAE/distributions/ars.py
+++ /dev/null
@@ -1,135 +0,0 @@
-import torch
-
-infty = torch.tensor(float('Inf'))
-
-def diff(x):
-    return x[:, 1:] - x[:, :-1]
-
-class ARS():
-    '''
-    This class implements the Adaptive Rejection Sampling technique of Gilks and Wild '92.
-    Where possible, naming convention has been borrowed from this paper.
-    The PDF must be log-concave.
-    Currently does not exploit lower hull described in paper- which is fine for drawing
-    only small amount of samples at a time.
-    '''
-
-    def __init__(self, logpdf, grad_logpdf, device, xi, lb=-infty, ub=infty, use_lower=False, ns=50, **fargs):
-        '''
-        initialize the upper (and if needed lower) hulls with the specified params
-
-        Parameters
-        ==========
-        f: function that computes log(f(u,...)), for given u, where f(u) is proportional to the
-           density we want to sample from
-        fprima:  d/du log(f(u,...))
-        xi: ordered vector of starting points in wich log(f(u,...) is defined
-            to initialize the hulls
-        use_lower: True means the lower sqeezing will be used; which is more efficient
-                   for drawing large numbers of samples
-
-
-        lb: lower bound of the domain
-        ub: upper bound of the domain
-        ns: maximum number of points defining the hulls
-        fargs: arguments for f and fprima
-        '''
-        self.device = device
-
-        self.lb = lb
-        self.ub = ub
-
-        self.logpdf = logpdf
-        self.grad_logpdf = grad_logpdf
-        self.fargs = fargs
-
-        #set limit on how many points to maintain on hull
-        self.ns = ns
-        self.xi = xi.to(self.device) # initialize x, the vector of absicassae at which the function h has been evaluated
-        self.B, self.K = self.xi.size() # hull size
-        self.h = torch.zeros(self.B, ns).to(self.device)
-        self.hprime = torch.zeros(self.B, ns).to(self.device)
-        self.x = torch.zeros(self.B, ns).to(self.device)
-        self.h[:, :self.K] = self.logpdf(self.xi, **self.fargs)
-        self.hprime[:, :self.K] = self.grad_logpdf(self.xi, **self.fargs)
-        self.x[:, :self.K] = self.xi
-        # Avoid under/overflow errors. the envelope and pdf are only
-        # proportional to the true pdf, so can choose any constant of proportionality.
-        self.offset = self.h.max(-1)[0].view(-1, 1)
-        self.h = self.h - self.offset 
-
-        # Derivative at first point in xi must be > 0
-        # Derivative at last point in xi must be < 0
-        if not (self.hprime[:, 0] > 0).all(): raise IOError('initial anchor points must span mode of PDF (left)')
-        if not (self.hprime[:, self.K-1] < 0).all(): raise IOError('initial anchor points must span mode of PDF (right)')
-        self.insert()
-
-
-    def sample(self, shape=torch.Size()):
-        '''
-        Draw N samples and update upper and lower hulls accordingly
-        '''
-        shape = shape if isinstance(shape, torch.Size) else torch.Size([shape])
-        samples = torch.ones(self.B, *shape).to(self.device)
-        bool_mask = (torch.ones(self.B, *shape) == 1).to(self.device)
-        count = 0
-        while bool_mask.sum() != 0:
-            count += 1
-            xt, i = self.sampleUpper(shape)
-            ht = self.logpdf(xt, **self.fargs)
-            # hprimet = self.grad_logpdf(xt, **self.fargs)
-            ht = ht - self.offset
-            ut = self.h.gather(1, i) + (xt - self.x.gather(1, i)) * self.hprime.gather(1, i)
-
-            # Accept sample?
-            u = torch.rand(shape).to(self.device)
-            accept = u < torch.exp(ht - ut)
-            reject = ~accept
-            samples[bool_mask * accept] = xt[bool_mask * accept]
-            bool_mask[bool_mask * accept] = reject[bool_mask * accept]
-            # Update hull with new function evaluations
-            # if self.K < self.ns:
-            #     nb_insert = self.ns - self.K
-            #     self.insert(nb_insert, xt[:, :nb_insert], ht[:, :nb_insert], hprimet[:, :nb_insert])
-
-        return samples.t().unsqueeze(-1)
-
-
-    def insert(self, nbnew=0, xnew=None, hnew=None, hprimenew=None):
-        '''
-        Update hulls with new point(s) if none given, just recalculate hull from existing x,h,hprime
-        # '''
-        # if xnew is not None:
-        #     self.x[:, self.K:self.K+nbnew] = xnew
-        #     self.x, idx = self.x.sort()
-        #     self.h[:, self.K:self.K+nbnew] = hnew
-        #     self.h = self.h.gather(1, idx)
-        #     self.hprime[:, self.K:self.K+nbnew] = hprimenew
-        #     self.hprime = self.hprime.gather(1, idx)
-
-        #     self.K += xnew.size(-1)
-
-        self.z = torch.zeros(self.B, self.K + 1).to(self.device)
-        self.z[:, 0] = self.lb; self.z[:, self.K] = self.ub
-        self.z[:, 1:self.K] = (diff(self.h[:, :self.K]) - diff(self.x[:, :self.K] * self.hprime[:, :self.K])) / -diff(self.hprime[:, :self.K]) 
-        idx = [0]+list(range(self.K))
-        self.u = self.h[:, idx] + self.hprime[:, idx] * (self.z-self.x[:, idx])
-
-        self.s = diff(torch.exp(self.u)) / self.hprime[:, :self.K]
-        self.s[self.hprime[:, :self.K] == 0.] = 0. # should be 0 when gradient is 0
-        self.cs = torch.cat((torch.zeros(self.B, 1).to(self.device), torch.cumsum(self.s, dim=-1)), dim=-1)
-        self.cu = self.cs[:, -1]
-
-    def sampleUpper(self, shape=torch.Size()):
-        '''
-        Return a single value randomly sampled from the upper hull and index of segment
-        '''
-
-        u = torch.rand(self.B, *shape).to(self.device)
-        i = (self.cs/self.cu.unsqueeze(-1)).unsqueeze(-1) <= u.unsqueeze(1).expand(*self.cs.shape, *shape)
-        idx = i.sum(1) - 1
-
-        xt = self.x.gather(1, idx) + (-self.h.gather(1, idx) + torch.log(self.hprime.gather(1, idx)*(self.cu.unsqueeze(-1)*u - self.cs.gather(1, idx)) + 
-        torch.exp(self.u.gather(1, idx)))) / self.hprime.gather(1, idx)
-
-        return xt, idx
diff --git a/PVAE/distributions/hyperbolic_radius.py b/PVAE/distributions/hyperbolic_radius.py
deleted file mode 100644
index cf559a8..0000000
--- a/PVAE/distributions/hyperbolic_radius.py
+++ /dev/null
@@ -1,295 +0,0 @@
-import math
-import torch
-from torch.autograd import Function, grad
-import torch.distributions as dist
-from Ghypeddings.PVAE.utils import Constants, logsinh, log_sum_exp_signs, rexpand
-from numbers import Number
-from Ghypeddings.PVAE.distributions.ars import ARS
-
-
-def cdf_r(value, scale, c, dim):
-    value = value.double()
-    scale = scale.double()
-    c = c.double()
-
-    if dim == 2:
-        return 1 / torch.erf(c.sqrt() * scale / math.sqrt(2)) * .5 * \
-    (2 * torch.erf(c.sqrt() * scale / math.sqrt(2)) + torch.erf((value - c.sqrt() * scale.pow(2)) / math.sqrt(2) / scale) - \
-        torch.erf((c.sqrt() * scale.pow(2) + value) / math.sqrt(2) / scale))
-    else:
-        device = value.device
-
-        k_float = rexpand(torch.arange(dim), *value.size()).double().to(device)
-        dim = torch.tensor(dim).to(device).double()
-
-        s1 = torch.lgamma(dim) - torch.lgamma(k_float + 1) - torch.lgamma(dim - k_float) \
-            + (dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2 \
-            + torch.log( \
-                torch.erf((value - (dim - 1 - 2 * k_float) * c.sqrt() * scale.pow(2)) / scale / math.sqrt(2)) \
-                + torch.erf((dim - 1 - 2 * k_float) * c.sqrt() * scale / math.sqrt(2)) \
-                )
-        s2 = torch.lgamma(dim) - torch.lgamma(k_float + 1) - torch.lgamma(dim - k_float) \
-            + (dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2 \
-            + torch.log1p(torch.erf((dim - 1 - 2 * k_float) * c.sqrt() * scale / math.sqrt(2)))
-
-        signs = torch.tensor([1., -1.]).double().to(device).repeat(((int(dim)+1) // 2)*2)[:int(dim)]
-        signs = rexpand(signs, *value.size())
-
-        S1 = log_sum_exp_signs(s1, signs, dim=0)
-        S2 = log_sum_exp_signs(s2, signs, dim=0)
-
-        output = torch.exp(S1 - S2)
-        zero_value_idx = value == 0.
-        output[zero_value_idx] = 0.
-        return output.float()
-
-
-def grad_cdf_value_scale(value, scale, c, dim):
-    device = value.device
-
-    dim = torch.tensor(int(dim)).to(device).double()
-
-    signs = torch.tensor([1., -1.]).double().to(device).repeat(((int(dim)+1) // 2)*2)[:int(dim)]
-    signs = rexpand(signs, *value.size())
-    k_float = rexpand(torch.arange(dim), *value.size()).double().to(device)
-
-    log_arg1 = (dim - 1 - 2 * k_float).pow(2) * c * scale * \
-    (\
-        torch.erf((value - (dim - 1 - 2 * k_float) * c.sqrt() * scale.pow(2)) / scale / math.sqrt(2)) \
-        + torch.erf((dim - 1 - 2 * k_float) * c.sqrt() * scale / math.sqrt(2)) \
-    )
-    
-    log_arg2 = math.sqrt(2 / math.pi) * ( \
-        (dim - 1 - 2 * k_float) * c.sqrt() * torch.exp(-(dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2) \
-        - ((value / scale.pow(2) + (dim - 1 - 2 * k_float) * c.sqrt()) * torch.exp(-(value - (dim - 1 - 2 * k_float) * c.sqrt() * scale.pow(2)).pow(2) / (2 * scale.pow(2)))) \
-        )
-
-    log_arg = log_arg1 + log_arg2
-    sign_log_arg = torch.sign(log_arg)
-
-    s = torch.lgamma(dim) - torch.lgamma(k_float + 1) - torch.lgamma(dim - k_float) \
-            + (dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2 \
-            + torch.log(sign_log_arg * log_arg)
-
-    log_grad_sum_sigma = log_sum_exp_signs(s, signs * sign_log_arg, dim=0)
-    grad_sum_sigma = torch.sum(signs * sign_log_arg * torch.exp(s), dim=0)
-
-    s1 = torch.lgamma(dim) - torch.lgamma(k_float + 1) - torch.lgamma(dim - k_float) \
-        + (dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2 \
-        + torch.log( \
-            torch.erf((value - (dim - 1 - 2 * k_float) * c.sqrt() * scale.pow(2)) / scale / math.sqrt(2)) \
-            + torch.erf((dim - 1 - 2 * k_float) * c.sqrt() * scale / math.sqrt(2)) \
-        )
-
-    S1 = log_sum_exp_signs(s1, signs, dim=0)
-    grad_log_cdf_scale = grad_sum_sigma / S1.exp()
-    log_unormalised_prob = - value.pow(2) / (2 * scale.pow(2)) + (dim - 1) * logsinh(c.sqrt() * value) - (dim - 1) / 2 * c.log()
-    
-    with torch.autograd.enable_grad():
-        scale = scale.float()
-        logZ = _log_normalizer_closed_grad.apply(scale, c, dim)
-        grad_logZ_scale = grad(logZ, scale, grad_outputs=torch.ones_like(scale))
-
-    grad_log_cdf_scale = - grad_logZ_scale[0] + 1 / scale + grad_log_cdf_scale.float()
-    cdf = cdf_r(value.double(), scale.double(), c.double(), int(dim)).float().squeeze(0)
-    grad_scale = cdf * grad_log_cdf_scale
-
-    grad_value = (log_unormalised_prob.float() - logZ).exp()
-    return grad_value, grad_scale
-
-
-class _log_normalizer_closed_grad(Function):
-    @staticmethod 
-    def forward(ctx, scale, c, dim):
-        scale = scale.double()
-        c = c.double()
-        ctx.scale = scale.clone().detach()
-        ctx.c = c.clone().detach()
-        ctx.dim = dim
-
-        device = scale.device
-        output = .5 * (Constants.logpi - Constants.log2) + scale.log() -(int(dim) - 1) * (c.log() / 2 + Constants.log2)
-        dim = torch.tensor(int(dim)).to(device).double()
-
-        k_float = rexpand(torch.arange(int(dim)), *scale.size()).double().to(device)
-        s = torch.lgamma(dim) - torch.lgamma(k_float + 1) - torch.lgamma(dim - k_float) \
-            + (dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2 \
-            + torch.log1p(torch.erf((dim - 1 - 2 * k_float) * c.sqrt() * scale / math.sqrt(2)))
-        signs = torch.tensor([1., -1.]).double().to(device).repeat(((int(dim)+1) // 2)*2)[:int(dim)]
-        signs = rexpand(signs, *scale.size())
-        ctx.log_sum_term = log_sum_exp_signs(s, signs, dim=0)
-        output = output + ctx.log_sum_term
-
-        return output.float()
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        grad_input = grad_output.clone()
-
-        device = grad_input.device
-        scale = ctx.scale
-        c = ctx.c
-        dim = torch.tensor(int(ctx.dim)).to(device).double()
-
-        k_float = rexpand(torch.arange(int(dim)), *scale.size()).double().to(device)
-        signs = torch.tensor([1., -1.]).double().to(device).repeat(((int(dim)+1) // 2)*2)[:int(dim)]
-        signs = rexpand(signs, *scale.size())
-
-        log_arg = (dim - 1 - 2 * k_float).pow(2) * c * scale * (1+torch.erf((dim - 1 - 2 * k_float) * c.sqrt() * scale / math.sqrt(2))) + \
-            torch.exp(-(dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2) * 2 / math.sqrt(math.pi) * (dim - 1 - 2 * k_float) * c.sqrt() / math.sqrt(2)
-        log_arg_signs = torch.sign(log_arg)
-        s = torch.lgamma(dim) - torch.lgamma(k_float + 1) - torch.lgamma(dim - k_float) \
-            + (dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2 \
-            + torch.log(log_arg_signs * log_arg)
-        log_grad_sum_sigma = log_sum_exp_signs(s, log_arg_signs * signs, dim=0)
-
-        grad_scale = torch.exp(log_grad_sum_sigma - ctx.log_sum_term)
-        grad_scale = 1 / ctx.scale + grad_scale
-
-        grad_scale = (grad_input * grad_scale.float()).view(-1, *grad_input.shape).sum(0)
-        return (grad_scale, None, None)
-
-
-class impl_rsample(Function):
-    @staticmethod
-    def forward(ctx, value, scale, c, dim):
-        ctx.scale = scale.clone().detach().double().requires_grad_(True)
-        ctx.value = value.clone().detach().double().requires_grad_(True)
-        ctx.c = c.clone().detach().double().requires_grad_(True)
-        ctx.dim = dim
-        return value
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        grad_input = grad_output.clone()
-        grad_cdf_value, grad_cdf_scale = grad_cdf_value_scale(ctx.value, ctx.scale, ctx.c, ctx.dim)
-        assert not torch.isnan(grad_cdf_value).any()
-        assert not torch.isnan(grad_cdf_scale).any()
-        grad_value_scale = -(grad_cdf_value).pow(-1) * grad_cdf_scale.expand(grad_input.shape)
-        grad_scale = (grad_input * grad_value_scale).view(-1, *grad_cdf_scale.shape).sum(0)
-        # grad_value_c = -(grad_cdf_value).pow(-1) * grad_cdf_c.expand(grad_input.shape)
-        # grad_c = (grad_input * grad_value_c).view(-1, *grad_cdf_c.shape).sum(0)
-        return (None, grad_scale, None, None)
-
-
-class HyperbolicRadius(dist.Distribution):
-    support = dist.constraints.positive
-    has_rsample = True
-
-    def __init__(self, dim, c, scale, ars=True, validate_args=None):
-        self.dim = dim
-        self.c = c
-        self.scale = scale
-        self.device = scale.device
-        self.ars = ars
-        if isinstance(scale, Number):
-            batch_shape = torch.Size()
-        else:
-            batch_shape = self.scale.size()
-        self.log_normalizer = self._log_normalizer()
-        if torch.isnan(self.log_normalizer).any() or torch.isinf(self.log_normalizer).any():
-            print('nan or inf in log_normalizer', torch.cat((self.log_normalizer, self.scale), dim=1))
-            raise
-        super(HyperbolicRadius, self).__init__(batch_shape)
-
-    def rsample(self, sample_shape=torch.Size()):
-        value = self.sample(sample_shape)
-        return impl_rsample.apply(value, self.scale, self.c, self.dim)
-
-    def sample(self, sample_shape=torch.Size()):
-        if sample_shape == torch.Size(): sample_shape=torch.Size([1])
-        with torch.no_grad():
-            mean = self.mean
-            stddev = self.stddev
-            if torch.isnan(stddev).any(): stddev[torch.isnan(stddev)] = self.scale[torch.isnan(stddev)]
-            if torch.isnan(mean).any(): mean[torch.isnan(mean)] = ((self.dim - 1) * self.scale.pow(2) * self.c.sqrt())[torch.isnan(mean)]
-            steps = torch.linspace(0.1, 3, 10).to(self.device)
-            steps = torch.cat((-steps.flip(0), steps))
-            xi = [mean + s * torch.min(stddev, .95 * mean / 3) for s in steps]
-            xi = torch.cat(xi, dim=1)
-            ars = ARS(self.log_prob, self.grad_log_prob, self.device, xi=xi, ns=20, lb=0)
-            value = ars.sample(sample_shape)
-        return value
-
-    def __while_loop(self, logM, proposal, sample_shape):
-        shape = self._extended_shape(sample_shape)
-        r, bool_mask = torch.ones(shape).to(self.device), (torch.ones(shape) == 1).to(self.device)
-        count = 0
-        while bool_mask.sum() != 0:
-            count += 1
-            r_ = proposal.sample(sample_shape).to(self.device)
-            u = torch.rand(shape).to(self.device)
-            log_ratio = self.log_prob(r_) - proposal.log_prob(r_) - logM
-            accept = log_ratio > torch.log(u)
-            reject = 1 - accept
-            r[bool_mask * accept] = r_[bool_mask * accept]
-            bool_mask[bool_mask * accept] = reject[bool_mask * accept]
-        return r
-
-    def log_prob(self, value):
-        res = - value.pow(2) / (2 * self.scale.pow(2)) + (self.dim - 1) * logsinh(self.c.sqrt() * value) \
-            - (self.dim - 1) / 2 * self.c.log() - self.log_normalizer#.expand(value.shape)
-        assert not torch.isnan(res).any()
-        return res
-
-    def grad_log_prob(self, value):
-        res = - value / self.scale.pow(2) + (self.dim - 1) * self.c.sqrt() * torch.cosh(self.c.sqrt() * value) / torch.sinh(self.c.sqrt() * value) 
-        return res
-
-    def cdf(self, value):
-        return cdf_r(value, self.scale, self.c, self.dim)
-
-    @property
-    def mean(self):
-        c = self.c.double()
-        scale = self.scale.double()
-        dim = torch.tensor(int(self.dim)).double().to(self.device)
-        signs = torch.tensor([1., -1.]).double().to(self.device).repeat(((self.dim+1) // 2)*2)[:self.dim].unsqueeze(-1).unsqueeze(-1).expand(self.dim, *self.scale.size())
-        
-        k_float = rexpand(torch.arange(self.dim), *self.scale.size()).double().to(self.device)
-        s2 = torch.lgamma(dim) - torch.lgamma(k_float + 1) - torch.lgamma(dim - k_float) \
-                + (dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2 \
-                + torch.log1p(torch.erf((dim - 1 - 2 * k_float) * c.sqrt() * scale / math.sqrt(2)))
-        S2 = log_sum_exp_signs(s2, signs, dim=0)
-
-        log_arg = (dim - 1 - 2 * k_float) * c.sqrt() * scale.pow(2) * (1 + torch.erf((dim - 1 - 2 * k_float) * c.sqrt() * scale / math.sqrt(2))) + \
-                torch.exp(-(dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2) * scale * math.sqrt(2 / math.pi)
-        log_arg_signs = torch.sign(log_arg)
-        s1 = torch.lgamma(dim) - torch.lgamma(k_float + 1) - torch.lgamma(dim - k_float) \
-                + (dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2 \
-                + torch.log(log_arg_signs * log_arg)
-        S1 = log_sum_exp_signs(s1, signs * log_arg_signs, dim=0)
-
-        output = torch.exp(S1 - S2)
-        return output.float()
-
-    @property
-    def variance(self):
-        c = self.c.double()
-        scale = self.scale.double()
-        dim = torch.tensor(int(self.dim)).double().to(self.device)
-        signs = torch.tensor([1., -1.]).double().to(self.device).repeat(((int(dim)+1) // 2)*2)[:int(dim)].unsqueeze(-1).unsqueeze(-1).expand(int(dim), *self.scale.size())
-
-        k_float = rexpand(torch.arange(self.dim), *self.scale.size()).double().to(self.device)
-        s2 = torch.lgamma(dim) - torch.lgamma(k_float + 1) - torch.lgamma(dim - k_float) \
-                + (dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2 \
-                + torch.log1p(torch.erf((dim - 1 - 2 * k_float) * c.sqrt() * scale / math.sqrt(2)))
-        S2 = log_sum_exp_signs(s2, signs, dim=0)
-
-        log_arg = (1 + (dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2)) * (1 + torch.erf((dim - 1 - 2 * k_float) * c.sqrt() * scale / math.sqrt(2))) + \
-               (dim - 1 - 2 * k_float) * c.sqrt() * torch.exp(-(dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2) * scale * math.sqrt(2 / math.pi)
-        log_arg_signs = torch.sign(log_arg)
-        s1 = torch.lgamma(dim) - torch.lgamma(k_float + 1) - torch.lgamma(dim - k_float) \
-                + (dim - 1 - 2 * k_float).pow(2) * c * scale.pow(2) / 2 \
-                + 2 * scale.log() \
-                + torch.log(log_arg_signs * log_arg)
-        S1 = log_sum_exp_signs(s1, signs * log_arg_signs, dim=0)
-
-        output = torch.exp(S1 - S2)
-        output = output.float() - self.mean.pow(2)
-        return output
-
-    @property
-    def stddev(self): return self.variance.sqrt()
-
-    def _log_normalizer(self): return _log_normalizer_closed_grad.apply(self.scale, self.c, self.dim)
diff --git a/PVAE/distributions/hyperspherical_uniform.py b/PVAE/distributions/hyperspherical_uniform.py
deleted file mode 100644
index 8a31f12..0000000
--- a/PVAE/distributions/hyperspherical_uniform.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import math
-import torch
-from torch.distributions.utils import _standard_normal
-
-class HypersphericalUniform(torch.distributions.Distribution):
-    """ source: https://github.com/nicola-decao/s-vae-pytorch/blob/master/hyperspherical_vae/distributions/von_mises_fisher.py """
-
-    support = torch.distributions.constraints.real
-    has_rsample = False
-    _mean_carrier_measure = 0
-
-    @property
-    def dim(self):
-        return self._dim
-    
-    def __init__(self, dim, device='cpu', validate_args=None):
-        super(HypersphericalUniform, self).__init__(torch.Size([dim]), validate_args=validate_args)
-        self._dim = dim
-        self._device = device
-
-    def sample(self, shape=torch.Size()):
-        with torch.no_grad():
-            return self.rsample(shape)
-
-    def rsample(self, sample_shape=torch.Size()):
-        shape = torch.Size([*sample_shape, self._dim + 1])
-        output = _standard_normal(shape, dtype=torch.float, device=self._device)
-
-        return output / output.norm(dim=-1, keepdim=True)
-
-    def entropy(self):
-        return self.__log_surface_area()
-    
-    def log_prob(self, x):
-        return - torch.ones(x.shape[:-1]).to(self._device) * self._log_normalizer()
-
-    def _log_normalizer(self):
-        return self._log_surface_area().to(self._device)
-
-    def _log_surface_area(self):
-        return math.log(2) + ((self._dim + 1) / 2) * math.log(math.pi) - torch.lgamma(
-            torch.Tensor([(self._dim + 1) / 2]))
diff --git a/PVAE/distributions/riemannian_normal.py b/PVAE/distributions/riemannian_normal.py
deleted file mode 100644
index ea59144..0000000
--- a/PVAE/distributions/riemannian_normal.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import torch
-import torch.distributions as dist
-from torch.distributions import constraints
-from numbers import Number
-from Ghypeddings.PVAE.distributions.hyperbolic_radius import HyperbolicRadius
-from Ghypeddings.PVAE.distributions.hyperspherical_uniform import HypersphericalUniform
-
-
-class RiemannianNormal(dist.Distribution):
-    arg_constraints = {'loc': dist.constraints.interval(-1, 1), 'scale': dist.constraints.positive}
-    support = dist.constraints.interval(-1, 1)
-    has_rsample = True
-
-    @property
-    def mean(self):
-        return self.loc
-    
-    def __init__(self, loc, scale, manifold, validate_args=None):
-        assert not (torch.isnan(loc).any() or torch.isnan(scale).any())
-        self.manifold = manifold
-        self.loc = loc
-        self.manifold.assert_check_point_on_manifold(self.loc)
-        self.scale = scale.clamp(min=0.1, max=7.)
-        self.radius = HyperbolicRadius(manifold.dim, manifold.c, self.scale)
-        self.direction = HypersphericalUniform(manifold.dim - 1, device=loc.device)
-        if isinstance(loc, Number) and isinstance(scale, Number):
-            batch_shape = torch.Size()
-        else:
-            batch_shape = self.loc.size()
-        super(RiemannianNormal, self).__init__(batch_shape, validate_args=validate_args)
-
-    def sample(self, shape=torch.Size()):
-        with torch.no_grad():
-            return self.rsample(shape)
-
-    def rsample(self, sample_shape=torch.Size()):
-        shape = self._extended_shape(sample_shape)
-        alpha = self.direction.sample(torch.Size([*shape[:-1]]))
-        radius = self.radius.rsample(sample_shape)
-        # u = radius * alpha / self.manifold.lambda_x(self.loc, keepdim=True)
-        # res = self.manifold.expmap(self.loc, u)
-        res = self.manifold.expmap_polar(self.loc, alpha, radius)
-        return res
-
-    def log_prob(self, value):
-        loc = self.loc.expand(value.shape)
-        radius_sq = self.manifold.dist(loc, value, keepdim=True).pow(2)
-        res = - radius_sq / 2 / self.scale.pow(2) - self.direction._log_normalizer() - self.radius.log_normalizer
-        return res
diff --git a/PVAE/distributions/wrapped_normal.py b/PVAE/distributions/wrapped_normal.py
deleted file mode 100644
index 29566d9..0000000
--- a/PVAE/distributions/wrapped_normal.py
+++ /dev/null
@@ -1,65 +0,0 @@
-import torch
-from torch.nn import functional as F
-from torch.distributions import Normal, Independent
-from numbers import Number
-from torch.distributions.utils import _standard_normal, broadcast_all
-
-
-class WrappedNormal(torch.distributions.Distribution):
-
-    arg_constraints = {'loc': torch.distributions.constraints.real,
-                       'scale': torch.distributions.constraints.positive}
-    support = torch.distributions.constraints.real
-    has_rsample = True
-    _mean_carrier_measure = 0
-
-    @property
-    def mean(self):
-        return self.loc
-
-    @property
-    def stddev(self):
-        raise NotImplementedError
-
-    @property
-    def scale(self):
-        return F.softplus(self._scale) if self.softplus else self._scale
-
-    def __init__(self, loc, scale, manifold, validate_args=None, softplus=False):
-        self.dtype = loc.dtype
-        self.softplus = softplus
-        self.loc, self._scale = broadcast_all(loc, scale)
-        self.manifold = manifold
-        self.manifold.assert_check_point_on_manifold(self.loc)
-        self.device = loc.device
-        if isinstance(loc, Number) and isinstance(scale, Number):
-            batch_shape, event_shape = torch.Size(), torch.Size()
-        else:
-            batch_shape = self.loc.shape[:-1]
-            event_shape = torch.Size([self.manifold.dim])
-        super(WrappedNormal, self).__init__(batch_shape, event_shape, validate_args=validate_args)
-
-    def sample(self, shape=torch.Size()):
-        with torch.no_grad():
-            return self.rsample(shape)
-
-    def rsample(self, sample_shape=torch.Size()):
-        shape = self._extended_shape(sample_shape)
-        v = self.scale * _standard_normal(shape, dtype=self.loc.dtype, device=self.loc.device)
-        self.manifold.assert_check_vector_on_tangent(self.manifold.zero, v)
-        v = v / self.manifold.lambda_x(self.manifold.zero, keepdim=True)
-        u = self.manifold.transp(self.manifold.zero, self.loc, v)
-        z = self.manifold.expmap(self.loc, u)
-        return z
-
-    def log_prob(self, x):
-        shape = x.shape
-        loc = self.loc.unsqueeze(0).expand(x.shape[0], *self.batch_shape, self.manifold.coord_dim)
-        if len(shape) < len(loc.shape): x = x.unsqueeze(1)
-        v = self.manifold.logmap(loc, x)
-        v = self.manifold.transp(loc, self.manifold.zero, v)
-        u = v * self.manifold.lambda_x(self.manifold.zero, keepdim=True)
-        norm_pdf = Normal(torch.zeros_like(self.scale), self.scale).log_prob(u).sum(-1, keepdim=True)
-        logdetexp = self.manifold.logdetexp(loc, x, keepdim=True)
-        result = norm_pdf - logdetexp
-        return result
diff --git a/PVAE/manifolds/__init__.py b/PVAE/manifolds/__init__.py
deleted file mode 100644
index cd1d107..0000000
--- a/PVAE/manifolds/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from Ghypeddings.PVAE.manifolds.euclidean import Euclidean
-from Ghypeddings.PVAE.manifolds.poincareball import PoincareBall
-
-__all__ = [Euclidean, PoincareBall]
\ No newline at end of file
diff --git a/PVAE/manifolds/euclidean.py b/PVAE/manifolds/euclidean.py
deleted file mode 100644
index a0b362b..0000000
--- a/PVAE/manifolds/euclidean.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import torch
-from geoopt.manifolds import Euclidean as EuclideanParent
-
-
-class Euclidean(EuclideanParent):
-
-    def __init__(self, dim, c=0.):
-        super().__init__(1)
-        self.register_buffer("dim", torch.as_tensor(dim, dtype=torch.int))
-        self.register_buffer("c", torch.as_tensor(c, dtype=torch.get_default_dtype()))
-
-    @property
-    def coord_dim(self):
-        return int(self.dim)
-
-    @property
-    def device(self):
-        return self.c.device
-
-    @property
-    def zero(self):
-        return torch.zeros(1, self.dim).to(self.device)
-
-    def logdetexp(self, x, y, is_vector=False, keepdim=False):
-        result = torch.zeros(x.shape[:-1]).to(x)
-        if keepdim: result = result.unsqueeze(-1)
-        return result
-
-    def expmap0(self, u):
-        return u
-
-    def logmap0(self, u):
-        return u
-
-    def proju0(self, u):
-        return self.proju(self.zero.expand_as(u), u)
-
-    def transp0(self, x, u):
-        return self.transp(self.zero.expand_as(u), x, u)
-
-    def lambda_x(self, x, *, keepdim=False, dim=-1):
-        return torch.ones_like(x.sum(dim=dim, keepdim=keepdim))
diff --git a/PVAE/manifolds/poincareball.py b/PVAE/manifolds/poincareball.py
deleted file mode 100644
index 924511d..0000000
--- a/PVAE/manifolds/poincareball.py
+++ /dev/null
@@ -1,84 +0,0 @@
-import torch
-from geoopt.manifolds import PoincareBall as PoincareBallParent
-from geoopt.manifolds.stereographic.math import _lambda_x, arsinh, tanh
-
-MIN_NORM = 1e-15
-
-
-class PoincareBall(PoincareBallParent):
-
-    def __init__(self, dim, c=1.0):
-        super().__init__(c)
-        self.register_buffer("dim", torch.as_tensor(dim, dtype=torch.int))
-
-    def proju0(self, u):
-        return self.proju(self.zero.expand_as(u), u)
-
-    @property
-    def coord_dim(self):
-        return int(self.dim)
-
-    @property
-    def device(self):
-        return self.c.device
-
-    @property
-    def zero(self):
-        return torch.zeros(1, self.dim).to(self.device)
-
-    def logdetexp(self, x, y, is_vector=False, keepdim=False):
-        d = self.norm(x, y, keepdim=keepdim) if is_vector else self.dist(x, y, keepdim=keepdim)
-        d[d == 0] = 1e-15
-        return (self.dim - 1) * (torch.sinh(self.c.sqrt()*d) / self.c.sqrt() / d).log()
-
-    def inner(self, x, u, v=None, *, keepdim=False, dim=-1):
-        if v is None: v = u
-        return _lambda_x(x, self.c, keepdim=keepdim, dim=dim) ** 2 * (u * v).sum(
-            dim=dim, keepdim=keepdim
-        )
-
-    def expmap_polar(self, x, u, r, dim: int = -1):
-        sqrt_c = self.c ** 0.5
-        u_norm = u.norm(dim=dim, p=2, keepdim=True).clamp_min(MIN_NORM)
-        second_term = (
-            tanh(sqrt_c / 2 * r)
-            * u
-            / (sqrt_c * u_norm)
-        )
-        gamma_1 = self.mobius_add(x, second_term, dim=dim)
-        return gamma_1
-
-    def normdist2plane(self, x, a, p, keepdim: bool = False, signed: bool = False, dim: int = -1, norm: bool = False):
-        c = self.c
-        sqrt_c = c ** 0.5
-        diff = self.mobius_add(-p, x, dim=dim)
-        diff_norm2 = diff.pow(2).sum(dim=dim, keepdim=keepdim).clamp_min(MIN_NORM)
-        sc_diff_a = (diff * a).sum(dim=dim, keepdim=keepdim)
-        if not signed:
-            sc_diff_a = sc_diff_a.abs()
-        a_norm = a.norm(dim=dim, keepdim=keepdim, p=2).clamp_min(MIN_NORM)
-        num = 2 * sqrt_c * sc_diff_a
-        denom = (1 - c * diff_norm2) * a_norm
-        res = arsinh(num / denom.clamp_min(MIN_NORM)) / sqrt_c
-        if norm:
-            res = res * a_norm# * self.lambda_x(a, dim=dim, keepdim=keepdim)
-        return res
-
-
-
-class PoincareBallExact(PoincareBall):
-    __doc__ = r"""
-    See Also
-    --------
-    :class:`PoincareBall`
-    Notes
-    -----
-    The implementation of retraction is an exact exponential map, this retraction will be used in optimization
-    """
-
-    retr_transp = PoincareBall.expmap_transp
-    transp_follow_retr = PoincareBall.transp_follow_expmap
-    retr = PoincareBall.expmap
-
-    def extra_repr(self):
-        return "exact"
diff --git a/PVAE/models/__init__.py b/PVAE/models/__init__.py
deleted file mode 100644
index bdb822c..0000000
--- a/PVAE/models/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from Ghypeddings.PVAE.models.tabular import Tabular
-__all__ = [Tabular]
\ No newline at end of file
diff --git a/PVAE/models/architectures.py b/PVAE/models/architectures.py
deleted file mode 100644
index 92a0496..0000000
--- a/PVAE/models/architectures.py
+++ /dev/null
@@ -1,180 +0,0 @@
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-from numpy import prod
-from Ghypeddings.PVAE.utils import Constants
-from Ghypeddings.PVAE.ops.manifold_layers import GeodesicLayer, MobiusLayer, LogZero, ExpZero
-from torch.nn.modules.module import Module
-
-def get_dim_act(args):
-    """
-    Helper function to get dimension and activation at every layer.
-    :param args:
-    :return:
-    """
-    if not args.act:
-        act = lambda x: x
-    else:
-        act = getattr(F, args.act)
-    acts = [act] * (args.num_layers - 1)
-    dims = [args.feat_dim] + ([args.hidden_dim] * (args.num_layers - 1))
-
-    return dims, acts
-
-
-class Encoder(nn.Module):
-    """
-    Encoder abstract class.
-    """
-
-    def __init__(self, c):
-        super(Encoder, self).__init__()
-        self.c = c
-
-    def encode(self, x, adj):
-        input = (x, adj)
-        output, _ = self.layers.forward(input)
-        return output
-
-class GraphConvolution(Module):
-    """
-    Simple GCN layer.
-    """
-
-    def __init__(self, in_features, out_features, dropout, act, use_bias):
-        super(GraphConvolution, self).__init__()
-        self.dropout = dropout
-        self.linear = nn.Linear(in_features, out_features, use_bias)
-        self.act = act
-        self.in_features = in_features
-        self.out_features = out_features
-
-    def forward(self, input):
-        x, adj = input
-        hidden = self.linear.forward(x)
-        hidden = F.dropout(hidden, self.dropout, training=self.training)
-        if adj.is_sparse:
-            support = torch.spmm(adj, hidden)
-        else:
-            support = torch.mm(adj, hidden)
-        output = self.act(support), adj
-        return output
-
-    def extra_repr(self):
-        return 'input_dim={}, output_dim={}'.format(
-                self.in_features, self.out_features
-        )
-
-class GCN(Encoder):
-    """
-    Graph Convolution Networks.
-    """
-
-    def __init__(self, c, args):
-        super(GCN, self).__init__(c)
-        assert args.num_layers > 0
-        dims, acts = get_dim_act(args)
-        gc_layers = []
-        for i in range(len(dims) - 1):
-            in_dim, out_dim = dims[i], dims[i + 1]
-            act = acts[i]
-            gc_layers.append(GraphConvolution(in_dim, out_dim, args.dropout, act, args.bias))
-        self.layers = nn.Sequential(*gc_layers)
-
-
-def extra_hidden_layer(hidden_dim, non_lin):
-     return nn.Sequential(nn.Linear(hidden_dim, hidden_dim), non_lin)       
-
-class EncWrapped(nn.Module):
-    """ Usual encoder followed by an exponential map """
-    def __init__(self,c,args, manifold, data_size, non_lin, num_hidden_layers, hidden_dim, prior_iso):
-        super(EncWrapped, self).__init__()
-        self.manifold = manifold
-        self.data_size = data_size
-        self.enc = GCN(c,args)
-        self.fc21 = nn.Linear(hidden_dim, manifold.coord_dim)
-        self.fc22 = nn.Linear(hidden_dim, manifold.coord_dim if not prior_iso else 1)
-
-    def forward(self,adj,x):
-        e = self.enc.encode(x,adj)
-        mu = self.fc21(e)          # flatten data
-        mu = self.manifold.expmap0(mu)
-        return mu, F.softplus(self.fc22(e)) + Constants.eta,  self.manifold
-
-
-class DecWrapped(nn.Module):
-    """ Usual encoder preceded by a logarithm map """
-    def __init__(self, manifold, data_size, non_lin, num_hidden_layers, hidden_dim):
-        super(DecWrapped, self).__init__()
-        self.data_size = data_size
-        self.manifold = manifold
-        modules = []
-        modules.append(nn.Sequential(nn.Linear(manifold.coord_dim, hidden_dim), non_lin))
-        modules.extend([extra_hidden_layer(hidden_dim, non_lin) for _ in range(num_hidden_layers - 1)])
-        self.dec = nn.Sequential(*modules)
-        # self.fc31 = nn.Linear(hidden_dim, prod(data_size))
-        self.fc31 = nn.Linear(hidden_dim, data_size[1])
-
-    def forward(self, z):
-        z = self.manifold.logmap0(z)
-        d = self.dec(z)
-        # mu = self.fc31(d).view(*z.size()[:-1], *self.data_size)  # reshape data
-        mu = self.fc31(d).view(*z.size()[:-1], 1, self.data_size[1]) 
-        return mu, torch.ones_like(mu)
-
-
-class DecGeo(nn.Module):
-    """ First layer is a Hypergyroplane followed by usual decoder """
-    def __init__(self, manifold, data_size, non_lin, num_hidden_layers, hidden_dim):
-        super(DecGeo, self).__init__()
-        self.data_size = data_size
-        modules = []
-        modules.append(nn.Sequential(GeodesicLayer(manifold.coord_dim, hidden_dim, manifold), non_lin))
-        modules.extend([extra_hidden_layer(hidden_dim, non_lin) for _ in range(num_hidden_layers - 1)])
-        self.dec = nn.Sequential(*modules)
-        self.fc31 = nn.Linear(hidden_dim, data_size[1])
-
-    def forward(self, z):
-        d = self.dec(z)
-        # mu = self.fc31(d).view(*z.size()[:-1], *self.data_size)  # reshape data
-        mu = self.fc31(d).view(*z.size()[:-1], 1, self.data_size[1]) 
-        return mu, torch.ones_like(mu)
-
-
-class EncMob(nn.Module):
-    """ Last layer is a Mobius layers """
-    def __init__(self,c,args, manifold, data_size, non_lin, num_hidden_layers, hidden_dim, prior_iso):
-        super(EncMob, self).__init__()
-        self.manifold = manifold
-        self.data_size = data_size
-        # modules = []
-        # modules.append(nn.Sequential(nn.Linear(data_size[1], hidden_dim), non_lin))
-        # modules.extend([extra_hidden_layer(hidden_dim, non_lin) for _ in range(num_hidden_layers - 1)])
-        # self.enc = nn.Sequential(*modules)
-        self.enc = GCN(c,args)
-        self.fc21 = MobiusLayer(hidden_dim, manifold.coord_dim, manifold)
-        self.fc22 = nn.Linear(hidden_dim, manifold.coord_dim if not prior_iso else 1)
-
-    def forward(self,adj,x):
-        #e = self.enc(x.view(*x.size()[:-len(self.data_size)], -1))            # flatten data
-        e = self.enc.encode(x,adj)
-        mu = self.fc21(e)          # flatten data
-        mu = self.manifold.expmap0(mu)
-        return mu, F.softplus(self.fc22(e)) + Constants.eta,  self.manifold
-
-
-class DecMob(nn.Module):
-    """ First layer is a Mobius Matrix multiplication """
-    def __init__(self, manifold, data_size, non_lin, num_hidden_layers, hidden_dim):
-        super(DecMob, self).__init__()
-        self.data_size = data_size
-        modules = []
-        modules.append(nn.Sequential(MobiusLayer(manifold.coord_dim, hidden_dim, manifold), LogZero(manifold), non_lin))
-        modules.extend([extra_hidden_layer(hidden_dim, non_lin) for _ in range(num_hidden_layers - 1)])
-        self.dec = nn.Sequential(*modules)
-        self.fc31 = nn.Linear(hidden_dim, prod(data_size))
-
-    def forward(self, z):
-        d = self.dec(z)
-        mu = self.fc31(d).view(*z.size()[:-1], *self.data_size)  # reshape data
-        return mu, torch.ones_like(mu)
diff --git a/PVAE/models/tabular.py b/PVAE/models/tabular.py
deleted file mode 100644
index 2c5b4d5..0000000
--- a/PVAE/models/tabular.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-import torch.distributions as dist
-from torch.utils.data import DataLoader
-
-import math
-from Ghypeddings.PVAE.models.vae import VAE
-
-from Ghypeddings.PVAE.distributions import RiemannianNormal, WrappedNormal
-from torch.distributions import Normal
-import Ghypeddings.PVAE.manifolds as manifolds
-from Ghypeddings.PVAE.models.architectures import EncWrapped, DecWrapped, EncMob, DecMob, DecGeo
-from Ghypeddings.PVAE.utils import get_activation
-
-class Tabular(VAE):
-    """ Derive a specific sub-class of a VAE for tabular data. """
-    def __init__(self, params):
-        c = nn.Parameter(params.c * torch.ones(1), requires_grad=False)
-        manifold = getattr(manifolds, 'PoincareBall')(params.dim, c)
-        super(Tabular, self).__init__(
-            eval(params.prior),           # prior distribution
-            eval(params.posterior),       # posterior distribution
-            dist.Normal,                  # likelihood distribution
-            eval('Enc' + params.enc)(params.c,params,manifold, params.data_size, get_activation(params), params.num_layers, params.hidden_dim, params.prior_iso),
-            eval('Dec' + params.dec)(manifold, params.data_size, get_activation(params), params.num_layers, params.hidden_dim),
-            params
-        )
-        self.manifold = manifold
-        self._pz_mu = nn.Parameter(torch.zeros(1, params.dim), requires_grad=False)
-        self._pz_logvar = nn.Parameter(torch.zeros(1, 1), requires_grad=params.learn_prior_std)
-        self.modelName = 'Tabular'
-
-    @property
-    def pz_params(self):
-        return self._pz_mu.mul(1), F.softplus(self._pz_logvar).div(math.log(2)).mul(self.prior_std), self.manifold
\ No newline at end of file
diff --git a/PVAE/models/vae.py b/PVAE/models/vae.py
deleted file mode 100644
index 2cb79df..0000000
--- a/PVAE/models/vae.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Base VAE class definition
-
-import math
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-import torch.distributions as dist
-from Ghypeddings.PVAE.utils import get_mean_param
-
-class VAE(nn.Module):
-    def __init__(self, prior_dist, posterior_dist, likelihood_dist, enc, dec, params):
-        super(VAE, self).__init__()
-        self.pz = prior_dist
-        self.px_z = likelihood_dist
-        self.qz_x = posterior_dist
-        self.enc = enc
-        self.dec = dec
-        self.modelName = None
-        self.params = params
-        self.data_size = params.data_size
-        self.prior_std = params.prior_std
-
-        if self.px_z == dist.RelaxedBernoulli:
-            self.px_z.log_prob = lambda self, value: \
-                -F.binary_cross_entropy_with_logits(
-                    self.probs if value.dim() <= self.probs.dim() else self.probs.expand_as(value),
-                    value.expand(self.batch_shape) if value.dim() <= self.probs.dim() else value,
-                    reduction='none'
-                )
-
-    def generate(self, N, K):
-        self.eval()
-        with torch.no_grad():
-            mean_pz = get_mean_param(self.pz_params)
-            mean = get_mean_param(self.dec(mean_pz))
-            px_z_params = self.dec(self.pz(*self.pz_params).sample(torch.Size([N])))
-            means = get_mean_param(px_z_params)
-            samples = self.px_z(*px_z_params).sample(torch.Size([K]))
-
-        return mean, \
-            means.view(-1, *means.size()[2:]), \
-            samples.view(-1, *samples.size()[3:])
-
-    def reconstruct(self, data , edge_index):
-        self.eval()
-        with torch.no_grad():
-            qz_x = self.qz_x(*self.enc(edge_index,data))
-            px_z_params = self.dec(qz_x.rsample(torch.Size([1])).squeeze(0))
-
-        return get_mean_param(px_z_params)
-
-    def forward(self, x , edge_index, K=1):
-        embeddings = self.enc(edge_index,x)
-        qz_x = self.qz_x(*embeddings)
-        zs = qz_x.rsample(torch.Size([K]))
-        px_z = self.px_z(*self.dec(zs))
-        return qz_x, px_z, zs , embeddings
-
-    @property
-    def pz_params(self):
-        return self._pz_mu.mul(1), F.softplus(self._pz_logvar).div(math.log(2)).mul(self.prior_std_scale)
-
-    def init_last_layer_bias(self, dataset): pass
diff --git a/PVAE/objectives.py b/PVAE/objectives.py
deleted file mode 100644
index fd9afea..0000000
--- a/PVAE/objectives.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import torch
-import torch.distributions as dist
-from numpy import prod
-from Ghypeddings.PVAE.utils import has_analytic_kl, log_mean_exp
-import torch.nn.functional as F
-
-def vae_objective(model, idx, x , graph, K=1, beta=1.0, components=False, analytical_kl=False, **kwargs):
-    """Computes E_{p(x)}[ELBO] """
-    qz_x, px_z, zs , embeddings = model(x, graph,K)
-    _, B, D = zs.size()
-    flat_rest = torch.Size([*px_z.batch_shape[:2], -1])
-    x = x.unsqueeze(0).unsqueeze(2)
-    lpx_z = px_z.log_prob(x.expand(px_z.batch_shape)).view(flat_rest).sum(-1)
-    pz = model.pz(*model.pz_params)
-    kld = dist.kl_divergence(qz_x, pz).unsqueeze(0).sum(-1) if \
-        has_analytic_kl(type(qz_x), model.pz) and analytical_kl else \
-        qz_x.log_prob(zs).sum(-1) - pz.log_prob(zs).sum(-1)
-    lpx_z_selected = lpx_z[:, idx]
-    kld_selected = kld[:, idx]
-    obj = -lpx_z_selected.mean(0).sum() + beta * kld_selected.mean(0).sum()
-    return (qz_x, px_z, lpx_z_selected, kld_selected, obj , embeddings) if components else obj
-
-def _iwae_objective_vec(model, x, K):
-    """Helper for IWAE estimate for log p_\theta(x) -- full vectorisation."""
-    qz_x, px_z, zs = model(x, K)
-    flat_rest = torch.Size([*px_z.batch_shape[:2], -1])
-    lpz = model.pz(*model.pz_params).log_prob(zs).sum(-1)
-    lpx_z = px_z.log_prob(x.expand(zs.size(0), *x.size())).view(flat_rest).sum(-1)
-    lqz_x = qz_x.log_prob(zs).sum(-1)
-    obj = lpz.squeeze(-1) + lpx_z.view(lpz.squeeze(-1).shape) - lqz_x.squeeze(-1)
-    return -log_mean_exp(obj).sum()
-
-
-def iwae_objective(model, x, K):
-    """Computes an importance-weighted ELBO estimate for log p_\theta(x)
-    Iterates over the batch as necessary.
-    Appropriate negation (for minimisation) happens in the helper
-    """
-    split_size = int(x.size(0) / (K * prod(x.size()) / (3e7)))  # rough heuristic
-    if split_size >= x.size(0):
-        obj = _iwae_objective_vec(model, x, K)
-    else:
-        obj = 0
-        for bx in x.split(split_size):
-            obj = obj + _iwae_objective_vec(model, bx, K)
-    return obj
diff --git a/PVAE/ops/__init__.py b/PVAE/ops/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/PVAE/ops/manifold_layers.py b/PVAE/ops/manifold_layers.py
deleted file mode 100644
index 643d80f..0000000
--- a/PVAE/ops/manifold_layers.py
+++ /dev/null
@@ -1,90 +0,0 @@
-import math
-import torch
-from torch import nn
-from torch.nn.parameter import Parameter
-from torch.nn import init
-from Ghypeddings.PVAE.manifolds import PoincareBall, Euclidean
-from geoopt import ManifoldParameter
-
-
-class RiemannianLayer(nn.Module):
-    def __init__(self, in_features, out_features, manifold, over_param, weight_norm):
-        super(RiemannianLayer, self).__init__()
-        self.in_features = in_features
-        self.out_features = out_features
-        self.manifold = manifold
-
-        self._weight = Parameter(torch.Tensor(out_features, in_features))
-        self.over_param = over_param
-        self.weight_norm = weight_norm
-        if self.over_param:
-            self._bias = ManifoldParameter(torch.Tensor(out_features, in_features), manifold=manifold)
-        else:
-            self._bias = Parameter(torch.Tensor(out_features, 1))
-        self.reset_parameters()
-
-    @property
-    def weight(self):
-        return self.manifold.transp0(self.bias, self._weight) # weight \in T_0 => weight \in T_bias
-
-    @property
-    def bias(self):
-        if self.over_param:
-            return self._bias
-        else:
-            return self.manifold.expmap0(self._weight * self._bias) # reparameterisation of a point on the manifold
-
-    def reset_parameters(self):
-        init.kaiming_normal_(self._weight, a=math.sqrt(5))
-        fan_in, _ = init._calculate_fan_in_and_fan_out(self._weight)
-        bound = 4 / math.sqrt(fan_in)
-        init.uniform_(self._bias, -bound, bound)
-        if self.over_param:
-            with torch.no_grad(): self._bias.set_(self.manifold.expmap0(self._bias))
-
-
-class GeodesicLayer(RiemannianLayer):
-    def __init__(self, in_features, out_features, manifold, over_param=False, weight_norm=False):
-        super(GeodesicLayer, self).__init__(in_features, out_features, manifold, over_param, weight_norm)
-
-    def forward(self, input):
-        input = input.unsqueeze(-2).expand(*input.shape[:-(len(input.shape) - 2)], self.out_features, self.in_features)
-        res = self.manifold.normdist2plane(input, self.bias, self.weight,
-                                               signed=True, norm=self.weight_norm)
-        return res
-
-
-class Linear(nn.Linear):
-    def __init__(self, in_features, out_features, **kwargs):
-        super(Linear, self).__init__(
-            in_features,
-            out_features,
-        )
-
-
-class MobiusLayer(RiemannianLayer):
-    def __init__(self, in_features, out_features, manifold, over_param=False, weight_norm=False):
-        super(MobiusLayer, self).__init__(in_features, out_features, manifold, over_param, weight_norm)
-
-    def forward(self, input):
-        res = self.manifold.mobius_matvec(self.weight, input)
-        return res
-
-
-class ExpZero(nn.Module):
-    def __init__(self, manifold):
-        super(ExpZero, self).__init__()
-        self.manifold = manifold
-
-    def forward(self, input):
-        return self.manifold.expmap0(input)
-
-
-class LogZero(nn.Module):
-    def __init__(self, manifold):
-        super(LogZero, self).__init__()
-        self.manifold = manifold
-
-    def forward(self, input):
-        return self.manifold.logmap0(input)
-
diff --git a/PVAE/pvae.py b/PVAE/pvae.py
deleted file mode 100644
index b131892..0000000
--- a/PVAE/pvae.py
+++ /dev/null
@@ -1,211 +0,0 @@
-import sys
-sys.path.append(".")
-sys.path.append("..")
-import os
-import datetime
-from collections import defaultdict
-import torch
-from torch import optim
-import numpy as np
-import logging
-import time
-
-from Ghypeddings.PVAE.utils import probe_infnan , process_data , create_args , get_classifier,get_clustering_algorithm,get_anomaly_detection_algorithm
-import Ghypeddings.PVAE.objectives as objectives
-from Ghypeddings.PVAE.models import Tabular
-
-from Ghypeddings.classifiers import calculate_metrics
-
-runId = datetime.datetime.now().isoformat().replace(':','_')
-torch.backends.cudnn.benchmark = True
-
-class PVAE:
-    def __init__(self,
-                adj,
-                features,
-                labels,
-                dim,
-                hidden_dim,
-                num_layers=2,
-                c=1.0,
-                act='relu',
-                lr=0.01,
-                cuda=0,
-                epochs=50,
-                seed=42,
-                eval_freq=1,
-                val_prop=0.,
-                test_prop=0.3,
-                dropout=0.1,
-                beta1=0.9,
-                beta2=.999,
-                K=1,
-                beta=.2,
-                analytical_kl=True,
-                posterior='WrappedNormal',
-                prior='WrappedNormal',
-                prior_iso=True,
-                prior_std=1.,
-                learn_prior_std=True,
-                enc='Mob',
-                dec='Geo',
-                bias=True,
-                alpha=0.5,
-                classifier=None,
-                clusterer=None,
-                log_freq=1,
-                normalize_adj=False,
-                normalize_feats=True,
-                anomaly_detector=None
-                ):
-
-        self.args = create_args(dim,hidden_dim,num_layers,c,act,lr,cuda,epochs,seed,eval_freq,val_prop,test_prop,dropout,beta1,beta2,K,beta,analytical_kl,posterior,prior,prior_iso,prior_std,learn_prior_std,enc,dec,bias,alpha,classifier,clusterer,log_freq,normalize_adj,normalize_feats,anomaly_detector)
-        self.args.n_classes = len(np.unique(labels))
-        self.args.feat_dim = features.shape[1]
-        self.data = process_data(self.args,adj,features,labels)
-        self.args.data_size = [adj.shape[0],self.args.feat_dim]
-        self.args.batch_size=1
-
-        self.cls = None
-
-        if int(self.args.cuda) >= 0:
-            torch.cuda.manual_seed(self.args.seed)
-            self.args.device = 'cuda:' + str(self.args.cuda) if int(self.args.cuda) >= 0 else 'cpu'
-        else:
-            self.args.device = 'cpu'
-
-        self.args.prior_iso = self.args.prior_iso or self.args.posterior == 'RiemannianNormal'
-
-        # Choosing and saving a random seed for reproducibility
-        if self.args.seed == 0: self.args.seed = int(torch.randint(0, 2**32 - 1, (1,)).item())
-        torch.manual_seed(self.args.seed)
-        np.random.seed(self.args.seed)
-        torch.cuda.manual_seed_all(self.args.seed)
-        torch.manual_seed(self.args.seed)
-        torch.backends.cudnn.deterministic = True
-        self.model = Tabular(self.args).to(self.args.device)
-        self.optimizer = optim.Adam(self.model.parameters(), lr=self.args.lr, amsgrad=True, betas=(self.args.beta1, self.args.beta2))
-        self.loss_function = getattr(objectives,'vae_objective')
-
-        if self.args.cuda is not None and int(self.args.cuda) >= 0 :
-            os.environ['CUDA_VISIBLE_DEVICES'] = str(self.args.cuda)
-            self.model = self.model.to(self.args.device)
-            for x, val in self.data.items():
-                if torch.is_tensor(self.data[x]):
-                    self.data[x] = self.data[x].to(self.args.device)
-
-        self.tb_embeddings = None
-
-
-    def fit(self):
-
-        tot_params = sum([np.prod(p.size()) for p in self.model.parameters()])
-        logging.info(f"Total number of parameters: {tot_params}")
-
-        t_total = time.time()
-        agg = defaultdict(list)
-        b_loss, b_recon, b_kl , b_mlik , tb_loss = sys.float_info.max, sys.float_info.max ,sys.float_info.max,sys.float_info.max,sys.float_info.max
-        
-        best_losses = []
-        train_losses = []
-        val_losses = []
-
-        for epoch in range(self.args.epochs):
-            self.model.train()
-            self.optimizer.zero_grad()
-
-            qz_x, px_z, lik, kl, loss , embeddings = self.loss_function(self.model,self.data['idx_train'], self.data['features'], self.data['adj_train'], K=self.args.K, beta=self.args.beta, components=True, analytical_kl=self.args.analytical_kl)
-            probe_infnan(loss, "Training loss:")
-            loss.backward()
-            self.optimizer.step()
-
-            t_loss = loss.item() / len(self.data['idx_train'])
-            t_recon = -lik.mean(0).sum().item() / len(self.data['idx_train'])
-            t_kl = kl.sum(-1).mean(0).sum().item() / len(self.data['idx_train'])
-
-            if(t_loss < b_loss):
-                b_loss = t_loss 
-                b_recon = t_recon 
-                b_kl = t_kl 
-
-
-            agg['train_loss'].append(t_loss )
-            agg['train_recon'].append(t_recon )
-            agg['train_kl'].append(t_kl )
-
-            train_losses.append(t_recon)
-            if(len(best_losses) == 0):
-                best_losses.append(train_losses[0])
-            elif (best_losses[-1] > train_losses[-1]):
-                best_losses.append(train_losses[-1])
-            else:
-                best_losses.append(best_losses[-1])
-
-            if (epoch + 1) % self.args.log_freq == 0:
-                print('====> Epoch: {:03d} Loss: {:.2f} Recon: {:.2f} KL: {:.2f}'.format(epoch, agg['train_loss'][-1], agg['train_recon'][-1], agg['train_kl'][-1]))
-
-            if (epoch + 1) % self.args.eval_freq == 0 and self.args.val_prop:
-                self.model.eval()
-                with torch.no_grad():
-                    qz_x, px_z, lik, kl, loss , embeddings= self.loss_function(self.model,self.data['idx_val'], self.data['features'],self.data['adj_train'], K=self.args.K, beta=self.args.beta, components=True)
-                    tt_loss = loss.item() / len(self.data['idx_val'])
-                    val_losses.append(tt_loss)
-                    if(tt_loss < tb_loss):
-                        tb_loss = tt_loss 
-                        self.tb_embeddings = embeddings[0]
-
-                    agg['test_loss'].append(tt_loss )
-                    print('====>             Test loss: {:.4f}'.format(agg['test_loss'][-1]))
-
-
-        logging.info("Optimization Finished!")
-        logging.info("Total time elapsed: {:.4f}s".format(time.time() - t_total))
-        print('====> Training: Best Loss: {:.2f} Best Recon: {:.2f} Best KL: {:.2f}'.format(b_loss,b_recon,b_kl))
-        print('====> Testing: Best Loss: {:.2f}'.format(tb_loss))
-
-        train_idx = self.data['idx_train']
-        val_idx = self.data['idx_val']
-        idx = np.unique(np.concatenate((train_idx,val_idx)))
-        X =  self.model.manifold.logmap0(self.tb_embeddings[idx]).cpu().detach().numpy()
-        y = self.data['labels'].cpu().reshape(-1,1)[idx]
-
-        if(self.args.classifier):
-            self.cls = get_classifier(self.args, X,y)
-            acc,f1,recall,precision,roc_auc = calculate_metrics(self.cls,X,y)
-        elif self.args.clusterer:
-            y = y.reshape(-1,)
-            acc,f1,recall,precision,roc_auc = get_clustering_algorithm(self.args.clusterer,X,y)[6:]
-        elif self.args.anomaly_detector:
-            y = y.reshape(-1,)
-            acc,f1,recall,precision,roc_auc = get_anomaly_detection_algorithm(self.args.anomaly_detector,X,y)[6:]
-
-        return {'train':train_losses,'best':best_losses,'val':val_losses},acc,f1,recall,precision,roc_auc,time.time() - t_total
-
-    def predict(self):
-        self.model.eval()
-        with torch.no_grad():
-            qz_x, px_z, lik, kl, loss , embeddings=self.loss_function(self.model,self.data['idx_test'], self.data['features'],self.data['adj_train'], K=self.args.K, beta=self.args.beta, components=True)
-            tt_loss = loss.item() / len(self.data['idx_test'])
-        test_idx = self.data['idx_test']
-        data = self.model.manifold.logmap0(embeddings[0][test_idx]).cpu().detach().numpy()
-        labels = self.data['labels'].reshape(-1,1).cpu()[test_idx]
-        if self.args.classifier:
-            acc,f1,recall,precision,roc_auc = calculate_metrics(self.cls,data,labels)
-        elif self.args.clusterer:
-            labels = labels.reshape(-1,)
-            acc,f1,recall,precision,roc_auc = get_clustering_algorithm(self.args.clusterer,data,labels)[6:]
-        elif self.args.anomaly_detector:
-            labels = labels.reshape(-1,)
-            acc,f1,recall,precision,roc_auc = get_anomaly_detection_algorithm(self.args.anomaly_detector,data,labels)[6:]
-        self.tb_embeddings = embeddings[0]
-        return abs(tt_loss) , acc, f1 , recall,precision,roc_auc
-
-
-    def save_embeddings(self,directory):
-        tb_embeddings_euc = self.model.manifold.logmap0(self.tb_embeddings)
-        for_classification_hyp = np.hstack((self.tb_embeddings.cpu().detach().numpy(),self.data['labels'].reshape(-1,1).cpu()))
-        for_classification_euc = np.hstack((tb_embeddings_euc.cpu().detach().numpy(),self.data['labels'].reshape(-1,1).cpu()))
-        hyp_file_path = os.path.join(directory,'pvae_embeddings_hyp.csv')
-        euc_file_path = os.path.join(directory,'pvae_embeddings_euc.csv')
-        np.savetxt(hyp_file_path, for_classification_hyp, delimiter=',')
-        np.savetxt(euc_file_path, for_classification_euc, delimiter=',')
diff --git a/PVAE/utils.py b/PVAE/utils.py
deleted file mode 100644
index 2f93595..0000000
--- a/PVAE/utils.py
+++ /dev/null
@@ -1,355 +0,0 @@
-import sys
-import math
-import time
-import os
-import shutil
-import torch
-import torch.distributions as dist
-from torch.autograd import Variable, Function, grad
-from sklearn.preprocessing import MinMaxScaler
-import pandas as pd
-import numpy as np
-import argparse
-import torch.nn as nn
-import scipy.sparse as sp
-
-
-def lexpand(A, *dimensions):
-    """Expand tensor, adding new dimensions on left."""
-    return A.expand(tuple(dimensions) + A.shape)
-
-
-def rexpand(A, *dimensions):
-    """Expand tensor, adding new dimensions on right."""
-    return A.view(A.shape + (1,)*len(dimensions)).expand(A.shape + tuple(dimensions))
-
-
-def assert_no_nan(name, g):
-    if torch.isnan(g).any(): raise Exception('nans in {}'.format(name))
-
-
-def assert_no_grad_nan(name, x):
-    if x.requires_grad: x.register_hook(lambda g: assert_no_nan(name, g))
-
-
-# Classes
-class Constants(object):
-    eta = 1e-5
-    log2 = math.log(2)
-    logpi = math.log(math.pi)
-    log2pi = math.log(2 * math.pi)
-    logceilc = 88                # largest cuda v s.t. exp(v) < inf
-    logfloorc = -104             # smallest cuda v s.t. exp(v) > 0
-    invsqrt2pi = 1. / math.sqrt(2 * math.pi)
-    sqrthalfpi = math.sqrt(math.pi/2)
-
-
-def logsinh(x):
-    # torch.log(sinh(x))
-    return x + torch.log(1 - torch.exp(-2 * x)) - Constants.log2
-
-
-def logcosh(x):
-    # torch.log(cosh(x))
-    return x + torch.log(1 + torch.exp(-2 * x)) - Constants.log2
-
-
-class Arccosh(Function):
-    # https://github.com/facebookresearch/poincare-embeddings/blob/master/model.py
-    @staticmethod
-    def forward(ctx, x):
-        ctx.z = torch.sqrt(x * x - 1)
-        return torch.log(x + ctx.z)
-
-    @staticmethod
-    def backward(ctx, g):
-        z = torch.clamp(ctx.z, min=Constants.eta)
-        z = g / z
-        return z
-
-
-class Arcsinh(Function):
-    @staticmethod
-    def forward(ctx, x):
-        ctx.z = torch.sqrt(x * x + 1)
-        return torch.log(x + ctx.z)
-
-    @staticmethod
-    def backward(ctx, g):
-        z = torch.clamp(ctx.z, min=Constants.eta)
-        z = g / z
-        return z
-
-
-# https://stackoverflow.com/questions/14906764/how-to-redirect-stdout-to-both-file-and-console-with-scripting
-class Logger(object):
-    def __init__(self, filename):
-        self.terminal = sys.stdout
-        self.log = open(filename, "a")
-
-    def write(self, message):
-        self.terminal.write(message)
-        self.log.write(message)
-
-    def flush(self):
-        # this flush method is needed for python 3 compatibility.
-        # this handles the flush command by doing nothing.
-        # you might want to specify some extra behavior here.
-        pass
-
-
-class Timer:
-    def __init__(self, name):
-        self.name = name
-
-    def __enter__(self):
-        self.begin = time.time()
-        return self
-
-    def __exit__(self, *args):
-        self.end = time.time()
-        self.elapsed = self.end - self.begin
-        self.elapsedH = time.gmtime(self.elapsed)
-        print('====> [{}] Time: {:7.3f}s or {}'
-              .format(self.name,
-                      self.elapsed,
-                      time.strftime("%H:%M:%S", self.elapsedH)))
-
-
-# Functions
-def save_vars(vs, filepath):
-    """
-    Saves variables to the given filepath in a safe manner.
-    """
-    if os.path.exists(filepath):
-        shutil.copyfile(filepath, '{}.old'.format(filepath))
-    torch.save(vs, filepath)
-
-
-def save_model(model, filepath):
-    """
-    To load a saved model, simply use
-    `model.load_state_dict(torch.load('path-to-saved-model'))`.
-    """
-    save_vars(model.state_dict(), filepath)
-
-
-def log_mean_exp(value, dim=0, keepdim=False):
-    return log_sum_exp(value, dim, keepdim) - math.log(value.size(dim))
-
-
-def log_sum_exp(value, dim=0, keepdim=False):
-    m, _ = torch.max(value, dim=dim, keepdim=True)
-    value0 = value - m
-    if keepdim is False:
-        m = m.squeeze(dim)
-    return m + torch.log(torch.sum(torch.exp(value0), dim=dim, keepdim=keepdim))
-
-
-def log_sum_exp_signs(value, signs, dim=0, keepdim=False):
-    m, _ = torch.max(value, dim=dim, keepdim=True)
-    value0 = value - m
-    if keepdim is False:
-        m = m.squeeze(dim)
-    return m + torch.log(torch.sum(signs * torch.exp(value0), dim=dim, keepdim=keepdim))
-
-
-def get_mean_param(params):
-    """Return the parameter used to show reconstructions or generations.
-    For example, the mean for Normal, or probs for Bernoulli.
-    For Bernoulli, skip first parameter, as that's (scalar) temperature
-    """
-    if params[0].dim() == 0:
-        return params[1]
-    # elif len(params) == 3:
-    #     return params[1]
-    else:
-        return params[0]
-
-
-def probe_infnan(v, name, extras={}):
-    nps = torch.isnan(v)
-    s = nps.sum().item()
-    if s > 0:
-        print('>>> {} >>>'.format(name))
-        print(name, s)
-        print(v[nps])
-        for k, val in extras.items():
-            print(k, val, val.sum().item())
-        quit()
-
-
-def has_analytic_kl(type_p, type_q):
-    return (type_p, type_q) in torch.distributions.kl._KL_REGISTRY
-
-
-def split_data(labels, test_prop,val_prop):
-    nb_nodes = labels.shape[0]
-    all_idx = np.arange(nb_nodes)
-    pos_idx = labels.nonzero()[0]
-    neg_idx = (1. - labels).nonzero()[0]
-    np.random.shuffle(pos_idx)
-    np.random.shuffle(neg_idx)
-    pos_idx = pos_idx.tolist()
-    neg_idx = neg_idx.tolist()
-    nb_pos_neg = min(len(pos_idx), len(neg_idx))
-    nb_val = round(val_prop * nb_pos_neg)
-    nb_test = round(test_prop * nb_pos_neg)
-    idx_val_pos, idx_test_pos, idx_train_pos = pos_idx[:nb_val], pos_idx[nb_val:nb_val + nb_test], pos_idx[
-                                                                                                   nb_val + nb_test:]
-    idx_val_neg, idx_test_neg, idx_train_neg = neg_idx[:nb_val], neg_idx[nb_val:nb_val + nb_test], neg_idx[
-                                                                                                   nb_val + nb_test:]
-    
-    return idx_test_pos + idx_test_neg, idx_train_pos + idx_train_neg, idx_val_pos + idx_val_neg,
-
-def process_data(args, adj,features,labels):
-    data = process_data_nc(args,adj,features,labels)
-    data['adj_train'], data['features'] = process(
-            data['adj_train'], data['features'],args.normalize_adj,args.normalize_feats
-    )
-    return data
-
-def process_data_nc(args,adj,features,labels):
-    idx_test, idx_train , idx_val= split_data(labels, args.test_prop,args.val_prop)
-    labels = torch.LongTensor(labels)
-    data = {'adj_train': sp.csr_matrix(adj), 'features': features, 'labels': labels, 'idx_train': idx_train,  'idx_test': idx_test , 'idx_val':idx_val}
-    return data
-
-def process(adj, features, normalize_adj, normalize_feats):
-    if sp.isspmatrix(features):
-        features = np.array(features.todense())
-    if normalize_feats: 
-        features = normalize(features)
-    features = torch.Tensor(features)
-    if normalize_adj:
-        adj = normalize(adj)
-    adj = sparse_mx_to_torch_sparse_tensor(adj)
-    return adj, features
-
-
-def normalize(mx):
-    """Row-normalize sparse matrix."""
-    rowsum = np.array(mx.sum(1))
-    r_inv = np.power(rowsum, -1).flatten()
-    r_inv[np.isinf(r_inv)] = 0.
-    r_mat_inv = sp.diags(r_inv)
-    mx = r_mat_inv.dot(mx)
-    return mx
-
-
-def sparse_mx_to_torch_sparse_tensor(sparse_mx):
-    """Convert a scipy sparse matrix to a torch sparse tensor."""
-    sparse_mx = sparse_mx.tocoo()
-    indices = torch.from_numpy(
-            np.vstack((sparse_mx.row, sparse_mx.col)).astype(np.int64)
-    )
-    values = torch.Tensor(sparse_mx.data)
-    shape = torch.Size(sparse_mx.shape)
-    return torch.sparse.FloatTensor(indices, values, shape)
-
-def create_args(*args):
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--dim', type=int, default=args[0])
-    parser.add_argument('--hidden_dim', type=int, default=args[1])
-    parser.add_argument('--num_layers', type=int, default=args[2])
-    parser.add_argument('--c', type=int, default=args[3])
-    parser.add_argument('--act', type=str, default=args[4])
-    parser.add_argument('--lr', type=float, default=args[5])
-    parser.add_argument('--cuda', type=int, default=args[6])
-    parser.add_argument('--epochs', type=int, default=args[7])
-    parser.add_argument('--seed', type=int, default=args[8])
-    parser.add_argument('--eval_freq', type=int, default=args[9])
-    parser.add_argument('--val_prop', type=float, default=args[10])
-    parser.add_argument('--test_prop', type=float, default=args[11])
-    parser.add_argument('--dropout', type=float, default=args[12])
-    parser.add_argument('--beta1', type=float, default=args[13])
-    parser.add_argument('--beta2', type=float, default=args[14])
-    parser.add_argument('--K', type=int, default=args[15])
-    parser.add_argument('--beta', type=float, default=args[16])
-    parser.add_argument('--analytical_kl', type=bool, default=args[17])
-    parser.add_argument('--posterior', type=str, default=args[18])
-    parser.add_argument('--prior', type=str, default=args[19])
-    parser.add_argument('--prior_iso', type=bool, default=args[20])
-    parser.add_argument('--prior_std', type=float, default=args[21])
-    parser.add_argument('--learn_prior_std', type=bool, default=args[22])
-    parser.add_argument('--enc', type=str, default=args[23])
-    parser.add_argument('--dec', type=str, default=args[24])
-    parser.add_argument('--bias', type=bool, default=args[25])
-    parser.add_argument('--alpha', type=float, default=args[26])
-    parser.add_argument('--classifier', type=str, default=args[27])
-    parser.add_argument('--clusterer', type=str, default=args[28])
-    parser.add_argument('--log_freq', type=int, default=args[29])
-    parser.add_argument('--normalize_adj', type=bool, default=args[30])
-    parser.add_argument('--normalize_feats', type=bool, default=args[31])
-    parser.add_argument('--anomaly_detector', type=str, default=args[32])
-    flags, unknown = parser.parse_known_args()
-    return flags
-
-
-def get_activation(args):
-    if args.act == 'leaky_relu':
-        return nn.LeakyReLU(args.alpha)
-    elif args.act == 'rrelu':
-        return nn.RReLU()
-    elif args.act == 'relu':
-        return nn.ReLU()
-    elif args.act == 'elu':
-        return nn.ELU()
-    elif args.act == 'prelu':
-        return nn.PReLU()
-    elif args.act == 'selu':
-        return nn.SELU()
-
-
-from Ghypeddings.classifiers import *
-def get_classifier(args,X,y):
-    if(args.classifier):
-        if(args.classifier == 'svm'):
-            return SVM(X,y)
-        elif(args.classifier == 'mlp'):
-            return mlp(X,y,1,10,seed=args.seed)
-        elif(args.classifier == 'decision tree'):
-            return decision_tree(X,y)
-        elif(args.classifier == 'random forest'):
-            return random_forest(X,y,args.seed)
-        elif(args.classifier == 'adaboost'):
-            return adaboost(X,y,args.seed)
-        elif(args.classifier == 'knn'):
-            return KNN(X,y)
-        elif(args.classifier == 'naive bayes'):
-            return naive_bayes(X,y)
-        else:
-            raise NotImplementedError
-    
-
-from Ghypeddings.clusterers import *
-def get_clustering_algorithm(clusterer,X,y):
-    if(clusterer == 'agglomerative_clustering'):
-        return agglomerative_clustering(X,y)
-    elif(clusterer == 'dbscan'):
-        return dbscan(X,y)
-    elif(clusterer == 'fuzzy_c_mean'):
-        return fuzzy_c_mean(X,y)
-    elif(clusterer == 'gaussian_mixture'):
-        return gaussian_mixture(X,y)
-    elif(clusterer == 'kmeans'):
-        return kmeans(X,y)
-    elif(clusterer == 'mean_shift'):
-        return mean_shift(X,y)
-    else:
-        raise NotImplementedError
-    
-from Ghypeddings.anomaly_detection import *
-def get_anomaly_detection_algorithm(algorithm,X,y):
-    if(algorithm == 'isolation_forest'):
-        return isolation_forest(X,y)
-    elif(algorithm == 'one_class_svm'):
-        return one_class_svm(X,y)
-    elif(algorithm == 'dbscan'):
-        return dbscan(X,y)
-    elif(algorithm == 'kmeans'):
-        return kmeans(X,y,n_clusters=2)
-    elif(algorithm == 'local_outlier_factor'):
-        return local_outlier_factor(X,y)
-    else:
-        raise NotImplementedError
\ No newline at end of file
diff --git a/Poincare/__init__.py b/Poincare/__init__.py
deleted file mode 100644
index bfa83a0..0000000
--- a/Poincare/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from __future__ import print_function
-from __future__ import division
diff --git a/Poincare/layers/__init__.py b/Poincare/layers/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/Poincare/layers/layers.py b/Poincare/layers/layers.py
deleted file mode 100644
index 94778f8..0000000
--- a/Poincare/layers/layers.py
+++ /dev/null
@@ -1,43 +0,0 @@
-"""Euclidean layers."""
-import math
-
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-from torch.nn.modules.module import Module
-from torch.nn.parameter import Parameter
-
-
-def get_dim_act(args):
-    """
-    Helper function to get dimension and activation at every layer.
-    :param args:
-    :return:
-    """
-    if not args.act:
-        act = lambda x: x
-    else:
-        act = getattr(F, args.act)
-    acts = [act] * (args.num_layers - 1)
-    dims = [args.feat_dim] + ([args.dim] * (args.num_layers - 1))
-    if args.task in ['lp', 'rec']:
-        dims += [args.dim]
-        acts += [act]
-    return dims, acts
-
-class Linear(Module):
-    """
-    Simple Linear layer with dropout.
-    """
-
-    def __init__(self, in_features, out_features, dropout, act, use_bias):
-        super(Linear, self).__init__()
-        self.dropout = dropout
-        self.linear = nn.Linear(in_features, out_features, use_bias)
-        self.act = act
-
-    def forward(self, x):
-        hidden = self.linear.forward(x)
-        hidden = F.dropout(hidden, self.dropout, training=self.training)
-        out = self.act(hidden)
-        return out
diff --git a/Poincare/manifolds/__init__.py b/Poincare/manifolds/__init__.py
deleted file mode 100644
index 1ac5720..0000000
--- a/Poincare/manifolds/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from Ghypeddings.Poincare.manifolds.base import ManifoldParameter
-from Ghypeddings.Poincare.manifolds.poincare import PoincareBall
-from Ghypeddings.Poincare.manifolds.euclidean import Euclidean
\ No newline at end of file
diff --git a/Poincare/manifolds/base.py b/Poincare/manifolds/base.py
deleted file mode 100644
index 925d4a6..0000000
--- a/Poincare/manifolds/base.py
+++ /dev/null
@@ -1,88 +0,0 @@
-"""Base manifold."""
-
-from torch.nn import Parameter
-
-
-class Manifold(object):
-    """
-    Abstract class to define operations on a manifold.
-    """
-
-    def __init__(self):
-        super().__init__()
-        self.eps = 10e-8
-
-    def sqdist(self, p1, p2, c):
-        """Squared distance between pairs of points."""
-        raise NotImplementedError
-
-    def egrad2rgrad(self, p, dp, c):
-        """Converts Euclidean Gradient to Riemannian Gradients."""
-        raise NotImplementedError
-
-    def proj(self, p, c):
-        """Projects point p on the manifold."""
-        raise NotImplementedError
-
-    def proj_tan(self, u, p, c):
-        """Projects u on the tangent space of p."""
-        raise NotImplementedError
-
-    def proj_tan0(self, u, c):
-        """Projects u on the tangent space of the origin."""
-        raise NotImplementedError
-
-    def expmap(self, u, p, c):
-        """Exponential map of u at point p."""
-        raise NotImplementedError
-
-    def logmap(self, p1, p2, c):
-        """Logarithmic map of point p1 at point p2."""
-        raise NotImplementedError
-
-    def expmap0(self, u, c):
-        """Exponential map of u at the origin."""
-        raise NotImplementedError
-
-    def logmap0(self, p, c):
-        """Logarithmic map of point p at the origin."""
-        raise NotImplementedError
-
-    def mobius_add(self, x, y, c, dim=-1):
-        """Adds points x and y."""
-        raise NotImplementedError
-
-    def mobius_matvec(self, m, x, c):
-        """Performs hyperboic martrix-vector multiplication."""
-        raise NotImplementedError
-
-    def init_weights(self, w, c, irange=1e-5):
-        """Initializes random weigths on the manifold."""
-        raise NotImplementedError
-
-    def inner(self, p, c, u, v=None, keepdim=False):
-        """Inner product for tangent vectors at point x."""
-        raise NotImplementedError
-
-    def ptransp(self, x, y, u, c):
-        """Parallel transport of u from x to y."""
-        raise NotImplementedError
-
-    def ptransp0(self, x, u, c):
-        """Parallel transport of u from the origin to y."""
-        raise NotImplementedError
-
-
-class ManifoldParameter(Parameter):
-    """
-    Subclass of torch.nn.Parameter for Riemannian optimization.
-    """
-    def __new__(cls, data, requires_grad, manifold, c):
-        return Parameter.__new__(cls, data, requires_grad)
-
-    def __init__(self, data, requires_grad, manifold, c):
-        self.c = c
-        self.manifold = manifold
-
-    def __repr__(self):
-        return '{} Parameter containing:\n'.format(self.manifold.name) + super(Parameter, self).__repr__()
diff --git a/Poincare/manifolds/euclidean.py b/Poincare/manifolds/euclidean.py
deleted file mode 100644
index 177ebb2..0000000
--- a/Poincare/manifolds/euclidean.py
+++ /dev/null
@@ -1,67 +0,0 @@
-"""Euclidean manifold."""
-
-from Ghypeddings.Poincare.manifolds.base import Manifold
-
-
-class Euclidean(Manifold):
-    """
-    Euclidean Manifold class.
-    """
-
-    def __init__(self):
-        super(Euclidean, self).__init__()
-        self.name = 'Euclidean'
-
-    def normalize(self, p):
-        dim = p.size(-1)
-        p.view(-1, dim).renorm_(2, 0, 1.)
-        return p
-
-    def sqdist(self, p1, p2, c):
-        return (p1 - p2).pow(2).sum(dim=-1)
-
-    def egrad2rgrad(self, p, dp, c):
-        return dp
-
-    def proj(self, p, c):
-        return p
-
-    def proj_tan(self, u, p, c):
-        return u
-
-    def proj_tan0(self, u, c):
-        return u
-
-    def expmap(self, u, p, c):
-        return p + u
-
-    def logmap(self, p1, p2, c):
-        return p2 - p1
-
-    def expmap0(self, u, c):
-        return u
-
-    def logmap0(self, p, c):
-        return p
-
-    def mobius_add(self, x, y, c, dim=-1):
-        return x + y
-
-    def mobius_matvec(self, m, x, c):
-        mx = x @ m.transpose(-1, -2)
-        return mx
-
-    def init_weights(self, w, c, irange=1e-5):
-        w.data.uniform_(-irange, irange)
-        return w
-
-    def inner(self, p, c, u, v=None, keepdim=False):
-        if v is None:
-            v = u
-        return (u * v).sum(dim=-1, keepdim=keepdim)
-
-    def ptransp(self, x, y, v, c):
-        return v
-
-    def ptransp0(self, x, v, c):
-        return x + v
diff --git a/Poincare/manifolds/poincare.py b/Poincare/manifolds/poincare.py
deleted file mode 100644
index 3f52cee..0000000
--- a/Poincare/manifolds/poincare.py
+++ /dev/null
@@ -1,145 +0,0 @@
-"""Poincare ball manifold."""
-
-import torch
-
-from Ghypeddings.Poincare.manifolds.base import Manifold
-from Ghypeddings.Poincare.utils.math_utils import artanh, tanh
-
-
-class PoincareBall(Manifold):
-    """
-    PoicareBall Manifold class.
-
-    We use the following convention: x0^2 + x1^2 + ... + xd^2 < 1 / c
-
-    Note that 1/sqrt(c) is the Poincare ball radius.
-
-    """
-
-    def __init__(self, ):
-        super(PoincareBall, self).__init__()
-        self.name = 'PoincareBall'
-        self.min_norm = 1e-15
-        self.eps = {torch.float32: 4e-3, torch.float64: 1e-5}
-
-    def sqdist(self, p1, p2, c):
-        sqrt_c = c ** 0.5
-        dist_c = artanh(
-            sqrt_c * self.mobius_add(-p1, p2, c, dim=-1).norm(dim=-1, p=2, keepdim=False)
-        )
-        dist = dist_c * 2 / sqrt_c
-        return dist ** 2
-
-    def _lambda_x(self, x, c):
-        x_sqnorm = torch.sum(x.data.pow(2), dim=-1, keepdim=True)
-        return 2 / (1. - c * x_sqnorm).clamp_min(self.min_norm)
-
-    def egrad2rgrad(self, p, dp, c):
-        lambda_p = self._lambda_x(p, c)
-        dp /= lambda_p.pow(2)
-        return dp
-
-    def proj(self, x, c):
-        norm = torch.clamp_min(x.norm(dim=-1, keepdim=True, p=2), self.min_norm)
-        maxnorm = (1 - self.eps[x.dtype]) / (c ** 0.5)
-        cond = norm > maxnorm
-        projected = x / norm * maxnorm
-        return torch.where(cond, projected, x)
-
-    def proj_tan(self, u, p, c):
-        return u
-
-    def proj_tan0(self, u, c):
-        return u
-
-    def expmap(self, u, p, c):
-        sqrt_c = c ** 0.5
-        u_norm = u.norm(dim=-1, p=2, keepdim=True).clamp_min(self.min_norm)
-        second_term = (
-                tanh(sqrt_c / 2 * self._lambda_x(p, c) * u_norm)
-                * u
-                / (sqrt_c * u_norm)
-        )
-        gamma_1 = self.mobius_add(p, second_term, c)
-        return gamma_1
-
-    def logmap(self, p1, p2, c):
-        sub = self.mobius_add(-p1, p2, c)
-        sub_norm = sub.norm(dim=-1, p=2, keepdim=True).clamp_min(self.min_norm)
-        lam = self._lambda_x(p1, c)
-        sqrt_c = c ** 0.5
-        return 2 / sqrt_c / lam * artanh(sqrt_c * sub_norm) * sub / sub_norm
-
-    def expmap0(self, u, c):
-        sqrt_c = c ** 0.5
-        u_norm = torch.clamp_min(u.norm(dim=-1, p=2, keepdim=True), self.min_norm)
-        gamma_1 = tanh(sqrt_c * u_norm) * u / (sqrt_c * u_norm)
-        return gamma_1
-
-    def logmap0(self, p, c):
-        sqrt_c = c ** 0.5
-        p_norm = p.norm(dim=-1, p=2, keepdim=True).clamp_min(self.min_norm)
-        scale = 1. / sqrt_c * artanh(sqrt_c * p_norm) / p_norm
-        return scale * p
-
-    def mobius_add(self, x, y, c, dim=-1):
-        x2 = x.pow(2).sum(dim=dim, keepdim=True)
-        y2 = y.pow(2).sum(dim=dim, keepdim=True)
-        xy = (x * y).sum(dim=dim, keepdim=True)
-        num = (1 + 2 * c * xy + c * y2) * x + (1 - c * x2) * y
-        denom = 1 + 2 * c * xy + c ** 2 * x2 * y2
-        return num / denom.clamp_min(self.min_norm)
-
-    def mobius_matvec(self, m, x, c):
-        sqrt_c = c ** 0.5
-        x_norm = x.norm(dim=-1, keepdim=True, p=2).clamp_min(self.min_norm)
-        mx = x @ m.transpose(-1, -2)
-        mx_norm = mx.norm(dim=-1, keepdim=True, p=2).clamp_min(self.min_norm)
-        res_c = tanh(mx_norm / x_norm * artanh(sqrt_c * x_norm)) * mx / (mx_norm * sqrt_c)
-        cond = (mx == 0).prod(-1, keepdim=True, dtype=torch.uint8)
-        res_0 = torch.zeros(1, dtype=res_c.dtype, device=res_c.device)
-        res = torch.where(cond, res_0, res_c)
-        return res
-
-    def init_weights(self, w, c, irange=1e-5):
-        w.data.uniform_(-irange, irange)
-        return w
-
-    def _gyration(self, u, v, w, c, dim: int = -1):
-        u2 = u.pow(2).sum(dim=dim, keepdim=True)
-        v2 = v.pow(2).sum(dim=dim, keepdim=True)
-        uv = (u * v).sum(dim=dim, keepdim=True)
-        uw = (u * w).sum(dim=dim, keepdim=True)
-        vw = (v * w).sum(dim=dim, keepdim=True)
-        c2 = c ** 2
-        a = -c2 * uw * v2 + c * vw + 2 * c2 * uv * vw
-        b = -c2 * vw * u2 - c * uw
-        d = 1 + 2 * c * uv + c2 * u2 * v2
-        return w + 2 * (a * u + b * v) / d.clamp_min(self.min_norm)
-
-    def inner(self, x, c, u, v=None, keepdim=False):
-        if v is None:
-            v = u
-        lambda_x = self._lambda_x(x, c)
-        return lambda_x ** 2 * (u * v).sum(dim=-1, keepdim=keepdim)
-
-    def ptransp(self, x, y, u, c):
-        lambda_x = self._lambda_x(x, c)
-        lambda_y = self._lambda_x(y, c)
-        return self._gyration(y, -x, u, c) * lambda_x / lambda_y
-
-    def ptransp_(self, x, y, u, c):
-        lambda_x = self._lambda_x(x, c)
-        lambda_y = self._lambda_x(y, c)
-        return self._gyration(y, -x, u, c) * lambda_x / lambda_y
-
-    def ptransp0(self, x, u, c):
-        lambda_x = self._lambda_x(x, c)
-        return 2 * u / lambda_x.clamp_min(self.min_norm)
-
-    def to_hyperboloid(self, x, c):
-        K = 1./ c
-        sqrtK = K ** 0.5
-        sqnorm = torch.norm(x, p=2, dim=1, keepdim=True) ** 2
-        return sqrtK * torch.cat([K + sqnorm, 2 * sqrtK * x], dim=1) / (K - sqnorm)
-
diff --git a/Poincare/models/__init__.py b/Poincare/models/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/Poincare/models/base_models.py b/Poincare/models/base_models.py
deleted file mode 100644
index 142b937..0000000
--- a/Poincare/models/base_models.py
+++ /dev/null
@@ -1,77 +0,0 @@
-"""Base model class."""
-
-import numpy as np
-from sklearn.metrics import roc_auc_score, average_precision_score
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-
-import Ghypeddings.Poincare.manifolds as manifolds
-import Ghypeddings.Poincare.models.encoders as encoders
-from Ghypeddings.Poincare.models.decoders import model2decoder
-from Ghypeddings.Poincare.utils.eval_utils import acc_f1
-
-
-class BaseModel(nn.Module):
-    """
-    Base model for graph embedding tasks.
-    """
-
-    def __init__(self, args):
-        super(BaseModel, self).__init__()
-        self.manifold_name = 'PoincareBall'
-        self.c = torch.tensor([1.0])
-        if not args.cuda == -1:
-            self.c = self.c.to(args.device)
-        self.manifold = getattr(manifolds, self.manifold_name)()
-        self.nnodes = args.n_nodes
-        self.encoder = getattr(encoders, 'Shallow')(self.c, args)
-
-    def encode(self, x):
-        h = self.encoder.encode(x)
-        return h
-
-    def compute_metrics(self, embeddings, data, split):
-        raise NotImplementedError
-
-    def init_metric_dict(self):
-        raise NotImplementedError
-
-    def has_improved(self, m1, m2):
-        raise NotImplementedError
-
-
-class NCModel(BaseModel):
-    """
-    Base model for node classification task.
-    """
-
-    def __init__(self, args):
-        super(NCModel, self).__init__(args)
-        self.decoder = model2decoder(1.0, args)
-        if args.n_classes > 2:
-            self.f1_average = 'micro'
-        else:
-            self.f1_average = 'binary'
-        
-        self.weights = torch.Tensor([1.] * args.n_classes)
-        if not args.cuda == -1:
-            self.weights = self.weights.to(args.device)
-
-    def decode(self, h, idx):
-        output = self.decoder.decode(h)
-        return F.log_softmax(output[idx], dim=1)
-
-    def compute_metrics(self, embeddings, data, split):
-        idx = data[f'idx_{split}']
-        output = self.decode(embeddings, idx)
-        loss = F.nll_loss(output, data['labels'][idx], self.weights)
-        acc, f1,recall,precision,roc_auc = acc_f1(output, data['labels'][idx], average=self.f1_average)
-        metrics = {'loss': loss, 'acc': acc, 'f1': f1,'recall':recall,'precision':precision,'roc_auc':roc_auc}
-        return metrics
-
-    def init_metric_dict(self):
-        return {'acc': -1, 'f1': -1}
-
-    def has_improved(self, m1, m2):
-        return m1["f1"] < m2["f1"]
\ No newline at end of file
diff --git a/Poincare/models/decoders.py b/Poincare/models/decoders.py
deleted file mode 100644
index 8532b62..0000000
--- a/Poincare/models/decoders.py
+++ /dev/null
@@ -1,46 +0,0 @@
-"""Graph decoders."""
-import Ghypeddings.Poincare.manifolds as manifolds
-import torch.nn as nn
-import torch.nn.functional as F
-from Ghypeddings.Poincare.layers.layers import  Linear
-import torch
-
-class Decoder(nn.Module):
-    """
-    Decoder abstract class for node classification tasks.
-    """
-
-    def __init__(self, c):
-        super(Decoder, self).__init__()
-        self.c = c
-
-    def decode(self, x):
-        probs = self.cls.forward(x)
-        return probs
-
-
-class LinearDecoder(Decoder):
-    """
-    MLP Decoder for Hyperbolic/Euclidean node classification models.
-    """
-
-    def __init__(self, c, args):
-        super(LinearDecoder, self).__init__(c)
-        self.manifold = getattr(manifolds, 'PoincareBall')()
-        self.input_dim = args.dim + args.feat_dim
-        self.output_dim = args.n_classes
-        self.bias = True
-        self.cls = Linear(self.input_dim, self.output_dim, args.dropout, lambda x: x, self.bias)
-
-    def decode(self, x):
-        h = self.manifold.proj_tan0(self.manifold.logmap0(x, c=self.c), c=self.c)
-        return super(LinearDecoder, self).decode(h)
-
-    def extra_repr(self):
-        return 'in_features={}, out_features={}, bias={}, c={}'.format(
-                self.input_dim, self.output_dim, self.bias, self.c
-        )
-
-
-model2decoder = LinearDecoder
-
diff --git a/Poincare/models/encoders.py b/Poincare/models/encoders.py
deleted file mode 100644
index 42e6504..0000000
--- a/Poincare/models/encoders.py
+++ /dev/null
@@ -1,42 +0,0 @@
-"""Graph encoders."""
-
-import numpy as np
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-
-import Ghypeddings.Poincare.manifolds as manifolds
-
-class Encoder(nn.Module):
-    """
-    Encoder abstract class.
-    """
-
-    def __init__(self, c):
-        super(Encoder, self).__init__()
-        self.c = c
-
-    def encode(self, x):
-        pass
-
-class Shallow(Encoder):
-    """
-    Shallow Embedding method.
-    Learns embeddings or loads pretrained embeddings and uses an MLP for classification.
-    """
-
-    def __init__(self, c, args):
-        super(Shallow, self).__init__(c)
-        self.manifold = getattr(manifolds, 'PoincareBall')()
-        weights = torch.Tensor(args.n_nodes, args.dim)
-        weights = self.manifold.init_weights(weights, self.c)
-        trainable = True
-        self.lt = manifolds.ManifoldParameter(weights, trainable, self.manifold, self.c)
-        self.all_nodes = torch.LongTensor(list(range(args.n_nodes)))
-        layers = []
-        self.layers = nn.Sequential(*layers)
-
-    def encode(self, x):
-        h = self.lt[self.all_nodes, :]
-        h = torch.cat((h, x), 1)
-        return h
diff --git a/Poincare/optimizers/__init__.py b/Poincare/optimizers/__init__.py
deleted file mode 100644
index 6b0d929..0000000
--- a/Poincare/optimizers/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from torch.optim import Adam
-from Ghypeddings.Poincare.optimizers.radam import RiemannianAdam
diff --git a/Poincare/optimizers/radam.py b/Poincare/optimizers/radam.py
deleted file mode 100644
index f490442..0000000
--- a/Poincare/optimizers/radam.py
+++ /dev/null
@@ -1,172 +0,0 @@
-"""Riemannian adam optimizer geoopt implementation (https://github.com/geoopt/)."""
-import torch.optim
-from Ghypeddings.Poincare.manifolds import Euclidean, ManifoldParameter
-
-_default_manifold = Euclidean()
-
-
-class OptimMixin(object):
-    def __init__(self, *args, stabilize=None, **kwargs):
-        self._stabilize = stabilize
-        super().__init__(*args, **kwargs)
-
-    def stabilize_group(self, group):
-        pass
-
-    def stabilize(self):
-        """Stabilize parameters if they are off-manifold due to numerical reasons
-        """
-        for group in self.param_groups:
-            self.stabilize_group(group)
-
-
-def copy_or_set_(dest, source):
-    """
-    A workaround to respect strides of :code:`dest` when copying :code:`source`
-    (https://github.com/geoopt/geoopt/issues/70)
-    Parameters
-    ----------
-    dest : torch.Tensor
-        Destination tensor where to store new data
-    source : torch.Tensor
-        Source data to put in the new tensor
-    Returns
-    -------
-    dest
-        torch.Tensor, modified inplace
-    """
-    if dest.stride() != source.stride():
-        return dest.copy_(source)
-    else:
-        return dest.set_(source)
-
-
-class RiemannianAdam(OptimMixin, torch.optim.Adam):
-    r"""Riemannian Adam with the same API as :class:`torch.optim.Adam`
-    Parameters
-    ----------
-    params : iterable
-        iterable of parameters to optimize or dicts defining
-        parameter groups
-    lr : float (optional)
-        learning rate (default: 1e-3)
-    betas : Tuple[float, float] (optional)
-        coefficients used for computing
-        running averages of gradient and its square (default: (0.9, 0.999))
-    eps : float (optional)
-        term added to the denominator to improve
-        numerical stability (default: 1e-8)
-    weight_decay : float (optional)
-        weight decay (L2 penalty) (default: 0)
-    amsgrad : bool (optional)
-        whether to use the AMSGrad variant of this
-        algorithm from the paper `On the Convergence of Adam and Beyond`_
-        (default: False)
-    Other Parameters
-    ----------------
-    stabilize : int
-        Stabilize parameters if they are off-manifold due to numerical
-        reasons every ``stabilize`` steps (default: ``None`` -- no stabilize)
-    .. _On the Convergence of Adam and Beyond:
-        https://openreview.net/forum?id=ryQu7f-RZ
-    """
-
-    def step(self, closure=None):
-        """Performs a single optimization step.
-        Arguments
-        ---------
-        closure : callable (optional)
-            A closure that reevaluates the model
-            and returns the loss.
-        """
-        loss = None
-        if closure is not None:
-            loss = closure()
-        with torch.no_grad():
-            for group in self.param_groups:
-                if "step" not in group:
-                    group["step"] = 0
-                betas = group["betas"]
-                weight_decay = group["weight_decay"]
-                eps = group["eps"]
-                learning_rate = group["lr"]
-                amsgrad = group["amsgrad"]
-                for point in group["params"]:
-                    grad = point.grad
-                    if grad is None:
-                        continue
-                    if isinstance(point, (ManifoldParameter)):
-                        manifold = point.manifold
-                        c = point.c
-                    else:
-                        manifold = _default_manifold
-                        c = None
-                    if grad.is_sparse:
-                        raise RuntimeError(
-                                "Riemannian Adam does not support sparse gradients yet (PR is welcome)"
-                        )
-
-                    state = self.state[point]
-
-                    # State initialization
-                    if len(state) == 0:
-                        state["step"] = 0
-                        # Exponential moving average of gradient values
-                        state["exp_avg"] = torch.zeros_like(point)
-                        # Exponential moving average of squared gradient values
-                        state["exp_avg_sq"] = torch.zeros_like(point)
-                        if amsgrad:
-                            # Maintains max of all exp. moving avg. of sq. grad. values
-                            state["max_exp_avg_sq"] = torch.zeros_like(point)
-                    # make local variables for easy access
-                    exp_avg = state["exp_avg"]
-                    exp_avg_sq = state["exp_avg_sq"]
-                    # actual step
-                    grad.add_(weight_decay, point)
-                    grad = manifold.egrad2rgrad(point, grad, c)
-                    exp_avg.mul_(betas[0]).add_(1 - betas[0], grad)
-                    exp_avg_sq.mul_(betas[1]).add_(
-                            1 - betas[1], manifold.inner(point, c, grad, keepdim=True)
-                    )
-                    if amsgrad:
-                        max_exp_avg_sq = state["max_exp_avg_sq"]
-                        # Maintains the maximum of all 2nd moment running avg. till now
-                        torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq)
-                        # Use the max. for normalizing running avg. of gradient
-                        denom = max_exp_avg_sq.sqrt().add_(eps)
-                    else:
-                        denom = exp_avg_sq.sqrt().add_(eps)
-                    group["step"] += 1
-                    bias_correction1 = 1 - betas[0] ** group["step"]
-                    bias_correction2 = 1 - betas[1] ** group["step"]
-                    step_size = (
-                        learning_rate * bias_correction2 ** 0.5 / bias_correction1
-                    )
-                    # copy the state, we need it for retraction
-                    # get the direction for ascend
-                    direction = exp_avg / denom
-                    # transport the exponential averaging to the new point
-                    new_point = manifold.proj(manifold.expmap(-step_size * direction, point, c), c)
-                    exp_avg_new = manifold.ptransp(point, new_point, exp_avg, c)
-                    # use copy only for user facing point
-                    copy_or_set_(point, new_point)
-                    exp_avg.set_(exp_avg_new)
-
-                    group["step"] += 1
-                if self._stabilize is not None and group["step"] % self._stabilize == 0:
-                    self.stabilize_group(group)
-        return loss
-
-    @torch.no_grad()
-    def stabilize_group(self, group):
-        for p in group["params"]:
-            if not isinstance(p, ManifoldParameter):
-                continue
-            state = self.state[p]
-            if not state:  # due to None grads
-                continue
-            manifold = p.manifold
-            c = p.c
-            exp_avg = state["exp_avg"]
-            copy_or_set_(p, manifold.proj(p, c))
-            exp_avg.set_(manifold.proj_tan(exp_avg, u, c))
diff --git a/Poincare/poincare.py b/Poincare/poincare.py
deleted file mode 100644
index 018bf5b..0000000
--- a/Poincare/poincare.py
+++ /dev/null
@@ -1,156 +0,0 @@
-from __future__ import division
-from __future__ import print_function
-
-import logging
-import os
-import time
-
-import numpy as np
-import Ghypeddings.Poincare.optimizers as optimizers
-import torch
-from Ghypeddings.Poincare.models.base_models import NCModel
-from Ghypeddings.Poincare.utils.data_utils import process_data
-from Ghypeddings.Poincare.utils.train_utils import format_metrics, create_args
-
-
-class POINCARE:
-    def __init__(self,
-                adj,
-                features,
-                labels,
-                dim,
-                grad_clip=None,
-                weight_decay=0.01,
-                lr=0.1,
-                gamma=0.5,
-                lr_reduce_freq=500,
-                cuda=0,
-                epochs=50,
-                min_epochs=50,
-                patience=None,
-                seed=42,
-                log_freq=1,
-                eval_freq=1,
-                val_prop=0.15,
-                test_prop=0.15,
-                double_precision=0,
-                dropout=0.01,
-                normalize_adj=False,
-                normalize_feats=True):
-        
-        self.args = create_args(dim,grad_clip,weight_decay,lr,gamma,lr_reduce_freq,cuda,epochs,min_epochs,patience,seed,log_freq,eval_freq,val_prop,test_prop,double_precision,dropout,normalize_adj,normalize_feats)
-        self.args.n_nodes = adj.shape[0]
-        self.args.feat_dim = features.shape[1]
-        self.args.n_classes = len(np.unique(labels))
-        self.data = process_data(self.args,adj,features,labels)
-
-        np.random.seed(self.args.seed)
-        torch.manual_seed(self.args.seed)
-        if int(self.args.double_precision):
-            torch.set_default_dtype(torch.float64)
-        if int(self.args.cuda) >= 0:
-            torch.cuda.manual_seed(self.args.seed)
-        self.args.device = 'cuda:' + str(self.args.cuda) if int(self.args.cuda) >= 0 else 'cpu'
-        self.args.patience = self.args.epochs if not self.args.patience else  int(self.args.patience)
-        if not self.args.lr_reduce_freq:
-            self.args.lr_reduce_freq = self.args.epochs
-        self.model = NCModel(self.args)
-        self.optimizer = getattr(optimizers, 'RiemannianAdam')(params=self.model.parameters(), lr=self.args.lr,
-                                                        weight_decay=self.args.weight_decay)
-        self.lr_scheduler = torch.optim.lr_scheduler.StepLR(
-            self.optimizer,
-            step_size=int(self.args.lr_reduce_freq),
-            gamma=float(self.args.gamma)
-        )
-
-        if self.args.cuda is not None and int(self.args.cuda) >= 0 :
-            os.environ['CUDA_VISIBLE_DEVICES'] = str(self.args.cuda)
-            self.model = self.model.to(self.args.device)
-            for x, val in self.data.items():
-                if torch.is_tensor(self.data[x]):
-                    self.data[x] = self.data[x].to(self.args.device)
-        self.best_emb = None
-
-
-    def fit(self):
-
-        logging.getLogger().setLevel(logging.INFO)
-        logging.info(str(self.model))
-        tot_params = sum([np.prod(p.size()) for p in self.model.parameters()])
-        logging.info(f"Total number of parameters: {tot_params}")
-
-        t_total = time.time()
-        counter = 0
-        best_val_metrics = self.model.init_metric_dict()
-
-        best_losses = []
-        train_losses = []
-        val_losses = []
-        for epoch in range(self.args.epochs):
-            t = time.time()
-            self.model.train()
-            self.optimizer.zero_grad()
-            embeddings = self.model.encode(self.data['features'])
-            assert not torch.isnan(embeddings).any()
-            train_metrics = self.model.compute_metrics(embeddings, self.data, 'train')
-            train_metrics['loss'].backward()
-            if self.args.grad_clip is not None:
-                max_norm = float(self.args.grad_clip)
-                all_params = list(self.model.parameters())
-                for param in all_params:
-                    torch.nn.utils.clip_grad_norm_(param, max_norm)
-            self.optimizer.step()
-            self.lr_scheduler.step()
-
-            train_losses.append(train_metrics['loss'].item())
-            if(len(best_losses) == 0):
-                best_losses.append(train_losses[0])
-            elif (best_losses[-1] > train_losses[-1]):
-                best_losses.append(train_losses[-1])
-            else:
-                best_losses.append(best_losses[-1])
-
-
-            if (epoch + 1) % self.args.log_freq == 0:
-                logging.info(" ".join(['Epoch: {:04d}'.format(epoch + 1),
-                                    'lr: {}'.format(self.lr_scheduler.get_lr()[0]),
-                                    format_metrics(train_metrics, 'train'),
-                                    'time: {:.4f}s'.format(time.time() - t)
-                                    ]))
-            if (epoch + 1) % self.args.eval_freq == 0:
-                self.model.eval()
-                embeddings = self.model.encode(self.data['features'])
-                val_metrics = self.model.compute_metrics(embeddings, self.data, 'val')
-                val_losses.append(val_metrics['loss'].item())
-                if (epoch + 1) % self.args.log_freq == 0:
-                    logging.info(" ".join(['Epoch: {:04d}'.format(epoch + 1), format_metrics(val_metrics, 'val')]))
-                    
-                if self.model.has_improved(best_val_metrics, val_metrics):
-                    self.best_emb = embeddings
-                    best_val_metrics = val_metrics
-                    counter = 0
-                else:
-                    counter += 1
-                    if counter == self.args.patience and epoch > self.args.min_epochs:
-                        logging.info("Early stopping")
-                        break
-
-        logging.info("Training Finished!")
-        logging.info("Total time elapsed: {:.4f}s".format(time.time() - t_total))
-
-        return {'train':train_losses,'best':best_losses,'val':val_losses},best_val_metrics['acc'],best_val_metrics['f1'],best_val_metrics['recall'],best_val_metrics['precision'],best_val_metrics['roc_auc'],time.time() - t_total
-    
-    def predict(self):
-        self.model.eval()
-        embeddings = self.model.encode(self.data['features'])
-        val_metrics = self.model.compute_metrics(embeddings, self.data, 'test')
-        return val_metrics['loss'].item(),val_metrics['acc'],val_metrics['f1'],val_metrics['recall'],val_metrics['precision'],val_metrics['roc_auc']
-
-    def save_embeddings(self):
-        tb_embeddings_euc = self.model.manifold.logmap0(self.best_emb,self.model.decoder.c)
-        for_classification_hyp = np.hstack((self.best_emb.cpu().detach().numpy(),self.data['labels'].cpu().reshape(-1,1)))
-        for_classification_euc = np.hstack((tb_embeddings_euc.cpu().detach().numpy(),self.data['labels'].cpu().reshape(-1,1)))
-        hyp_file_path = os.path.join(os.getcwd(),'poincare_embeddings_hyp.csv')
-        euc_file_path = os.path.join(os.getcwd(),'poincare_embeddings_euc.csv')
-        np.savetxt(hyp_file_path, for_classification_hyp, delimiter=',')
-        np.savetxt(euc_file_path, for_classification_euc, delimiter=',')
\ No newline at end of file
diff --git a/Poincare/utils/__init__.py b/Poincare/utils/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/Poincare/utils/data_utils.py b/Poincare/utils/data_utils.py
deleted file mode 100644
index bc5c634..0000000
--- a/Poincare/utils/data_utils.py
+++ /dev/null
@@ -1,83 +0,0 @@
-"""Data utils functions for pre-processing and data loading."""
-import os
-import pickle as pkl
-import sys
-
-import networkx as nx
-import numpy as np
-import scipy.sparse as sp
-import torch
-
-
-def process_data(args, adj,features,labels):
-    data = process_data_nc(args,adj,features,labels)
-    data['adj_train_norm'], data['features'] = process(
-            data['adj_train'], data['features'], args.normalize_adj,args.normalize_feats
-    )
-    return data
-
-def process(adj, features, normalize_adj, normalize_feats):
-    if sp.isspmatrix(features):
-        features = np.array(features.todense())
-    if normalize_feats:
-        features = normalize(features)
-    features = torch.Tensor(features)
-    if normalize_adj:
-        adj = normalize(adj + sp.eye(adj.shape[0]))
-    adj = sparse_mx_to_torch_sparse_tensor(adj)
-    return adj, features
-
-
-def normalize(mx):
-    """Row-normalize sparse matrix."""
-    rowsum = np.array(mx.sum(1))
-    r_inv = np.power(rowsum, -1).flatten()
-    r_inv[np.isinf(r_inv)] = 0.
-    r_mat_inv = sp.diags(r_inv)
-    mx = r_mat_inv.dot(mx)
-    return mx
-
-
-def sparse_mx_to_torch_sparse_tensor(sparse_mx):
-    """Convert a scipy sparse matrix to a torch sparse tensor."""
-    sparse_mx = sparse_mx.tocoo()
-    indices = torch.from_numpy(
-            np.vstack((sparse_mx.row, sparse_mx.col)).astype(np.int64)
-    )
-    values = torch.Tensor(sparse_mx.data)
-    shape = torch.Size(sparse_mx.shape)
-    return torch.sparse.FloatTensor(indices, values, shape)
-
-
-def augment(adj, features, normalize_feats=True):
-    deg = np.squeeze(np.sum(adj, axis=0).astype(int))
-    deg[deg > 5] = 5
-    deg_onehot = torch.tensor(np.eye(6)[deg], dtype=torch.float).squeeze()
-    const_f = torch.ones(features.size(0), 1)
-    features = torch.cat((features, deg_onehot, const_f), dim=1)
-    return features
-
-def split_data(labels, val_prop, test_prop, seed):
-    np.random.seed(seed)
-    nb_nodes = labels.shape[0]
-    all_idx = np.arange(nb_nodes)
-    pos_idx = labels.nonzero()[0]
-    neg_idx = (1. - labels).nonzero()[0]
-    np.random.shuffle(pos_idx)
-    np.random.shuffle(neg_idx)
-    pos_idx = pos_idx.tolist()
-    neg_idx = neg_idx.tolist()
-    nb_pos_neg = min(len(pos_idx), len(neg_idx))
-    nb_val = round(val_prop * nb_pos_neg)
-    nb_test = round(test_prop * nb_pos_neg)
-    idx_val_pos, idx_test_pos, idx_train_pos = pos_idx[:nb_val], pos_idx[nb_val:nb_val + nb_test], pos_idx[
-                                                                                                   nb_val + nb_test:]
-    idx_val_neg, idx_test_neg, idx_train_neg = neg_idx[:nb_val], neg_idx[nb_val:nb_val + nb_test], neg_idx[
-                                                                                                   nb_val + nb_test:]
-    return idx_val_pos + idx_val_neg, idx_test_pos + idx_test_neg, idx_train_pos + idx_train_neg
-
-def process_data_nc(args,adj,features,labels):
-    idx_val, idx_test, idx_train = split_data(labels, args.val_prop, args.test_prop, seed=args.seed)
-    labels = torch.LongTensor(labels)
-    data = {'adj_train': sp.csr_matrix(adj), 'features': features, 'labels': labels, 'idx_train': idx_train, 'idx_val': idx_val, 'idx_test': idx_test}
-    return data
diff --git a/Poincare/utils/eval_utils.py b/Poincare/utils/eval_utils.py
deleted file mode 100644
index 7494c5f..0000000
--- a/Poincare/utils/eval_utils.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from sklearn.metrics import accuracy_score, f1_score,precision_score,recall_score,roc_auc_score
-
-def acc_f1(output, labels, average='binary'):
-    preds = output.max(1)[1].type_as(labels)
-    if preds.is_cuda:
-        preds = preds.cpu()
-        labels = labels.cpu()
-    accuracy = accuracy_score(labels,preds)
-    recall = recall_score(labels,preds)
-    precision = precision_score(labels,preds)
-    roc_auc = roc_auc_score(labels,preds)
-    f1 = f1_score(labels,preds, average=average)
-    return accuracy, f1,recall,precision,roc_auc
-
diff --git a/Poincare/utils/math_utils.py b/Poincare/utils/math_utils.py
deleted file mode 100644
index a2fee95..0000000
--- a/Poincare/utils/math_utils.py
+++ /dev/null
@@ -1,69 +0,0 @@
-"""Math utils functions."""
-
-import torch
-
-
-def cosh(x, clamp=15):
-    return x.clamp(-clamp, clamp).cosh()
-
-
-def sinh(x, clamp=15):
-    return x.clamp(-clamp, clamp).sinh()
-
-
-def tanh(x, clamp=15):
-    return x.clamp(-clamp, clamp).tanh()
-
-
-def arcosh(x):
-    return Arcosh.apply(x)
-
-
-def arsinh(x):
-    return Arsinh.apply(x)
-
-
-def artanh(x):
-    return Artanh.apply(x)
-
-
-class Artanh(torch.autograd.Function):
-    @staticmethod
-    def forward(ctx, x):
-        x = x.clamp(-1 + 1e-7, 1 - 1e-7)
-        ctx.save_for_backward(x)
-        z = x.double()
-        return (torch.log_(1 + z).sub_(torch.log_(1 - z))).mul_(0.5).to(x.dtype)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        input, = ctx.saved_tensors
-        return grad_output / (1 - input ** 2)
-
-
-class Arsinh(torch.autograd.Function):
-    @staticmethod
-    def forward(ctx, x):
-        ctx.save_for_backward(x)
-        z = x.double()
-        return (z + torch.sqrt_(1 + z.pow(2))).clamp_min_(1e-7).log_().to(x.dtype)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        input, = ctx.saved_tensors
-        return grad_output / (1 + input ** 2) ** 0.5
-
-
-class Arcosh(torch.autograd.Function):
-    @staticmethod
-    def forward(ctx, x):
-        x = x.clamp(min=1.0 + 1e-7)
-        ctx.save_for_backward(x)
-        z = x.double()
-        return (z + torch.sqrt_(z.pow(2) - 1)).clamp_min_(1e-7).log_().to(x.dtype)
-
-    @staticmethod
-    def backward(ctx, grad_output):
-        input, = ctx.saved_tensors
-        return grad_output / (input ** 2 - 1) ** 0.5
-
diff --git a/Poincare/utils/train_utils.py b/Poincare/utils/train_utils.py
deleted file mode 100644
index fb43e0d..0000000
--- a/Poincare/utils/train_utils.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import os
-
-import numpy as np
-import torch
-import torch.nn.functional as F
-import torch.nn.modules.loss
-import argparse
-
-
-def format_metrics(metrics, split):
-    """Format metric in metric dict for logging."""
-    return " ".join(
-            ["{}_{}: {:.4f}".format(split, metric_name, metric_val) for metric_name, metric_val in metrics.items()])
-
-
-def create_args(*args):
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--dim', type=int, default=args[0])
-    parser.add_argument('--grad_clip', type=float, default=args[1])
-    parser.add_argument('--weight_decay', type=float, default=args[2])
-    parser.add_argument('--lr', type=float, default=args[3])
-    parser.add_argument('--gamma', type=float, default=args[4])
-    parser.add_argument('--lr_reduce_freq', type=int, default=args[5])
-    parser.add_argument('--cuda', type=int, default=args[6])
-    parser.add_argument('--epochs', type=int, default=args[7])
-    parser.add_argument('--min_epochs', type=int, default=args[8])
-    parser.add_argument('--patience', type=int, default=args[9])
-    parser.add_argument('--seed', type=int, default=args[10])
-    parser.add_argument('--log_freq', type=int, default=args[11])
-    parser.add_argument('--eval_freq', type=int, default=args[12])
-    parser.add_argument('--val_prop', type=float, default=args[13])
-    parser.add_argument('--test_prop', type=float, default=args[14])
-    parser.add_argument('--double_precision', type=int, default=args[15])
-    parser.add_argument('--dropout', type=float, default=args[16])
-    parser.add_argument('--normalize_adj', type=bool, default=args[17])
-    parser.add_argument('--normalize_feats', type=bool, default=args[18])
-    flags, unknown = parser.parse_known_args()
-    return flags
\ No newline at end of file
diff --git a/README.md b/README.md
index 929877d..b3a38bd 100644
--- a/README.md
+++ b/README.md
@@ -1,71 +1,3 @@
-# G-Hypeddings
+# Note
 
-## 1. Overview
-
-G-hypeddings is a **Python library** designed for **graph hyperbolic embeddings**, primarily utilized in **detecting cybersecurity anomalies**. It includes 06 distinct models with various configurations, all of which utilize **hyperbolic geometry** for their operations. The library is built on top of the [PyTorch framework](https://pytorch.org/).
-
-### 1.1. Models
-
-The models can be divided into three main categories based on the model's overall architecture namely Shallow models (Poincaré), Convolutional-based models (HGCN & HGNN), and Autoencoder-based models (HGCAE & PVAE).
-
-| Name     | Year     | Encoder  | Decoder | Manifold                  | Ref   |
-|----------|----------|----------|---------|---------------------------|-------|
-| Poincaré | 2017     | /        | MLP     | Poincaré Ball             | [1]   |
-| HGNN     | 2019     | HGCN     | MLP     | Poincaré Ball, Lorentz    | [2]   |
-| HGCN     | 2019     | HGCN     | MLP     | Lorentz                   | [3]   |
-| P-VAE    | 2019     | GCN      | MLP     | Poincaré Ball             | [4]   |
-| H2H-GCN  | 2021     | HGCN     | MLP     | Lorentz                   | [5]   |
-| HGCAE    | 2021     | HGCN     | HGCN    | Poincaré Ball             | [6]   |
-
-In this library, we provide a variety of binary classifiers, clustering algorithms, and unsupervised anomaly detection algorithms to use with the autoencoder-based models (HGCAE & PVAE). All of these are [Scikit-learn](https://scikit-learn.org/) models tuned using the Grid-Search technique.
-
-| Name                                        | Type                        |
-|---------------------------------------------|-----------------------------|
-| Support Vector Machine (SVM)                | Binary Classifier           |
-| Multilayer Perceptrone (MLP)                | Binary Classifier           |
-| Decision Tree                               | Binary Classifier           |
-| Random Forest                               | Binary Classifier           |
-| AdaBoost                                    | Binary Classifier           |
-| K-Nearest Neighbors (KNN)                   | Binary Classifier           |
-| Naive Bayes                                 | Binary Classifier           |
-| Agglomerative Hierarchical Clustering (AHC) | Clustering Algorithm        |
-| DBSCAN                                      | Clustering Algorithm        |
-| Fuzzy C mean                                | Clustering Algorithm        |
-| Gaussian Mixture                            | Clustering Algorithm        |
-| K-means                                     | Clustering Algorithm        |
-| Mean shift                                  | Clustering Algorithm        |
-| Isolation Forest                            | Anomaly Detection Algorithm |
-| One-class SVM                               | Anomaly Detection Algorithm |
-
-### 1.2. Datasets
-
-The following intrusion detection datasets were used to test and evaluate the models. Our code includes all the pre-processing steps required to convert these datasets from tabular format into graphs. Due to usage restrictions, this library provides only a single graph of each dataset, with 5,000 nodes, already pre-processed and normalized.
-
-| Name            | Ref   |
-|-----------------|-------|
-| CIC-DDoS2019    | [7]   |
-| AWID3           |       |
-
-
-
-## 2. Installation
-
-## 3. Usage
-
-Training and evaluation a model using our library is done in 03 lines of code only!
-
-### 3.1. Models
-
-### 3.2. Datasets
-
-## 4. Citation
-
-## 5. References
-
-[1]: [Nickel, Maximillian, and Douwe Kiela. "Poincaré embeddings for learning hierarchical representations." Advances in neural information processing systems 30 (2017).](https://proceedings.neurips.cc/paper_files/paper/2017/hash/59dfa2df42d9e3d41f5b02bfc32229dd-Abstract.html)
-[2]: [Liu, Qi, Maximilian Nickel, and Douwe Kiela. "Hyperbolic graph neural networks." Advances in neural information processing systems 32 (2019).](https://proceedings.neurips.cc/paper/2019/hash/103303dd56a731e377d01f6a37badae3-Abstract.html)
-[3]: [Chami, Ines, et al. "Hyperbolic graph convolutional neural networks." Advances in neural information processing systems 32 (2019).](https://proceedings.neurips.cc/paper_files/paper/2019/hash/0415740eaa4d9decbc8da001d3fd805f-Abstract.html)
-[4]: [Mathieu, Emile, et al. "Continuous hierarchical representations with poincaré variational auto-encoders." Advances in neural information processing systems 32 (2019).](https://proceedings.neurips.cc/paper/2019/hash/0ec04cb3912c4f08874dd03716f80df1-Abstract.html)
-[5]: [Dai, Jindou, et al. "A hyperbolic-to-hyperbolic graph convolutional network." Proceedings of the IEEE/CVF conference on computer vision and pattern recognition. 2021.](https://www.computer.org/csdl/proceedings-article/cvpr/2021/450900a154/1yeJgfbgw6Y)
-[6]: [Park, Jiwoong, et al. "Unsupervised hyperbolic representation learning via message passing auto-encoders." Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition. 2021.](https://ieeexplore.ieee.org/document/9577649)
-[7]: [CIC-DDoS2019](https://www.unb.ca/cic/datasets/ddos-2019.html)
\ No newline at end of file
+This project has been moved to the following [repository](https://gitlab.liris.cnrs.fr/gladis/ghypeddings)
\ No newline at end of file
diff --git a/__init__.py b/__init__.py
deleted file mode 100644
index 3793673..0000000
--- a/__init__.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from Ghypeddings.H2HGCN.h2hgcn import H2HGCN
-from Ghypeddings.HGCAE.hgcae import HGCAE
-from Ghypeddings.HGCN.hgcn import HGCN
-from Ghypeddings.HGNN.hgnn import HGNN
-from Ghypeddings.Poincare.poincare import POINCARE
-from Ghypeddings.PVAE.pvae import PVAE
-
-from Ghypeddings.datasets.datasets import CIC_DDoS2019
-from Ghypeddings.datasets.datasets import NF_CIC_IDS2018_v2
-from Ghypeddings.datasets.datasets import NF_UNSW_NB15_v2
-from Ghypeddings.datasets.datasets import Darknet
-from Ghypeddings.datasets.datasets import AWID3
-from Ghypeddings.datasets.datasets import NF_TON_IoT_v2
-from Ghypeddings.datasets.datasets import NF_BOT_IoT_v2
\ No newline at end of file
diff --git a/anomaly_detection/__init__.py b/anomaly_detection/__init__.py
deleted file mode 100644
index 41092b1..0000000
--- a/anomaly_detection/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from Ghypeddings.anomaly_detection.isolation_forest import isolation_forest
-from Ghypeddings.anomaly_detection.one_class_svm import one_class_svm
-from Ghypeddings.anomaly_detection.dbscan import dbscan
-from Ghypeddings.anomaly_detection.kmeans import kmeans
-from Ghypeddings.anomaly_detection.local_outlier_factor import local_outlier_factor
\ No newline at end of file
diff --git a/anomaly_detection/dbscan.py b/anomaly_detection/dbscan.py
deleted file mode 100644
index 00bc3d6..0000000
--- a/anomaly_detection/dbscan.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from sklearn.cluster import DBSCAN
-from Ghypeddings.anomaly_detection.utils import calculate_metrics
-
-
-def dbscan(X,y):
-    dbscan = DBSCAN(eps=0.5, min_samples=5)
-    labels = dbscan.fit_predict(X)
-    outliers = labels == -1
-    return calculate_metrics(y,outliers)
diff --git a/anomaly_detection/isolation_forest.py b/anomaly_detection/isolation_forest.py
deleted file mode 100644
index 52ea904..0000000
--- a/anomaly_detection/isolation_forest.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from Ghypeddings.anomaly_detection.utils import calculate_metrics
-
-
-from sklearn.ensemble import IsolationForest
-
-def isolation_forest(X,y,anomalies_percentage = 0.1):
-    model = IsolationForest(contamination=anomalies_percentage)
-    model.fit(X)
-    y_pred = model.predict(X)
-    y_pred[y_pred == 1] = 0
-    y_pred[y_pred == -1]= 1
-    return calculate_metrics(y,y_pred)
\ No newline at end of file
diff --git a/anomaly_detection/kmeans.py b/anomaly_detection/kmeans.py
deleted file mode 100644
index a5fbfc8..0000000
--- a/anomaly_detection/kmeans.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from sklearn.cluster import KMeans
-from Ghypeddings.anomaly_detection.utils import calculate_metrics
-import numpy as np
-
-def kmeans(X,y,n_clusters,outlier_percentage=.1):
-    model = KMeans(n_clusters=n_clusters)
-    model.fit(X)
-    # y_pred = model.predict(X)
-    distances = model.transform(X).min(axis=1)
-    threshold = np.percentile(distances, 100 * (1 - outlier_percentage))
-    outliers = distances > threshold
-    return calculate_metrics(y,outliers)
\ No newline at end of file
diff --git a/anomaly_detection/local_outlier_factor.py b/anomaly_detection/local_outlier_factor.py
deleted file mode 100644
index 36caa70..0000000
--- a/anomaly_detection/local_outlier_factor.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from sklearn.neighbors import LocalOutlierFactor
-from Ghypeddings.anomaly_detection.utils import calculate_metrics
-import numpy as np
-
-def local_outlier_factor(X,y,n_neighbors=20,outlier_percentage=.1):
-    lof = LocalOutlierFactor(n_neighbors=n_neighbors, contamination=outlier_percentage)
-    y_pred = lof.fit_predict(X)
-    y_pred[y_pred == 1] = 0
-    y_pred[y_pred == -1] = 1
-    return calculate_metrics(y,y_pred)
\ No newline at end of file
diff --git a/anomaly_detection/one_class_svm.py b/anomaly_detection/one_class_svm.py
deleted file mode 100644
index c383e8d..0000000
--- a/anomaly_detection/one_class_svm.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from Ghypeddings.anomaly_detection.utils import calculate_metrics
-
-
-from sklearn.svm import OneClassSVM
-
-def one_class_svm(X,y, kernel='rbf',nu=0.1):
-    model = OneClassSVM(kernel=kernel, nu=nu)
-    model.fit(X)
-    y_pred = model.predict(X)
-    y_pred[y_pred == -1]=0
-    return calculate_metrics(y,y_pred)
\ No newline at end of file
diff --git a/anomaly_detection/utils.py b/anomaly_detection/utils.py
deleted file mode 100644
index dfb39f3..0000000
--- a/anomaly_detection/utils.py
+++ /dev/null
@@ -1,22 +0,0 @@
-## external evaluation metrics
-from sklearn.metrics import adjusted_rand_score
-from sklearn.metrics import normalized_mutual_info_score
-from sklearn.metrics import fowlkes_mallows_score
-## additional evaluation metrics
-from sklearn.metrics import homogeneity_score, completeness_score, v_measure_score
-## classification metrics
-from sklearn.metrics import precision_score, recall_score, f1_score, roc_auc_score, accuracy_score
-
-def calculate_metrics(y_true,y_pred):
-    ari = adjusted_rand_score(y_true, y_pred)
-    nmi = normalized_mutual_info_score(y_true, y_pred)
-    fmi = fowlkes_mallows_score(y_true, y_pred)
-    homogeneity = homogeneity_score(y_true, y_pred)
-    completeness = completeness_score(y_true, y_pred)
-    v_measure = v_measure_score(y_true, y_pred)
-    acc = accuracy_score(y_true,y_pred)
-    f1 = f1_score(y_true,y_pred)
-    rec = recall_score(y_true,y_pred)
-    pre = precision_score(y_true,y_pred)
-    roc = roc_auc_score(y_true,y_pred)
-    return ari,nmi,fmi,homogeneity,completeness,v_measure,acc,f1,rec,pre,roc
\ No newline at end of file
diff --git a/classifiers/__init__.py b/classifiers/__init__.py
deleted file mode 100644
index fd5dc32..0000000
--- a/classifiers/__init__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from Ghypeddings.classifiers.svm import SVM
-from Ghypeddings.classifiers.mlp import mlp
-from Ghypeddings.classifiers.decision_tree import decision_tree
-from Ghypeddings.classifiers.random_forest import random_forest
-from Ghypeddings.classifiers.adaboost import adaboost
-from Ghypeddings.classifiers.knn import KNN
-from Ghypeddings.classifiers.naive_bayes import naive_bayes
-
-from sklearn.metrics import accuracy_score , f1_score , recall_score , precision_score , roc_auc_score
-
-
-def calculate_metrics(clf,X,y):
-    y_pred = clf.predict(X)
-    accuracy = accuracy_score(y, y_pred)
-    f1 = f1_score(y, y_pred)
-    recall = recall_score(y, y_pred)
-    precision = precision_score(y, y_pred)
-    roc_auc = roc_auc_score(y, y_pred)
-    return accuracy,f1,recall,precision,roc_auc
\ No newline at end of file
diff --git a/classifiers/adaboost.py b/classifiers/adaboost.py
deleted file mode 100644
index 35c469f..0000000
--- a/classifiers/adaboost.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from sklearn.ensemble import AdaBoostClassifier
-
-def adaboost(X,y,seed,n_estimators=2):
-    ada_boost = AdaBoostClassifier(n_estimators=n_estimators, random_state=seed)
-    return ada_boost.fit(X, y)
\ No newline at end of file
diff --git a/classifiers/decision_tree.py b/classifiers/decision_tree.py
deleted file mode 100644
index c591083..0000000
--- a/classifiers/decision_tree.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from sklearn.tree import DecisionTreeClassifier
-
-def decision_tree(X,y,max_depth=2):
-    clf = DecisionTreeClassifier(max_depth=max_depth)
-    return clf.fit(X, y)
\ No newline at end of file
diff --git a/classifiers/knn.py b/classifiers/knn.py
deleted file mode 100644
index 70823c0..0000000
--- a/classifiers/knn.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from sklearn.neighbors import KNeighborsClassifier
-
-def KNN(X,y,k=5):
-    knn = KNeighborsClassifier(n_neighbors=k)
-    return knn.fit(X, y)
\ No newline at end of file
diff --git a/classifiers/mlp.py b/classifiers/mlp.py
deleted file mode 100644
index 0d76b43..0000000
--- a/classifiers/mlp.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from sklearn.neural_network import MLPClassifier
-import time
-import numpy as np
-
-def mlp(X,y,n_hidden_layers,hidden_dim,epochs=50,batch_size=64,seed=42):
-    mlp = MLPClassifier(hidden_layer_sizes=(n_hidden_layers, hidden_dim),learning_rate='adaptive',batch_size=batch_size ,activation='identity', solver='lbfgs', max_iter=epochs, random_state=seed)
-    return mlp.fit(X, y)
\ No newline at end of file
diff --git a/classifiers/naive_bayes.py b/classifiers/naive_bayes.py
deleted file mode 100644
index 62d6d9b..0000000
--- a/classifiers/naive_bayes.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from sklearn.naive_bayes import GaussianNB
-
-def naive_bayes(X,y):
-    clf = GaussianNB()
-    return clf.fit(X, y)
\ No newline at end of file
diff --git a/classifiers/random_forest.py b/classifiers/random_forest.py
deleted file mode 100644
index 24c10c4..0000000
--- a/classifiers/random_forest.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from sklearn.ensemble import RandomForestClassifier
-
-def random_forest(X,y,seed,n_estimators=10,max_depth=10,max_features='log2'):
-    clf = RandomForestClassifier(max_features=max_features,n_estimators=n_estimators, max_depth=max_depth, random_state=seed)
-    return clf.fit(X, y)
\ No newline at end of file
diff --git a/classifiers/svm.py b/classifiers/svm.py
deleted file mode 100644
index a48c0a5..0000000
--- a/classifiers/svm.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from sklearn import svm
-
-
-def SVM(X,y,kernel='rbf',gamma='scale',C=1):    
-    cls = svm.SVC(kernel=kernel, gamma=gamma, C=C)
-    return cls.fit(X, y)
\ No newline at end of file
diff --git a/clusterers/__init__.py b/clusterers/__init__.py
deleted file mode 100644
index 5bb80fb..0000000
--- a/clusterers/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from Ghypeddings.clusterers.ahc import agglomerative_clustering
-from Ghypeddings.clusterers.dbscan import dbscan
-from Ghypeddings.clusterers.fuzzy_c_mean import fuzzy_c_mean
-from Ghypeddings.clusterers.gaussian_mixture import gaussian_mixture
-from Ghypeddings.clusterers.kmeans import kmeans
-from Ghypeddings.clusterers.mean_shift import mean_shift
\ No newline at end of file
diff --git a/clusterers/ahc.py b/clusterers/ahc.py
deleted file mode 100644
index aee3bfd..0000000
--- a/clusterers/ahc.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from sklearn.cluster import AgglomerativeClustering
-from Ghypeddings.clusterers.utils import calculate_metrics
-
-def agglomerative_clustering(X,y,n_clusters =2, linkage = 'ward'):
-    model = AgglomerativeClustering(n_clusters=n_clusters,linkage=linkage)
-    labels = model.fit_predict(X)
-    return calculate_metrics(y,labels)
\ No newline at end of file
diff --git a/clusterers/dbscan.py b/clusterers/dbscan.py
deleted file mode 100644
index 0b17e55..0000000
--- a/clusterers/dbscan.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from Ghypeddings.clusterers.utils import calculate_metrics
-from sklearn.cluster import DBSCAN
-
-def dbscan(X,y,eps=1e-4,min_samples=300):
-    model = DBSCAN(eps=eps, min_samples=min_samples)
-    y_pred = model.fit_predict(X)
-    mask = y_pred != -1
-    y_true_filtered = y[mask]
-    y_pred_filtered = y_pred[mask]
-    y_pred_filtered[y_pred_filtered>0] = -1
-    y_pred_filtered[y_pred_filtered == 0] = 1
-    y_pred_filtered[y_pred_filtered == -1]=0
-    return calculate_metrics(y_true_filtered,y_pred_filtered)
\ No newline at end of file
diff --git a/clusterers/fuzzy_c_mean.py b/clusterers/fuzzy_c_mean.py
deleted file mode 100644
index af934ee..0000000
--- a/clusterers/fuzzy_c_mean.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from Ghypeddings.clusterers.utils import calculate_metrics
-import skfuzzy as fuzz
-import numpy as np
-
-def fuzzy_c_mean(X,y,n_clusters=5,power=2,error=0.005,maxiter=1000,init=None):
-    X_transposed = np.transpose(X)
-    cntr, u, u0, d, jm, p, fpc = fuzz.cluster.cmeans(X_transposed, n_clusters, power, error=error, maxiter=maxiter, init=init)
-    y_pred = np.argmax(u, axis=0)
-    return calculate_metrics(y,y_pred)
\ No newline at end of file
diff --git a/clusterers/gaussian_mixture.py b/clusterers/gaussian_mixture.py
deleted file mode 100644
index 3405e01..0000000
--- a/clusterers/gaussian_mixture.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from sklearn.mixture import GaussianMixture
-from Ghypeddings.clusterers.utils import calculate_metrics
-
-def gaussian_mixture(X,y,n_components=2):
-    model = GaussianMixture(n_components=2)
-    y_pred = model.fit_predict(X)
-    return calculate_metrics(y,y_pred)
\ No newline at end of file
diff --git a/clusterers/kmeans.py b/clusterers/kmeans.py
deleted file mode 100644
index 848fef4..0000000
--- a/clusterers/kmeans.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from Ghypeddings.clusterers.utils import calculate_metrics
-
-from sklearn.cluster import KMeans
-
-
-def kmeans(X,y,n_clusters=2,n_init=10):
-    model = KMeans(n_clusters=n_clusters,n_init=n_init)
-    model.fit(X)
-    y_pred = model.labels_
-    y_pred[y_pred!=1]=0
-    return calculate_metrics(y,y_pred)
\ No newline at end of file
diff --git a/clusterers/mean_shift.py b/clusterers/mean_shift.py
deleted file mode 100644
index ba98754..0000000
--- a/clusterers/mean_shift.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from Ghypeddings.clusterers.utils import calculate_metrics
-
-from sklearn.cluster import MeanShift
-
-def mean_shift(X,y):
-    y_pred = MeanShift().fit_predict(X)
-    y_pred[y_pred>0] = -1
-    y_pred[y_pred == 0] = 1
-    y_pred[y_pred == -1]=0
-    return calculate_metrics(y,y_pred)
\ No newline at end of file
diff --git a/clusterers/utils.py b/clusterers/utils.py
deleted file mode 100644
index dfb39f3..0000000
--- a/clusterers/utils.py
+++ /dev/null
@@ -1,22 +0,0 @@
-## external evaluation metrics
-from sklearn.metrics import adjusted_rand_score
-from sklearn.metrics import normalized_mutual_info_score
-from sklearn.metrics import fowlkes_mallows_score
-## additional evaluation metrics
-from sklearn.metrics import homogeneity_score, completeness_score, v_measure_score
-## classification metrics
-from sklearn.metrics import precision_score, recall_score, f1_score, roc_auc_score, accuracy_score
-
-def calculate_metrics(y_true,y_pred):
-    ari = adjusted_rand_score(y_true, y_pred)
-    nmi = normalized_mutual_info_score(y_true, y_pred)
-    fmi = fowlkes_mallows_score(y_true, y_pred)
-    homogeneity = homogeneity_score(y_true, y_pred)
-    completeness = completeness_score(y_true, y_pred)
-    v_measure = v_measure_score(y_true, y_pred)
-    acc = accuracy_score(y_true,y_pred)
-    f1 = f1_score(y_true,y_pred)
-    rec = recall_score(y_true,y_pred)
-    pre = precision_score(y_true,y_pred)
-    roc = roc_auc_score(y_true,y_pred)
-    return ari,nmi,fmi,homogeneity,completeness,v_measure,acc,f1,rec,pre,roc
\ No newline at end of file
diff --git a/datasets/.gitignore b/datasets/.gitignore
deleted file mode 100644
index d22b9a2..0000000
--- a/datasets/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-outlier_datasets.py
-
-repetition_datasets.py
\ No newline at end of file
diff --git a/datasets/__init__.py b/datasets/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/datasets/datasets.py b/datasets/datasets.py
deleted file mode 100644
index db7cd2c..0000000
--- a/datasets/datasets.py
+++ /dev/null
@@ -1,299 +0,0 @@
-import os
-
-import pandas as pd
-import numpy as np
-from sklearn.preprocessing import MinMaxScaler
-from sklearn.preprocessing import StandardScaler
-import pickle
-from sklearn.preprocessing import LabelEncoder
-import time
-import datetime
-import progressbar
-import category_encoders as ce
-
-class Dataset:
-    def __init__(self,features_path='',adj_path='',labels_path='',directory=''):
-        self.features_path = features_path
-        self.adj_path = adj_path
-        self.labels_path = labels_path
-        self.directory = directory
-
-    def _get_files(self):
-        return [os.path.join(self.directory,file) for file in os.listdir(self.directory) if os.path.isfile(os.path.join(self.directory, file)) and '.gitignore' not in file]
-
-    def save_samples(self,adj,features,labels):
-        with open(self.adj_path,'wb') as f:
-            pickle.dump(adj,f)
-        with open(self.features_path,'wb') as f:
-            pickle.dump(features,f)
-        with open(self.labels_path,'wb') as f:
-            pickle.dump(labels,f)
-
-    def load_samples(self):
-        with open(self.adj_path,'rb') as f:
-            adj = pickle.load(f)
-        with open(self.features_path,'rb') as f:
-            features = pickle.load(f)
-        with open(self.labels_path,'rb') as f:
-            labels = pickle.load(f)
-        print('features:',features.shape,'adj',adj.shape,'labels',labels.shape)
-        return adj,features,labels
-
-class CIC_DDoS2019(Dataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CICDDoS2019','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CICDDoS2019','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CICDDoS2019','labels.pkl'),
-            directory=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CICDDoS2019','original')
-        )
-
-    def build(self,n_nodes,n_classes=2):
-        df = self._create_file_bc(n_nodes,n_classes)
-        for column in df.columns:
-            max_value = df.loc[df[column] != np.inf, column].max()
-            min_value = df.loc[df[column] != -np.inf, column].min()
-            df.loc[df[column] == np.inf, column] = max_value
-            df.loc[df[column] == -np.inf, column] = min_value
-        adj = self._filling_adjacency_numpy(df)
-        labels = df[' Label'].apply(lambda x: 0 if x == 'BENIGN' else 1).to_numpy()
-        columns_to_exclude = ['Unnamed: 0', 'Flow ID', ' Source IP',' Source Port',' Destination Port',' Flow Duration',' Protocol', ' Destination IP', ' Timestamp', 'SimillarHTTP',' Inbound',' Label']
-        df.drop(columns_to_exclude, axis=1, inplace=True)
-        features = df.to_numpy()
-        scaler = MinMaxScaler()
-        features = scaler.fit_transform(features)
-        self.save_samples(adj,features,labels)
-        return adj, features, labels
-    
-    def _load_file(self,path,max_per_class,list_classes=[]):
-        df = pd.read_csv(path,low_memory=False)
-        df.dropna(axis=0, inplace=True)
-        if(len(list_classes)):
-            df = df[df[' Label'].isin(list_classes)]
-            df = df.groupby([' Label']).apply(lambda x: x.sample(max_per_class)).reset_index(drop=True)
-        return df
-        
-    def _create_file_bc(self,n_nodes,n_classes):
-        file_paths = self._get_files()
-        max_per_class = int(n_nodes / (n_classes * len(file_paths))) +1
-        df_list = []
-        for path in file_paths:
-            class_name = path.split('\\')[-1].split('.')[0]
-            list_classes = ['BENIGN',class_name]
-            df_list.append(self._load_file(path,max_per_class,list_classes))
-            print('finishing loading the file : {}'.format(path))
-        df = pd.concat(df_list,ignore_index=True)
-        df = df.sample(n=n_nodes).reset_index(drop=True)
-        print(df.shape)
-        # print(df[' Label'].value_counts())
-        # df = pd.read_csv(os.path.join(self.directory,'all.csv'),low_memory=False)
-        # df[' Label'] = df[' Label'].apply(lambda x: 0 if x == 'BENIGN' else 1)
-        # node_per_class = int(n_nodes/n_classes)
-        # df = df.groupby([' Label']).apply(lambda x: x.sample(node_per_class)).reset_index(drop=True)
-        return df
-
-    def _filling_adjacency_numpy(self,data):
-        N = data.shape[0]
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-
-        source_ips = data[' Source IP'].to_numpy()
-        destination_ips = data[' Destination IP'].to_numpy()
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips)| (destination_ips[:, np.newaxis] == destination_ips) )
-        adjacency[mask] = True
-        return adjacency
-
-class NetFlowDataset(Dataset):
-    def __init__(self,features_path,adj_path,labels_path,file):
-        super().__init__(features_path,adj_path,labels_path)
-        self.file = file
-
-    def build(self,n_nodes,n_classes=2):
-        df = pd.read_csv(self.file) 
-        df = df.groupby(['Label']).apply(lambda x: x.sample(int(n_nodes/n_classes))).reset_index(drop=True) 
-        df = df.sample(frac=1).reset_index(drop=True)
-        adj = self._filling_adjacency_numpy(df)
-        labels = df['Label'].to_numpy()
-        labels = labels.astype(np.bool_)
-        df.drop(['IPV4_SRC_ADDR','IPV4_DST_ADDR','Attack','Label','L4_SRC_PORT','L4_DST_PORT'],axis=1,inplace=True)
-        #df = pd.get_dummies(df,columns=['PROTOCOL','DNS_QUERY_TYPE','FTP_COMMAND_RET_CODE'])
-
-        encoder = ce.TargetEncoder(cols=['TCP_FLAGS','L7_PROTO','PROTOCOL'])
-        encoder.fit(df,labels)
-        df = encoder.transform(df)
- 
-        features = df.to_numpy()
-        scaler = MinMaxScaler()
-        features = scaler.fit_transform(features)
-        print("features:",features.shape)
-        self.save_samples(adj,features,labels)
-        return adj,features,labels
-
-    def _filling_adjacency_numpy(self,data):
-        N = data.shape[0]
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-
-        if 'bot_iot' in self.file:
-            data['IPV4_SRC_ADDR'] = data['IPV4_SRC_ADDR'].apply(str)
-            data['IPV4_DST_ADDR'] = data['IPV4_DST_ADDR'].apply(str)
-            data['L4_SRC_PORT'] = data['L4_SRC_PORT'].apply(str)
-            data['L4_DST_PORT'] = data['L4_DST_PORT'].apply(str)
-            data['IPV4_SRC_ADDR'] = data['IPV4_SRC_ADDR']+':'+data['L4_SRC_PORT']
-            data['IPV4_DST_ADDR'] = data['IPV4_DST_ADDR']+':'+data['L4_DST_PORT']
-
-        source_ips = data['IPV4_SRC_ADDR'].to_numpy()
-        destination_ips = data['IPV4_DST_ADDR'].to_numpy()
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips) | (destination_ips[:, np.newaxis] == destination_ips))
-        adjacency[mask] = True
-        return adjacency
-
-class NF_CIC_IDS2018_v2(NetFlowDataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CIC_IDS2018','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CIC_IDS2018','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CIC_IDS2018','labels.pkl'),
-            file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CIC_IDS2018','original','cic_ids2018.csv')
-        )   
-
-class NF_UNSW_NB15_v2(NetFlowDataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','UNSW_NB15','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','UNSW_NB15','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','UNSW_NB15','labels.pkl'),
-            file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','UNSW_NB15','original','unsw_nb15.csv')
-        )
-
-class Darknet(Dataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','Darknet','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','Darknet','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','Darknet','labels.pkl')
-        )
-        self.file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','Darknet','original','Darknet.csv')
-
-    def _to_binary_classification(self,x):
-        if 'Non' in x:
-            return 0
-        else:
-            return 1
-
-    def build(self,n_nodes,n_classes=2):
-        df = pd.read_csv(self.file)
-        df.dropna(axis=0, inplace=True)
-        df['Label'] = df['Label'].apply(self._to_binary_classification)
-        df = df.groupby(['Label']).apply(lambda x: x.sample(int(n_nodes/n_classes))).reset_index(drop=True)
-        df = df.sample(n=n_nodes).reset_index(drop=True)
-        data = df.to_numpy()
-        adj = self._filling_adjacency_numpy(data,1,3)
-        labels = df['Label'].to_numpy()
-        columns_to_exclude = ['Flow ID', 'Src IP','Src Port', 'Dst IP','Dst Port', 'Timestamp','Label','Label.1','Protocol','Flow Duration']
-        df.drop(columns_to_exclude, axis=1, inplace=True)
-        features = df.to_numpy()
-        self.save_samples(adj,features,labels)
-        return adj,features,labels
-    
-    def _filling_adjacency_numpy(self,data,source_ip_index, destination_ip_index):
-        N = data.shape[0]
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-        source_ips = data[:, source_ip_index]
-        destination_ips = data[:, destination_ip_index]
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips) | (destination_ips[:, np.newaxis] == destination_ips))
-        adjacency[mask] = True
-        return adjacency
-
-class NF_BOT_IoT_v2(NetFlowDataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','BOT_IOT','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','BOT_IOT','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','BOT_IOT','labels.pkl'),
-            file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','BOT_IOT','original','bot_iot.csv')
-        )
-
-class NF_TON_IoT_v2(NetFlowDataset):
-    def __init__(self):
-        # directory=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT','original'),
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT','labels.pkl'),
-            file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT','original','ton_iot.csv')
-        )
-
-class AWID3(Dataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','AWID3','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','AWID3','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','AWID3','labels.pkl'),
-            directory=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','AWID3','original')
-        )
-
-    def _config_signal(self,x):
-        words = str(x).split('-')
-        return np.mean([float(i)*-1 for i in words if i!=''])
-    
-    def build(self,n_nodes):
-        path = os.path.join(os.getcwd(),'Ghypeddings','datasets','examples','AWID3','original','awid3.csv')
-        df = pd.read_csv(path)
-        df['Label'] = df['Label'].apply(lambda x: 0 if 'Normal' in x else 1)
-        df = df.groupby(['Label']).apply(lambda x: x.sample(int(n_nodes/2))).reset_index(drop=True)
-        df = df.sample(frac=1).reset_index(drop=True)
-        data=df[['ip.src','ip.dst']]
-        df.dropna(axis=1, inplace=True)
-        to_drop = ['frame.number','frame.time','radiotap.timestamp.ts','frame.time_delta_displayed','frame.time_epoch','frame.time_relative','wlan.duration','wlan.ra']
-        df.drop(columns=to_drop,axis=1,inplace=True)
-        alone = []
-        for c in df.columns:
-            if(len(df[c].unique()) == 1):
-                alone.append(c)
-            elif len(df[c].unique()) == 2:
-                df = pd.get_dummies(df,columns=[c],drop_first=True)
-            elif len(df[c].unique()) <=8:
-                df = pd.get_dummies(df,columns=[c])
-            elif len(df[c].unique()) <=15:
-                labels = df['Label']
-                df.drop(columns=['Label'],axis=1,inplace=True)
-                encoder = ce.TargetEncoder(cols=[c])
-                encoder.fit(df,labels)
-                df = encoder.transform(df)
-                df['Label']=labels
-            else:
-                if(df[c].dtype == 'object' and c!='radiotap.dbm_antsignal'):
-                    print(c,df[c].unique(),len(df[c].unique()))
-        df.drop(columns=alone,axis=1,inplace=True)
-        df['radiotap.dbm_antsignal'] = df['radiotap.dbm_antsignal'].apply(self._config_signal) # It contains a list
-        labels = df['Label_1'].to_numpy()
-        adj = self._filling_adjacency_numpy(data)
-        df.drop(columns=['frame.time_delta','Label_1'],axis=1,inplace=True)
-        features = df.to_numpy()
-        scaler = StandardScaler()
-        features = scaler.fit_transform(features)
-        # scaler = MinMaxScaler()
-        # features = scaler.fit_transform(features)
-        self.save_samples(adj=adj,features=features,labels=labels)
-        return adj,features,labels
-    
-    def _filling_adjacency_numpy(self,data):
-        N = data.shape[0]
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-        source_ips = data['ip.src'].to_numpy()
-        destination_ips = data['ip.dst'].to_numpy()
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips) | (destination_ips[:, np.newaxis] == destination_ips) )
-        adjacency[mask] = True
-        np.fill_diagonal(adjacency, True)
-        return adjacency
\ No newline at end of file
diff --git a/datasets/outlier_datasets.py b/datasets/outlier_datasets.py
deleted file mode 100644
index 10c1304..0000000
--- a/datasets/outlier_datasets.py
+++ /dev/null
@@ -1,314 +0,0 @@
-import os
-
-import pandas as pd
-import numpy as np
-from sklearn.preprocessing import MinMaxScaler
-from sklearn.preprocessing import StandardScaler
-import pickle
-from sklearn.preprocessing import LabelEncoder
-import time
-import datetime
-import category_encoders as ce
-
-class Dataset:
-    def __init__(self,features_path='',adj_path='',labels_path='',directory=''):
-        self.features_path = features_path
-        self.adj_path = adj_path
-        self.labels_path = labels_path
-        self.directory = directory
-
-    def _get_files(self):
-        return [os.path.join(self.directory,file) for file in os.listdir(self.directory) if os.path.isfile(os.path.join(self.directory, file)) and '.gitignore' not in file]
-
-    def save_samples(self,adj,features,labels):
-
-        with open(self.adj_path,'wb') as f:
-            pickle.dump(adj,f)
-        with open(self.features_path,'wb') as f:
-            pickle.dump(features,f)
-        with open(self.labels_path,'wb') as f:
-            pickle.dump(labels,f)
-
-    def load_samples(self):
-        with open(self.adj_path,'rb') as f:
-            adj = pickle.load(f)
-        with open(self.features_path,'rb') as f:
-            features = pickle.load(f)
-        with open(self.labels_path,'rb') as f:
-            labels = pickle.load(f)
-        print('features:',features.shape,'adj',adj.shape,'labels',labels.shape)
-        return adj,features,labels
-
-class CIC_DDoS2019(Dataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','CICDDoS2019','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','CICDDoS2019','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','CICDDoS2019','labels.pkl'),
-            directory=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CICDDoS2019','original')
-        )
-
-    def build(self,n_nodes,n_classes=2):
-        df = self._create_file_bc(n_nodes,n_classes)
-        for column in df.columns:
-            max_value = df.loc[df[column] != np.inf, column].max()
-            min_value = df.loc[df[column] != -np.inf, column].min()
-            df.loc[df[column] == np.inf, column] = max_value
-            df.loc[df[column] == -np.inf, column] = min_value
-        adj = self._filling_adjacency_numpy(df)
-        labels = df[' Label'].apply(lambda x: 0 if x == 'BENIGN' else 1).to_numpy()
-        columns_to_exclude = ['Unnamed: 0', 'Flow ID', ' Source IP',' Source Port',' Destination Port',' Flow Duration',' Protocol', ' Destination IP', ' Timestamp', 'SimillarHTTP',' Inbound',' Label']
-        df.drop(columns_to_exclude, axis=1, inplace=True)
-        features = df.to_numpy()
-        scaler = MinMaxScaler()
-        features = scaler.fit_transform(features)
-        self.save_samples(adj,features,labels)
-        return adj, features, labels
-    
-    def _load_file(self,path,max_per_class,list_classes=[]):
-        df = pd.read_csv(path,low_memory=False)
-        df.dropna(axis=0, inplace=True)
-        normal_df = df[df[' Label'] == 'BENIGN']
-        if(len(list_classes)):
-            df = df[df[' Label'].isin(list_classes)]
-            df = df.groupby([' Label']).apply(lambda x: x.sample(max_per_class)).reset_index(drop=True)
-        return df , normal_df
-        
-    def _create_file_bc(self,n_nodes,n_classes):
-        outlier_percentage = .1
-        file_paths = self._get_files()
-        max_per_class = int(n_nodes * outlier_percentage /  len(file_paths)) +1
-        df_list = []
-        benign_df = pd.DataFrame([])
-        for path in file_paths:
-            class_name = path.split('\\')[-1].split('.')[0]
-            tmp = self._load_file(path,max_per_class,[class_name])
-            df_list.append(tmp[0])
-            benign_df = pd.concat([benign_df,tmp[1]],ignore_index=True)
-            print('finishing loading the file : {}'.format(path))
-        df = pd.concat(df_list,ignore_index=True)
-        print(df.shape)
-        print(benign_df.shape)
-        benign_df = benign_df.sample(n=int(n_nodes * (1-outlier_percentage))).reset_index(drop=True)
-        print(benign_df.shape)
-        df = pd.concat([benign_df,df],ignore_index=True)
-        print(df.shape)
-        df = df.sample(n=n_nodes).reset_index(drop=True)
-        print(df.shape)
-        # print(df[' Label'].value_counts())
-        # df = pd.read_csv(os.path.join(self.directory,'all.csv'),low_memory=False)
-        # df[' Label'] = df[' Label'].apply(lambda x: 0 if x == 'BENIGN' else 1)
-        # node_per_class = int(n_nodes/n_classes)
-        # df = df.groupby([' Label']).apply(lambda x: x.sample(node_per_class)).reset_index(drop=True)
-        return df
-
-    def _filling_adjacency_numpy(self,data):
-        N = data.shape[0]
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-
-        source_ips = data[' Source IP'].to_numpy()
-        destination_ips = data[' Destination IP'].to_numpy()
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips)| (destination_ips[:, np.newaxis] == destination_ips) )
-        adjacency[mask] = True
-        return adjacency
-
-class NetFlowDataset(Dataset):
-    def __init__(self,features_path,adj_path,labels_path,file):
-        super().__init__(features_path,adj_path,labels_path)
-        self.file = file
-
-    def build(self,n_nodes):
-        outlier_percentage = .1
-        df = pd.read_csv(self.file)
-        df = df.groupby(['Label']).apply(lambda x: x.sample(int(n_nodes * (1-outlier_percentage))) if pd.unique(x['Label'])[0] == 0 else x.sample(int(n_nodes * outlier_percentage))).reset_index(drop=True) 
-        df = df.sample(frac=1).reset_index(drop=True)
-        print(df['Label'].value_counts())
-        adj = self._filling_adjacency_numpy(df)
-        labels = df['Label'].to_numpy()
-        labels = labels.astype(np.bool_)
-        df.drop(['IPV4_SRC_ADDR','IPV4_DST_ADDR','Attack','Label','L4_SRC_PORT','L4_DST_PORT'],axis=1,inplace=True)
-        #df = pd.get_dummies(df,columns=['PROTOCOL','DNS_QUERY_TYPE','FTP_COMMAND_RET_CODE'])
-
-        encoder = ce.TargetEncoder(cols=['TCP_FLAGS','L7_PROTO','PROTOCOL'])
-        encoder.fit(df,labels)
-        df = encoder.transform(df)
- 
-        features = df.to_numpy()
-        scaler = MinMaxScaler()
-        features = scaler.fit_transform(features)
-        print("features:",features.shape)
-        self.save_samples(adj,features,labels)
-        return adj,features,labels
-
-    def _filling_adjacency_numpy(self,data):
-        N = data.shape[0]
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-
-        if 'bot_iot' in self.file:
-            data['IPV4_SRC_ADDR'] = data['IPV4_SRC_ADDR'].apply(str)
-            data['IPV4_DST_ADDR'] = data['IPV4_DST_ADDR'].apply(str)
-            data['L4_SRC_PORT'] = data['L4_SRC_PORT'].apply(str)
-            data['L4_DST_PORT'] = data['L4_DST_PORT'].apply(str)
-            data['IPV4_SRC_ADDR'] = data['IPV4_SRC_ADDR']+':'+data['L4_SRC_PORT']
-            data['IPV4_DST_ADDR'] = data['IPV4_DST_ADDR']+':'+data['L4_DST_PORT']
-
-        source_ips = data['IPV4_SRC_ADDR'].to_numpy()
-        destination_ips = data['IPV4_DST_ADDR'].to_numpy()
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips) | (destination_ips[:, np.newaxis] == destination_ips))
-        adjacency[mask] = True
-        return adjacency
-
-class NF_CIC_IDS2018_v2(NetFlowDataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','CIC_IDS2018','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','CIC_IDS2018','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','CIC_IDS2018','labels.pkl'),
-            file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CIC_IDS2018','original','cic_ids2018.csv')
-        )   
-
-class NF_UNSW_NB15_v2(NetFlowDataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','UNSW_NB15','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','UNSW_NB15','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','UNSW_NB15','labels.pkl'),
-            file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'UNSW_NB15','original','unsw_nb15.csv')
-        )
-
-class Darknet(Dataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','Darknet','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','Darknet','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','Darknet','labels.pkl')
-        )
-        self.file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','Darknet','original','Darknet.csv')
-
-    def _to_binary_classification(self,x):
-        if 'Non' in x:
-            return 0
-        else:
-            return 1
-
-    def build(self,n_nodes,n_classes=2):
-        df = pd.read_csv(self.file)
-        df.dropna(axis=0, inplace=True)
-        df['Label'] = df['Label'].apply(self._to_binary_classification)
-        df = df.groupby(['Label']).apply(lambda x: x.sample(int(n_nodes/n_classes))).reset_index(drop=True)
-        df = df.sample(n=n_nodes).reset_index(drop=True)
-        data = df.to_numpy()
-        adj = self._filling_adjacency_numpy(data,1,3)
-        labels = df['Label'].to_numpy()
-        columns_to_exclude = ['Flow ID', 'Src IP','Src Port', 'Dst IP','Dst Port', 'Timestamp','Label','Label.1','Protocol','Flow Duration']
-        df.drop(columns_to_exclude, axis=1, inplace=True)
-        features = df.to_numpy()
-        self.save_samples(adj,features,labels)
-        print('features:',features.shape)
-        return adj,features,labels
-    
-    def _filling_adjacency_numpy(self,data,source_ip_index, destination_ip_index):
-        N = data.shape[0]
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-        source_ips = data[:, source_ip_index]
-        destination_ips = data[:, destination_ip_index]
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips) | (destination_ips[:, np.newaxis] == destination_ips))
-        adjacency[mask] = True
-        return adjacency
-
-class NF_BOT_IoT_v2(NetFlowDataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','BOT_IOT','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','BOT_IOT','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','BOT_IOT','labels.pkl'),
-            file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','BOT_IOT','original','bot_iot.csv')
-        )
-
-class NF_TON_IoT_v2(NetFlowDataset):
-    def __init__(self):
-        # directory=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','TON_IOT','original'),
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','TON_IOT','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','TON_IOT','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','TON_IOT','labels.pkl'),
-            file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT','original','ton_iot.csv')
-        )
-
-class AWID3(Dataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','AWID3','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','AWID3','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'outlier','AWID3','labels.pkl'),
-            directory=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples', 'AWID3','original')
-        )
-
-    def _config_signal(self,x):
-        words = str(x).split('-')
-        return np.mean([float(i)*-1 for i in words if i!=''])
-    
-    def build(self,n_nodes):
-        outlier_percentage = .1
-        path = os.path.join(os.getcwd(),'Ghypeddings','datasets','examples','AWID3','original','awid3.csv')
-        df = pd.read_csv(path)
-        df['Label'] = df['Label'].apply(lambda x: 0 if 'Normal' in x else 1)
-        df = df.groupby(['Label']).apply(lambda x: x.sample(int(n_nodes*(1-outlier_percentage))) if pd.unique(x['Label'])[0] == 0 else  x.sample(int(n_nodes*outlier_percentage)) ).reset_index(drop=True)
-        print(df['Label'].value_counts())
-        df = df.sample(frac=1).reset_index(drop=True)
-        data=df[['ip.src','ip.dst']]
-        df.dropna(axis=1, inplace=True)
-        to_drop = ['frame.number','frame.time','radiotap.timestamp.ts','frame.time_delta_displayed','frame.time_epoch','frame.time_relative','wlan.duration','wlan.ra']
-        df.drop(columns=to_drop,axis=1,inplace=True)
-        alone = []
-        for c in df.columns:
-            if(len(df[c].unique()) == 1):
-                alone.append(c)
-            elif len(df[c].unique()) == 2:
-                df = pd.get_dummies(df,columns=[c],drop_first=True)
-            elif len(df[c].unique()) <=8:
-                df = pd.get_dummies(df,columns=[c])
-            elif len(df[c].unique()) <=15:
-                labels = df['Label']
-                df.drop(columns=['Label'],axis=1,inplace=True)
-                encoder = ce.TargetEncoder(cols=[c])
-                encoder.fit(df,labels)
-                df = encoder.transform(df)
-                df['Label']=labels
-            else:
-                if(df[c].dtype == 'object' and c!='radiotap.dbm_antsignal'):
-                    print(c,df[c].unique(),len(df[c].unique()))
-        df.drop(columns=alone,axis=1,inplace=True)
-        df['radiotap.dbm_antsignal'] = df['radiotap.dbm_antsignal'].apply(self._config_signal)
-        labels = df['Label_1'].to_numpy()
-        adj = self._filling_adjacency_numpy(data)
-        df.drop(columns=['frame.time_delta','Label_1'],axis=1,inplace=True)
-        features = df.to_numpy()
-        scaler = StandardScaler()
-        features = scaler.fit_transform(features)
-        # scaler = MinMaxScaler()
-        # features = scaler.fit_transform(features)
-        self.save_samples(adj=adj,features=features,labels=labels)
-        return adj,features,labels
-    
-    def _filling_adjacency_numpy(self,data):
-        N = data.shape[0]
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-        source_ips = data['ip.src'].to_numpy()
-        destination_ips = data['ip.dst'].to_numpy()
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips) | (destination_ips[:, np.newaxis] == destination_ips) )
-        adjacency[mask] = True
-        np.fill_diagonal(adjacency, True)
-        return adjacency
\ No newline at end of file
diff --git a/datasets/repetition_datasets.py b/datasets/repetition_datasets.py
deleted file mode 100644
index 14b1256..0000000
--- a/datasets/repetition_datasets.py
+++ /dev/null
@@ -1,308 +0,0 @@
-import os
-
-import pandas as pd
-import numpy as np
-from sklearn.preprocessing import MinMaxScaler
-from sklearn.preprocessing import StandardScaler
-import pickle
-from sklearn.preprocessing import LabelEncoder
-import time
-import datetime
-import category_encoders as ce
-
-class Dataset:
-    def __init__(self,features_path='',adj_path='',labels_path='',directory=''):
-        self.features_path = features_path
-        self.adj_path = adj_path
-        self.labels_path = labels_path
-        self.directory = directory
-
-    def _get_files(self):
-        return [os.path.join(self.directory,file) for file in os.listdir(self.directory) if os.path.isfile(os.path.join(self.directory, file)) and '.gitignore' not in file]
-
-    def save_samples(self,adj,features,labels,repetition):
-        # features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CICDDoS2019',f'features_{repetition}.pkl')
-        # adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CICDDoS2019',f'adjacency_{repetition}.pkl')
-        # labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CICDDoS2019',f'labels_{repetition}.pkl')
-        
-        features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CICDDoS2019',f'features_{repetition}.pkl')
-        adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CICDDoS2019',f'adjacency_{repetition}.pkl')
-        labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CICDDoS2019',f'labels_{repetition}.pkl')
-
-
-        with open(adj_path,'wb') as f:
-            pickle.dump(adj,f)
-        with open(features_path,'wb') as f:
-            pickle.dump(features,f)
-        with open(labels_path,'wb') as f:
-            pickle.dump(labels,f)
-
-    def load_samples(self,repetition):
-        features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT',f'features_{repetition}.pkl')
-        adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT',f'adjacency_{repetition}.pkl')
-        labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT',f'labels_{repetition}.pkl')
-        with open(adj_path,'rb') as f:
-            adj = pickle.load(f)
-        with open(features_path,'rb') as f:
-            features = pickle.load(f)
-        with open(labels_path,'rb') as f:
-            labels = pickle.load(f)
-        print('features:',features.shape,'adj',adj.shape,'labels',labels.shape)
-        return adj,features,labels
-
-class CIC_DDoS2019(Dataset):
-    def __init__(self):
-        super().__init__(
-            directory=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CICDDoS2019','original')
-        )
-
-    def build(self,n_nodes,n_classes=2,repetition=1):
-        df = self._create_file_bc(n_nodes,n_classes)
-        for column in df.columns:
-            max_value = df.loc[df[column] != np.inf, column].max()
-            min_value = df.loc[df[column] != -np.inf, column].min()
-            df.loc[df[column] == np.inf, column] = max_value
-            df.loc[df[column] == -np.inf, column] = min_value
-        adj = self._filling_adjacency_numpy(df)
-        labels = df[' Label'].apply(lambda x: 0 if x == 'BENIGN' else 1).to_numpy()
-        columns_to_exclude = ['Unnamed: 0', 'Flow ID', ' Source IP',' Source Port',' Destination Port',' Flow Duration',' Protocol', ' Destination IP', ' Timestamp', 'SimillarHTTP',' Inbound',' Label']
-        df.drop(columns_to_exclude, axis=1, inplace=True)
-        features = df.to_numpy()
-        scaler = MinMaxScaler()
-        features = scaler.fit_transform(features)
-        self.save_samples(adj,features,labels,repetition)
-        return adj, features, labels
-    
-    def _load_file(self,path,max_per_class,list_classes=[]):
-        df = pd.read_csv(path,low_memory=False)
-        df.dropna(axis=0, inplace=True)
-        if(len(list_classes)):
-            df = df[df[' Label'].isin(list_classes)]
-            df = df.groupby([' Label']).apply(lambda x: x.sample(max_per_class)).reset_index(drop=True)
-        return df
-        
-    def _create_file_bc(self,n_nodes,n_classes):
-        file_paths = self._get_files()
-        max_per_class = int(n_nodes / (n_classes * len(file_paths))) +1
-        df_list = []
-        for path in file_paths:
-            class_name = path.split('\\')[-1].split('.')[0]
-            list_classes = ['BENIGN',class_name]
-            df_list.append(self._load_file(path,max_per_class,list_classes))
-            print('finishing loading the file : {}'.format(path))
-        df = pd.concat(df_list,ignore_index=True)
-        df = df.sample(n=n_nodes).reset_index(drop=True)
-        print(df.shape)
-        # print(df[' Label'].value_counts())
-        # df = pd.read_csv(os.path.join(self.directory,'all.csv'),low_memory=False)
-        # df[' Label'] = df[' Label'].apply(lambda x: 0 if x == 'BENIGN' else 1)
-        # node_per_class = int(n_nodes/n_classes)
-        # df = df.groupby([' Label']).apply(lambda x: x.sample(node_per_class)).reset_index(drop=True)
-        return df
-
-    def _filling_adjacency_numpy(self,data):
-        N = data.shape[0]
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-
-        source_ips = data[' Source IP'].to_numpy()
-        destination_ips = data[' Destination IP'].to_numpy()
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips)| (destination_ips[:, np.newaxis] == destination_ips) )
-        adjacency[mask] = True
-        return adjacency
-
-class NetFlowDataset(Dataset):
-    def __init__(self,features_path,adj_path,labels_path,file):
-        super().__init__(features_path,adj_path,labels_path)
-        self.file = file
-
-    def build(self,n_nodes,n_classes=2,repetition=1):
-        df = pd.read_csv(self.file)
-        df = df.groupby(['Label']).apply(lambda x: x.sample(int(n_nodes/n_classes))).reset_index(drop=True) 
-        df = df.sample(frac=1).reset_index(drop=True)
-        adj = self._filling_adjacency_numpy(df)
-        labels = df['Label'].to_numpy()
-        labels = labels.astype(np.bool_)
-        df.drop(['IPV4_SRC_ADDR','IPV4_DST_ADDR','Attack','Label','L4_SRC_PORT','L4_DST_PORT'],axis=1,inplace=True)
-        #df = pd.get_dummies(df,columns=['PROTOCOL','DNS_QUERY_TYPE','FTP_COMMAND_RET_CODE'])
-
-        encoder = ce.TargetEncoder(cols=['TCP_FLAGS','L7_PROTO','PROTOCOL'])
-        encoder.fit(df,labels)
-        df = encoder.transform(df)
- 
-        features = df.to_numpy()
-        scaler = MinMaxScaler()
-        features = scaler.fit_transform(features)
-        print("features:",features.shape)
-        self.save_samples(adj,features,labels,repetition)
-        return adj,features,labels
-
-    def _filling_adjacency_numpy(self,data):
-        N = data.shape[0]
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-
-        if 'bot_iot' in self.file:
-            data['IPV4_SRC_ADDR'] = data['IPV4_SRC_ADDR'].apply(str)
-            data['IPV4_DST_ADDR'] = data['IPV4_DST_ADDR'].apply(str)
-            data['L4_SRC_PORT'] = data['L4_SRC_PORT'].apply(str)
-            data['L4_DST_PORT'] = data['L4_DST_PORT'].apply(str)
-            data['IPV4_SRC_ADDR'] = data['IPV4_SRC_ADDR']+':'+data['L4_SRC_PORT']
-            data['IPV4_DST_ADDR'] = data['IPV4_DST_ADDR']+':'+data['L4_DST_PORT']
-
-        source_ips = data['IPV4_SRC_ADDR'].to_numpy()
-        destination_ips = data['IPV4_DST_ADDR'].to_numpy()
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips) | (destination_ips[:, np.newaxis] == destination_ips))
-        adjacency[mask] = True
-        return adjacency
-
-class NF_CIC_IDS2018_v2(NetFlowDataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CIC_IDS2018','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CIC_IDS2018','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CIC_IDS2018','labels.pkl'),
-            file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','CIC_IDS2018','original','cic_ids2018.csv')
-        )   
-
-class NF_UNSW_NB15_v2(NetFlowDataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','UNSW_NB15','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','UNSW_NB15','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','UNSW_NB15','labels.pkl'),
-            file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','UNSW_NB15','original','unsw_nb15.csv')
-        )
-
-class Darknet(Dataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','Darknet','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','Darknet','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','Darknet','labels.pkl')
-        )
-        self.file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','Darknet','original','Darknet.csv')
-
-    def _to_binary_classification(self,x):
-        if 'Non' in x:
-            return 0
-        else:
-            return 1
-
-    def build(self,n_nodes,n_classes=2,repetition=1):
-        df = pd.read_csv(self.file)
-        df.dropna(axis=0, inplace=True)
-        df['Label'] = df['Label'].apply(self._to_binary_classification)
-        df = df.groupby(['Label']).apply(lambda x: x.sample(int(n_nodes/n_classes))).reset_index(drop=True)
-        df = df.sample(n=n_nodes).reset_index(drop=True)
-        data = df.to_numpy()
-        adj = self._filling_adjacency_numpy(data,1,3)
-        labels = df['Label'].to_numpy()
-        columns_to_exclude = ['Flow ID', 'Src IP','Src Port', 'Dst IP','Dst Port', 'Timestamp','Label','Label.1','Protocol','Flow Duration']
-        df.drop(columns_to_exclude, axis=1, inplace=True)
-        features = df.to_numpy()
-        self.save_samples(adj,features,labels,repetition)
-        print('features:',features.shape)
-        return adj,features,labels
-    
-    def _filling_adjacency_numpy(self,data,source_ip_index, destination_ip_index):
-        N = data.shape[0]
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-        source_ips = data[:, source_ip_index]
-        destination_ips = data[:, destination_ip_index]
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips) | (destination_ips[:, np.newaxis] == destination_ips))
-        adjacency[mask] = True
-        return adjacency
-
-class NF_BOT_IoT_v2(NetFlowDataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','BOT_IOT','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','BOT_IOT','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','BOT_IOT','labels.pkl'),
-            file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','BOT_IOT','original','bot_iot.csv')
-        )
-
-class NF_TON_IoT_v2(NetFlowDataset):
-    def __init__(self):
-        # directory=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT','original'),
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT','labels.pkl'),
-            file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','TON_IOT','original','ton_iot.csv')
-        )
-
-class AWID3(Dataset):
-    def __init__(self):
-        super().__init__(
-            features_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','AWID3','features.pkl'),
-            adj_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','AWID3','adjacency.pkl'),
-            labels_path= os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','AWID3','labels.pkl'),
-            directory=os.path.join(os.path.dirname(os.path.abspath(__file__)),'examples','AWID3','original')
-        )
-
-    def _config_signal(self,x):
-        words = str(x).split('-')
-        return np.mean([float(i)*-1 for i in words if i!=''])
-    
-    def build(self,n_nodes,repetition):
-        path = os.path.join(os.getcwd(),'Ghypeddings','datasets','examples','AWID3','original','awid3.csv')
-        df = pd.read_csv(path)
-        df['Label'] = df['Label'].apply(lambda x: 0 if 'Normal' in x else 1)
-        df = df.groupby(['Label']).apply(lambda x: x.sample(int(n_nodes/2))).reset_index(drop=True)
-        df = df.sample(frac=1).reset_index(drop=True)
-        data=df[['ip.src','ip.dst']]
-        df.dropna(axis=1, inplace=True)
-        to_drop = ['frame.number','frame.time','radiotap.timestamp.ts','frame.time_delta_displayed','frame.time_epoch','frame.time_relative','wlan.duration','wlan.ra']
-        df.drop(columns=to_drop,axis=1,inplace=True)
-        alone = []
-        for c in df.columns:
-            if(len(df[c].unique()) == 1):
-                alone.append(c)
-            elif len(df[c].unique()) == 2:
-                df = pd.get_dummies(df,columns=[c],drop_first=True)
-            elif len(df[c].unique()) <=8:
-                df = pd.get_dummies(df,columns=[c])
-            elif len(df[c].unique()) <=15:
-                labels = df['Label']
-                df.drop(columns=['Label'],axis=1,inplace=True)
-                encoder = ce.TargetEncoder(cols=[c])
-                encoder.fit(df,labels)
-                df = encoder.transform(df)
-                df['Label']=labels
-            else:
-                if(df[c].dtype == 'object' and c!='radiotap.dbm_antsignal'):
-                    print(c,df[c].unique(),len(df[c].unique()))
-        df.drop(columns=alone,axis=1,inplace=True)
-        df['radiotap.dbm_antsignal'] = df['radiotap.dbm_antsignal'].apply(self._config_signal)
-        labels = df['Label_1'].to_numpy()
-        adj = self._filling_adjacency_numpy(data)
-        df.drop(columns=['frame.time_delta','Label_1'],axis=1,inplace=True)
-        features = df.to_numpy()
-        scaler = StandardScaler()
-        features = scaler.fit_transform(features)
-        # scaler = MinMaxScaler()
-        # features = scaler.fit_transform(features)
-        self.save_samples(adj=adj,features=features,labels=labels,repetition=repetition)
-        return adj,features,labels
-    
-    def _filling_adjacency_numpy(self,data):
-        N = data.shape[0]
-        try:
-            adjacency = np.zeros((N,N), dtype=bool)
-        except Exception as e:
-            print(f"An error occurred: {e}")
-        source_ips = data['ip.src'].to_numpy()
-        destination_ips = data['ip.dst'].to_numpy()
-        mask = ((source_ips[:, np.newaxis] == source_ips) | (source_ips[:, np.newaxis] == destination_ips) | (destination_ips[:, np.newaxis] == source_ips) | (destination_ips[:, np.newaxis] == destination_ips) )
-        adjacency[mask] = True
-        np.fill_diagonal(adjacency, True)
-        return adjacency
\ No newline at end of file
diff --git a/datasets/utils.py b/datasets/utils.py
deleted file mode 100644
index a65a154..0000000
--- a/datasets/utils.py
+++ /dev/null
@@ -1,32 +0,0 @@
-import os
-import pickle as pkl
-import sys
-import time
-import scipy.sparse as sp
-import networkx as nx
-import numpy as np
-from tqdm import tqdm
-
-def hyperbolicity(adj, num_samples):
-    curr_time = time.time()
-    hyps = []
-    G = nx.from_numpy_array(adj)
-    for _ in tqdm(range(num_samples)):
-        node_tuple = np.random.choice(G.nodes(), 4, replace=False)
-        s = []
-        try:
-            d01 = nx.shortest_path_length(G, source=node_tuple[0], target=node_tuple[1], weight=None)
-            d23 = nx.shortest_path_length(G, source=node_tuple[2], target=node_tuple[3], weight=None)
-            d02 = nx.shortest_path_length(G, source=node_tuple[0], target=node_tuple[2], weight=None)
-            d13 = nx.shortest_path_length(G, source=node_tuple[1], target=node_tuple[3], weight=None)
-            d03 = nx.shortest_path_length(G, source=node_tuple[0], target=node_tuple[3], weight=None)
-            d12 = nx.shortest_path_length(G, source=node_tuple[1], target=node_tuple[2], weight=None)
-            s.append(d01 + d23)
-            s.append(d02 + d13)
-            s.append(d03 + d12)
-            s.sort()
-            hyps.append((s[-1] - s[-2]) / 2)
-        except Exception as e:
-            continue
-    print('Time for hyp: ', time.time() - curr_time , 'hyp:', max(hyps))
-    return max(hyps)
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index 11e5ded51ddc2ffb101c513fca2f39b932241db7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1106
zcmbW1?@q!%5XAShiSOWdB3dZ_OiXwL-@p_&Xag+>Mdjty-`rg(Au%TA($enE&dttV
z`Tkm&vn^|9wcXj2Yh?w`9m~1b#1Hml53CT+?PxRW+MJrwN85T~+P7}3m|AA3B~(1x
zgxZnyZOpUt?}|I}srA5&ZD0!`6Mhqr!p+Fd$vPsbEy>;54eADHJJ~a<kDdf%mn-B>
z<ecrT0#R}uP_3@qzj|EKfmF`CQ)_q~jE?A@c#aD>d;GRz>%)+KCMZ?sVpBiP_nW{q
zgDYbViTC~Uf}ETQ{w?WvOfJELjJnkKTKL&z^p<-s<U$htkQXIbO>qOR=3cN*<JlNo
z-?LPpN;p5y9O4<poTKuC`n|0qLXHQoD>!T7mz+tgJHpw_NSb=|rn_`)+3`qaex<2*
zM(jXTIFRAB*h5C$ss4pdHmohml$}u5s@hYN`FKh^oR|Zi7AVy@xTiAAukt9VQ+3c5
zkeABkdN(>ACa<%g^QFCm=WTuMb2=G~?l6%K3XU-8q^pM(_Zq((&7g+20NK<I&bnH>
uyjy_Uo>718ARp`KNtkWpWXt*v<H56D_NAF6{2yFve?vj(_m{`RINKj`6sN`j

-- 
GitLab