Skip to content

Commit

Permalink
nx-cugraph: automatically generate tables in README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
eriknw committed Feb 8, 2024
1 parent 9ad7389 commit 04ab590
Show file tree
Hide file tree
Showing 14 changed files with 189 additions and 80 deletions.
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ repos:
language_version: python3
args: [--target-version=py38]
files: ^(python/.*|benchmarks/.*)$
exclude: ^python/nx-cugraph/
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
hooks:
Expand Down
7 changes: 7 additions & 0 deletions ci/test_python.sh
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ python -m nx_cugraph.scripts.print_tree --dispatch-name --plc --incomplete --dif
python -m nx_cugraph.scripts.print_table
popd

rapids-logger "ensure nx-cugraph autogenerated files are up to date"
pushd python/nx-cugraph
make || true
git diff --exit-code .
git checkout .
popd

rapids-logger "pytest cugraph-service (single GPU)"
pushd python/cugraph-service
pytest \
Expand Down
8 changes: 6 additions & 2 deletions python/nx-cugraph/Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Copyright (c) 2023, NVIDIA CORPORATION.
# Copyright (c) 2023-2024, NVIDIA CORPORATION.
SHELL= /bin/bash

.PHONY: all
all: plugin-info lint
all: plugin-info lint readme

.PHONY: lint
lint:
Expand All @@ -15,3 +15,7 @@ lint-update:
.PHONY: plugin-info
plugin-info:
python _nx_cugraph/__init__.py

.PHONY: readme
readme:
python scripts/update_readme.py README.md
12 changes: 6 additions & 6 deletions python/nx-cugraph/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Below is the list of algorithms that are currently supported in nx-cugraph.

### Algorithms

```
<pre>
bipartite
├─ basic
│ └─ is_bipartite
Expand Down Expand Up @@ -170,11 +170,11 @@ tree
├─ is_branching
├─ is_forest
└─ is_tree
```
</pre>

### Generators

```
<pre>
classic
├─ barbell_graph
├─ circular_ladder_graph
Expand Down Expand Up @@ -220,15 +220,15 @@ social
├─ florentine_families_graph
├─ karate_club_graph
└─ les_miserables_graph
```
</pre>

### Other

```
<pre>
convert_matrix
├─ from_pandas_edgelist
└─ from_scipy_sparse_array
```
</pre>

To request nx-cugraph backend support for a NetworkX API that is not listed
above, visit the [cuGraph GitHub repo](https://github.com/rapidsai/cugraph).
8 changes: 4 additions & 4 deletions python/nx-cugraph/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ repos:
- id: pyupgrade
args: [--py39-plus]
- repo: https://github.com/psf/black
rev: 23.12.1
rev: 24.1.1
hooks:
- id: black
# - id: black-jupyter
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.14
rev: v0.2.1
hooks:
- id: ruff
args: [--fix-only, --show-fixes] # --unsafe-fixes]
Expand All @@ -62,7 +62,7 @@ repos:
additional_dependencies: &flake8_dependencies
# These versions need updated manually
- flake8==7.0.0
- flake8-bugbear==24.1.17
- flake8-bugbear==24.2.6
- flake8-simplify==0.21.0
- repo: https://github.com/asottile/yesqa
rev: v1.5.0
Expand All @@ -77,7 +77,7 @@ repos:
additional_dependencies: [tomli]
files: ^(nx_cugraph|docs)/
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.14
rev: v0.2.1
hooks:
- id: ruff
- repo: https://github.com/pre-commit/pre-commit-hooks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ def hits(
resource_handle=plc.ResourceHandle(),
graph=G._get_plc_graph(weight, 1, dtype, store_transposed=True),
tol=tol,
initial_hubs_guess_vertices=None
if nstart is None
else cp.arange(N, dtype=index_dtype),
initial_hubs_guess_vertices=(
None if nstart is None else cp.arange(N, dtype=index_dtype)
),
initial_hubs_guess_values=nstart,
max_iter=max_iter,
normalized=normalized,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ def pagerank(
"graph": G._get_plc_graph(weight, 1, dtype, store_transposed=True),
"precomputed_vertex_out_weight_vertices": None,
"precomputed_vertex_out_weight_sums": None,
"initial_guess_vertices": None
if nstart is None
else cp.arange(N, dtype=index_dtype),
"initial_guess_vertices": (
None if nstart is None else cp.arange(N, dtype=index_dtype)
),
"initial_guess_values": nstart,
"alpha": alpha,
"epsilon": N * tol,
Expand Down
3 changes: 1 addition & 2 deletions python/nx-cugraph/nx_cugraph/classes/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,7 @@ def _get_plc_graph(
"pylibcugraph only supports float16 and float32 dtypes."
)
elif (
edge_array.dtype == np.uint64
and edge_array.max().tolist() > 2**53
edge_array.dtype == np.uint64 and edge_array.max().tolist() > 2**53
):
raise ValueError(
f"Integer value of value is too large (> 2**53): {val}; "
Expand Down
4 changes: 1 addition & 3 deletions python/nx-cugraph/nx_cugraph/classes/multigraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,7 @@ def get_edge_data(
if k not in self.edge_masks or self.edge_masks[k][index]
}
return {
edge_keys[index]
if edge_keys is not None
else index: {
edge_keys[index] if edge_keys is not None else index: {
k: v[index].tolist()
for k, v in self.edge_values.items()
if k not in self.edge_masks or self.edge_masks[k][index]
Expand Down
6 changes: 3 additions & 3 deletions python/nx-cugraph/nx_cugraph/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,9 @@ def key(testpath):
)
if sys.version_info[:2] == (3, 9):
# This test is sensitive to RNG, which depends on Python version
xfail[
key("test_louvain.py:test_threshold")
] = "Louvain does not support seed parameter"
xfail[key("test_louvain.py:test_threshold")] = (
"Louvain does not support seed parameter"
)
if nxver.major == 3 and nxver.minor >= 2:
xfail.update(
{
Expand Down
3 changes: 2 additions & 1 deletion python/nx-cugraph/nx_cugraph/scripts/print_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ def main(path_to_info=None, *, file=sys.stdout):
lines = ["networkx_path,dispatch_name,version_added,plc,is_incomplete,is_different"]
lines.extend(",".join(map(str, info)) for info in path_to_info.values())
text = "\n".join(lines)
print(text, file=file)
if file is not None:
print(text, file=file)
return text


Expand Down
107 changes: 60 additions & 47 deletions python/nx-cugraph/nx_cugraph/scripts/print_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,44 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import re
import sys

import networkx as nx
from nx_cugraph.scripts.print_table import Info, get_path_to_info

from nx_cugraph.scripts.print_table import get_path_to_info

def assoc_in(d, keys, value):
"""Like Clojure's assoc-in, but modifies d in-place."""
inner = d
keys = iter(keys)
key = next(keys)
for next_key in keys:
if key not in inner:
inner[key] = {}
inner = inner[key]
key = next_key
inner[key] = value
return d

def add_branch(G, path, extra="", *, skip=0):
branch = path.split(".")
prev = ".".join(branch[: skip + 1])
for i in range(skip + 2, len(branch)):
cur = ".".join(branch[:i])
G.add_edge(prev, cur)
prev = cur
if extra:
if not isinstance(extra, str):
extra = ", ".join(extra)
path += f" ({extra})"
G.add_edge(prev, path)

def tree_lines(tree, parents=(), are_levels_closing=()):
pre = "".join(
" " if is_level_closing else " │ "
for is_level_closing in are_levels_closing
)
c = "├"
are_levels_closing += (False,)
for i, (key, val) in enumerate(tree.items(), 1):
if i == len(tree): # Last item
c = "└"
are_levels_closing = are_levels_closing[:-1] + (True,)
if isinstance(val, str):
yield pre + f" {c}─ " + val
else:
yield pre + f" {c}─ " + key
yield from tree_lines(val, (parents, *key), are_levels_closing)


def get_extra(
def get_payload(
info,
*,
networkx_path=False,
Expand Down Expand Up @@ -64,7 +79,10 @@ def get_extra(
extra.append("is-incomplete")
if different and info.is_different:
extra.append("is-different")
return extra
extra = ", ".join(extra)
if extra:
extra = f" ({extra})"
return info.networkx_path.rsplit(".", 1)[-1] + extra


def create_tree(
Expand All @@ -80,20 +98,27 @@ def create_tree(
incomplete=False,
different=False,
prefix="",
strip_networkx=True,
):
if path_to_info is None:
path_to_info = get_path_to_info()
if strip_networkx:
path_to_info = {
key: Info(info.networkx_path.replace("networkx.", "", 1), *info[1:])
for key, info in path_to_info.items()
}
if isinstance(by, str):
by = [by]
G = nx.DiGraph()
# We rely on the fact that dicts maintain order
tree = {}
for info in sorted(
path_to_info.values(),
key=lambda x: (*(getattr(x, b) for b in by), x.networkx_path),
):
if not all(getattr(info, b) for b in by):
continue
path = prefix + ".".join(getattr(info, b) for b in by)
extra = get_extra(
payload = get_payload(
info,
networkx_path=networkx_path,
dispatch_name=dispatch_name,
Expand All @@ -103,8 +128,8 @@ def create_tree(
incomplete=incomplete,
different=different,
)
add_branch(G, path, extra=extra, skip=skip)
return G
assoc_in(tree, path.split("."), payload)
return tree


def main(
Expand Down Expand Up @@ -132,45 +157,33 @@ def main(
"different": different,
}
if by == "networkx_path":
G = create_tree(path_to_info, by="networkx_path", **kwargs)
text = re.sub(
r" [A-Za-z_\./]+\.", " ", ("\n".join(nx.generate_network_text(G)))
)
tree = create_tree(path_to_info, by="networkx_path", **kwargs)
text = "\n".join(tree_lines(tree))
elif by == "plc":
G = create_tree(
path_to_info, by=["plc", "networkx_path"], prefix="plc-", **kwargs
)
text = re.sub(
"plc-",
"plc.",
re.sub(
r" plc-[A-Za-z_\./]*\.",
" ",
"\n".join(nx.generate_network_text(G)),
),
tree = create_tree(
path_to_info,
by=["plc", "networkx_path"],
prefix="plc-",
**kwargs,
)
text = "\n".join(tree_lines(tree)).replace("plc-", "plc.")
elif by == "version_added":
G = create_tree(
tree = create_tree(
path_to_info,
by=["version_added", "networkx_path"],
prefix="version_added-",
**kwargs,
)
text = re.sub(
"version_added-",
"version: ",
re.sub(
r" version_added-[-0-9A-Za-z_\./]*\.",
" ",
"\n".join(nx.generate_network_text(G)),
),
).replace("-", ".")
text = "\n".join(tree_lines(tree)).replace("version_added-", "version: ")
for digit in "0123456789":
text = text.replace(f"2{digit}-", f"2{digit}.")
else:
raise ValueError(
"`by` argument should be one of {'networkx_path', 'plc', 'version_added' "
f"got: {by}"
)
print(text, file=file)
if file is not None:
print(text, file=file)
return text


Expand Down
Loading

0 comments on commit 04ab590

Please sign in to comment.