|
nxpp
Header-only graph utilities on top of Boost Graph Library
|
This document defines the intended long-term shape of the public nxpp API.
It exists to answer two recurring questions:
nxpp::Graphnxpp::Generated-reference companions:
nxpp is a BGL-backed graph wrapper with a NetworkX-inspired surface.
The primary public shape is:
nxpp should not try to force every capability into methods, and it should not try to mirror all of NetworkX one-to-one.
Operations belong on Graph when they primarily:
G[u][v] or G.node(u)[key]Examples:
add_nodeadd_edgeremove_edgeremove_nodeclearneighborssuccessorspredecessorshas_nodehas_edgeget_edge_weightget_node_attr<T>get_edge_attr<T>Attribute-specific note:
G[u][v]["key"] and G.node(u)["key"] is acceptable as part of the graph-local ergonomic surfaceget_*_attr<T> and try_get_*_attr<T> should still be treated as the primary read-oriented API for robust user codeOperations should prefer methods on Graph when they primarily:
GExamples:
bfs_edgesdfs_edgesbreadth_first_searchdepth_first_searchshortest_pathdijkstra_pathdijkstra_shortest_pathsbellman_ford_shortest_pathsconnected_componentsstrongly_connected_componentstopological_sortmaximum_flowminimum_cutmax_flow_min_costdegree_centralityFor this project, user-facing coherence now outranks preserving these as namespace-level calls. That means the long-term primary entry points should be G.algorithm(...) for most existing-graph operations.
Graph generators should remain free functions that return graph values.
Examples:
complete_graphpath_grapherdos_renyi_graphThey are better treated as constructors/factories at namespace scope than as methods on an existing graph instance.
NetworkX-inspired entry points are still useful, especially when they:
But they should be treated as compatibility-friendly wrappers, not as a promise of full NetworkX parity.
That means:
The nxpp:: namespace should now keep only functions that do not belong to the context of one existing graph object.
Examples:
complete_graphpath_grapherdos_renyi_graphThe old nxpp::foo(G, ...) forms for existing-graph operations are deprecated.
Before adding a new public API surface, ask:
If the answer is unclear, prefer the narrower surface.
When the graph can contain parallel edges, the public API should be explicit about whether an operation is:
(u, v) ergonomics without promising stable selection of one particular parallel edgeThe default precise path is the wrapper-managed edge_id surface.
That means:
edge_id(u, v) forms may remain in the API for parity and ergonomics but should be documented as convenience-oriented in multigraphs unless they explicitly guarantee stronger behaviorExamples:
add_edge_with_id(...)edge_ids(...)remove_edge(edge_id)get_edge_attr(edge_id, ...)set_edge_attr(edge_id, ...)get_edge_weight(edge_id)has_edge(u, v)get_edge_weight(u, v)get_edge_attr(u, v, ...)try_get_edge_attr(u, v, ...)G[u][v]G[u][v]["key"]The current codebase is already broadly aligned with this policy:
Graph owns mutation, attributes, proxies, and local lookupsSo the immediate goal is:
nxpp:: focused on functions that do not belong to one graph instance