| @@ -47,7 +47,7 @@ class CommonWalk(GraphKernel): | |||
| itr = combinations_with_replacement(range(0, len(self._graphs)), 2) | |||
| len_itr = int(len(self._graphs) * (len(self._graphs) + 1) / 2) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, | |||
| length=len_itr, verbose=(self._verbose >= 2)) | |||
| length=len_itr, verbose=(self.verbose >= 2)) | |||
| # direct product graph method - exponential | |||
| if self._compute_method == 'exp': | |||
| @@ -86,7 +86,7 @@ class CommonWalk(GraphKernel): | |||
| do_fun = self._wrapper_kernel_do_geo | |||
| parallel_gm(do_fun, gram_matrix, self._graphs, init_worker=_init_worker_gm, | |||
| glbv=(self._graphs,), n_jobs=self._n_jobs, verbose=self._verbose) | |||
| glbv=(self._graphs,), n_jobs=self.n_jobs, verbose=self.verbose) | |||
| return gram_matrix | |||
| @@ -100,9 +100,9 @@ class CommonWalk(GraphKernel): | |||
| # compute kernel list. | |||
| kernel_list = [None] * len(g_list) | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', | |||
| file=sys.stdout, length=len(g_list), verbose=(self._verbose >= 2)) | |||
| file=sys.stdout, length=len(g_list), verbose=(self.verbose >= 2)) | |||
| else: | |||
| iterator = range(len(g_list)) | |||
| @@ -148,7 +148,7 @@ class CommonWalk(GraphKernel): | |||
| len_itr = len(g_list) | |||
| parallel_me(do_fun, func_assign, kernel_list, itr, len_itr=len_itr, | |||
| init_worker=_init_worker_list, glbv=(g1, g_list), method='imap_unordered', | |||
| n_jobs=self._n_jobs, itr_desc='Computing kernels', verbose=self._verbose) | |||
| n_jobs=self.n_jobs, itr_desc='Computing kernels', verbose=self.verbose) | |||
| return kernel_list | |||
| @@ -35,7 +35,7 @@ class ConjugateGradient(RandomWalkMeta): | |||
| def _compute_gm_series(self): | |||
| self._check_edge_weight(self._graphs, self._verbose) | |||
| self._check_edge_weight(self._graphs, self.verbose) | |||
| self._check_graphs(self._graphs) | |||
| lmda = self._weight | |||
| @@ -44,7 +44,7 @@ class ConjugateGradient(RandomWalkMeta): | |||
| gram_matrix = np.zeros((len(self._graphs), len(self._graphs))) | |||
| # Reindex nodes using consecutive integers for the convenience of kernel computation. | |||
| iterator = get_iters(self._graphs, desc='Reindex vertices', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(self._graphs, desc='Reindex vertices', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| self._graphs = [nx.convert_node_labels_to_integers(g, first_label=0, label_attribute='label_orignal') for g in iterator] | |||
| if self._p is None and self._q is None: # p and q are uniform distributions as default. | |||
| @@ -52,7 +52,7 @@ class ConjugateGradient(RandomWalkMeta): | |||
| from itertools import combinations_with_replacement | |||
| itr = combinations_with_replacement(range(0, len(self._graphs)), 2) | |||
| len_itr = int(len(self._graphs) * (len(self._graphs) + 1) / 2) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, length=len_itr, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, length=len_itr, verbose=(self.verbose >= 2)) | |||
| for i, j in iterator: | |||
| kernel = self._kernel_do(self._graphs[i], self._graphs[j], lmda) | |||
| @@ -66,7 +66,7 @@ class ConjugateGradient(RandomWalkMeta): | |||
| def _compute_gm_imap_unordered(self): | |||
| self._check_edge_weight(self._graphs, self._verbose) | |||
| self._check_edge_weight(self._graphs, self.verbose) | |||
| self._check_graphs(self._graphs) | |||
| # Compute Gram matrix. | |||
| @@ -74,7 +74,7 @@ class ConjugateGradient(RandomWalkMeta): | |||
| # @todo: parallel this. | |||
| # Reindex nodes using consecutive integers for the convenience of kernel computation. | |||
| iterator = get_iters(self._graphs, desc='Reindex vertices', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(self._graphs, desc='Reindex vertices', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| self._graphs = [nx.convert_node_labels_to_integers(g, first_label=0, label_attribute='label_orignal') for g in iterator] | |||
| if self._p is None and self._q is None: # p and q are uniform distributions as default. | |||
| @@ -86,7 +86,7 @@ class ConjugateGradient(RandomWalkMeta): | |||
| do_fun = self._wrapper_kernel_do | |||
| parallel_gm(do_fun, gram_matrix, self._graphs, init_worker=init_worker, | |||
| glbv=(self._graphs,), n_jobs=self._n_jobs, verbose=self._verbose) | |||
| glbv=(self._graphs,), n_jobs=self.n_jobs, verbose=self.verbose) | |||
| else: # @todo | |||
| pass | |||
| @@ -95,7 +95,7 @@ class ConjugateGradient(RandomWalkMeta): | |||
| def _compute_kernel_list_series(self, g1, g_list): | |||
| self._check_edge_weight(g_list + [g1], self._verbose) | |||
| self._check_edge_weight(g_list + [g1], self.verbose) | |||
| self._check_graphs(g_list + [g1]) | |||
| lmda = self._weight | |||
| @@ -105,11 +105,11 @@ class ConjugateGradient(RandomWalkMeta): | |||
| # Reindex nodes using consecutive integers for the convenience of kernel computation. | |||
| g1 = nx.convert_node_labels_to_integers(g1, first_label=0, label_attribute='label_orignal') | |||
| iterator = get_iters(g_list, desc='Reindex vertices', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(g_list, desc='Reindex vertices', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| g_list = [nx.convert_node_labels_to_integers(g, first_label=0, label_attribute='label_orignal') for g in iterator] | |||
| if self._p is None and self._q is None: # p and q are uniform distributions as default. | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self.verbose >= 2)) | |||
| for i in iterator: | |||
| kernel = self._kernel_do(g1, g_list[i], lmda) | |||
| @@ -122,7 +122,7 @@ class ConjugateGradient(RandomWalkMeta): | |||
| def _compute_kernel_list_imap_unordered(self, g1, g_list): | |||
| self._check_edge_weight(g_list + [g1], self._verbose) | |||
| self._check_edge_weight(g_list + [g1], self.verbose) | |||
| self._check_graphs(g_list + [g1]) | |||
| # compute kernel list. | |||
| @@ -131,7 +131,7 @@ class ConjugateGradient(RandomWalkMeta): | |||
| # Reindex nodes using consecutive integers for the convenience of kernel computation. | |||
| g1 = nx.convert_node_labels_to_integers(g1, first_label=0, label_attribute='label_orignal') | |||
| # @todo: parallel this. | |||
| iterator = get_iters(g_list, desc='Reindex vertices', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(g_list, desc='Reindex vertices', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| g_list = [nx.convert_node_labels_to_integers(g, first_label=0, label_attribute='label_orignal') for g in iterator] | |||
| if self._p is None and self._q is None: # p and q are uniform distributions as default. | |||
| @@ -149,7 +149,7 @@ class ConjugateGradient(RandomWalkMeta): | |||
| len_itr = len(g_list) | |||
| parallel_me(do_fun, func_assign, kernel_list, itr, len_itr=len_itr, | |||
| init_worker=init_worker, glbv=(g1, g_list), method='imap_unordered', | |||
| n_jobs=self._n_jobs, itr_desc='Computing kernels', verbose=self._verbose) | |||
| n_jobs=self.n_jobs, itr_desc='Computing kernels', verbose=self.verbose) | |||
| else: # @todo | |||
| pass | |||
| @@ -162,7 +162,7 @@ class ConjugateGradient(RandomWalkMeta): | |||
| def _compute_single_kernel_series(self, g1, g2): | |||
| self._check_edge_weight([g1] + [g2], self._verbose) | |||
| self._check_edge_weight([g1] + [g2], self.verbose) | |||
| self._check_graphs([g1] + [g2]) | |||
| lmda = self._weight | |||
| @@ -35,7 +35,7 @@ class FixedPoint(RandomWalkMeta): | |||
| def _compute_gm_series(self): | |||
| self._check_edge_weight(self._graphs, self._verbose) | |||
| self._check_edge_weight(self._graphs, self.verbose) | |||
| self._check_graphs(self._graphs) | |||
| lmda = self._weight | |||
| @@ -44,7 +44,7 @@ class FixedPoint(RandomWalkMeta): | |||
| gram_matrix = np.zeros((len(self._graphs), len(self._graphs))) | |||
| # Reindex nodes using consecutive integers for the convenience of kernel computation. | |||
| iterator = get_iters(self._graphs, desc='Reindex vertices', file=sys.stdout,verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(self._graphs, desc='Reindex vertices', file=sys.stdout,verbose=(self.verbose >= 2)) | |||
| self._graphs = [nx.convert_node_labels_to_integers(g, first_label=0, label_attribute='label_orignal') for g in iterator] | |||
| if self._p is None and self._q is None: # p and q are uniform distributions as default. | |||
| @@ -52,7 +52,7 @@ class FixedPoint(RandomWalkMeta): | |||
| from itertools import combinations_with_replacement | |||
| itr = combinations_with_replacement(range(0, len(self._graphs)), 2) | |||
| len_itr = int(len(self._graphs) * (len(self._graphs) + 1) / 2) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, length=len_itr, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, length=len_itr, verbose=(self.verbose >= 2)) | |||
| for i, j in iterator: | |||
| kernel = self._kernel_do(self._graphs[i], self._graphs[j], lmda) | |||
| @@ -66,7 +66,7 @@ class FixedPoint(RandomWalkMeta): | |||
| def _compute_gm_imap_unordered(self): | |||
| self._check_edge_weight(self._graphs, self._verbose) | |||
| self._check_edge_weight(self._graphs, self.verbose) | |||
| self._check_graphs(self._graphs) | |||
| # Compute Gram matrix. | |||
| @@ -74,7 +74,7 @@ class FixedPoint(RandomWalkMeta): | |||
| # @todo: parallel this. | |||
| # Reindex nodes using consecutive integers for the convenience of kernel computation. | |||
| iterator = get_iters(self._graphs, desc='Reindex vertices', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(self._graphs, desc='Reindex vertices', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| self._graphs = [nx.convert_node_labels_to_integers(g, first_label=0, label_attribute='label_orignal') for g in iterator] | |||
| if self._p is None and self._q is None: # p and q are uniform distributions as default. | |||
| @@ -86,7 +86,7 @@ class FixedPoint(RandomWalkMeta): | |||
| do_fun = self._wrapper_kernel_do | |||
| parallel_gm(do_fun, gram_matrix, self._graphs, init_worker=init_worker, | |||
| glbv=(self._graphs,), n_jobs=self._n_jobs, verbose=self._verbose) | |||
| glbv=(self._graphs,), n_jobs=self.n_jobs, verbose=self.verbose) | |||
| else: # @todo | |||
| pass | |||
| @@ -95,7 +95,7 @@ class FixedPoint(RandomWalkMeta): | |||
| def _compute_kernel_list_series(self, g1, g_list): | |||
| self._check_edge_weight(g_list + [g1], self._verbose) | |||
| self._check_edge_weight(g_list + [g1], self.verbose) | |||
| self._check_graphs(g_list + [g1]) | |||
| lmda = self._weight | |||
| @@ -105,12 +105,12 @@ class FixedPoint(RandomWalkMeta): | |||
| # Reindex nodes using consecutive integers for the convenience of kernel computation. | |||
| g1 = nx.convert_node_labels_to_integers(g1, first_label=0, label_attribute='label_orignal') | |||
| iterator = get_iters(g_list, desc='Reindex vertices', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(g_list, desc='Reindex vertices', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| g_list = [nx.convert_node_labels_to_integers(g, first_label=0, label_attribute='label_orignal') for g in iterator] | |||
| if self._p is None and self._q is None: # p and q are uniform distributions as default. | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self.verbose >= 2)) | |||
| for i in iterator: | |||
| kernel = self._kernel_do(g1, g_list[i], lmda) | |||
| @@ -123,7 +123,7 @@ class FixedPoint(RandomWalkMeta): | |||
| def _compute_kernel_list_imap_unordered(self, g1, g_list): | |||
| self._check_edge_weight(g_list + [g1], self._verbose) | |||
| self._check_edge_weight(g_list + [g1], self.verbose) | |||
| self._check_graphs(g_list + [g1]) | |||
| # compute kernel list. | |||
| @@ -132,7 +132,7 @@ class FixedPoint(RandomWalkMeta): | |||
| # Reindex nodes using consecutive integers for the convenience of kernel computation. | |||
| g1 = nx.convert_node_labels_to_integers(g1, first_label=0, label_attribute='label_orignal') | |||
| # @todo: parallel this. | |||
| iterator = get_iters(g_list, desc='Reindex vertices', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(g_list, desc='Reindex vertices', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| g_list = [nx.convert_node_labels_to_integers(g, first_label=0, label_attribute='label_orignal') for g in iterator] | |||
| if self._p is None and self._q is None: # p and q are uniform distributions as default. | |||
| @@ -150,7 +150,7 @@ class FixedPoint(RandomWalkMeta): | |||
| len_itr = len(g_list) | |||
| parallel_me(do_fun, func_assign, kernel_list, itr, len_itr=len_itr, | |||
| init_worker=init_worker, glbv=(g1, g_list), method='imap_unordered', | |||
| n_jobs=self._n_jobs, itr_desc='Computing kernels', verbose=self._verbose) | |||
| n_jobs=self.n_jobs, itr_desc='Computing kernels', verbose=self.verbose) | |||
| else: # @todo | |||
| pass | |||
| @@ -163,7 +163,7 @@ class FixedPoint(RandomWalkMeta): | |||
| def _compute_single_kernel_series(self, g1, g2): | |||
| self._check_edge_weight([g1] + [g2], self._verbose) | |||
| self._check_edge_weight([g1] + [g2], self.verbose) | |||
| self._check_graphs([g1] + [g2]) | |||
| lmda = self._weight | |||
| @@ -9,27 +9,372 @@ import numpy as np | |||
| import networkx as nx | |||
| import multiprocessing | |||
| import time | |||
| # from abc import ABC, abstractmethod | |||
| from sklearn.base import BaseEstimator # , TransformerMixin | |||
| from sklearn.utils.validation import check_is_fitted # check_X_y, check_array, | |||
| from sklearn.exceptions import NotFittedError | |||
| from gklearn.utils import normalize_gram_matrix | |||
| class GraphKernel(object): | |||
| class GraphKernel(BaseEstimator): #, ABC): | |||
| """The basic graph kernel class. | |||
| 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 | |||
| Attributes | |||
| ---------- | |||
| _graphs : list | |||
| Stores the input graphs on fit input data. | |||
| Default format of the list objects is `NetworkX` graphs. | |||
| **We don't guarantee that the input graphs remain unchanged during the | |||
| computation.** | |||
| References | |||
| ---------- | |||
| https://ysig.github.io/GraKeL/0.1a8/_modules/grakel/kernels/kernel.html#Kernel. | |||
| """ | |||
| def __init__(self, parallel=None, n_jobs=None, chunksize=None, normalize=True, verbose=2): | |||
| """`__init__` for `GraphKernel` object.""" | |||
| # @todo: the default settings of the parameters are different from those in the self.compute method. | |||
| # self._graphs = None | |||
| self.parallel = parallel | |||
| self.n_jobs = n_jobs | |||
| self.chunksize = chunksize | |||
| self.normalize = normalize | |||
| self.verbose = verbose | |||
| # self._run_time = 0 | |||
| # self._gram_matrix = None | |||
| # self._gram_matrix_unnorm = None | |||
| ########################################################################## | |||
| # The following is the 1st paradigm to compute kernel matrix, which is | |||
| # compatible with `scikit-learn`. | |||
| # ------------------------------------------------------------------- | |||
| # Special thanks to the "GraKeL" library for providing an excellent template! | |||
| ########################################################################## | |||
| def fit(self, X, y=None): | |||
| """Fit a graph dataset for a transformer. | |||
| Parameters | |||
| ---------- | |||
| X : iterable | |||
| DESCRIPTION. | |||
| y : None, optional | |||
| There is no need of a target in a transformer, yet the `scikit-learn` | |||
| pipeline API requires this parameter. | |||
| Returns | |||
| ------- | |||
| object | |||
| Returns self. | |||
| """ | |||
| # self._is_tranformed = False | |||
| # Clear any prior attributes stored on the estimator, # @todo: unless warm_start is used; | |||
| self.clear_attributes() | |||
| # X = check_array(X, accept_sparse=True) | |||
| # Validate parameters for the transformer. | |||
| self.validate_parameters() | |||
| # Validate the input. | |||
| self._graphs = self.validate_input(X) | |||
| # self._X = X | |||
| # self._kernel = self._get_kernel_instance() | |||
| # Return the transformer. | |||
| return self | |||
| def transform(self, X): | |||
| """Compute the graph kernel matrix between given and fitted data. | |||
| Parameters | |||
| ---------- | |||
| X : TYPE | |||
| DESCRIPTION. | |||
| Raises | |||
| ------ | |||
| ValueError | |||
| DESCRIPTION. | |||
| Returns | |||
| ------- | |||
| None. | |||
| """ | |||
| # Check if method "fit" had been called. | |||
| check_is_fitted(self, '_graphs') | |||
| # Validate the input. | |||
| Y = self.validate_input(X) | |||
| # Transform: compute the graph kernel matrix. | |||
| kernel_matrix = self.compute_kernel_matrix(Y) | |||
| self._Y = Y | |||
| # Self transform must appear before the diagonal call on normilization. | |||
| self._is_transformed = True | |||
| if self.normalize: | |||
| X_diag, Y_diag = self.diagonals() | |||
| kernel_matrix /= np.sqrt(np.outer(Y_diag, X_diag)) | |||
| return kernel_matrix | |||
| def fit_transform(self, X): | |||
| """Fit and transform: compute Gram matrix on the same data. | |||
| Parameters | |||
| ---------- | |||
| X : list of graphs | |||
| Input graphs. | |||
| Returns | |||
| ------- | |||
| gram_matrix : numpy array, shape = [len(X), len(X)] | |||
| The Gram matrix of X. | |||
| """ | |||
| self.fit(X) | |||
| # Transform: compute Gram matrix. | |||
| gram_matrix = self.compute_kernel_matrix() | |||
| # Normalize. | |||
| self._X_diag = np.diagonal(gram_matrix).copy() | |||
| if self.normalize: | |||
| gram_matrix /= np.sqrt(np.outer(self._X_diag, self._X_diag)) | |||
| return gram_matrix | |||
| def get_params(self): | |||
| pass | |||
| def set_params(self): | |||
| pass | |||
| def clear_attributes(self): | |||
| if hasattr(self, '_X_diag'): | |||
| delattr(self, '_X_diag') | |||
| if hasattr(self, '_graphs'): | |||
| delattr(self, '_graphs') | |||
| if hasattr(self, '_Y'): | |||
| delattr(self, '_Y') | |||
| if hasattr(self, '_run_time'): | |||
| delattr(self, '_run_time') | |||
| def validate_parameters(self): | |||
| """Validate all parameters for the transformer. | |||
| Returns | |||
| ------- | |||
| None. | |||
| """ | |||
| if self.parallel is not None and self.parallel != 'imap_unordered': | |||
| raise ValueError('Parallel mode is not set correctly.') | |||
| if self.parallel == 'imap_unordered' and self.n_jobs is None: | |||
| self.n_jobs = multiprocessing.cpu_count() | |||
| def validate_input(self, X): | |||
| """Validate the given input and raise errors if it is invalid. | |||
| Parameters | |||
| ---------- | |||
| X : list | |||
| The input to check. Should be a list of graph. | |||
| Raises | |||
| ------ | |||
| ValueError | |||
| Raise if the input is not correct. | |||
| Returns | |||
| ------- | |||
| X : list | |||
| The input. A list of graph. | |||
| """ | |||
| if X is None: | |||
| raise ValueError('Please add graphs before computing.') | |||
| elif not isinstance(X, list): | |||
| raise ValueError('Cannot detect graphs.') | |||
| elif len(X) == 0: | |||
| raise ValueError('The graph list given is empty. No computation will be performed.') | |||
| return X | |||
| def compute_kernel_matrix(self, Y=None): | |||
| """Compute the kernel matrix between a given target graphs (Y) and | |||
| the fitted graphs (X / self._graphs) or the Gram matrix for the fitted | |||
| graphs (X / self._graphs). | |||
| Parameters | |||
| ---------- | |||
| Y : list of graphs, optional | |||
| The target graphs. The default is None. If None kernel is computed | |||
| between X and itself. | |||
| Returns | |||
| ------- | |||
| kernel_matrix : numpy array, shape = [n_targets, n_inputs] | |||
| The computed kernel matrix. | |||
| """ | |||
| if Y is None: | |||
| # Compute Gram matrix for self._graphs (X). | |||
| kernel_matrix = self._compute_gram_matrix() | |||
| # self._gram_matrix_unnorm = np.copy(self._gram_matrix) | |||
| else: | |||
| # Compute kernel matrix between Y and self._graphs (X). | |||
| start_time = time.time() | |||
| if self.parallel == 'imap_unordered': | |||
| kernel_matrix = self._compute_kernel_matrix_imap_unordered(Y) | |||
| elif self.parallel is None: | |||
| kernel_matrix = self._compute_kernel_matrix_series(Y) | |||
| self._run_time = time.time() - start_time | |||
| if self.verbose: | |||
| print('Kernel matrix of size (%d, %d) built in %s seconds.' | |||
| % (len(Y), len(self._graphs), self._run_time)) | |||
| return kernel_matrix | |||
| def _compute_kernel_matrix_series(self, Y): | |||
| """Compute the kernel matrix between a given target graphs (Y) and | |||
| the fitted graphs (X / self._graphs) without parallelization. | |||
| Parameters | |||
| ---------- | |||
| Y : list of graphs, optional | |||
| The target graphs. | |||
| Returns | |||
| ------- | |||
| kernel_matrix : numpy array, shape = [n_targets, n_inputs] | |||
| The computed kernel matrix. | |||
| """ | |||
| kernel_matrix = np.zeros((len(Y), len(self._graphs))) | |||
| for i_y, g_y in enumerate(Y): | |||
| for i_x, g_x in enumerate(self._graphs): | |||
| kernel_matrix[i_y, i_x] = self.pairwise_kernel(g_y, g_x) | |||
| return kernel_matrix | |||
| def _compute_kernel_matrix_imap_unordered(self, Y): | |||
| """Compute the kernel matrix between a given target graphs (Y) and | |||
| the fitted graphs (X / self._graphs) using imap unordered parallelization. | |||
| Parameters | |||
| ---------- | |||
| Y : list of graphs, optional | |||
| The target graphs. | |||
| Returns | |||
| ------- | |||
| kernel_matrix : numpy array, shape = [n_targets, n_inputs] | |||
| The computed kernel matrix. | |||
| """ | |||
| raise Exception('Parallelization for kernel matrix is not implemented.') | |||
| def diagonals(self): | |||
| """Compute the kernel matrix diagonals of the fit/transformed data. | |||
| Returns | |||
| ------- | |||
| X_diag : numpy array | |||
| The diagonal of the kernel matrix between the fitted data. | |||
| This consists of each element calculated with itself. | |||
| Y_diag : numpy array | |||
| The diagonal of the kernel matrix, of the transform. | |||
| This consists of each element calculated with itself. | |||
| """ | |||
| # Check if method "fit" had been called. | |||
| check_is_fitted(self, ['_graphs']) | |||
| # Check if the diagonals of X exist. | |||
| try: | |||
| check_is_fitted(self, ['_X_diag']) | |||
| except NotFittedError: | |||
| # Compute diagonals of X. | |||
| self._X_diag = np.empty(shape=(len(self._graphs),)) | |||
| for i, x in enumerate(self._graphs): | |||
| self._X_diag[i] = self.pairwise_kernel(x, x) # @todo: parallel? | |||
| try: | |||
| # If transform has happened, return both diagonals. | |||
| check_is_fitted(self, ['_Y']) | |||
| self._Y_diag = np.empty(shape=(len(self._Y),)) | |||
| for (i, y) in enumerate(self._Y): | |||
| self._Y_diag[i] = self.pairwise_kernel(y, y) # @todo: parallel? | |||
| return self._X_diag, self._Y_diag | |||
| except NotFittedError: | |||
| # Else just return both X_diag | |||
| return self._X_diag | |||
| # @abstractmethod | |||
| def pairwise_kernel(self, x, y): | |||
| """Compute pairwise kernel between two graphs. | |||
| Parameters | |||
| ---------- | |||
| x, y : NetworkX Graph. | |||
| Graphs bewteen which the kernel is computed. | |||
| Returns | |||
| ------- | |||
| kernel: float | |||
| The computed kernel. | |||
| # Notes | |||
| # ----- | |||
| # This method is abstract and must be implemented by a subclass. | |||
| """ | |||
| raise NotImplementedError('Pairwise kernel computation is not implemented!') | |||
| ########################################################################## | |||
| # The following is the 2nd paradigm to compute kernel matrix. It is | |||
| # simplified and not compatible with `scikit-learn`. | |||
| ########################################################################## | |||
| 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) | |||
| 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) | |||
| self.validate_parameters() | |||
| if len(graphs) == 1: | |||
| if not isinstance(graphs[0], list): | |||
| @@ -40,7 +385,7 @@ class GraphKernel(object): | |||
| self._graphs = [g.copy() for g in graphs[0]] # @todo: might be very slow. | |||
| self._gram_matrix = self._compute_gram_matrix() | |||
| self._gram_matrix_unnorm = np.copy(self._gram_matrix) | |||
| if self._normalize: | |||
| if self.normalize: | |||
| self._gram_matrix = normalize_gram_matrix(self._gram_matrix) | |||
| return self._gram_matrix, self._run_time | |||
| @@ -103,15 +448,15 @@ class GraphKernel(object): | |||
| def _compute_gram_matrix(self): | |||
| start_time = time.time() | |||
| if self._parallel == 'imap_unordered': | |||
| if self.parallel == 'imap_unordered': | |||
| gram_matrix = self._compute_gm_imap_unordered() | |||
| elif self._parallel is None: | |||
| elif self.parallel is 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: | |||
| if self.verbose: | |||
| print('Gram matrix of size %d built in %s seconds.' | |||
| % (len(self._graphs), self._run_time)) | |||
| @@ -129,15 +474,15 @@ class GraphKernel(object): | |||
| def _compute_kernel_list(self, g1, g_list): | |||
| start_time = time.time() | |||
| if self._parallel == 'imap_unordered': | |||
| if self.parallel == 'imap_unordered': | |||
| kernel_list = self._compute_kernel_list_imap_unordered(g1, g_list) | |||
| elif self._parallel is None: | |||
| elif self.parallel is 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: | |||
| 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)) | |||
| @@ -158,7 +503,7 @@ class GraphKernel(object): | |||
| kernel = self._compute_single_kernel_series(g1, g2) | |||
| self._run_time = time.time() - start_time | |||
| if self._verbose: | |||
| if self.verbose: | |||
| print('Graph kernel bewteen two graphs built in %s seconds.' % (self._run_time)) | |||
| return kernel | |||
| @@ -185,24 +530,24 @@ class GraphKernel(object): | |||
| return self._graphs | |||
| @property | |||
| def parallel(self): | |||
| return self._parallel | |||
| # @property | |||
| # def parallel(self): | |||
| # return self.parallel | |||
| @property | |||
| def n_jobs(self): | |||
| return self._n_jobs | |||
| # @property | |||
| # def n_jobs(self): | |||
| # return self.n_jobs | |||
| @property | |||
| def verbose(self): | |||
| return self._verbose | |||
| # @property | |||
| # def verbose(self): | |||
| # return self.verbose | |||
| @property | |||
| def normalize(self): | |||
| return self._normalize | |||
| # @property | |||
| # def normalize(self): | |||
| # return self.normalize | |||
| @property | |||
| @@ -46,7 +46,7 @@ class Marginalized(GraphKernel): | |||
| self._add_dummy_labels(self._graphs) | |||
| if self._remove_totters: | |||
| iterator = get_iters(self._graphs, desc='removing tottering', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(self._graphs, desc='removing tottering', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| # @todo: this may not work. | |||
| self._graphs = [untotterTransformation(G, self._node_labels, self._edge_labels) for G in iterator] | |||
| @@ -57,7 +57,7 @@ class Marginalized(GraphKernel): | |||
| itr = combinations_with_replacement(range(0, len(self._graphs)), 2) | |||
| len_itr = int(len(self._graphs) * (len(self._graphs) + 1) / 2) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, | |||
| length=len_itr, verbose=(self._verbose >= 2)) | |||
| length=len_itr, verbose=(self.verbose >= 2)) | |||
| for i, j in iterator: | |||
| kernel = self._kernel_do(self._graphs[i], self._graphs[j]) | |||
| gram_matrix[i][j] = kernel | |||
| @@ -70,16 +70,16 @@ class Marginalized(GraphKernel): | |||
| self._add_dummy_labels(self._graphs) | |||
| if self._remove_totters: | |||
| pool = Pool(self._n_jobs) | |||
| pool = Pool(self.n_jobs) | |||
| itr = range(0, len(self._graphs)) | |||
| if len(self._graphs) < 100 * self._n_jobs: | |||
| chunksize = int(len(self._graphs) / self._n_jobs) + 1 | |||
| if len(self._graphs) < 100 * self.n_jobs: | |||
| chunksize = int(len(self._graphs) / self.n_jobs) + 1 | |||
| else: | |||
| chunksize = 100 | |||
| remove_fun = self._wrapper_untotter | |||
| iterator = get_iters(pool.imap_unordered(remove_fun, itr, chunksize), | |||
| desc='removing tottering', file=sys.stdout, | |||
| length=len(self._graphs), verbose=(self._verbose >= 2)) | |||
| length=len(self._graphs), verbose=(self.verbose >= 2)) | |||
| for i, g in iterator: | |||
| self._graphs[i] = g | |||
| pool.close() | |||
| @@ -93,7 +93,7 @@ class Marginalized(GraphKernel): | |||
| G_gn = gn_toshare | |||
| do_fun = self._wrapper_kernel_do | |||
| parallel_gm(do_fun, gram_matrix, self._graphs, init_worker=init_worker, | |||
| glbv=(self._graphs,), n_jobs=self._n_jobs, verbose=self._verbose) | |||
| glbv=(self._graphs,), n_jobs=self.n_jobs, verbose=self.verbose) | |||
| return gram_matrix | |||
| @@ -103,13 +103,13 @@ class Marginalized(GraphKernel): | |||
| if self._remove_totters: | |||
| g1 = untotterTransformation(g1, self._node_labels, self._edge_labels) # @todo: this may not work. | |||
| iterator = get_iters(g_list, desc='removing tottering', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(g_list, desc='removing tottering', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| # @todo: this may not work. | |||
| g_list = [untotterTransformation(G, self._node_labels, self._edge_labels) for G in iterator] | |||
| # compute kernel list. | |||
| kernel_list = [None] * len(g_list) | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self.verbose >= 2)) | |||
| for i in iterator: | |||
| kernel = self._kernel_do(g1, g_list[i]) | |||
| kernel_list[i] = kernel | |||
| @@ -122,16 +122,16 @@ class Marginalized(GraphKernel): | |||
| if self._remove_totters: | |||
| g1 = untotterTransformation(g1, self._node_labels, self._edge_labels) # @todo: this may not work. | |||
| pool = Pool(self._n_jobs) | |||
| pool = Pool(self.n_jobs) | |||
| itr = range(0, len(g_list)) | |||
| if len(g_list) < 100 * self._n_jobs: | |||
| chunksize = int(len(g_list) / self._n_jobs) + 1 | |||
| if len(g_list) < 100 * self.n_jobs: | |||
| chunksize = int(len(g_list) / self.n_jobs) + 1 | |||
| else: | |||
| chunksize = 100 | |||
| remove_fun = self._wrapper_untotter | |||
| iterator = get_iters(pool.imap_unordered(remove_fun, itr, chunksize), | |||
| desc='removing tottering', file=sys.stdout, | |||
| length=len(g_list), verbose=(self._verbose >= 2)) | |||
| length=len(g_list), verbose=(self.verbose >= 2)) | |||
| for i, g in iterator: | |||
| g_list[i] = g | |||
| pool.close() | |||
| @@ -151,7 +151,7 @@ class Marginalized(GraphKernel): | |||
| len_itr = len(g_list) | |||
| parallel_me(do_fun, func_assign, kernel_list, itr, len_itr=len_itr, | |||
| init_worker=init_worker, glbv=(g1, g_list), method='imap_unordered', | |||
| n_jobs=self._n_jobs, itr_desc='Computing kernels', verbose=self._verbose) | |||
| n_jobs=self.n_jobs, itr_desc='Computing kernels', verbose=self.verbose) | |||
| return kernel_list | |||
| @@ -41,10 +41,10 @@ class PathUpToH(GraphKernel): # @todo: add function for k_func is None | |||
| from itertools import combinations_with_replacement | |||
| itr_kernel = combinations_with_replacement(range(0, len(self._graphs)), 2) | |||
| iterator_ps = get_iters(range(0, len(self._graphs)), desc='getting paths', file=sys.stdout, length=len(self._graphs), verbose=(self._verbose >= 2)) | |||
| iterator_ps = get_iters(range(0, len(self._graphs)), desc='getting paths', file=sys.stdout, length=len(self._graphs), verbose=(self.verbose >= 2)) | |||
| len_itr = int(len(self._graphs) * (len(self._graphs) + 1) / 2) | |||
| iterator_kernel = get_iters(itr_kernel, desc='Computing kernels', | |||
| file=sys.stdout, length=len_itr, verbose=(self._verbose >= 2)) | |||
| file=sys.stdout, length=len_itr, verbose=(self.verbose >= 2)) | |||
| gram_matrix = np.zeros((len(self._graphs), len(self._graphs))) | |||
| @@ -69,10 +69,10 @@ class PathUpToH(GraphKernel): # @todo: add function for k_func is None | |||
| # get all paths of all graphs before computing kernels to save time, | |||
| # but this may cost a lot of memory for large datasets. | |||
| pool = Pool(self._n_jobs) | |||
| pool = Pool(self.n_jobs) | |||
| itr = zip(self._graphs, range(0, len(self._graphs))) | |||
| if len(self._graphs) < 100 * self._n_jobs: | |||
| chunksize = int(len(self._graphs) / self._n_jobs) + 1 | |||
| if len(self._graphs) < 100 * self.n_jobs: | |||
| chunksize = int(len(self._graphs) / self.n_jobs) + 1 | |||
| else: | |||
| chunksize = 100 | |||
| all_paths = [[] for _ in range(len(self._graphs))] | |||
| @@ -84,7 +84,7 @@ class PathUpToH(GraphKernel): # @todo: add function for k_func is None | |||
| get_ps_fun = partial(self._wrapper_find_all_paths_until_length, False) | |||
| iterator = get_iters(pool.imap_unordered(get_ps_fun, itr, chunksize), | |||
| desc='getting paths', file=sys.stdout, | |||
| length=len(self._graphs), verbose=(self._verbose >= 2)) | |||
| length=len(self._graphs), verbose=(self.verbose >= 2)) | |||
| for i, ps in iterator: | |||
| all_paths[i] = ps | |||
| pool.close() | |||
| @@ -109,7 +109,7 @@ class PathUpToH(GraphKernel): # @todo: add function for k_func is None | |||
| G_plist = plist_toshare | |||
| do_fun = self._wrapper_kernel_do_kernelless # @todo: what is this? | |||
| parallel_gm(do_fun, gram_matrix, self._graphs, init_worker=init_worker, | |||
| glbv=(all_paths,), n_jobs=self._n_jobs, verbose=self._verbose) | |||
| glbv=(all_paths,), n_jobs=self.n_jobs, verbose=self.verbose) | |||
| return gram_matrix | |||
| @@ -117,8 +117,8 @@ class PathUpToH(GraphKernel): # @todo: add function for k_func is None | |||
| def _compute_kernel_list_series(self, g1, g_list): | |||
| self._add_dummy_labels(g_list + [g1]) | |||
| iterator_ps = get_iters(g_list, desc='getting paths', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator_kernel = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self._verbose >= 2)) | |||
| iterator_ps = get_iters(g_list, desc='getting paths', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| iterator_kernel = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self.verbose >= 2)) | |||
| kernel_list = [None] * len(g_list) | |||
| @@ -143,10 +143,10 @@ class PathUpToH(GraphKernel): # @todo: add function for k_func is None | |||
| # get all paths of all graphs before computing kernels to save time, | |||
| # but this may cost a lot of memory for large datasets. | |||
| pool = Pool(self._n_jobs) | |||
| pool = Pool(self.n_jobs) | |||
| itr = zip(g_list, range(0, len(g_list))) | |||
| if len(g_list) < 100 * self._n_jobs: | |||
| chunksize = int(len(g_list) / self._n_jobs) + 1 | |||
| if len(g_list) < 100 * self.n_jobs: | |||
| chunksize = int(len(g_list) / self.n_jobs) + 1 | |||
| else: | |||
| chunksize = 100 | |||
| paths_g_list = [[] for _ in range(len(g_list))] | |||
| @@ -161,7 +161,7 @@ class PathUpToH(GraphKernel): # @todo: add function for k_func is None | |||
| get_ps_fun = partial(self._wrapper_find_all_paths_until_length, False) | |||
| iterator = get_iters(pool.imap_unordered(get_ps_fun, itr, chunksize), | |||
| desc='getting paths', file=sys.stdout, | |||
| length=len(g_list), verbose=(self._verbose >= 2)) | |||
| length=len(g_list), verbose=(self.verbose >= 2)) | |||
| for i, ps in iterator: | |||
| paths_g_list[i] = ps | |||
| pool.close() | |||
| @@ -180,7 +180,7 @@ class PathUpToH(GraphKernel): # @todo: add function for k_func is None | |||
| itr = range(len(g_list)) | |||
| len_itr = len(g_list) | |||
| parallel_me(do_fun, func_assign, kernel_list, itr, len_itr=len_itr, | |||
| init_worker=init_worker, glbv=(paths_g1, paths_g_list), method='imap_unordered', n_jobs=self._n_jobs, itr_desc='Computing kernels', verbose=self._verbose) | |||
| init_worker=init_worker, glbv=(paths_g1, paths_g_list), method='imap_unordered', n_jobs=self.n_jobs, itr_desc='Computing kernels', verbose=self.verbose) | |||
| return kernel_list | |||
| @@ -38,7 +38,7 @@ class ShortestPath(GraphKernel): | |||
| def _compute_gm_series(self): | |||
| self._all_graphs_have_edges(self._graphs) | |||
| # get shortest path graph of each graph. | |||
| iterator = get_iters(self._graphs, desc='getting sp graphs', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(self._graphs, desc='getting sp graphs', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| self._graphs = [getSPGraph(g, edge_weight=self._edge_weight) for g in iterator] | |||
| # compute Gram matrix. | |||
| @@ -48,7 +48,7 @@ class ShortestPath(GraphKernel): | |||
| itr = combinations_with_replacement(range(0, len(self._graphs)), 2) | |||
| len_itr = int(len(self._graphs) * (len(self._graphs) + 1) / 2) | |||
| iterator = get_iters(itr, desc='Computing kernels', | |||
| length=len_itr, file=sys.stdout,verbose=(self._verbose >= 2)) | |||
| length=len_itr, file=sys.stdout,verbose=(self.verbose >= 2)) | |||
| for i, j in iterator: | |||
| kernel = self._sp_do(self._graphs[i], self._graphs[j]) | |||
| gram_matrix[i][j] = kernel | |||
| @@ -60,16 +60,16 @@ class ShortestPath(GraphKernel): | |||
| def _compute_gm_imap_unordered(self): | |||
| self._all_graphs_have_edges(self._graphs) | |||
| # get shortest path graph of each graph. | |||
| pool = Pool(self._n_jobs) | |||
| pool = Pool(self.n_jobs) | |||
| get_sp_graphs_fun = self._wrapper_get_sp_graphs | |||
| itr = zip(self._graphs, range(0, len(self._graphs))) | |||
| if len(self._graphs) < 100 * self._n_jobs: | |||
| chunksize = int(len(self._graphs) / self._n_jobs) + 1 | |||
| if len(self._graphs) < 100 * self.n_jobs: | |||
| chunksize = int(len(self._graphs) / self.n_jobs) + 1 | |||
| else: | |||
| chunksize = 100 | |||
| iterator = get_iters(pool.imap_unordered(get_sp_graphs_fun, itr, chunksize), | |||
| desc='getting sp graphs', file=sys.stdout, | |||
| length=len(self._graphs), verbose=(self._verbose >= 2)) | |||
| length=len(self._graphs), verbose=(self.verbose >= 2)) | |||
| for i, g in iterator: | |||
| self._graphs[i] = g | |||
| pool.close() | |||
| @@ -83,7 +83,7 @@ class ShortestPath(GraphKernel): | |||
| G_gs = gs_toshare | |||
| do_fun = self._wrapper_sp_do | |||
| parallel_gm(do_fun, gram_matrix, self._graphs, init_worker=init_worker, | |||
| glbv=(self._graphs,), n_jobs=self._n_jobs, verbose=self._verbose) | |||
| glbv=(self._graphs,), n_jobs=self.n_jobs, verbose=self.verbose) | |||
| return gram_matrix | |||
| @@ -92,12 +92,12 @@ class ShortestPath(GraphKernel): | |||
| self._all_graphs_have_edges([g1] + g_list) | |||
| # get shortest path graphs of g1 and each graph in g_list. | |||
| g1 = getSPGraph(g1, edge_weight=self._edge_weight) | |||
| iterator = get_iters(g_list, desc='getting sp graphs', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(g_list, desc='getting sp graphs', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| g_list = [getSPGraph(g, edge_weight=self._edge_weight) for g in iterator] | |||
| # compute kernel list. | |||
| kernel_list = [None] * len(g_list) | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self.verbose >= 2)) | |||
| for i in iterator: | |||
| kernel = self._sp_do(g1, g_list[i]) | |||
| kernel_list[i] = kernel | |||
| @@ -109,16 +109,16 @@ class ShortestPath(GraphKernel): | |||
| self._all_graphs_have_edges([g1] + g_list) | |||
| # get shortest path graphs of g1 and each graph in g_list. | |||
| g1 = getSPGraph(g1, edge_weight=self._edge_weight) | |||
| pool = Pool(self._n_jobs) | |||
| pool = Pool(self.n_jobs) | |||
| get_sp_graphs_fun = self._wrapper_get_sp_graphs | |||
| itr = zip(g_list, range(0, len(g_list))) | |||
| if len(g_list) < 100 * self._n_jobs: | |||
| chunksize = int(len(g_list) / self._n_jobs) + 1 | |||
| if len(g_list) < 100 * self.n_jobs: | |||
| chunksize = int(len(g_list) / self.n_jobs) + 1 | |||
| else: | |||
| chunksize = 100 | |||
| iterator = get_iters(pool.imap_unordered(get_sp_graphs_fun, itr, chunksize), | |||
| desc='getting sp graphs', file=sys.stdout, | |||
| length=len(g_list), verbose=(self._verbose >= 2)) | |||
| length=len(g_list), verbose=(self.verbose >= 2)) | |||
| for i, g in iterator: | |||
| g_list[i] = g | |||
| pool.close() | |||
| @@ -137,7 +137,7 @@ class ShortestPath(GraphKernel): | |||
| itr = range(len(g_list)) | |||
| len_itr = len(g_list) | |||
| parallel_me(do_fun, func_assign, kernel_list, itr, len_itr=len_itr, | |||
| init_worker=init_worker, glbv=(g1, g_list), method='imap_unordered', n_jobs=self._n_jobs, itr_desc='Computing kernels', verbose=self._verbose) | |||
| init_worker=init_worker, glbv=(g1, g_list), method='imap_unordered', n_jobs=self.n_jobs, itr_desc='Computing kernels', verbose=self.verbose) | |||
| return kernel_list | |||
| @@ -28,9 +28,9 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| def _compute_gm_series(self): | |||
| self._check_edge_weight(self._graphs, self._verbose) | |||
| self._check_edge_weight(self._graphs, self.verbose) | |||
| self._check_graphs(self._graphs) | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| import warnings | |||
| warnings.warn('All labels are ignored. Only works for undirected graphs.') | |||
| @@ -41,7 +41,7 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| # precompute the spectral decomposition of each graph. | |||
| P_list = [] | |||
| D_list = [] | |||
| iterator = get_iters(self._graphs, desc='spectral decompose', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(self._graphs, desc='spectral decompose', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| for G in iterator: | |||
| # don't normalize adjacency matrices if q is a uniform vector. Note | |||
| # A actually is the transpose of the adjacency matrix. | |||
| @@ -58,7 +58,7 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| from itertools import combinations_with_replacement | |||
| itr = combinations_with_replacement(range(0, len(self._graphs)), 2) | |||
| len_itr = int(len(self._graphs) * (len(self._graphs) + 1) / 2) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, length=len_itr, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, length=len_itr, verbose=(self.verbose >= 2)) | |||
| for i, j in iterator: | |||
| kernel = self._kernel_do(q_T_list[i], q_T_list[j], P_list[i], P_list[j], D_list[i], D_list[j], self._weight, self._sub_kernel) | |||
| @@ -74,9 +74,9 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| def _compute_gm_imap_unordered(self): | |||
| self._check_edge_weight(self._graphs, self._verbose) | |||
| self._check_edge_weight(self._graphs, self.verbose) | |||
| self._check_graphs(self._graphs) | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| import warnings | |||
| warnings.warn('All labels are ignored. Only works for undirected graphs.') | |||
| @@ -87,7 +87,7 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| # precompute the spectral decomposition of each graph. | |||
| P_list = [] | |||
| D_list = [] | |||
| iterator = get_iters(self._graphs, desc='spectral decompose', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(self._graphs, desc='spectral decompose', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| for G in iterator: | |||
| # don't normalize adjacency matrices if q is a uniform vector. Note | |||
| # A actually is the transpose of the adjacency matrix. | |||
| @@ -107,7 +107,7 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| do_fun = self._wrapper_kernel_do | |||
| parallel_gm(do_fun, gram_matrix, self._graphs, init_worker=init_worker, | |||
| glbv=(q_T_list, P_list, D_list), n_jobs=self._n_jobs, verbose=self._verbose) | |||
| glbv=(q_T_list, P_list, D_list), n_jobs=self.n_jobs, verbose=self.verbose) | |||
| else: # @todo | |||
| pass | |||
| @@ -118,9 +118,9 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| def _compute_kernel_list_series(self, g1, g_list): | |||
| self._check_edge_weight(g_list + [g1], self._verbose) | |||
| self._check_edge_weight(g_list + [g1], self.verbose) | |||
| self._check_graphs(g_list + [g1]) | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| import warnings | |||
| warnings.warn('All labels are ignored. Only works for undirected graphs.') | |||
| @@ -133,7 +133,7 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| D1, P1 = np.linalg.eig(A1) | |||
| P_list = [] | |||
| D_list = [] | |||
| iterator = get_iters(g_list, desc='spectral decompose', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(g_list, desc='spectral decompose', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| for G in iterator: | |||
| # don't normalize adjacency matrices if q is a uniform vector. Note | |||
| # A actually is the transpose of the adjacency matrix. | |||
| @@ -145,7 +145,7 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| if self._p is None: # p is uniform distribution as default. | |||
| q_T1 = 1 / nx.number_of_nodes(g1) | |||
| q_T_list = [np.full((1, nx.number_of_nodes(G)), 1 / nx.number_of_nodes(G)) for G in g_list] | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self.verbose >= 2)) | |||
| for i in iterator: | |||
| kernel = self._kernel_do(q_T1, q_T_list[i], P1, P_list[i], D1, D_list[i], self._weight, self._sub_kernel) | |||
| @@ -160,9 +160,9 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| def _compute_kernel_list_imap_unordered(self, g1, g_list): | |||
| self._check_edge_weight(g_list + [g1], self._verbose) | |||
| self._check_edge_weight(g_list + [g1], self.verbose) | |||
| self._check_graphs(g_list + [g1]) | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| import warnings | |||
| warnings.warn('All labels are ignored. Only works for undirected graphs.') | |||
| @@ -175,8 +175,8 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| D1, P1 = np.linalg.eig(A1) | |||
| P_list = [] | |||
| D_list = [] | |||
| if self._verbose >= 2: | |||
| iterator = tqdm(g_list, desc='spectral decompose', file=sys.stdout) | |||
| if self.verbose >= 2: | |||
| iterator = get_iters(g_list, desc='spectral decompose', file=sys.stdout) | |||
| else: | |||
| iterator = g_list | |||
| for G in iterator: | |||
| @@ -207,7 +207,7 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| itr = range(len(g_list)) | |||
| len_itr = len(g_list) | |||
| parallel_me(do_fun, func_assign, kernel_list, itr, len_itr=len_itr, | |||
| init_worker=init_worker, glbv=(q_T1, P1, D1, q_T_list, P_list, D_list), method='imap_unordered', n_jobs=self._n_jobs, itr_desc='Computing kernels', verbose=self._verbose) | |||
| init_worker=init_worker, glbv=(q_T1, P1, D1, q_T_list, P_list, D_list), method='imap_unordered', n_jobs=self.n_jobs, itr_desc='Computing kernels', verbose=self.verbose) | |||
| else: # @todo | |||
| pass | |||
| @@ -222,9 +222,9 @@ class SpectralDecomposition(RandomWalkMeta): | |||
| def _compute_single_kernel_series(self, g1, g2): | |||
| self._check_edge_weight([g1] + [g2], self._verbose) | |||
| self._check_edge_weight([g1] + [g2], self.verbose) | |||
| self._check_graphs([g1] + [g2]) | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| import warnings | |||
| warnings.warn('All labels are ignored. Only works for undirected graphs.') | |||
| @@ -41,7 +41,7 @@ class StructuralSP(GraphKernel): | |||
| def _compute_gm_series(self): | |||
| # get shortest paths of each graph in the graphs. | |||
| splist = [] | |||
| iterator = get_iters(self._graphs, desc='getting sp graphs', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(self._graphs, desc='getting sp graphs', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| if self._compute_method == 'trie': | |||
| for g in iterator: | |||
| splist.append(self._get_sps_as_trie(g)) | |||
| @@ -56,7 +56,7 @@ class StructuralSP(GraphKernel): | |||
| itr = combinations_with_replacement(range(0, len(self._graphs)), 2) | |||
| len_itr = int(len(self._graphs) * (len(self._graphs) + 1) / 2) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, | |||
| length=len_itr, verbose=(self._verbose >= 2)) | |||
| length=len_itr, verbose=(self.verbose >= 2)) | |||
| if self._compute_method == 'trie': | |||
| for i, j in iterator: | |||
| kernel = self._ssp_do_trie(self._graphs[i], self._graphs[j], splist[i], splist[j]) | |||
| @@ -76,10 +76,10 @@ class StructuralSP(GraphKernel): | |||
| def _compute_gm_imap_unordered(self): | |||
| # get shortest paths of each graph in the graphs. | |||
| splist = [None] * len(self._graphs) | |||
| pool = Pool(self._n_jobs) | |||
| pool = Pool(self.n_jobs) | |||
| itr = zip(self._graphs, range(0, len(self._graphs))) | |||
| if len(self._graphs) < 100 * self._n_jobs: | |||
| chunksize = int(len(self._graphs) / self._n_jobs) + 1 | |||
| if len(self._graphs) < 100 * self.n_jobs: | |||
| chunksize = int(len(self._graphs) / self.n_jobs) + 1 | |||
| else: | |||
| chunksize = 100 | |||
| # get shortest path graphs of self._graphs | |||
| @@ -89,7 +89,7 @@ class StructuralSP(GraphKernel): | |||
| get_sps_fun = self._wrapper_get_sps_naive | |||
| iterator = get_iters(pool.imap_unordered(get_sps_fun, itr, chunksize), | |||
| desc='getting shortest paths', file=sys.stdout, | |||
| length=len(self._graphs), verbose=(self._verbose >= 2)) | |||
| length=len(self._graphs), verbose=(self.verbose >= 2)) | |||
| for i, sp in iterator: | |||
| splist[i] = sp | |||
| pool.close() | |||
| @@ -107,7 +107,7 @@ class StructuralSP(GraphKernel): | |||
| else: | |||
| do_fun = self._wrapper_ssp_do_naive | |||
| parallel_gm(do_fun, gram_matrix, self._graphs, init_worker=init_worker, | |||
| glbv=(splist, self._graphs), n_jobs=self._n_jobs, verbose=self._verbose) | |||
| glbv=(splist, self._graphs), n_jobs=self.n_jobs, verbose=self.verbose) | |||
| return gram_matrix | |||
| @@ -117,7 +117,7 @@ class StructuralSP(GraphKernel): | |||
| sp1 = get_shortest_paths(g1, self._edge_weight, self._ds_infos['directed']) | |||
| splist = [] | |||
| iterator = get_iters(g_list, desc='getting sp graphs', file=sys.stdout, | |||
| verbose=(self._verbose >= 2)) | |||
| verbose=(self.verbose >= 2)) | |||
| if self._compute_method == 'trie': | |||
| for g in iterator: | |||
| splist.append(self._get_sps_as_trie(g)) | |||
| @@ -128,7 +128,7 @@ class StructuralSP(GraphKernel): | |||
| # compute kernel list. | |||
| kernel_list = [None] * len(g_list) | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', | |||
| file=sys.stdout, length=len(g_list), verbose=(self._verbose >= 2)) | |||
| file=sys.stdout, length=len(g_list), verbose=(self.verbose >= 2)) | |||
| if self._compute_method == 'trie': | |||
| for i in iterator: | |||
| kernel = self._ssp_do_trie(g1, g_list[i], sp1, splist[i]) | |||
| @@ -145,10 +145,10 @@ class StructuralSP(GraphKernel): | |||
| # get shortest paths of g1 and each graph in g_list. | |||
| sp1 = get_shortest_paths(g1, self._edge_weight, self._ds_infos['directed']) | |||
| splist = [None] * len(g_list) | |||
| pool = Pool(self._n_jobs) | |||
| pool = Pool(self.n_jobs) | |||
| itr = zip(g_list, range(0, len(g_list))) | |||
| if len(g_list) < 100 * self._n_jobs: | |||
| chunksize = int(len(g_list) / self._n_jobs) + 1 | |||
| if len(g_list) < 100 * self.n_jobs: | |||
| chunksize = int(len(g_list) / self.n_jobs) + 1 | |||
| else: | |||
| chunksize = 100 | |||
| # get shortest path graphs of g_list | |||
| @@ -158,7 +158,7 @@ class StructuralSP(GraphKernel): | |||
| get_sps_fun = self._wrapper_get_sps_naive | |||
| iterator = get_iters(pool.imap_unordered(get_sps_fun, itr, chunksize), | |||
| desc='getting shortest paths', file=sys.stdout, | |||
| length=len(g_list), verbose=(self._verbose >= 2)) | |||
| length=len(g_list), verbose=(self.verbose >= 2)) | |||
| for i, sp in iterator: | |||
| splist[i] = sp | |||
| pool.close() | |||
| @@ -182,7 +182,7 @@ class StructuralSP(GraphKernel): | |||
| itr = range(len(g_list)) | |||
| len_itr = len(g_list) | |||
| parallel_me(do_fun, func_assign, kernel_list, itr, len_itr=len_itr, | |||
| init_worker=init_worker, glbv=(sp1, splist, g1, g_list), method='imap_unordered', n_jobs=self._n_jobs, itr_desc='Computing kernels', verbose=self._verbose) | |||
| init_worker=init_worker, glbv=(sp1, splist, g1, g_list), method='imap_unordered', n_jobs=self.n_jobs, itr_desc='Computing kernels', verbose=self.verbose) | |||
| return kernel_list | |||
| @@ -27,9 +27,9 @@ class SylvesterEquation(RandomWalkMeta): | |||
| def _compute_gm_series(self): | |||
| self._check_edge_weight(self._graphs, self._verbose) | |||
| self._check_edge_weight(self._graphs, self.verbose) | |||
| self._check_graphs(self._graphs) | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| import warnings | |||
| warnings.warn('All labels are ignored.') | |||
| @@ -41,7 +41,7 @@ class SylvesterEquation(RandomWalkMeta): | |||
| if self._q is None: | |||
| # don't normalize adjacency matrices if q is a uniform vector. Note | |||
| # A_wave_list actually contains the transposes of the adjacency matrices. | |||
| iterator = get_iters(self._graphs, desc='compute adjacency matrices', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(self._graphs, desc='compute adjacency matrices', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| A_wave_list = [nx.adjacency_matrix(G, self._edge_weight).todense().transpose() for G in iterator] | |||
| # # normalized adjacency matrices | |||
| # A_wave_list = [] | |||
| @@ -55,7 +55,7 @@ class SylvesterEquation(RandomWalkMeta): | |||
| from itertools import combinations_with_replacement | |||
| itr = combinations_with_replacement(range(0, len(self._graphs)), 2) | |||
| len_itr = int(len(self._graphs) * (len(self._graphs) + 1) / 2) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, length=len_itr, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, length=len_itr, verbose=(self.verbose >= 2)) | |||
| for i, j in iterator: | |||
| kernel = self._kernel_do(A_wave_list[i], A_wave_list[j], lmda) | |||
| @@ -71,9 +71,9 @@ class SylvesterEquation(RandomWalkMeta): | |||
| def _compute_gm_imap_unordered(self): | |||
| self._check_edge_weight(self._graphs, self._verbose) | |||
| self._check_edge_weight(self._graphs, self.verbose) | |||
| self._check_graphs(self._graphs) | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| import warnings | |||
| warnings.warn('All labels are ignored.') | |||
| @@ -83,7 +83,7 @@ class SylvesterEquation(RandomWalkMeta): | |||
| if self._q is None: | |||
| # don't normalize adjacency matrices if q is a uniform vector. Note | |||
| # A_wave_list actually contains the transposes of the adjacency matrices. | |||
| iterator = get_iters(self._graphs, desc='compute adjacency matrices', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(self._graphs, desc='compute adjacency matrices', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| A_wave_list = [nx.adjacency_matrix(G, self._edge_weight).todense().transpose() for G in iterator] # @todo: parallel? | |||
| if self._p is None: # p is uniform distribution as default. | |||
| @@ -94,7 +94,7 @@ class SylvesterEquation(RandomWalkMeta): | |||
| do_fun = self._wrapper_kernel_do | |||
| parallel_gm(do_fun, gram_matrix, self._graphs, init_worker=init_worker, | |||
| glbv=(A_wave_list,), n_jobs=self._n_jobs, verbose=self._verbose) | |||
| glbv=(A_wave_list,), n_jobs=self.n_jobs, verbose=self.verbose) | |||
| else: # @todo | |||
| pass | |||
| @@ -105,9 +105,9 @@ class SylvesterEquation(RandomWalkMeta): | |||
| def _compute_kernel_list_series(self, g1, g_list): | |||
| self._check_edge_weight(g_list + [g1], self._verbose) | |||
| self._check_edge_weight(g_list + [g1], self.verbose) | |||
| self._check_graphs(g_list + [g1]) | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| import warnings | |||
| warnings.warn('All labels are ignored.') | |||
| @@ -120,11 +120,11 @@ class SylvesterEquation(RandomWalkMeta): | |||
| # don't normalize adjacency matrices if q is a uniform vector. Note | |||
| # A_wave_list actually contains the transposes of the adjacency matrices. | |||
| A_wave_1 = nx.adjacency_matrix(g1, self._edge_weight).todense().transpose() | |||
| iterator = get_iters(g_list, desc='compute adjacency matrices', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(g_list, desc='compute adjacency matrices', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| A_wave_list = [nx.adjacency_matrix(G, self._edge_weight).todense().transpose() for G in iterator] | |||
| if self._p is None: # p is uniform distribution as default. | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self.verbose >= 2)) | |||
| for i in iterator: | |||
| kernel = self._kernel_do(A_wave_1, A_wave_list[i], lmda) | |||
| @@ -139,9 +139,9 @@ class SylvesterEquation(RandomWalkMeta): | |||
| def _compute_kernel_list_imap_unordered(self, g1, g_list): | |||
| self._check_edge_weight(g_list + [g1], self._verbose) | |||
| self._check_edge_weight(g_list + [g1], self.verbose) | |||
| self._check_graphs(g_list + [g1]) | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| import warnings | |||
| warnings.warn('All labels are ignored.') | |||
| @@ -152,7 +152,7 @@ class SylvesterEquation(RandomWalkMeta): | |||
| # don't normalize adjacency matrices if q is a uniform vector. Note | |||
| # A_wave_list actually contains the transposes of the adjacency matrices. | |||
| A_wave_1 = nx.adjacency_matrix(g1, self._edge_weight).todense().transpose() | |||
| iterator = get_iters(g_list, desc='compute adjacency matrices', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(g_list, desc='compute adjacency matrices', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| A_wave_list = [nx.adjacency_matrix(G, self._edge_weight).todense().transpose() for G in iterator] # @todo: parallel? | |||
| if self._p is None: # p is uniform distribution as default. | |||
| @@ -169,7 +169,7 @@ class SylvesterEquation(RandomWalkMeta): | |||
| len_itr = len(g_list) | |||
| parallel_me(do_fun, func_assign, kernel_list, itr, len_itr=len_itr, | |||
| init_worker=init_worker, glbv=(A_wave_1, A_wave_list), method='imap_unordered', | |||
| n_jobs=self._n_jobs, itr_desc='Computing kernels', verbose=self._verbose) | |||
| n_jobs=self.n_jobs, itr_desc='Computing kernels', verbose=self.verbose) | |||
| else: # @todo | |||
| pass | |||
| @@ -184,9 +184,9 @@ class SylvesterEquation(RandomWalkMeta): | |||
| def _compute_single_kernel_series(self, g1, g2): | |||
| self._check_edge_weight([g1] + [g2], self._verbose) | |||
| self._check_edge_weight([g1] + [g2], self.verbose) | |||
| self._check_graphs([g1] + [g2]) | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| import warnings | |||
| warnings.warn('All labels are ignored.') | |||
| @@ -18,6 +18,8 @@ import numpy as np | |||
| import networkx as nx | |||
| from collections import Counter | |||
| from itertools import chain | |||
| from sklearn.utils.validation import check_is_fitted | |||
| from sklearn.exceptions import NotFittedError | |||
| from gklearn.utils import SpecialLabel | |||
| from gklearn.utils.parallel import parallel_gm, parallel_me | |||
| from gklearn.utils.utils import find_all_paths, get_mlti_dim_node_attrs | |||
| @@ -26,14 +28,211 @@ from gklearn.kernels import GraphKernel | |||
| class Treelet(GraphKernel): | |||
| def __init__(self, **kwargs): | |||
| GraphKernel.__init__(self) | |||
| self._node_labels = kwargs.get('node_labels', []) | |||
| self._edge_labels = kwargs.get('edge_labels', []) | |||
| self._sub_kernel = kwargs.get('sub_kernel', None) | |||
| self._ds_infos = kwargs.get('ds_infos', {}) | |||
| if self._sub_kernel is None: | |||
| raise Exception('Sub kernel not set.') | |||
| def __init__(self, parallel=None, n_jobs=None, chunksize=None, normalize=True, verbose=2, precompute_canonkeys=True, save_canonkeys=False, **kwargs): | |||
| """Initialise a treelet kernel. | |||
| """ | |||
| super().__init__(parallel=parallel, n_jobs=n_jobs, chunksize=chunksize, normalize=normalize, verbose=verbose) | |||
| self.node_labels = kwargs.get('node_labels', []) | |||
| self.edge_labels = kwargs.get('edge_labels', []) | |||
| self.sub_kernel = kwargs.get('sub_kernel', None) | |||
| self.ds_infos = kwargs.get('ds_infos', {}) | |||
| self.precompute_canonkeys = precompute_canonkeys | |||
| self.save_canonkeys = save_canonkeys | |||
| ########################################################################## | |||
| # The following is the 1st paradigm to compute kernel matrix, which is | |||
| # compatible with `scikit-learn`. | |||
| # ------------------------------------------------------------------- | |||
| # Special thanks to the "GraKeL" library for providing an excellent template! | |||
| ########################################################################## | |||
| def clear_attributes(self): | |||
| super().clear_attributes() | |||
| if hasattr(self, '_canonkeys'): | |||
| delattr(self, '_canonkeys') | |||
| if hasattr(self, '_Y_canonkeys'): | |||
| delattr(self, '_Y_canonkeys') | |||
| if hasattr(self, '_dummy_labels_considered'): | |||
| delattr(self, '_dummy_labels_considered') | |||
| def validate_parameters(self): | |||
| """Validate all parameters for the transformer. | |||
| Returns | |||
| ------- | |||
| None. | |||
| """ | |||
| super().validate_parameters() | |||
| if self.sub_kernel is None: | |||
| raise ValueError('Sub-kernel not set.') | |||
| def _compute_kernel_matrix_series(self, Y): | |||
| """Compute the kernel matrix between a given target graphs (Y) and | |||
| the fitted graphs (X / self._graphs) without parallelization. | |||
| Parameters | |||
| ---------- | |||
| Y : list of graphs, optional | |||
| The target graphs. | |||
| Returns | |||
| ------- | |||
| kernel_matrix : numpy array, shape = [n_targets, n_inputs] | |||
| The computed kernel matrix. | |||
| """ | |||
| # self._add_dummy_labels will modify the input in place. | |||
| self._add_dummy_labels() # For self._graphs | |||
| # Y = [g.copy() for g in Y] # @todo: ? | |||
| self._add_dummy_labels(Y) | |||
| # get all canonical keys of all graphs before computing kernels to save | |||
| # time, but this may cost a lot of memory for large dataset. | |||
| # Canonical keys for self._graphs. | |||
| try: | |||
| check_is_fitted(self, ['_canonkeys']) | |||
| canonkeys_list1 = self._canonkeys | |||
| except NotFittedError: | |||
| canonkeys_list1 = [] | |||
| iterator = get_iters(self._graphs, desc='getting canonkeys for X', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| for g in iterator: | |||
| canonkeys_list1.append(self._get_canonkeys(g)) | |||
| if self.save_canonkeys: | |||
| self._canonkeys = canonkeys_list1 | |||
| # Canonical keys for Y. | |||
| canonkeys_list2 = [] | |||
| iterator = get_iters(Y, desc='getting canonkeys for Y', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| for g in iterator: | |||
| canonkeys_list2.append(self._get_canonkeys(g)) | |||
| if self.save_canonkeys: | |||
| self._Y_canonkeys = canonkeys_list2 | |||
| # compute kernel matrix. | |||
| kernel_matrix = np.zeros((len(Y), len(canonkeys_list1))) | |||
| from itertools import product | |||
| itr = product(range(len(Y)), range(len(canonkeys_list1))) | |||
| len_itr = int(len(Y) * len(canonkeys_list1)) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, | |||
| length=len_itr, verbose=(self.verbose >= 2)) | |||
| for i_y, i_x in iterator: | |||
| kernel = self._kernel_do(canonkeys_list2[i_y], canonkeys_list1[i_x]) | |||
| kernel_matrix[i_y][i_x] = kernel | |||
| return kernel_matrix | |||
| def _compute_kernel_matrix_imap_unordered(self, Y): | |||
| """Compute the kernel matrix between a given target graphs (Y) and | |||
| the fitted graphs (X / self._graphs) using imap unordered parallelization. | |||
| Parameters | |||
| ---------- | |||
| Y : list of graphs, optional | |||
| The target graphs. | |||
| Returns | |||
| ------- | |||
| kernel_matrix : numpy array, shape = [n_targets, n_inputs] | |||
| The computed kernel matrix. | |||
| """ | |||
| raise Exception('Parallelization for kernel matrix is not implemented.') | |||
| def pairwise_kernel(self, x, y, are_keys=False): | |||
| """Compute pairwise kernel between two graphs. | |||
| Parameters | |||
| ---------- | |||
| x, y : NetworkX Graph. | |||
| Graphs bewteen which the kernel is computed. | |||
| are_keys : boolean, optional | |||
| If `True`, `x` and `y` are canonical keys, otherwise are graphs. | |||
| The default is False. | |||
| Returns | |||
| ------- | |||
| kernel: float | |||
| The computed kernel. | |||
| """ | |||
| if are_keys: | |||
| # x, y are canonical keys. | |||
| kernel = self._kernel_do(x, y) | |||
| else: | |||
| # x, y are graphs. | |||
| kernel = self._compute_single_kernel_series(x, y) | |||
| return kernel | |||
| def diagonals(self): | |||
| """Compute the kernel matrix diagonals of the fit/transformed data. | |||
| Returns | |||
| ------- | |||
| X_diag : numpy array | |||
| The diagonal of the kernel matrix between the fitted data. | |||
| This consists of each element calculated with itself. | |||
| Y_diag : numpy array | |||
| The diagonal of the kernel matrix, of the transform. | |||
| This consists of each element calculated with itself. | |||
| """ | |||
| # Check if method "fit" had been called. | |||
| check_is_fitted(self, ['_graphs']) | |||
| # Check if the diagonals of X exist. | |||
| try: | |||
| check_is_fitted(self, ['_X_diag']) | |||
| except NotFittedError: | |||
| # Compute diagonals of X. | |||
| self._X_diag = np.empty(shape=(len(self._graphs),)) | |||
| try: | |||
| check_is_fitted(self, ['_canonkeys']) | |||
| for i, x in enumerate(self._canonkeys): | |||
| self._X_diag[i] = self.pairwise_kernel(x, x, are_keys=True) # @todo: parallel? | |||
| except NotFittedError: | |||
| for i, x in enumerate(self._graphs): | |||
| self._X_diag[i] = self.pairwise_kernel(x, x, are_keys=False) # @todo: parallel? | |||
| try: | |||
| # If transform has happened, return both diagonals. | |||
| check_is_fitted(self, ['_Y']) | |||
| self._Y_diag = np.empty(shape=(len(self._Y),)) | |||
| try: | |||
| check_is_fitted(self, ['_Y_canonkeys']) | |||
| for (i, y) in enumerate(self._Y_canonkeys): | |||
| self._Y_diag[i] = self.pairwise_kernel(y, y, are_keys=True) # @todo: parallel? | |||
| except NotFittedError: | |||
| for (i, y) in enumerate(self._Y): | |||
| self._Y_diag[i] = self.pairwise_kernel(y, y, are_keys=False) # @todo: parallel? | |||
| return self._X_diag, self._Y_diag | |||
| except NotFittedError: | |||
| # Else just return both X_diag | |||
| return self._X_diag | |||
| ########################################################################## | |||
| # The following is the 2nd paradigm to compute kernel matrix. It is | |||
| # simplified and not compatible with `scikit-learn`. | |||
| ########################################################################## | |||
| def _compute_gm_series(self): | |||
| @@ -43,10 +242,13 @@ class Treelet(GraphKernel): | |||
| # time, but this may cost a lot of memory for large dataset. | |||
| canonkeys = [] | |||
| iterator = get_iters(self._graphs, desc='getting canonkeys', file=sys.stdout, | |||
| verbose=(self._verbose >= 2)) | |||
| verbose=(self.verbose >= 2)) | |||
| for g in iterator: | |||
| canonkeys.append(self._get_canonkeys(g)) | |||
| if self.save_canonkeys: | |||
| self._canonkeys = canonkeys | |||
| # compute Gram matrix. | |||
| gram_matrix = np.zeros((len(self._graphs), len(self._graphs))) | |||
| @@ -54,7 +256,7 @@ class Treelet(GraphKernel): | |||
| itr = combinations_with_replacement(range(0, len(self._graphs)), 2) | |||
| len_itr = int(len(self._graphs) * (len(self._graphs) + 1) / 2) | |||
| iterator = get_iters(itr, desc='Computing kernels', file=sys.stdout, | |||
| length=len_itr, verbose=(self._verbose >= 2)) | |||
| length=len_itr, verbose=(self.verbose >= 2)) | |||
| for i, j in iterator: | |||
| kernel = self._kernel_do(canonkeys[i], canonkeys[j]) | |||
| gram_matrix[i][j] = kernel | |||
| @@ -68,22 +270,25 @@ class Treelet(GraphKernel): | |||
| # get all canonical keys of all graphs before computing kernels to save | |||
| # time, but this may cost a lot of memory for large dataset. | |||
| pool = Pool(self._n_jobs) | |||
| pool = Pool(self.n_jobs) | |||
| itr = zip(self._graphs, range(0, len(self._graphs))) | |||
| if len(self._graphs) < 100 * self._n_jobs: | |||
| chunksize = int(len(self._graphs) / self._n_jobs) + 1 | |||
| if len(self._graphs) < 100 * self.n_jobs: | |||
| chunksize = int(len(self._graphs) / self.n_jobs) + 1 | |||
| else: | |||
| chunksize = 100 | |||
| canonkeys = [[] for _ in range(len(self._graphs))] | |||
| get_fun = self._wrapper_get_canonkeys | |||
| iterator = get_iters(pool.imap_unordered(get_fun, itr, chunksize), | |||
| desc='getting canonkeys', file=sys.stdout, | |||
| length=len(self._graphs), verbose=(self._verbose >= 2)) | |||
| length=len(self._graphs), verbose=(self.verbose >= 2)) | |||
| for i, ck in iterator: | |||
| canonkeys[i] = ck | |||
| pool.close() | |||
| pool.join() | |||
| if self.save_canonkeys: | |||
| self._canonkeys = canonkeys | |||
| # compute Gram matrix. | |||
| gram_matrix = np.zeros((len(self._graphs), len(self._graphs))) | |||
| @@ -92,7 +297,7 @@ class Treelet(GraphKernel): | |||
| G_canonkeys = canonkeys_toshare | |||
| do_fun = self._wrapper_kernel_do | |||
| parallel_gm(do_fun, gram_matrix, self._graphs, init_worker=init_worker, | |||
| glbv=(canonkeys,), n_jobs=self._n_jobs, verbose=self._verbose) | |||
| glbv=(canonkeys,), n_jobs=self.n_jobs, verbose=self.verbose) | |||
| return gram_matrix | |||
| @@ -104,13 +309,13 @@ class Treelet(GraphKernel): | |||
| # time, but this may cost a lot of memory for large dataset. | |||
| canonkeys_1 = self._get_canonkeys(g1) | |||
| canonkeys_list = [] | |||
| iterator = get_iters(g_list, desc='getting canonkeys', file=sys.stdout, verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(g_list, desc='getting canonkeys', file=sys.stdout, verbose=(self.verbose >= 2)) | |||
| for g in iterator: | |||
| canonkeys_list.append(self._get_canonkeys(g)) | |||
| # compute kernel list. | |||
| kernel_list = [None] * len(g_list) | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self._verbose >= 2)) | |||
| iterator = get_iters(range(len(g_list)), desc='Computing kernels', file=sys.stdout, length=len(g_list), verbose=(self.verbose >= 2)) | |||
| for i in iterator: | |||
| kernel = self._kernel_do(canonkeys_1, canonkeys_list[i]) | |||
| kernel_list[i] = kernel | |||
| @@ -125,16 +330,16 @@ class Treelet(GraphKernel): | |||
| # time, but this may cost a lot of memory for large dataset. | |||
| canonkeys_1 = self._get_canonkeys(g1) | |||
| canonkeys_list = [[] for _ in range(len(g_list))] | |||
| pool = Pool(self._n_jobs) | |||
| pool = Pool(self.n_jobs) | |||
| itr = zip(g_list, range(0, len(g_list))) | |||
| if len(g_list) < 100 * self._n_jobs: | |||
| chunksize = int(len(g_list) / self._n_jobs) + 1 | |||
| if len(g_list) < 100 * self.n_jobs: | |||
| chunksize = int(len(g_list) / self.n_jobs) + 1 | |||
| else: | |||
| chunksize = 100 | |||
| get_fun = self._wrapper_get_canonkeys | |||
| iterator = get_iters(pool.imap_unordered(get_fun, itr, chunksize), | |||
| desc='getting canonkeys', file=sys.stdout, | |||
| length=len(g_list), verbose=(self._verbose >= 2)) | |||
| length=len(g_list), verbose=(self.verbose >= 2)) | |||
| for i, ck in iterator: | |||
| canonkeys_list[i] = ck | |||
| pool.close() | |||
| @@ -154,7 +359,7 @@ class Treelet(GraphKernel): | |||
| len_itr = len(g_list) | |||
| parallel_me(do_fun, func_assign, kernel_list, itr, len_itr=len_itr, | |||
| init_worker=init_worker, glbv=(canonkeys_1, canonkeys_list), method='imap_unordered', | |||
| n_jobs=self._n_jobs, itr_desc='Computing kernels', verbose=self._verbose) | |||
| n_jobs=self.n_jobs, itr_desc='Computing kernels', verbose=self.verbose) | |||
| return kernel_list | |||
| @@ -187,7 +392,7 @@ class Treelet(GraphKernel): | |||
| keys = set(canonkey1.keys()) & set(canonkey2.keys()) # find same canonical keys in both graphs | |||
| vector1 = np.array([(canonkey1[key] if (key in canonkey1.keys()) else 0) for key in keys]) | |||
| vector2 = np.array([(canonkey2[key] if (key in canonkey2.keys()) else 0) for key in keys]) | |||
| kernel = self._sub_kernel(vector1, vector2) | |||
| kernel = self.sub_kernel(vector1, vector2) | |||
| return kernel | |||
| @@ -223,7 +428,7 @@ class Treelet(GraphKernel): | |||
| patterns['0'] = list(G.nodes()) | |||
| canonkey['0'] = nx.number_of_nodes(G) | |||
| for i in range(1, 6): # for i in range(1, 6): | |||
| patterns[str(i)] = find_all_paths(G, i, self._ds_infos['directed']) | |||
| patterns[str(i)] = find_all_paths(G, i, self.ds_infos['directed']) | |||
| canonkey[str(i)] = len(patterns[str(i)]) | |||
| # n-star patterns | |||
| @@ -317,11 +522,11 @@ class Treelet(GraphKernel): | |||
| ### pattern obtained in the structural analysis section above, which is a | |||
| ### string corresponding to a unique treelet. A dictionary is built to keep | |||
| ### track of the amount of every treelet. | |||
| if len(self._node_labels) > 0 or len(self._edge_labels) > 0: | |||
| if len(self.node_labels) > 0 or len(self.edge_labels) > 0: | |||
| canonkey_l = {} # canonical key, a dictionary which keeps track of amount of every treelet. | |||
| # linear patterns | |||
| canonkey_t = Counter(get_mlti_dim_node_attrs(G, self._node_labels)) | |||
| canonkey_t = Counter(get_mlti_dim_node_attrs(G, self.node_labels)) | |||
| for key in canonkey_t: | |||
| canonkey_l[('0', key)] = canonkey_t[key] | |||
| @@ -330,9 +535,9 @@ class Treelet(GraphKernel): | |||
| for pattern in patterns[str(i)]: | |||
| canonlist = [] | |||
| for idx, node in enumerate(pattern[:-1]): | |||
| canonlist.append(tuple(G.nodes[node][nl] for nl in self._node_labels)) | |||
| canonlist.append(tuple(G[node][pattern[idx+1]][el] for el in self._edge_labels)) | |||
| canonlist.append(tuple(G.nodes[pattern[-1]][nl] for nl in self._node_labels)) | |||
| canonlist.append(tuple(G.nodes[node][nl] for nl in self.node_labels)) | |||
| canonlist.append(tuple(G[node][pattern[idx+1]][el] for el in self.edge_labels)) | |||
| canonlist.append(tuple(G.nodes[pattern[-1]][nl] for nl in self.node_labels)) | |||
| canonkey_t = canonlist if canonlist < canonlist[::-1] else canonlist[::-1] | |||
| treelet.append(tuple([str(i)] + canonkey_t)) | |||
| canonkey_l.update(Counter(treelet)) | |||
| @@ -343,13 +548,13 @@ class Treelet(GraphKernel): | |||
| for pattern in patterns[str(i) + 'star']: | |||
| canonlist = [] | |||
| for leaf in pattern[1:]: | |||
| nlabels = tuple(G.nodes[leaf][nl] for nl in self._node_labels) | |||
| elabels = tuple(G[leaf][pattern[0]][el] for el in self._edge_labels) | |||
| nlabels = tuple(G.nodes[leaf][nl] for nl in self.node_labels) | |||
| elabels = tuple(G[leaf][pattern[0]][el] for el in self.edge_labels) | |||
| canonlist.append(tuple((nlabels, elabels))) | |||
| canonlist.sort() | |||
| canonlist = list(chain.from_iterable(canonlist)) | |||
| canonkey_t = tuple(['d' if i == 5 else str(i * 2)] + | |||
| [tuple(G.nodes[pattern[0]][nl] for nl in self._node_labels)] | |||
| [tuple(G.nodes[pattern[0]][nl] for nl in self.node_labels)] | |||
| + canonlist) | |||
| treelet.append(canonkey_t) | |||
| canonkey_l.update(Counter(treelet)) | |||
| @@ -359,17 +564,17 @@ class Treelet(GraphKernel): | |||
| for pattern in patterns['7']: | |||
| canonlist = [] | |||
| for leaf in pattern[1:3]: | |||
| nlabels = tuple(G.nodes[leaf][nl] for nl in self._node_labels) | |||
| elabels = tuple(G[leaf][pattern[0]][el] for el in self._edge_labels) | |||
| nlabels = tuple(G.nodes[leaf][nl] for nl in self.node_labels) | |||
| elabels = tuple(G[leaf][pattern[0]][el] for el in self.edge_labels) | |||
| canonlist.append(tuple((nlabels, elabels))) | |||
| canonlist.sort() | |||
| canonlist = list(chain.from_iterable(canonlist)) | |||
| canonkey_t = tuple(['7'] | |||
| + [tuple(G.nodes[pattern[0]][nl] for nl in self._node_labels)] + canonlist | |||
| + [tuple(G.nodes[pattern[3]][nl] for nl in self._node_labels)] | |||
| + [tuple(G[pattern[3]][pattern[0]][el] for el in self._edge_labels)] | |||
| + [tuple(G.nodes[pattern[4]][nl] for nl in self._node_labels)] | |||
| + [tuple(G[pattern[4]][pattern[3]][el] for el in self._edge_labels)]) | |||
| + [tuple(G.nodes[pattern[0]][nl] for nl in self.node_labels)] + canonlist | |||
| + [tuple(G.nodes[pattern[3]][nl] for nl in self.node_labels)] | |||
| + [tuple(G[pattern[3]][pattern[0]][el] for el in self.edge_labels)] | |||
| + [tuple(G.nodes[pattern[4]][nl] for nl in self.node_labels)] | |||
| + [tuple(G[pattern[4]][pattern[3]][el] for el in self.edge_labels)]) | |||
| treelet.append(canonkey_t) | |||
| canonkey_l.update(Counter(treelet)) | |||
| @@ -378,38 +583,38 @@ class Treelet(GraphKernel): | |||
| for pattern in patterns['11']: | |||
| canonlist = [] | |||
| for leaf in pattern[1:4]: | |||
| nlabels = tuple(G.nodes[leaf][nl] for nl in self._node_labels) | |||
| elabels = tuple(G[leaf][pattern[0]][el] for el in self._edge_labels) | |||
| nlabels = tuple(G.nodes[leaf][nl] for nl in self.node_labels) | |||
| elabels = tuple(G[leaf][pattern[0]][el] for el in self.edge_labels) | |||
| canonlist.append(tuple((nlabels, elabels))) | |||
| canonlist.sort() | |||
| canonlist = list(chain.from_iterable(canonlist)) | |||
| canonkey_t = tuple(['b'] | |||
| + [tuple(G.nodes[pattern[0]][nl] for nl in self._node_labels)] + canonlist | |||
| + [tuple(G.nodes[pattern[4]][nl] for nl in self._node_labels)] | |||
| + [tuple(G[pattern[4]][pattern[0]][el] for el in self._edge_labels)] | |||
| + [tuple(G.nodes[pattern[5]][nl] for nl in self._node_labels)] | |||
| + [tuple(G[pattern[5]][pattern[4]][el] for el in self._edge_labels)]) | |||
| + [tuple(G.nodes[pattern[0]][nl] for nl in self.node_labels)] + canonlist | |||
| + [tuple(G.nodes[pattern[4]][nl] for nl in self.node_labels)] | |||
| + [tuple(G[pattern[4]][pattern[0]][el] for el in self.edge_labels)] | |||
| + [tuple(G.nodes[pattern[5]][nl] for nl in self.node_labels)] | |||
| + [tuple(G[pattern[5]][pattern[4]][el] for el in self.edge_labels)]) | |||
| treelet.append(canonkey_t) | |||
| canonkey_l.update(Counter(treelet)) | |||
| # pattern 10 | |||
| treelet = [] | |||
| for pattern in patterns['10']: | |||
| canonkey4 = [tuple(G.nodes[pattern[5]][nl] for nl in self._node_labels), | |||
| tuple(G[pattern[5]][pattern[4]][el] for el in self._edge_labels)] | |||
| canonkey4 = [tuple(G.nodes[pattern[5]][nl] for nl in self.node_labels), | |||
| tuple(G[pattern[5]][pattern[4]][el] for el in self.edge_labels)] | |||
| canonlist = [] | |||
| for leaf in pattern[1:3]: | |||
| nlabels = tuple(G.nodes[leaf][nl] for nl in self._node_labels) | |||
| elabels = tuple(G[leaf][pattern[0]][el] for el in self._edge_labels) | |||
| nlabels = tuple(G.nodes[leaf][nl] for nl in self.node_labels) | |||
| elabels = tuple(G[leaf][pattern[0]][el] for el in self.edge_labels) | |||
| canonlist.append(tuple((nlabels, elabels))) | |||
| canonlist.sort() | |||
| canonkey0 = list(chain.from_iterable(canonlist)) | |||
| canonkey_t = tuple(['a'] | |||
| + [tuple(G.nodes[pattern[3]][nl] for nl in self._node_labels)] | |||
| + [tuple(G.nodes[pattern[4]][nl] for nl in self._node_labels)] | |||
| + [tuple(G[pattern[4]][pattern[3]][el] for el in self._edge_labels)] | |||
| + [tuple(G.nodes[pattern[0]][nl] for nl in self._node_labels)] | |||
| + [tuple(G[pattern[0]][pattern[3]][el] for el in self._edge_labels)] | |||
| + [tuple(G.nodes[pattern[3]][nl] for nl in self.node_labels)] | |||
| + [tuple(G.nodes[pattern[4]][nl] for nl in self.node_labels)] | |||
| + [tuple(G[pattern[4]][pattern[3]][el] for el in self.edge_labels)] | |||
| + [tuple(G.nodes[pattern[0]][nl] for nl in self.node_labels)] | |||
| + [tuple(G[pattern[0]][pattern[3]][el] for el in self.edge_labels)] | |||
| + canonkey4 + canonkey0) | |||
| treelet.append(canonkey_t) | |||
| canonkey_l.update(Counter(treelet)) | |||
| @@ -419,15 +624,15 @@ class Treelet(GraphKernel): | |||
| for pattern in patterns['12']: | |||
| canonlist0 = [] | |||
| for leaf in pattern[1:3]: | |||
| nlabels = tuple(G.nodes[leaf][nl] for nl in self._node_labels) | |||
| elabels = tuple(G[leaf][pattern[0]][el] for el in self._edge_labels) | |||
| nlabels = tuple(G.nodes[leaf][nl] for nl in self.node_labels) | |||
| elabels = tuple(G[leaf][pattern[0]][el] for el in self.edge_labels) | |||
| canonlist0.append(tuple((nlabels, elabels))) | |||
| canonlist0.sort() | |||
| canonlist0 = list(chain.from_iterable(canonlist0)) | |||
| canonlist3 = [] | |||
| for leaf in pattern[4:6]: | |||
| nlabels = tuple(G.nodes[leaf][nl] for nl in self._node_labels) | |||
| elabels = tuple(G[leaf][pattern[3]][el] for el in self._edge_labels) | |||
| nlabels = tuple(G.nodes[leaf][nl] for nl in self.node_labels) | |||
| elabels = tuple(G[leaf][pattern[3]][el] for el in self.edge_labels) | |||
| canonlist3.append(tuple((nlabels, elabels))) | |||
| canonlist3.sort() | |||
| canonlist3 = list(chain.from_iterable(canonlist3)) | |||
| @@ -435,14 +640,14 @@ class Treelet(GraphKernel): | |||
| # 2 possible key can be generated from 2 nodes with extended label 3, | |||
| # select the one with lower lexicographic order. | |||
| canonkey_t1 = tuple(['c'] | |||
| + [tuple(G.nodes[pattern[0]][nl] for nl in self._node_labels)] + canonlist0 | |||
| + [tuple(G.nodes[pattern[3]][nl] for nl in self._node_labels)] | |||
| + [tuple(G[pattern[3]][pattern[0]][el] for el in self._edge_labels)] | |||
| + [tuple(G.nodes[pattern[0]][nl] for nl in self.node_labels)] + canonlist0 | |||
| + [tuple(G.nodes[pattern[3]][nl] for nl in self.node_labels)] | |||
| + [tuple(G[pattern[3]][pattern[0]][el] for el in self.edge_labels)] | |||
| + canonlist3) | |||
| canonkey_t2 = tuple(['c'] | |||
| + [tuple(G.nodes[pattern[3]][nl] for nl in self._node_labels)] + canonlist3 | |||
| + [tuple(G.nodes[pattern[0]][nl] for nl in self._node_labels)] | |||
| + [tuple(G[pattern[0]][pattern[3]][el] for el in self._edge_labels)] | |||
| + [tuple(G.nodes[pattern[3]][nl] for nl in self.node_labels)] + canonlist3 | |||
| + [tuple(G.nodes[pattern[0]][nl] for nl in self.node_labels)] | |||
| + [tuple(G[pattern[0]][pattern[3]][el] for el in self.edge_labels)] | |||
| + canonlist0) | |||
| treelet.append(canonkey_t1 if canonkey_t1 < canonkey_t2 else canonkey_t2) | |||
| canonkey_l.update(Counter(treelet)) | |||
| @@ -450,24 +655,24 @@ class Treelet(GraphKernel): | |||
| # pattern 9 | |||
| treelet = [] | |||
| for pattern in patterns['9']: | |||
| canonkey2 = [tuple(G.nodes[pattern[4]][nl] for nl in self._node_labels), | |||
| tuple(G[pattern[4]][pattern[2]][el] for el in self._edge_labels)] | |||
| canonkey3 = [tuple(G.nodes[pattern[5]][nl] for nl in self._node_labels), | |||
| tuple(G[pattern[5]][pattern[3]][el] for el in self._edge_labels)] | |||
| prekey2 = [tuple(G.nodes[pattern[2]][nl] for nl in self._node_labels), | |||
| tuple(G[pattern[2]][pattern[0]][el] for el in self._edge_labels)] | |||
| prekey3 = [tuple(G.nodes[pattern[3]][nl] for nl in self._node_labels), | |||
| tuple(G[pattern[3]][pattern[0]][el] for el in self._edge_labels)] | |||
| canonkey2 = [tuple(G.nodes[pattern[4]][nl] for nl in self.node_labels), | |||
| tuple(G[pattern[4]][pattern[2]][el] for el in self.edge_labels)] | |||
| canonkey3 = [tuple(G.nodes[pattern[5]][nl] for nl in self.node_labels), | |||
| tuple(G[pattern[5]][pattern[3]][el] for el in self.edge_labels)] | |||
| prekey2 = [tuple(G.nodes[pattern[2]][nl] for nl in self.node_labels), | |||
| tuple(G[pattern[2]][pattern[0]][el] for el in self.edge_labels)] | |||
| prekey3 = [tuple(G.nodes[pattern[3]][nl] for nl in self.node_labels), | |||
| tuple(G[pattern[3]][pattern[0]][el] for el in self.edge_labels)] | |||
| if prekey2 + canonkey2 < prekey3 + canonkey3: | |||
| canonkey_t = [tuple(G.nodes[pattern[1]][nl] for nl in self._node_labels)] \ | |||
| + [tuple(G[pattern[1]][pattern[0]][el] for el in self._edge_labels)] \ | |||
| canonkey_t = [tuple(G.nodes[pattern[1]][nl] for nl in self.node_labels)] \ | |||
| + [tuple(G[pattern[1]][pattern[0]][el] for el in self.edge_labels)] \ | |||
| + prekey2 + prekey3 + canonkey2 + canonkey3 | |||
| else: | |||
| canonkey_t = [tuple(G.nodes[pattern[1]][nl] for nl in self._node_labels)] \ | |||
| + [tuple(G[pattern[1]][pattern[0]][el] for el in self._edge_labels)] \ | |||
| canonkey_t = [tuple(G.nodes[pattern[1]][nl] for nl in self.node_labels)] \ | |||
| + [tuple(G[pattern[1]][pattern[0]][el] for el in self.edge_labels)] \ | |||
| + prekey3 + prekey2 + canonkey3 + canonkey2 | |||
| treelet.append(tuple(['9'] | |||
| + [tuple(G.nodes[pattern[0]][nl] for nl in self._node_labels)] | |||
| + [tuple(G.nodes[pattern[0]][nl] for nl in self.node_labels)] | |||
| + canonkey_t)) | |||
| canonkey_l.update(Counter(treelet)) | |||
| @@ -482,12 +687,33 @@ class Treelet(GraphKernel): | |||
| return i, self._get_canonkeys(g) | |||
| def _add_dummy_labels(self, Gn): | |||
| if len(self._node_labels) == 0 or (len(self._node_labels) == 1 and self._node_labels[0] == SpecialLabel.DUMMY): | |||
| for i in range(len(Gn)): | |||
| nx.set_node_attributes(Gn[i], '0', SpecialLabel.DUMMY) | |||
| self._node_labels = [SpecialLabel.DUMMY] | |||
| if len(self._edge_labels) == 0 or (len(self._edge_labels) == 1 and self._edge_labels[0] == SpecialLabel.DUMMY): | |||
| for i in range(len(Gn)): | |||
| nx.set_edge_attributes(Gn[i], '0', SpecialLabel.DUMMY) | |||
| self._edge_labels = [SpecialLabel.DUMMY] | |||
| def _add_dummy_labels(self, Gn=None): | |||
| def _add_dummy(Gn): | |||
| if len(self.node_labels) == 0 or (len(self.node_labels) == 1 and self.node_labels[0] == SpecialLabel.DUMMY): | |||
| for i in range(len(Gn)): | |||
| nx.set_node_attributes(Gn[i], '0', SpecialLabel.DUMMY) | |||
| self.node_labels = [SpecialLabel.DUMMY] | |||
| if len(self.edge_labels) == 0 or (len(self.edge_labels) == 1 and self.edge_labels[0] == SpecialLabel.DUMMY): | |||
| for i in range(len(Gn)): | |||
| nx.set_edge_attributes(Gn[i], '0', SpecialLabel.DUMMY) | |||
| self.edge_labels = [SpecialLabel.DUMMY] | |||
| if Gn is None or Gn is self._graphs: | |||
| # Add dummy labels for the copy of self._graphs. | |||
| try: | |||
| check_is_fitted(self, ['_dummy_labels_considered']) | |||
| if not self._dummy_labels_considered: | |||
| Gn = self._graphs # @todo: ?[g.copy() for g in self._graphs] | |||
| _add_dummy(Gn) | |||
| self._graphs = Gn | |||
| self._dummy_labels_considered = True | |||
| except NotFittedError: | |||
| Gn = self._graphs # @todo: ?[g.copy() for g in self._graphs] | |||
| _add_dummy(Gn) | |||
| self._graphs = Gn | |||
| self._dummy_labels_considered = True | |||
| else: | |||
| # Add dummy labels for the input. | |||
| _add_dummy(Gn) | |||
| @@ -33,7 +33,7 @@ class WeisfeilerLehman(GraphKernel): # @todo: sp, edge user kernel. | |||
| def _compute_gm_series(self): | |||
| # if self._verbose >= 2: | |||
| # if self.verbose >= 2: | |||
| # import warnings | |||
| # warnings.warn('A part of the computation is parallelized.') | |||
| @@ -74,17 +74,17 @@ class WeisfeilerLehman(GraphKernel): # @todo: sp, edge user kernel. | |||
| G_gn = gn_toshare | |||
| do_fun = self._wrapper_pairwise | |||
| parallel_gm(do_fun, gram_matrix, self._graphs, init_worker=init_worker, | |||
| glbv=(self._graphs,), n_jobs=self._n_jobs, verbose=self._verbose) | |||
| glbv=(self._graphs,), n_jobs=self.n_jobs, verbose=self.verbose) | |||
| return gram_matrix | |||
| else: | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| import warnings | |||
| warnings.warn('This base kernel is not parallelized. The serial computation is used instead.') | |||
| return self._compute_gm_series() | |||
| def _compute_kernel_list_series(self, g1, g_list): # @todo: this should be better. | |||
| # if self._verbose >= 2: | |||
| # if self.verbose >= 2: | |||
| # import warnings | |||
| # warnings.warn('A part of the computation is parallelized.') | |||
| @@ -126,10 +126,10 @@ class WeisfeilerLehman(GraphKernel): # @todo: sp, edge user kernel. | |||
| len_itr = len(g_list) | |||
| parallel_me(do_fun, func_assign, kernel_list, itr, len_itr=len_itr, | |||
| init_worker=init_worker, glbv=(g1, g_list), method='imap_unordered', | |||
| n_jobs=self._n_jobs, itr_desc='Computing kernels', verbose=self._verbose) | |||
| n_jobs=self.n_jobs, itr_desc='Computing kernels', verbose=self.verbose) | |||
| return kernel_list | |||
| else: | |||
| if self._verbose >= 2: | |||
| if self.verbose >= 2: | |||
| import warnings | |||
| warnings.warn('This base kernel is not parallelized. The serial computation is used instead.') | |||
| return self._compute_kernel_list_series(g1, g_list) | |||
| @@ -332,15 +332,15 @@ class WeisfeilerLehman(GraphKernel): # @todo: sp, edge user kernel. | |||
| def _compute_gram_itr(self, gram_matrix, all_num_of_each_label): | |||
| """Compute Gram matrix using the base kernel. | |||
| """ | |||
| # if self._parallel == 'imap_unordered': | |||
| # if self.parallel == 'imap_unordered': | |||
| # # compute kernels. | |||
| # def init_worker(alllabels_toshare): | |||
| # global G_alllabels | |||
| # G_alllabels = alllabels_toshare | |||
| # do_partial = partial(self._wrapper_compute_subtree_kernel, gram_matrix) | |||
| # parallel_gm(do_partial, gram_matrix, Gn, init_worker=init_worker, | |||
| # glbv=(all_num_of_each_label,), n_jobs=self._n_jobs, verbose=self._verbose) | |||
| # elif self._parallel is None: | |||
| # glbv=(all_num_of_each_label,), n_jobs=self.n_jobs, verbose=self.verbose) | |||
| # elif self.parallel is None: | |||
| for i in range(len(gram_matrix)): | |||
| for j in range(i, len(gram_matrix)): | |||
| gram_matrix[i][j] = self._compute_subtree_kernel(all_num_of_each_label[i], | |||