{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# from base import fetch_dataset\n",
    "# from grakel.datasets import fetch_dataset\n",
    "import multiprocessing\n",
    "# multiprocessing.set_start_method('forkserver')\n",
    "from concurrent.futures import ProcessPoolExecutor\n",
    "import controlpy\n",
    "import time\n",
    "import networkx as nx\n",
    "import numpy as np\n",
    "import csv\n",
    "import itertools\n",
    "import scipy\n",
    "import numpy.linalg as LA\n",
    "import scipy as sc\n",
    "from scipy import stats\n",
    "import numpy as np\n",
    "from os import listdir\n",
    "from os.path import join\n",
    "# from igraph import  *\n",
    "import scipy as sc\n",
    "from scipy import stats\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "# import sys,igraph\n",
    "import scipy.spatial.distance\n",
    "from math import sqrt\n",
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "from pylab import *\n",
    "from scipy import sparse\n",
    "import sys\n",
    "## from joblib import Parallel, delayed\n",
    "from joblib import Parallel, delayed\n",
    "import multiprocessing\n",
    "from tqdm.notebook import tqdm\n",
    "import tqdm\n",
    "from sklearn.model_selection import GridSearchCV,StratifiedKFold\n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "from sklearn.model_selection import cross_val_score\n",
    "from torch_geometric.data import Data\n",
    "from torch_geometric.utils import to_networkx\n",
    "from torch_geometric.datasets import TUDataset\n",
    "from sklearn.utils import shuffle\n",
    "num_cores = multiprocessing.cpu_count()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#from grakel.datasets import fetch_dataset\n",
    "#default parameters\n",
    "INCLUDE_GRM = True\n",
    "INCLUDE_INVERSE_GRM = False #-----\n",
    "INCLUDE_EIGEN_VALUES = True\n",
    "INCLUDE_MIN_MAX = True\n",
    "INCLUDE_MEAN = True\n",
    "INCLUDE_LAP_SPECT = True\n",
    "INCLUDE_LAP_SPECT_EXT = True\n",
    "INCLUDE_METRIC_DIMENSION = True\n",
    "INCLUDE_FEATURES = True\n",
    "LAPLACIAN_ENERGY = True\n",
    "ECC_SPECTRUM = True\n",
    "ECC_ENERGY = True\n",
    "WEINER_INDEX = True\n",
    "TRACE_DEG_SEQ = True\n",
    "INCLUDE_CYCLES = True\n",
    "\n",
    "def get_descriptor(G,num_iterations = 30):\n",
    "#     G = G.subgraph(max(nx.connected_components(G), key=len) )\n",
    "    G = nx.convert_node_labels_to_integers(G)\n",
    "    if G.number_of_nodes()<10:\n",
    "#         return list(np.zeros(162, dtype = float))\n",
    "        G = add_multiple_copies(G)\n",
    "    A1 = -(np.matrix(nx.laplacian_matrix(G,nodelist=sorted(G.nodes())).todense()))\n",
    "    n = A1.shape[0]\n",
    "    desc = {}\n",
    "    leaders = []\n",
    "    for num_l_idx, num_leaders in enumerate([1,2,5,9,int(n*2/100)+1,int(n*5/100)+1,int(n*10/100)+1,int(n*20/100)+1,int(n*30/100)+1]):\n",
    "#         A1 = np.matrix( nx.laplacian_matrix(G).todense() )\n",
    "        old_n = A1.shape[0]\n",
    "        traces = []\n",
    "        ranks = []\n",
    "        min_eigs = []\n",
    "        max_eigs = []\n",
    "        itraces = []\n",
    "        iranks = []\n",
    "        imin_eigs = []\n",
    "        imax_eigs = []\n",
    "        metric_dimension = []\n",
    "        for i in range(num_iterations):\n",
    "            follows = np.random.choice(old_n,old_n-num_leaders,replace=False)\n",
    "            leaders = list(set(range(old_n))-set(follows))\n",
    "            A2 = A1[follows, :]\n",
    "            A3 = A2[:, follows]\n",
    "            A = 1*A3\n",
    "            n = A.shape[0]\n",
    "            mask = np.ones(old_n, dtype=bool)\n",
    "            mask[leaders] = False\n",
    "            B = A1[mask,:] #removing corresponding rows of leaders from laplacian\n",
    "            B = B[:,leaders] #selecting corresponding columns of leaders from laplacian\n",
    "            A = np.mat(A)\n",
    "            B = np.mat(B)\n",
    "            if INCLUDE_GRM:\n",
    "                grm = controlpy.analysis.controllability_gramian(A,B)\n",
    "                rnk = LA.matrix_rank(grm)\n",
    "                ranks.append(rnk)\n",
    "                traces.append( np.trace(grm) )\n",
    "                if INCLUDE_EIGEN_VALUES :\n",
    "                    w, v = LA.eig(grm)\n",
    "                    a = np.real(w)\n",
    "                    a[a == 0] = 0.0001\n",
    "                    minval = np.min(a)\n",
    "                    min_eigs.append( minval ) \n",
    "                    max_eigs.append(np.max( a ) )\n",
    "                if INCLUDE_INVERSE_GRM :\n",
    "                    try:\n",
    "                        grm = LA.pinv( grm ,hermitian=True)\n",
    "                    except:\n",
    "                        print(\"Oops!\", sys.exc_info()[0], \"occurred.\")\n",
    "                        return zero_des()\n",
    "                    itraces.append(np.trace(grm))\n",
    "                    iranks.append( LA.matrix_rank(grm) )\n",
    "                    if INCLUDE_EIGEN_VALUES :\n",
    "                        w, v = LA.eig(grm)\n",
    "                        a = np.real(w)\n",
    "                        a[a == 0] = 0.0001\n",
    "                        #if sum(a) == 0:\n",
    "                        #    print(a)\n",
    "                        #    print(grm)\n",
    "                        #    print(A1)\n",
    "                        minval = np.min(a)\n",
    "                        imin_eigs.append( np.min( minval ) )\n",
    "                        imax_eigs.append( np.max( a ) )  \n",
    "\n",
    "            if INCLUDE_METRIC_DIMENSION:            \n",
    "                metric_dimension.append(compute_metric_dimension(G, leaders))\n",
    "\n",
    "        if INCLUDE_MIN_MAX :\n",
    "            desc['GRM_MAX_TRACE_'+str(num_l_idx)] = np.max(traces)\n",
    "            desc['GRM_MIN_TRACE_'+str(num_l_idx)] = np.min(traces) \n",
    "            desc['GRM_MAX_RANK_'+str(num_l_idx)]  = np.max(ranks) \n",
    "            desc['GRM_MIN_RANK_'+str(num_l_idx)]  = np.min(ranks) \n",
    "            if INCLUDE_EIGEN_VALUES :\n",
    "\n",
    "                desc['GRM_MAX_of_MIN_EIG_'+str(num_l_idx)] = np.max(min_eigs)\n",
    "                desc['GRM_MIN_of_MIN_EIG_'+str(num_l_idx)] = np.min(min_eigs)\n",
    "\n",
    "                desc['GRM_MAX_of_MAX_EIG_'+str(num_l_idx)] = np.max(max_eigs)\n",
    "                desc['GRM_MIN_of_MAX_EIG_'+str(num_l_idx)] = np.min(max_eigs)\n",
    "            if INCLUDE_INVERSE_GRM :    \n",
    "\n",
    "                desc['INV_GRM_MAX_TRACE_'+str(num_l_idx)] = np.max(itraces)\n",
    "                desc['INV_GRM_MIN_TRACE_'+str(num_l_idx)] = np.min(itraces)\n",
    "\n",
    "        if INCLUDE_MEAN :\n",
    "            desc['GRM_MEAN_TRACE_'+str(num_l_idx)] = np.mean(traces)\n",
    "            desc['GRM_MEAN_RANK_'+str(num_l_idx)] = np.mean(ranks)\n",
    "\n",
    "            if INCLUDE_EIGEN_VALUES :\n",
    "                desc['GRM_MEAN_MAX_EIG_'+str(num_l_idx)] = np.mean(max_eigs)\n",
    "                desc['GRM_MEAN_MIN_EIG_'+str(num_l_idx)] = np.mean(min_eigs)\n",
    "\n",
    "            if INCLUDE_INVERSE_GRM :\n",
    "                desc['INV_GRM_MEAN_TRACE_'+str(num_l_idx)] = np.mean(itraces)\n",
    "                desc['INV_GRM_MEAN_RANK_'+str(num_l_idx)] = np.mean(iranks)\n",
    "\n",
    "                if INCLUDE_EIGEN_VALUES :\n",
    "                    desc['INV_GRM_MEAN_MIN_EIG_'+str(num_l_idx)] = np.mean(imin_eigs)\n",
    "                    desc['INV_GRM_MEAN_MAX_EIG_'+str(num_l_idx)] =np.mean(imax_eigs)\n",
    "\n",
    "        if INCLUDE_METRIC_DIMENSION:\n",
    "            desc['METRIC_DIMENSION_MEAN'+str(num_l_idx)] = np.mean(metric_dimension)\n",
    "            desc['METRIC_DIMENSION_MIN'+str(num_l_idx)] = np.min(metric_dimension)\n",
    "            desc['METRIC_DIMENSION_MAX'+str(num_l_idx)] = np.max(metric_dimension)\n",
    "\n",
    "    n,m = G.number_of_nodes(),G.number_of_edges()\n",
    "    desc['no_nodes'] = n\n",
    "    desc['no_edges'] = m\n",
    "    desc['no_bi_conn_comp'] =len(list(nx.biconnected_components(G)))\n",
    "    if INCLUDE_LAP_SPECT :\n",
    "        Ls = sorted(nx.laplacian_spectrum(G))\n",
    "        desc['LS_0'] = Ls[0]\n",
    "        desc['LS_1'] = Ls[1]\n",
    "        desc['LS_2'] = Ls[2]\n",
    "    if INCLUDE_LAP_SPECT_EXT :\n",
    "        desc['LSE_3'] = Ls[3]\n",
    "        desc['LSE_4'] = Ls[4]\n",
    "        desc['LSE_-1'] = Ls[-1]\n",
    "        desc['LSE_-2'] = Ls[-2]\n",
    "        desc['LSE_-3'] = Ls[-3]\n",
    "    if INCLUDE_CYCLES:\n",
    "        if n-m == 1:\n",
    "            desc['0cyc'] = 1  \n",
    "        else:\n",
    "            desc['0cyc'] = 0\n",
    "        if n-m == 0:\n",
    "            desc['1cyc'] = 1\n",
    "        else:\n",
    "            desc['1cyc'] = 0\n",
    "        if n-m == -1:\n",
    "            desc['2cyc'] = 1\n",
    "        else:\n",
    "            desc['2cyc'] = 0\n",
    "        if n-m < -1:\n",
    "            desc['g2cyc'] = 1\n",
    "        else:\n",
    "            desc['g2cyc'] = 0\n",
    "\n",
    "    if INCLUDE_FEATURES:\n",
    "        desc.update(add_features(G))\n",
    "    return(desc)\n",
    "    \n",
    "\n",
    "def add_multiple_copies(G):\n",
    "    no_node = G.number_of_nodes()   \n",
    "    H = G.copy()\n",
    "    H = nx.convert_node_labels_to_integers(H, ordering='sorted')\n",
    "    val = sorted(G.nodes())\n",
    "    val0 = val[0]\n",
    "    while H.number_of_nodes()<10:\n",
    "        val1 = H.number_of_nodes()-1\n",
    "        H = nx.union(H, G, rename=('G1-', 'G2-'))\n",
    "        H.add_edge('G1-'+str(val1), 'G2-'+str(val0))\n",
    "        H = nx.convert_node_labels_to_integers(H, ordering='sorted')\n",
    "    return H\n",
    "\n",
    "def trace_deq_seq(G):\n",
    "    seq = sorted(list(dict(nx.degree(G)).values()),reverse = False)\n",
    "    trc = 0\n",
    "    for idx, i in enumerate(seq):\n",
    "        if idx+1<=i:\n",
    "            trc = idx+1\n",
    "    return trc\n",
    "\n",
    "def add_features(G):\n",
    "    L = nx.laplacian_matrix(G).todense()\n",
    "    eig = LA.eigvals(L)\n",
    "    avg_deg = 2*(G.number_of_edges()/G.number_of_nodes()) # made it faster\n",
    "    lap_energy = sum([abs(i-avg_deg) for i in eig])\n",
    "    dist_matrix =np.array(nx.floyd_warshall_numpy(G,nodelist=sorted(G.nodes()))) #nodelist, important argument, I will let you know\n",
    "    eccentricity = dist_matrix * (dist_matrix >= np.sort(dist_matrix, axis=1)[:,[-1]]).astype(int) #can be computed through networkx thats why nodelist argument is added\n",
    "    e_vals = LA.eigvals(eccentricity) \n",
    "    largest_eig = np.real(max(e_vals))\n",
    "    energy = np.real(sum([abs(x) for x in e_vals]))\n",
    "    wiener_index = nx.wiener_index(G)\n",
    "    trace_DS = trace_deq_seq(G)  #it was different then your implementation kindly read the document again as sent by the dr. Waseem or go through by my implementation\n",
    "    return {'lap_energy':lap_energy,'ecc_spectrum':largest_eig,'ecc_energy':energy,'wiener_index':wiener_index,'trace_deg_seq':trace_DS}\n",
    "\n",
    "def compute_metric_dimension(G, leaders):\n",
    "    nodes_list = list(G.nodes()) \n",
    "    distance_vec = []\n",
    "    for n in nodes_list:\n",
    "        v_ = [nx.shortest_path_length(G, source=n, target=l) for l in leaders]\n",
    "        distance_vec.append(v_)\n",
    "    distance_vec = np.array(distance_vec)\n",
    "    return np.unique(distance_vec, axis=0).shape[0]\n",
    "\n",
    "        \n",
    "def add_vertex(G):\n",
    "    G = nx.convert_node_labels_to_integers(G)\n",
    "    nodes = sorted(list(G.nodes()))\n",
    "    new_vertex = nodes[-1]+1 \n",
    "    G.add_node(new_vertex)\n",
    "    for n in G.nodes():\n",
    "        if n !=new_vertex:\n",
    "            G.add_edge(new_vertex, n)\n",
    "    return G\n",
    "    \n",
    "def zero_des(): \n",
    "    return {'GRM_MAX_TRACE_0': 0.0, 'GRM_MIN_TRACE_0': 0.0, 'GRM_MAX_RANK_0': 0.0, 'GRM_MIN_RANK_0': 0.0, 'GRM_MAX_of_MIN_EIG_0': 0.0, 'GRM_MIN_of_MIN_EIG_0': 0.0, 'GRM_MAX_of_MAX_EIG_0': 0.0, 'GRM_MIN_of_MAX_EIG_0': 0.0, 'INV_GRM_MAX_TRACE_0': 0.0, 'INV_GRM_MIN_TRACE_0': 0.0, 'GRM_MEAN_TRACE_0': 0.0, 'GRM_MEAN_RANK_0': 0.0, 'GRM_MEAN_MAX_EIG_0': 0.0, 'GRM_MEAN_MIN_EIG_0': 0.0, 'INV_GRM_MEAN_TRACE_0': 0.0, 'INV_GRM_MEAN_RANK_0': 0.0, 'INV_GRM_MEAN_MIN_EIG_0': 0.0, 'INV_GRM_MEAN_MAX_EIG_0': 0.0, 'METRIC_DIMENSION_MEAN0': 0.0, 'METRIC_DIMENSION_MIN0': 0.0, 'METRIC_DIMENSION_MAX0': 0.0, 'GRM_MAX_TRACE_1': 0.0, 'GRM_MIN_TRACE_1': 0.0, 'GRM_MAX_RANK_1': 0.0, 'GRM_MIN_RANK_1': 0.0, 'GRM_MAX_of_MIN_EIG_1': 0.0, 'GRM_MIN_of_MIN_EIG_1': 0.0, 'GRM_MAX_of_MAX_EIG_1': 0.0, 'GRM_MIN_of_MAX_EIG_1': 0.0, 'INV_GRM_MAX_TRACE_1': 0.0, 'INV_GRM_MIN_TRACE_1': 0.0, 'GRM_MEAN_TRACE_1': 0.0, 'GRM_MEAN_RANK_1': 0.0, 'GRM_MEAN_MAX_EIG_1': 0.0, 'GRM_MEAN_MIN_EIG_1': 0.0, 'INV_GRM_MEAN_TRACE_1': 0.0, 'INV_GRM_MEAN_RANK_1': 0.0, 'INV_GRM_MEAN_MIN_EIG_1': 0.0, 'INV_GRM_MEAN_MAX_EIG_1': 0.0, 'METRIC_DIMENSION_MEAN1': 0.0, 'METRIC_DIMENSION_MIN1': 0.0, 'METRIC_DIMENSION_MAX1': 0.0, 'GRM_MAX_TRACE_2': 0.0, 'GRM_MIN_TRACE_2': 0.0, 'GRM_MAX_RANK_2': 0.0, 'GRM_MIN_RANK_2': 0.0, 'GRM_MAX_of_MIN_EIG_2': 0.0, 'GRM_MIN_of_MIN_EIG_2': 0.0, 'GRM_MAX_of_MAX_EIG_2': 0.0, 'GRM_MIN_of_MAX_EIG_2': 0.0, 'INV_GRM_MAX_TRACE_2': 0.0, 'INV_GRM_MIN_TRACE_2': 0.0, 'GRM_MEAN_TRACE_2': 0.0, 'GRM_MEAN_RANK_2': 0.0, 'GRM_MEAN_MAX_EIG_2': 0.0, 'GRM_MEAN_MIN_EIG_2': 0.0, 'INV_GRM_MEAN_TRACE_2': 0.0, 'INV_GRM_MEAN_RANK_2': 0.0, 'INV_GRM_MEAN_MIN_EIG_2': 0.0, 'INV_GRM_MEAN_MAX_EIG_2': 0.0, 'METRIC_DIMENSION_MEAN2': 0.0, 'METRIC_DIMENSION_MIN2': 0.0, 'METRIC_DIMENSION_MAX2': 0.0, 'GRM_MAX_TRACE_3': 0.0, 'GRM_MIN_TRACE_3': 0.0, 'GRM_MAX_RANK_3': 0.0, 'GRM_MIN_RANK_3': 0.0, 'GRM_MAX_of_MIN_EIG_3': 0.0, 'GRM_MIN_of_MIN_EIG_3': 0.0, 'GRM_MAX_of_MAX_EIG_3': 0.0, 'GRM_MIN_of_MAX_EIG_3': 0.0, 'INV_GRM_MAX_TRACE_3': 0.0, 'INV_GRM_MIN_TRACE_3': 0.0, 'GRM_MEAN_TRACE_3': 0.0, 'GRM_MEAN_RANK_3': 0.0, 'GRM_MEAN_MAX_EIG_3': 0.0, 'GRM_MEAN_MIN_EIG_3': 0.0, 'INV_GRM_MEAN_TRACE_3': 0.0, 'INV_GRM_MEAN_RANK_3': 0.0, 'INV_GRM_MEAN_MIN_EIG_3': 0.0, 'INV_GRM_MEAN_MAX_EIG_3': 0.0, 'METRIC_DIMENSION_MEAN3': 0.0, 'METRIC_DIMENSION_MIN3': 0.0, 'METRIC_DIMENSION_MAX3': 0.0, 'GRM_MAX_TRACE_4': 0.0, 'GRM_MIN_TRACE_4': 0.0, 'GRM_MAX_RANK_4': 0.0, 'GRM_MIN_RANK_4': 0.0, 'GRM_MAX_of_MIN_EIG_4': 0.0, 'GRM_MIN_of_MIN_EIG_4': 0.0, 'GRM_MAX_of_MAX_EIG_4': 0.0, 'GRM_MIN_of_MAX_EIG_4': 0.0, 'INV_GRM_MAX_TRACE_4': 0.0, 'INV_GRM_MIN_TRACE_4': 0.0, 'GRM_MEAN_TRACE_4': 0.0, 'GRM_MEAN_RANK_4': 0.0, 'GRM_MEAN_MAX_EIG_4': 0.0, 'GRM_MEAN_MIN_EIG_4': 0.0, 'INV_GRM_MEAN_TRACE_4': 0.0, 'INV_GRM_MEAN_RANK_4': 0.0, 'INV_GRM_MEAN_MIN_EIG_4': 0.0, 'INV_GRM_MEAN_MAX_EIG_4': 0.0, 'METRIC_DIMENSION_MEAN4': 0.0, 'METRIC_DIMENSION_MIN4': 0.0, 'METRIC_DIMENSION_MAX4': 0.0, 'GRM_MAX_TRACE_5': 0.0, 'GRM_MIN_TRACE_5': 0.0, 'GRM_MAX_RANK_5': 0.0, 'GRM_MIN_RANK_5': 0.0, 'GRM_MAX_of_MIN_EIG_5': 0.0, 'GRM_MIN_of_MIN_EIG_5': 0.0, 'GRM_MAX_of_MAX_EIG_5': 0.0, 'GRM_MIN_of_MAX_EIG_5': 0.0, 'INV_GRM_MAX_TRACE_5': 0.0, 'INV_GRM_MIN_TRACE_5': 0.0, 'GRM_MEAN_TRACE_5': 0.0, 'GRM_MEAN_RANK_5': 0.0, 'GRM_MEAN_MAX_EIG_5': 0.0, 'GRM_MEAN_MIN_EIG_5': 0.0, 'INV_GRM_MEAN_TRACE_5': 0.0, 'INV_GRM_MEAN_RANK_5': 0.0, 'INV_GRM_MEAN_MIN_EIG_5': 0.0, 'INV_GRM_MEAN_MAX_EIG_5': 0.0, 'METRIC_DIMENSION_MEAN5': 0.0, 'METRIC_DIMENSION_MIN5': 0.0, 'METRIC_DIMENSION_MAX5': 0.0, 'GRM_MAX_TRACE_6': 0.0, 'GRM_MIN_TRACE_6': 0.0, 'GRM_MAX_RANK_6': 0.0, 'GRM_MIN_RANK_6': 0.0, 'GRM_MAX_of_MIN_EIG_6': 0.0, 'GRM_MIN_of_MIN_EIG_6': 0.0, 'GRM_MAX_of_MAX_EIG_6': 0.0, 'GRM_MIN_of_MAX_EIG_6': 0.0, 'INV_GRM_MAX_TRACE_6': 0.0, 'INV_GRM_MIN_TRACE_6': 0.0, 'GRM_MEAN_TRACE_6': 0.0, 'GRM_MEAN_RANK_6': 0.0, 'GRM_MEAN_MAX_EIG_6': 0.0, 'GRM_MEAN_MIN_EIG_6': 0.0, 'INV_GRM_MEAN_TRACE_6': 0.0, 'INV_GRM_MEAN_RANK_6': 0.0, 'INV_GRM_MEAN_MIN_EIG_6': 0.0, 'INV_GRM_MEAN_MAX_EIG_6': 0.0, 'METRIC_DIMENSION_MEAN6': 0.0, 'METRIC_DIMENSION_MIN6': 0.0, 'METRIC_DIMENSION_MAX6': 0.0, 'GRM_MAX_TRACE_7': 0.0, 'GRM_MIN_TRACE_7': 0.0, 'GRM_MAX_RANK_7': 0.0, 'GRM_MIN_RANK_7': 0.0, 'GRM_MAX_of_MIN_EIG_7': 0.0, 'GRM_MIN_of_MIN_EIG_7': 0.0, 'GRM_MAX_of_MAX_EIG_7': 0.0, 'GRM_MIN_of_MAX_EIG_7': 0.0, 'INV_GRM_MAX_TRACE_7': 0.0, 'INV_GRM_MIN_TRACE_7': 0.0, 'GRM_MEAN_TRACE_7': 0.0, 'GRM_MEAN_RANK_7': 0.0, 'GRM_MEAN_MAX_EIG_7': 0.0, 'GRM_MEAN_MIN_EIG_7': 0.0, 'INV_GRM_MEAN_TRACE_7': 0.0, 'INV_GRM_MEAN_RANK_7': 0.0, 'INV_GRM_MEAN_MIN_EIG_7': 0.0, 'INV_GRM_MEAN_MAX_EIG_7': 0.0, 'METRIC_DIMENSION_MEAN7': 0.0, 'METRIC_DIMENSION_MIN7': 0.0, 'METRIC_DIMENSION_MAX7': 0.0, 'GRM_MAX_TRACE_8': 0.0, 'GRM_MIN_TRACE_8': 0.0, 'GRM_MAX_RANK_8': 0.0, 'GRM_MIN_RANK_8': 0.0, 'GRM_MAX_of_MIN_EIG_8': 0.0, 'GRM_MIN_of_MIN_EIG_8': 0.0, 'GRM_MAX_of_MAX_EIG_8': 0.0, 'GRM_MIN_of_MAX_EIG_8': 0.0, 'INV_GRM_MAX_TRACE_8': 0.0, 'INV_GRM_MIN_TRACE_8': 0.0, 'GRM_MEAN_TRACE_8': 0.0, 'GRM_MEAN_RANK_8': 0.0, 'GRM_MEAN_MAX_EIG_8': 0.0, 'GRM_MEAN_MIN_EIG_8': 0.0, 'INV_GRM_MEAN_TRACE_8': 0.0, 'INV_GRM_MEAN_RANK_8': 0.0, 'INV_GRM_MEAN_MIN_EIG_8': 0.0, 'INV_GRM_MEAN_MAX_EIG_8': 0.0, 'METRIC_DIMENSION_MEAN8': 0.0, 'METRIC_DIMENSION_MIN8': 0.0, 'METRIC_DIMENSION_MAX8': 0.0, 'no_nodes': 0.0, 'no_edges': 0.0, 'no_bi_conn_comp': 0.0, 'LS_0': 0.0, 'LS_1': 0.0, 'LS_2': 0.0, 'LSE_3': 0.0, 'LSE_4': 0.0, 'LSE_-1': 0.0, 'LSE_-2': 0.0, 'LSE_-3': 0.0, '0cyc': 0.0, '1cyc': 0.0, '2cyc': 0.0, 'g2cyc': 0.0, 'lap_energy': 0.0, 'ecc_spectrum': 0.0, 'ecc_energy': 0.0, 'wiener_index': 0.0, 'trace_deg_seq': 0.0}\n",
    "def return_dataset(file_name):\n",
    "    #i = 'G_nci1'\n",
    "    dd = fetch_dataset(file_name)\n",
    "    graph_list = []\n",
    "    for gg in dd.data:\n",
    "        g_ = nx.Graph()\n",
    "        g_.add_edges_from([(i[0], i[1]) for i in gg[0]])\n",
    "        graph_list.append(g_)\n",
    "    data_y = dd.target\n",
    "    return graph_list, data_y\n",
    "\n",
    "def apply_RF_Grid(data_X,data_y):\n",
    "    num_cores = multiprocessing.cpu_count()\n",
    "    max_arr = []\n",
    "    estimator  = RandomForestClassifier(criterion='gini', max_depth=None, min_weight_fraction_leaf=0.0,\n",
    "                                            max_leaf_nodes=None, bootstrap=True, \n",
    "                                            oob_score=False, n_jobs=num_cores,verbose=0, warm_start=False,\n",
    "                                            class_weight=None)\n",
    "         \n",
    "    param_grid = {'n_estimators':[50,100,500], 'max_features':['sqrt'], \n",
    "                  'min_samples_split':[2,3,4,5,10], 'min_samples_leaf':[1,2,5]}\n",
    "    kf = StratifiedKFold(n_splits=10, random_state = 890, shuffle = True)\n",
    "    grid_rf    = GridSearchCV(estimator, param_grid, scoring='accuracy', n_jobs=num_cores, \n",
    "                 refit=True, cv=kf, verbose=1, pre_dispatch='n_jobs', \n",
    "                 error_score='raise')\n",
    "\n",
    "    grid_rf.fit(data_X, data_y)\n",
    "    \n",
    "    cv_results = pd.DataFrame(grid_rf.cv_results_)\n",
    "    std = cv_results.loc[grid_rf.best_index_].std_test_score\n",
    "    best_score = grid_rf.best_score_\n",
    "    return best_score, std\n",
    "\n",
    "\n",
    "\n",
    "def apply_RF(data_X, data_y):\n",
    "    num_cores = multiprocessing.cpu_count()\n",
    "    max_arr     = []\n",
    "    feature_imp = []\n",
    "    estimator  = RandomForestClassifier(criterion='gini', max_depth=None, min_weight_fraction_leaf=0.0,\n",
    "                                            max_leaf_nodes=None, bootstrap=True, \n",
    "                                            oob_score=False, n_jobs=num_cores-2,verbose=0, warm_start=False,\n",
    "                                            class_weight=None,n_estimators=500)\n",
    "    for i in range(10):\n",
    "         \n",
    "        kf = StratifiedKFold(n_splits=10, shuffle = True)\n",
    "        grid_rf    = GridSearchCV(estimator, {}, scoring='accuracy', n_jobs=num_cores-2, \n",
    "                     refit=True, cv=kf, verbose=1, pre_dispatch='n_jobs', \n",
    "                     error_score='raise')\n",
    "\n",
    "        grid_rf.fit(data_X, data_y)\n",
    "        max_arr.append(grid_rf.best_score_)\n",
    "        feature_imp.append(grid_rf.best_estimator_.feature_importances_)\n",
    "        \n",
    "    return np.mean(max_arr), np.mean(feature_imp,axis=0)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if __name__ == '__main__':\n",
    "    datasets = [\"PROTEINS_full\", \"DD\",\"IMDB-BINARY\",\"IMDB-MULTI\",\"REDDIT-BINARY\",\"REDDIT-MULTI-5K\"]\n",
    "    \n",
    "    file = open(\"results/social_networks.csv\",'a',newline = '')\n",
    "    res_writer = csv.writer(file, delimiter=',',quotechar='|', quoting=csv.QUOTE_MINIMAL)\n",
    "    res_writer.writerow([\"dataset\",\"CTRL_ACC\",\"std\",\"time\"])\n",
    "    for d in datasets:\n",
    "        graph_dataset = TUDataset(root = \"data/TUDataset\", name=d)\n",
    "        graphs = [to_networkx(d, to_undirected = True) for d in graph_dataset]\n",
    "        graph_data      = [G if nx.is_connected(G) else add_vertex(G) for G in graphs]\n",
    "\n",
    "        print(\"dataset {} is loaded with {} number of graphs\".format(d,len(graph_data)))\n",
    "        \n",
    "        start = time.time()\n",
    "        control_des = Parallel(n_jobs=-1, verbose=2)(delayed(get_descriptor)\n",
    "                            (G) for G in graph_data)\n",
    "        labels = [int(x.y.item()) for x in graph_dataset]\n",
    "        end = time.time()\n",
    "        print(\"time:\",end-start)\n",
    "        \n",
    "        print(\"dataset {} loaded successfully,control desciptor shape:{}\".format(d, len(control_des)))\n",
    "        control_des = pd.DataFrame(control_des)\n",
    "        acc, std = apply_RF_Grid(control_des, labels)\n",
    "        to_write = [d,acc, std]\n",
    "        res_writer.writerow(to_write)\n",
    "        print(\"features of {} dataset saved successfully! acc, std, time: {}, {}\".format(d,acc, std))\n",
    "        file.flush()\n",
    "#         break\n",
    "    file.close()    "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
