Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Changelog

All notable changes to this project are documented in this file.

## v0.1.1

### Added
- DGL integration wrappers in `rings.integrations` (`DGLOriginal`, `DGLEmptyFeatures`, `DGLRandomFeatures`, `DGLEmptyGraph`, `DGLCompleteGraph`, `DGLRandomGraph`).
- DGL/PyG conversion helpers in `rings.integrations.dgl` to round-trip homogeneous DGL graphs through existing RINGS perturbations.
- Test coverage for DGL integration behavior and seed/feature handling in `tests/test_dgl_integration.py`.
- Lightning integration tests that validate both PyG and DGL usage in `tests/test_lightning_framework_integration.py`.

### Changed
- Optional dependency model now includes explicit install targets for `lightning`, `dgl`, and combined `integrations` extras/groups in `pyproject.toml`.
- Integration documentation now includes DGL setup and usage examples in `README.md` and `docs/source/integrations.rst`.
- Package version updated to `0.1.1`.

## v0.1.0

### Added
- Initial `rings-evaluation` release on `main` with the core perturbation framework for graph-learning dataset evaluation.
- Support for integration into existing GNN workflows via `SeparabilityStudy`.
- PyTorch Lightning callback support via `SeparabilityCallback`.
- Documentation and runnable examples for integrating RINGS into model evaluation pipelines.
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@ pip install rings-evaluation

Requires Python 3.11+.

### Optional integrations

Install only what you need:

```bash
# PyTorch Lightning integration
pip install "rings-evaluation[lightning]"

# DGL integration (available for Python < 3.13)
pip install "rings-evaluation[dgl]"

# Both integrations
pip install "rings-evaluation[integrations]"
```

### From source

To contribute or run the examples in this repo:
Expand All @@ -26,6 +41,14 @@ git clone https://github.com/aidos-lab/rings.git && cd rings
uv sync && source .venv/bin/activate
```

Enable optional integration groups as needed:

```bash
uv sync --group lightning
uv sync --group dgl
uv sync --group integrations
```

---

## Quickstart
Expand Down Expand Up @@ -78,6 +101,27 @@ for name, transform, seed in study.runs():
results = study.evaluate()
```

**DGL** — use the DGL wrappers from `rings.integrations` (backed by the same core perturbation logic):

```python
from rings.integrations import DGLOriginal, DGLEmptyGraph, SeparabilityStudy

study = SeparabilityStudy(
perturbations={
"Original": DGLOriginal(),
"EmptyGraph": DGLEmptyGraph(),
},
num_seeds=5,
)

for name, transform, seed in study.runs():
perturbed = study.apply(base_dgl_graph, transform)
score = train_and_eval_dgl(perturbed, seed=seed) # your code
study.record(name, score)

results = study.evaluate()
```

**Custom evaluator** (GraphBench, OGB, anything that returns a scalar): just pass the number to `study.record(name, score)`.

### Runnable examples
Expand Down
24 changes: 24 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,22 @@ Install

Requires Python 3.11+. Package on `PyPI <https://pypi.org/project/rings-evaluation/>`__.

Optional integrations
~~~~~~~~~~~~~~~~~~~~~

Install only what you need:

.. code-block:: bash

# PyTorch Lightning integration
pip install "rings-evaluation[lightning]"

# DGL integration (available for Python < 3.13)
pip install "rings-evaluation[dgl]"

# Both integrations
pip install "rings-evaluation[integrations]"

From source
~~~~~~~~~~~

Expand All @@ -32,6 +48,14 @@ To contribute or run the examples in this repo:
git clone https://github.com/aidos-lab/rings.git && cd rings
uv sync && source .venv/bin/activate

Enable optional integration groups as needed:

.. code-block:: bash

uv sync --group lightning
uv sync --group dgl
uv sync --group integrations

Quickstart
----------------------------------------------

Expand Down
59 changes: 59 additions & 0 deletions docs/source/integrations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,57 @@ Lightning

Your ``LightningModule.test_step`` must call ``self.log("test_acc", acc)`` (or whatever ``metric_key`` you pass to ``SeparabilityCallback``).

DGL
---

Install the optional integration dependencies:

.. code-block:: bash

pip install "rings-evaluation[dgl]"
# or with uv:
uv sync --group dgl

RINGS keeps PyG perturbations as the source of truth and exposes DGL-compatible wrappers
through ``rings.integrations``:

- ``DGLOriginal``
- ``DGLEmptyFeatures``
- ``DGLRandomFeatures``
- ``DGLEmptyGraph``
- ``DGLCompleteGraph``
- ``DGLRandomGraph``

These wrappers convert a ``dgl.DGLGraph`` to a temporary PyG ``Data`` object, apply the
underlying RINGS perturbation, and convert the result back to DGL.

.. code-block:: python

from rings.integrations import (
DGLOriginal,
DGLEmptyGraph,
DGLRandomFeatures,
SeparabilityStudy,
)

study = SeparabilityStudy(
perturbations={
"Original": DGLOriginal(),
"EmptyGraph": DGLEmptyGraph(),
"RandomFeatures": DGLRandomFeatures(shuffle=True),
},
num_seeds=5,
comparator="ks",
alpha=0.05,
)

for name, transform, seed in study.runs():
perturbed = study.apply(base_dgl_graph, transform)
score = train_and_eval_dgl(perturbed, seed=seed) # your code
study.record(name, score)

results = study.evaluate()

Custom evaluators
-----------------

Expand Down Expand Up @@ -89,3 +140,11 @@ SeparabilityCallback
:members:
:undoc-members:
:show-inheritance:

DGL perturbation wrappers
^^^^^^^^^^^^^^^^^^^^^^^^^

.. automodule:: rings.integrations.dgl
:members:
:undoc-members:
:show-inheritance:
26 changes: 23 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "rings-evaluation"
version = "0.1.0"
version = "0.1.1"
description = "RINGS: Relevant Information in Node Features and Graph Structure. An evaluation framework for graph-learning based on first principles."
readme = "README.md"
license = "BSD-3-Clause"
Expand Down Expand Up @@ -28,14 +28,25 @@ classifiers = [
]
dependencies = [
"networkx>=3.4.2",
"pandas>=3.0.3",
"pot>=0.9.5",
"scikit-learn>=1.7.0",
"seaborn>=0.13.2",
"torch>=2.7.0",
"torch-geometric>=2.6.1",
"torchvision>=0.22.0",
]

[project.optional-dependencies]
lightning = [
"lightning>=2.6.1",
]
dgl = [
"dgl>=1.1,<3; python_version < '3.13'",
]
integrations = [
"rings-evaluation[lightning,dgl]",
]

[project.urls]
Documentation = "https://aidos.group/rings/"
Repository = "https://github.com/aidos-lab/rings"
Expand All @@ -59,11 +70,20 @@ build-backend = "hatchling.build"
[dependency-groups]
dev = [
"ipykernel>=6.29.5",
"lightning>=2.6.1",
"pytest>=8.4.1",
"pytest-cov>=6.2.1",
"ruff>=0.15.13",
]
lightning = [
"lightning>=2.6.1",
]
dgl = [
"dgl>=1.1,<3; python_version < '3.13'",
]
integrations = [
"lightning>=2.6.1",
"dgl>=1.1,<3; python_version < '3.13'",
]
docs = [
"furo>=2024.8.6",
"sphinx>=8.2.3",
Expand Down
2 changes: 1 addition & 1 deletion rings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
)
from rings import integrations

__version__ = "0.1.0"
__version__ = "0.1.1"

__all__ = [
"Original",
Expand Down
24 changes: 23 additions & 1 deletion rings/integrations/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
from rings.integrations.study import SeparabilityStudy

__all__ = ["SeparabilityStudy", "SeparabilityCallback"]
__all__ = [
"SeparabilityStudy",
"SeparabilityCallback",
"DGLOriginal",
"DGLEmptyFeatures",
"DGLRandomFeatures",
"DGLEmptyGraph",
"DGLCompleteGraph",
"DGLRandomGraph",
]


def __getattr__(name):
if name == "SeparabilityCallback":
from rings.integrations.lightning import SeparabilityCallback

return SeparabilityCallback

if name in [
"DGLOriginal",
"DGLEmptyFeatures",
"DGLRandomFeatures",
"DGLEmptyGraph",
"DGLCompleteGraph",
"DGLRandomGraph",
]:
from rings.integrations import dgl

return getattr(dgl, name)

raise AttributeError(f"module 'rings.integrations' has no attribute {name!r}")
Loading
Loading