-
-
Notifications
You must be signed in to change notification settings - Fork 259
Add AdjacencyList python wrapper
#3509
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
Changes from 6 commits
468f8a2
2310b1c
b5f508f
cb294e3
a0602b7
5780928
620b60f
0c6b4f1
b56ee8e
65c56a8
1d47a97
447bbdf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| # Copyright (C) 2021 Garth N. Wells | ||
| # Copyright (C) 2021-2024 Garth N. Wells and Paul T. Kühner | ||
| # | ||
| # This file is part of DOLFINx (https://www.fenicsproject.org) | ||
| # | ||
|
|
@@ -7,7 +7,10 @@ | |
|
|
||
| from __future__ import annotations | ||
|
|
||
| from typing import Optional, Union | ||
|
|
||
| import numpy as np | ||
| import numpy.typing as npt | ||
|
|
||
| from dolfinx import cpp as _cpp | ||
| from dolfinx.cpp.graph import partitioner | ||
|
|
@@ -28,10 +31,66 @@ | |
| pass | ||
|
|
||
|
|
||
| __all__ = ["adjacencylist", "partitioner"] | ||
| __all__ = ["AdjacencyList", "adjacencylist", "partitioner"] | ||
|
|
||
|
|
||
| class AdjacencyList: | ||
| _cpp_object: Union[_cpp.la.AdjacencyList_int32, _cpp.la.AdjacencyList_int64] | ||
|
|
||
| def __init__(self, cpp_object: Union[_cpp.la.AdjacencyList_int32, _cpp.la.AdjacencyList_int64]): | ||
| """Creates a Python wrapper for the exported adjacency list class. | ||
|
|
||
| Note: | ||
| This constructor does not create a new adjacency list, see :func:`adjacencylist` for | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| that. | ||
|
|
||
| Args: | ||
| The underlying cpp instance that this object will wrap. | ||
| """ | ||
| self._cpp_object = cpp_object | ||
|
|
||
| def links(self, node: Union[np.int32, np.int64]) -> npt.NDArray[Union[np.int32, np.int64]]: | ||
| """Retrieve the links of a node. | ||
|
|
||
| Args: | ||
| Node to retrieve the connectitivty of. | ||
|
|
||
| Returns: | ||
| Neighbors of the node. | ||
| """ | ||
| return self._cpp_object.links(node) | ||
|
|
||
| def adjacencylist(data: np.ndarray, offsets=None): | ||
| @property | ||
| def array(self) -> npt.NDArray[Union[np.int32, np.int64]]: | ||
| """Array representation of the adjacency list. | ||
|
|
||
| Returns: | ||
| Flattened array representation of the adjacency list. | ||
| """ | ||
| return self._cpp_object.array | ||
|
|
||
| @property | ||
| def offsets(self) -> npt.NDArray[np.int32]: | ||
| """Offsets for each node in the :func:`array`. | ||
|
|
||
| Returns: | ||
| Array of indices with shape `(num_nodes+1)`. | ||
| """ | ||
| return self._cpp_object.offsets | ||
|
|
||
| @property | ||
| def num_nodes(self) -> np.int32: | ||
| """Number of nodes in the adjacency list. | ||
|
|
||
| Returns: | ||
| Number of nodes. | ||
| """ | ||
| return self._cpp_object.num_nodes | ||
|
|
||
|
|
||
| def adjacencylist( | ||
| data: npt.NDArray[Union[np.int32, np.int64]], offsets: Optional[npt.NDArray[np.int32]] = None | ||
| ) -> AdjacencyList: | ||
| """Create an AdjacencyList for int32 or int64 datasets. | ||
|
|
||
| Args: | ||
|
|
@@ -42,15 +101,9 @@ def adjacencylist(data: np.ndarray, offsets=None): | |
|
|
||
| Returns: | ||
| An adjacency list. | ||
|
|
||
| """ | ||
| if offsets is None: | ||
| try: | ||
| return _cpp.graph.AdjacencyList_int32(data) | ||
| except TypeError: | ||
| return _cpp.graph.AdjacencyList_int64(data) | ||
| else: | ||
| try: | ||
| return _cpp.graph.AdjacencyList_int32(data, offsets) | ||
| except TypeError: | ||
| return _cpp.graph.AdjacencyList_int64(data, offsets) | ||
| # Switch to np.isdtype(data.dtype, np.int32) once numpy >= 2.0 is enforced | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| is_32bit = data.dtype == np.int32 | ||
|
schnellerhase marked this conversation as resolved.
Outdated
|
||
| cpp_t = _cpp.graph.AdjacencyList_int32 if is_32bit else _cpp.graph.AdjacencyList_int64 | ||
| cpp_object = cpp_t(data, offsets) if offsets is not None else cpp_t(data) | ||
| return AdjacencyList(cpp_object) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So we need a guard for invalid input style (ie np.floating), or do we think the general nanobind error is sufficient? Usually the nanobind type arrays aren’t very expressive when it comes to dtype.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Defending against such calls would require quite a bit of additional logic. It doesn't end there if we did that, then we would need for example also checks of the shapes of the arrays. Given that it can not cause a false positive, i.e. if we call with a |
||
Uh oh!
There was an error while loading. Please reload this page.