Skip to main content

Graph Dependence

This repository contains the reference implementation for Dependence Is Not Advantage: What Randomizing the Graph Does Not Measure. The paper is by Prahas Duggireddy and the package is maintained by Third Wheel.

The package reports two comparisons that are easy to mix up in graph-ablation studies:

  • Dependence: how a graph procedure changes when the observed graph is replaced by a stated graph null.
  • Advantage: how that procedure compares with a named scorer that does not receive the graph.

Randomization answers the first question. It does not answer the second one by itself. The implementation is intentionally small, typed, and close to these definitions. Version 0.1.0 is an early reference implementation, not a general graph-learning framework or a full reproduction of the paper.

Paper and project links:

Quick start

The smallest complete example needs no network access. From a checkout:

python -m pip install .
python examples/minimal.py

It uses a fixed graph, fixed node-content features, a degree-preserving null, and seed 7. The command prints a JSON-compatible report that is small enough to read alongside the source.

For an evaluation of your own, the central call looks like this:

from graph_dependence import DegreePreservingNull, binary_auc, diagnose

# Provide these objects from your evaluation protocol.
report = diagnose(
    graph=graph,
    examples=examples,
    targets=targets,
    graph_scorer=score_with_graph,
    graph_free_scorer=score_without_graph,
    null_model=DegreePreservingNull(attempts_per_edge=10),
    metric=binary_auc,
    null_draws=10,
    seed=7,
)
print(report.to_dict())

The call keeps the intact, null, and graph-free comparator scores together. The resulting report can be serialized with to_dict() without a custom encoder.

What the report means

Field Comparison Interpretation
dependence observed_score - null_score Change under the declared graph intervention.
advantage observed_score - comparator_score Difference from the named graph-free scorer.
null_survival null_score / observed_score Fraction of the observed score that remains after randomization.

advantage is None when no graph-free scorer is supplied. null_survival is None when the observed score is not positive, because the ratio is undefined there. The report also records the three reference scores, the seed, the null model name, and sampler diagnostics.

The public API

Symbol Use
diagnose Evaluate the intact, null, and optional graph-free arms and return one report.
DegreePreservingNull Generate fixed-budget double-edge-swap null graphs and record the checks performed.
DependenceReport Store scores, contrasts, seed, and metadata; to_dict() returns JSON-compatible values.
binary_auc Provide a small dependency-free binary ranking metric for examples and tests.
GraphScorer, GraphFreeScorer, Metric, NullModel Define the typed callable boundaries supplied by the caller.

The formal definitions, empirical results, and claim boundaries remain in the paper. The package implements the diagnostic around them; it does not recreate the paper's training runs or manuscript tables.

Supplying scorers and metrics

A graph scorer receives a NetworkX graph and the evaluation examples. A graph-free scorer receives the same examples without the graph. Both return one score per example. A metric receives those scores and the targets and returns a scalar, with larger values meaning better performance.

def score_with_graph(graph, examples):
    return [len(list(nx.common_neighbors(graph, u, v))) for u, v in examples]


def score_without_graph(examples):
    return [content_similarity[u, v] for u, v in examples]

Custom scorers and metrics are ordinary callables. If a scorer trains a model or uses randomness, condition-specific fitting and seed control are the caller's responsibility. The seed argument controls null generation only.

The degree-preserving null

DegreePreservingNull applies a fixed budget of double-edge-swap attempts to an undirected, simple, unweighted graph. It rejects self-loops, duplicate edges, and new edges listed in forbidden_edges. Each draw records accepted swaps, edge retention, component counts, and explicit degree and edge-count checks.

Degree preservation describes a constraint, not a unique probability distribution. The implementation records its sampler and budget and does not claim uniform sampling over all graphs with the same degree sequence. Edge attributes are rejected because assigning them to newly formed edges would silently define a different intervention.

Public-data example

examples/cora.py downloads the public Cora citation graph, constructs a deterministic link-prediction split, and compares common-neighbor scores with a graph-free bag-of-words Jaccard scorer:

python examples/cora.py

This is an API example, not a reproduction of the paper's Cora row. The paper uses the published HeaRT split, its hard negatives, and Hits@20. The example uses a small deterministic split and AUC so that it can remain independent of a training framework.

Repository layout

src/graph_dependence/  package implementation and py.typed marker
examples/minimal.py    deterministic, network-free example
examples/cora.py       optional public-data example
tests/                 package and scientific-boundary tests
site/                  paper page, searchable PDF, figure, and citations

The paper and visible landing page are authoritative for scholarly claims. pyproject.toml is authoritative for package version and support metadata; CITATION.cff is authoritative for software citation metadata.

Scope

This repository does not train GraphSAGE, recreate manuscript tables, prescribe a universally valid null model, or turn predictive improvement into evidence of downstream recommendation benefit. It is a reference implementation for separating dependence from advantage in an evaluation protocol.

For the formal definitions and empirical study, see the paper. For software reuse, cite the version used and see CITATION.cff.

Development

The package supports Python 3.11 and newer. To run the local checks after an editable install:

python -m pip install -e '.[dev]'
ruff check .
mypy --strict .
pytest --cov=graph_dependence --cov-branch

Metadata

Release files for graph-dependence 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for graph-dependence 0.1.0
File Size Uploaded
graph_dependence-0.1.0.tar.gz 1.0 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for graph-dependence 0.1.0
File Interpreter ABI Platform
graph_dependence-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.1 MB

Release files / graph_dependence-0.1.0.tar.gz

Download URL graph_dependence-0.1.0.tar.gz
Size 1.0 MB
Tags Source
SHA-256 checksum
How to use checksums
2285965c1c604b4cb1bd10beabb2f03e735aae674f0c719dbb35fb0df7836855
BLAKE2b-256 checksum
How to use checksums
b64451a6142086c7080b3c435804a2e1baaa71e8beb8dbc54160a6323815b68c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / graph_dependence-0.1.0-py3-none-any.whl

Download URL graph_dependence-0.1.0-py3-none-any.whl
Size 14.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7cad3eb4dada382e271716a722edc3914ea5609d5140ccc391044ae1e18c22ac
BLAKE2b-256 checksum
How to use checksums
cea164e958d40ceb016bd21b94b9a5d10d73505dd5e53c7b335de367ac9c7c72
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page