Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Origin/0.1a10 #100

Merged
merged 22 commits into from
Oct 24, 2023
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- DOC_REPO: GraKeL

# The base URL for the Github page where the documentation will be hosted
- DOC_URL: 0.1a8
- DOC_URL: 0.1a10

# The email is to be used for commits in the Github Page
- EMAIL: [email protected]
Expand Down
2 changes: 2 additions & 0 deletions .conda_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ conda-build . --output-folder conda_build/ --python 3.7
conda-build . --output-folder conda_build/ --python 3.8
conda-build . --output-folder conda_build/ --python 3.9
conda-build . --output-folder conda_build/ --python 3.10
conda-build . --output-folder conda_build/ --python 3.11
conda-build . --output-folder conda_build/ --python 3.12
conda convert -f --platform all conda_build/linux-64/*.tar.bz2 -o conda_build
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
# 1 runner per combination of (os, py)
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
py: ["cp37-*", "cp38-*", "cp39-*", "cp310-*"]
py: ["cp37-*", "cp38-*", "cp39-*", "cp310-*", "cp311-*", "cp312-*"]
# All workers independent, don't cancel all if one fails
fail-fast: false

Expand Down
10 changes: 8 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ env:

import-package-name: grakel
extra-requires: "[dev]" # "" for no extra_requires
extra-requires-soft: "[test]" # "" for no extra_requires
test-dir: grakel/tests

# https://github.com/eddiebergman/GraKeL/blob/63a2723fc9488257a7c880fa9b5e5cc95ada9f42/ci_scripts/travis/install.sh#L8-L11
Expand All @@ -47,7 +48,7 @@ jobs:
strategy:
fail-fast: false
matrix:
py: ["3.7", "3.8", "3.9", "3.10"]
py: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
os: ["ubuntu-latest", "macos-latest", "windows-latest"]

steps:
Expand All @@ -62,7 +63,12 @@ jobs:
- name: Install ${{ env.import-package-name }}
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e ".${{ env.extra-requires }}"
# escape for cvxopt
if ( [[ "${{ matrix.os }}" == "windows-latest" ]] && [[ "${{ matrix.py }}" == "3.7" ]] ) || [[ "${{ matrix.py }}" == "3.12" ]];then
python -m pip install -e ".${{ env.extra-requires-soft }}"
else
python -m pip install -e ".${{ env.extra-requires }}"
fi

- name: Tests
run: |
Expand Down
2 changes: 2 additions & 0 deletions grakel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from grakel.utils import graph_from_networkx
from grakel.utils import graph_from_pandas
from grakel.utils import graph_from_csv
from grakel.utils import graph_from_torch_geometric

__all__ = [
"datasets",
Expand Down Expand Up @@ -67,6 +68,7 @@
"graph_from_networkx",
"graph_from_pandas",
"graph_from_csv",
"graph_from_torch_geometric",
"KMTransformer",
"cross_validate_Kfold_SVM"
]
Expand Down
58 changes: 57 additions & 1 deletion grakel/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import absolute_import
import numbers
import warnings
import copy

import numpy as np

Expand Down Expand Up @@ -773,7 +774,6 @@
raise ValueError('Graph does not have any labels for edges.')
return self.edge_labels
else:

raise ValueError('label type can only be "vertex" or "edge"')

def get_label_group(self, label_type="vertex", purpose="dictionary"):
Expand Down Expand Up @@ -1479,6 +1479,62 @@

return subgraph

def copy(self):
"""Returns a copy of the `self` graph.

Parameters
----------
None.

Returns
-------
copy : graph
The copied graph.

"""
return copy.deepcopy(self)

Check warning on line 1495 in grakel/graph.py

View check run for this annotation

Codecov / codecov/patch

grakel/graph.py#L1495

Added line #L1495 was not covered by tests

def clone(self):
"""Alias for copy function.

Parameters
----------
None.

Returns
-------
clone : graph
The cloned graph.

"""
return self.copy()

Check warning on line 1510 in grakel/graph.py

View check run for this annotation

Codecov / codecov/patch

grakel/graph.py#L1510

Added line #L1510 was not covered by tests

def __repr__(self):
output = ["#vertices"]
output += [','.join(map(str, self.get_vertices('any')))]

Check warning on line 1514 in grakel/graph.py

View check run for this annotation

Codecov / codecov/patch

grakel/graph.py#L1513-L1514

Added lines #L1513 - L1514 were not covered by tests

output += ["#edges"]
output += ['\n'.join(map(lambda x: str(x[0]) + ',' + str(x[1]), self.get_edges('any')))]

Check warning on line 1517 in grakel/graph.py

View check run for this annotation

Codecov / codecov/patch

grakel/graph.py#L1516-L1517

Added lines #L1516 - L1517 were not covered by tests

def list_repr(x):

Check warning on line 1519 in grakel/graph.py

View check run for this annotation

Codecov / codecov/patch

grakel/graph.py#L1519

Added line #L1519 was not covered by tests
# convert numpy to list
if type(x) in [np.array, np.ndarray]:
x = x.tolist()
elif isinstance(x, Iterable):
x = list(x)

Check warning on line 1524 in grakel/graph.py

View check run for this annotation

Codecov / codecov/patch

grakel/graph.py#L1521-L1524

Added lines #L1521 - L1524 were not covered by tests
else:
return str(x)
return '[' + ','.join(map(str, x)) + ']'

Check warning on line 1527 in grakel/graph.py

View check run for this annotation

Codecov / codecov/patch

grakel/graph.py#L1526-L1527

Added lines #L1526 - L1527 were not covered by tests

if bool(self.node_labels):
output += ["#node_labels"]
output += ['\n'.join(map(lambda x: str(x[0]) + '->'+ list_repr(x[1]), self.node_labels.items()))]

Check warning on line 1531 in grakel/graph.py

View check run for this annotation

Codecov / codecov/patch

grakel/graph.py#L1529-L1531

Added lines #L1529 - L1531 were not covered by tests

if bool(self.edge_labels):
output += ["#edge_labels"]
output += ['\n'.join(map(lambda x: str(x[0][0]) + ',' + str(x[0][1]) + '->' + list_repr(x[1]), self.edge_labels.items()))]

Check warning on line 1535 in grakel/graph.py

View check run for this annotation

Codecov / codecov/patch

grakel/graph.py#L1533-L1535

Added lines #L1533 - L1535 were not covered by tests

return '\n'.join(output)

Check warning on line 1537 in grakel/graph.py

View check run for this annotation

Codecov / codecov/patch

grakel/graph.py#L1537

Added line #L1537 was not covered by tests

def is_adjacency(g, transform=False):
"""Define if input is in a valid adjacency matrix format.
Expand Down
2 changes: 1 addition & 1 deletion grakel/kernels/graphlet_sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def transform(self, X):
km /= np.sqrt(np.outer(Y_diag, X_diag))
return km

def fit_transform(self, X):
def fit_transform(self, X, y=None):
"""Fit and transform, on the same dataset.

Parameters
Expand Down
2 changes: 1 addition & 1 deletion grakel/kernels/kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def transform(self, X):
km /= np.sqrt(np.outer(Y_diag, X_diag))
return km

def fit_transform(self, X):
def fit_transform(self, X, y=None):
"""Fit and transform, on the same dataset.

Parameters
Expand Down
2 changes: 1 addition & 1 deletion grakel/kernels/neighborhood_hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def fit(self, X, y=None):
# Return the transformer
return self

def fit_transform(self, X):
def fit_transform(self, X, y=None):
"""Fit and transform, on the same dataset.

Parameters
Expand Down
7 changes: 5 additions & 2 deletions grakel/kernels/neighborhood_subgraph_pairwise_distance.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def transform(self, X, y=None):
S /= np.sqrt(np.outer(*self.diagonal()))
return S

def fit_transform(self, X):
def fit_transform(self, X, y=None):
"""Fit and transform, on the same dataset.

Parameters
Expand Down Expand Up @@ -311,7 +311,10 @@ def fit_transform(self, X):
K = M.dot(M.T).toarray()
K_diag = K.diagonal()
N[key] = K_diag
S += np.nan_to_num(K / np.sqrt(np.outer(K_diag, K_diag)))
Q = K / np.sqrt(np.outer(K_diag, K_diag))
np.fill_diagonal(Q, np.nan_to_num(np.diag(Q), nan=1.))
Q = np.nan_to_num(Q)
S = S + Q

self._X_level_norm_factor = N

Expand Down
6 changes: 3 additions & 3 deletions grakel/kernels/random_walk.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@
if not self._initialized["p"]:
if self.p is not None:
if type(self.p) is int and self.p > 0:
if self.kernel_type == "geometric":
if self.kernel_type == "exponential":

Check warning on line 105 in grakel/kernels/random_walk.py

View check run for this annotation

Codecov / codecov/patch

grakel/kernels/random_walk.py#L105

Added line #L105 was not covered by tests
self.mu_ = [1]
fact = 1
power = 1
for k in range(1, self.p + 1):
fact *= k
power *= self.lamda
self.mu_.append(fact/power)
self.mu_.append(power/fact)

Check warning on line 112 in grakel/kernels/random_walk.py

View check run for this annotation

Codecov / codecov/patch

grakel/kernels/random_walk.py#L112

Added line #L112 was not covered by tests
else:
self.mu_ = [1]
power = 1
Expand Down Expand Up @@ -437,7 +437,7 @@
P = np.eye(XY.shape[0])
S = self.mu_[0] * P
for k in self.mu_[1:]:
P *= XY
P = np.matmul(P, XY)

Check warning on line 440 in grakel/kernels/random_walk.py

View check run for this annotation

Codecov / codecov/patch

grakel/kernels/random_walk.py#L440

Added line #L440 was not covered by tests
S += k*P
elif self.kernel_type == "exponential":
S = expm(self.lamda*XY).T
Expand Down
32 changes: 24 additions & 8 deletions grakel/kernels/weisfeiler_lehman.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,7 @@
raise ValueError('input must be an iterable\n')
else:
nx = 0
distinct_values = set()
Gs_ed, L = dict(), dict()
Gs_ed, L, distinct_values, extras = dict(), dict(), set(), dict()
for (i, x) in enumerate(iter(X)):
is_iter = isinstance(x, Iterable)
if is_iter:
Expand All @@ -348,17 +347,34 @@
+ str(i))
continue

elif len(x) in [2, 3]:
x = Graph(x[0], x[1], {}, self._graph_format)
else:
if len(x) > 2:
extra = tuple()
if len(x) > 3:
extra = tuple(x[3:])
x = Graph(x[0], x[1], x[2], graph_format=self._graph_format)
extra = (x.get_labels(purpose=self._graph_format, label_type="edge", return_none=True),) + extra

Check warning on line 356 in grakel/kernels/weisfeiler_lehman.py

View check run for this annotation

Codecov / codecov/patch

grakel/kernels/weisfeiler_lehman.py#L352-L356

Added lines #L352 - L356 were not covered by tests
else:
x = Graph(x[0], x[1], {}, graph_format=self._graph_format)
extra = tuple()

elif type(x) is Graph:
x.desired_format("dictionary")
el = x.get_labels(purpose=self._graph_format, label_type="edge", return_none=True)
if el is None:
extra = tuple()
else:
extra = (el, )

Check warning on line 367 in grakel/kernels/weisfeiler_lehman.py

View check run for this annotation

Codecov / codecov/patch

grakel/kernels/weisfeiler_lehman.py#L367

Added line #L367 was not covered by tests
else:
raise ValueError('each element of X must have at ' +
'least one and at most 3 elements\n')
raise TypeError('each element of X must be either a ' +

Check warning on line 369 in grakel/kernels/weisfeiler_lehman.py

View check run for this annotation

Codecov / codecov/patch

grakel/kernels/weisfeiler_lehman.py#L369

Added line #L369 was not covered by tests
'graph object or a list with at least ' +
'a graph like object and node labels ' +
'dict \n')
Gs_ed[nx] = x.get_edge_dictionary()
L[nx] = x.get_labels(purpose="dictionary")

# Hold all the distinct values
extras[nx] = extra
distinct_values |= set(
v for v in itervalues(L[nx])
if v not in self._inv_labels[0])
Expand All @@ -382,7 +398,7 @@
new_labels[k] = WL_labels_inverse[v]
L[j] = new_labels
# produce the new graphs
new_graphs.append([Gs_ed[j], new_labels])
new_graphs.append((Gs_ed[j], new_labels) + extras[j])
yield new_graphs

for i in range(1, self._n_iter):
Expand Down Expand Up @@ -418,7 +434,7 @@
new_labels[k] = WL_labels_inverse[v]
L[j] = new_labels
# Create the new graphs with the new labels.
new_graphs.append([Gs_ed[j], new_labels])
new_graphs.append((Gs_ed[j], new_labels) + extras[j])
yield new_graphs

if self._parallel is None:
Expand Down
Loading