| @@ -0,0 +1,227 @@ | |||||
| #!/usr/bin/env python3 | |||||
| # -*- coding: utf-8 -*- | |||||
| """ | |||||
| Created on Mon Mar 30 11:52:47 2020 | |||||
| @author: ljia | |||||
| """ | |||||
| import numpy as np | |||||
| import networkx as nx | |||||
| import multiprocessing | |||||
| import time | |||||
| class GraphKernel(object): | |||||
| def __init__(self): | |||||
| self._graphs = None | |||||
| self._parallel = '' | |||||
| self._n_jobs = 0 | |||||
| self._verbose = None | |||||
| self._normalize = True | |||||
| self._run_time = 0 | |||||
| self._gram_matrix = None | |||||
| self._gram_matrix_unnorm = None | |||||
| def compute(self, *graphs, **kwargs): | |||||
| self._parallel = kwargs.get('parallel', 'imap_unordered') | |||||
| self._n_jobs = kwargs.get('n_jobs', multiprocessing.cpu_count()) | |||||
| self._normalize = kwargs.get('normalize', True) | |||||
| self._verbose = kwargs.get('verbose', 2) | |||||
| if len(graphs) == 1: | |||||
| if not isinstance(graphs[0], list): | |||||
| raise Exception('Cannot detect graphs.') | |||||
| elif len(graphs[0]) == 0: | |||||
| raise Exception('The graph list given is empty. No computation was performed.') | |||||
| else: | |||||
| self._graphs = [g.copy() for g in graphs[0]] | |||||
| self._gram_matrix = self.__compute_gram_matrix() | |||||
| self._gram_matrix_unnorm = np.copy(self._gram_matrix) | |||||
| if self._normalize: | |||||
| self._gram_matrix = self.normalize_gm(self._gram_matrix) | |||||
| return self._gram_matrix, self._run_time | |||||
| elif len(graphs) == 2: | |||||
| if self.is_graph(graphs[0]) and self.is_graph(graphs[1]): | |||||
| kernel = self.__compute_single_kernel(graphs[0].copy(), graphs[1].copy()) | |||||
| return kernel, self._run_time | |||||
| elif self.is_graph(graphs[0]) and isinstance(graphs[1], list): | |||||
| g1 = graphs[0].copy() | |||||
| g_list = [g.copy() for g in graphs[1]] | |||||
| kernel_list = self.__compute_kernel_list(g1, g_list) | |||||
| return kernel_list, self._run_time | |||||
| elif isinstance(graphs[0], list) and self.is_graph(graphs[1]): | |||||
| g1 = graphs[1].copy() | |||||
| g_list = [g.copy() for g in graphs[0]] | |||||
| kernel_list = self.__compute_kernel_list(g1, g_list) | |||||
| return kernel_list, self._run_time | |||||
| else: | |||||
| raise Exception('Cannot detect graphs.') | |||||
| elif len(graphs) == 0 and self._graphs is None: | |||||
| raise Exception('Please add graphs before computing.') | |||||
| else: | |||||
| raise Exception('Cannot detect graphs.') | |||||
| def normalize_gm(self, gram_matrix): | |||||
| import warnings | |||||
| warnings.warn('gklearn.kernels.graph_kernel.normalize_gm will be deprecated, use gklearn.utils.normalize_gram_matrix instead', DeprecationWarning) | |||||
| diag = gram_matrix.diagonal().copy() | |||||
| for i in range(len(gram_matrix)): | |||||
| for j in range(i, len(gram_matrix)): | |||||
| gram_matrix[i][j] /= np.sqrt(diag[i] * diag[j]) | |||||
| gram_matrix[j][i] = gram_matrix[i][j] | |||||
| return gram_matrix | |||||
| def compute_distance_matrix(self): | |||||
| if self._gram_matrix is None: | |||||
| raise Exception('Please compute the Gram matrix before computing distance matrix.') | |||||
| dis_mat = np.empty((len(self._gram_matrix), len(self._gram_matrix))) | |||||
| for i in range(len(self._gram_matrix)): | |||||
| for j in range(i, len(self._gram_matrix)): | |||||
| dis = self._gram_matrix[i, i] + self._gram_matrix[j, j] - 2 * self._gram_matrix[i, j] | |||||
| if dis < 0: | |||||
| if dis > -1e-10: | |||||
| dis = 0 | |||||
| else: | |||||
| raise ValueError('The distance is negative.') | |||||
| dis_mat[i, j] = np.sqrt(dis) | |||||
| dis_mat[j, i] = dis_mat[i, j] | |||||
| dis_max = np.max(np.max(dis_mat)) | |||||
| dis_min = np.min(np.min(dis_mat[dis_mat != 0])) | |||||
| dis_mean = np.mean(np.mean(dis_mat)) | |||||
| return dis_mat, dis_max, dis_min, dis_mean | |||||
| def __compute_gram_matrix(self): | |||||
| start_time = time.time() | |||||
| if self._parallel == 'imap_unordered': | |||||
| gram_matrix = self._compute_gm_imap_unordered() | |||||
| elif self._parallel == None: | |||||
| gram_matrix = self._compute_gm_series() | |||||
| else: | |||||
| raise Exception('Parallel mode is not set correctly.') | |||||
| self._run_time = time.time() - start_time | |||||
| if self._verbose: | |||||
| print('Gram matrix of size %d built in %s seconds.' | |||||
| % (len(self._graphs), self._run_time)) | |||||
| return gram_matrix | |||||
| def _compute_gm_series(self): | |||||
| pass | |||||
| def _compute_gm_imap_unordered(self): | |||||
| pass | |||||
| def __compute_kernel_list(self, g1, g_list): | |||||
| start_time = time.time() | |||||
| if self._parallel == 'imap_unordered': | |||||
| kernel_list = self._compute_kernel_list_imap_unordered(g1, g_list) | |||||
| elif self._parallel == None: | |||||
| kernel_list = self._compute_kernel_list_series(g1, g_list) | |||||
| else: | |||||
| raise Exception('Parallel mode is not set correctly.') | |||||
| self._run_time = time.time() - start_time | |||||
| if self._verbose: | |||||
| print('Graph kernel bewteen a graph and a list of %d graphs built in %s seconds.' | |||||
| % (len(g_list), self._run_time)) | |||||
| return kernel_list | |||||
| def _compute_kernel_list_series(self, g1, g_list): | |||||
| pass | |||||
| def _compute_kernel_list_imap_unordered(self, g1, g_list): | |||||
| pass | |||||
| def __compute_single_kernel(self, g1, g2): | |||||
| start_time = time.time() | |||||
| kernel = self._compute_single_kernel_series(g1, g2) | |||||
| self._run_time = time.time() - start_time | |||||
| if self._verbose: | |||||
| print('Graph kernel bewteen two graphs built in %s seconds.' % (self._run_time)) | |||||
| return kernel | |||||
| def _compute_single_kernel_series(self, g1, g2): | |||||
| pass | |||||
| def is_graph(self, graph): | |||||
| if isinstance(graph, nx.Graph): | |||||
| return True | |||||
| if isinstance(graph, nx.DiGraph): | |||||
| return True | |||||
| if isinstance(graph, nx.MultiGraph): | |||||
| return True | |||||
| if isinstance(graph, nx.MultiDiGraph): | |||||
| return True | |||||
| return False | |||||
| @property | |||||
| def graphs(self): | |||||
| return self._graphs | |||||
| @property | |||||
| def parallel(self): | |||||
| return self._parallel | |||||
| @property | |||||
| def n_jobs(self): | |||||
| return self._n_jobs | |||||
| @property | |||||
| def verbose(self): | |||||
| return self._verbose | |||||
| @property | |||||
| def normalize(self): | |||||
| return self._normalize | |||||
| @property | |||||
| def run_time(self): | |||||
| return self._run_time | |||||
| @property | |||||
| def gram_matrix(self): | |||||
| return self._gram_matrix | |||||
| @gram_matrix.setter | |||||
| def gram_matrix(self, value): | |||||
| self._gram_matrix = value | |||||
| @property | |||||
| def gram_matrix_unnorm(self): | |||||
| return self._gram_matrix_unnorm | |||||
| @gram_matrix_unnorm.setter | |||||
| def gram_matrix_unnorm(self, value): | |||||
| self._gram_matrix_unnorm = value | |||||