Skip to content

Bglws2#27

Merged
pratzl merged 17 commits intomainfrom
bglws2
Apr 30, 2026
Merged

Bglws2#27
pratzl merged 17 commits intomainfrom
bglws2

Conversation

@pratzl
Copy link
Copy Markdown
Collaborator

@pratzl pratzl commented Apr 29, 2026

BGL interop improvements

Phil Ratzloff added 17 commits April 29, 2026 12:37
… bgl_graph_adapt_goal.md: defines requirements, scope, acceptance criteria\n for adapting BGL graphs to work with graph-v3 views and algorithms\n- bgl_graph_adapt_strategy.md: technical strategy covering CPO adaptation\n surface, iterator wrapping, property bridge, performance, and risks\n- bgl_graph_adapt_plan.md: phased implementation plan (phases 0-9) with\n file-level instructions, code sketches, and verification commands"
- Add placeholder headers: graph_adaptor.hpp, bgl_edge_iterator.hpp,
  property_bridge.hpp under include/graph/adaptors/bgl/
- Add tests/adaptors/CMakeLists.txt with conditional TEST_BGL_ADAPTOR
  option and Boost header auto-detection
- Add 8 stub test files (SUCCEED() placeholders) for each adaptor phase
- Wire tests/adaptors into tests/CMakeLists.txt via add_subdirectory

All stub tests pass: graph3_bgl_adaptor_tests 1/1.
Implement bgl_edge_iterator — a thin wrapper that adds iterator_concept
to BGL's boost::iterator_facade-based iterators, satisfying
std::forward_iterator for C++20 ranges.

- Conditional operator-> via requires clause (only when reference is
  an lvalue reference; adjacency_list returns proxy, CSR returns lvalue)
- base() accessor for underlying BGL iterator

Tests verify:
- static_assert forward_iterator for adjacency_list and CSR wrappers
- Reference type preservation from underlying BGL iterators
- Runtime iteration matches boost::target() results
- subrange of wrapped iterators models forward_range
- CSR operator-> returns same address as &*it
Phase 2 — graph_adaptor and core ADL free functions:
- graph_adaptor<BGL_Graph>: non-owning wrapper with CTAD
- ADL vertices(), num_vertices(), edges() (out_edges CPO), target_id(),
  source_id() in namespace graph::bgl
- graph_bgl_adl namespace with call_* helpers outside namespace graph to
  avoid CPO objects blocking ADL (C++ [basic.lookup.argdep]/3)

Phase 3 — concept satisfaction:
- static_assert adjacency_list<adapted_t> and index_adjacency_list<adapted_t>
- Runtime vertexlist() smoke test confirms descriptor wiring is correct

All 25 assertions in 15 test cases pass.
Implement property_bridge.hpp with three bridge types:

- bgl_readable_property_map_fn: wraps any BGL readable property map into
  a graph-v3 edge_value_function/vertex_value_function callable
- bgl_lvalue_property_map_fn: same but static_asserts that get() returns
  an lvalue reference, enabling write-through for writable property maps
- edge_key_extractor: extracts BGL edge_descriptor from graph-v3 edge
  descriptor via *uv.value()
- make_bgl_edge_weight_fn: convenience factory for edge weight maps
- vertex_vector_property_fn / make_vertex_id_property_fn: wraps
  std::vector<T>& into a (const G&, vertex_id_t) -> T& function for
  Dijkstra distance and predecessor storage

Tests verify:
- Readable map reads correct weights from BGL bundled properties
- Integration with incidence(g, u, evf) view
- Lvalue write-through propagates to underlying BGL graph
- Vector distance and predecessor storage round-trips correctly
- static_assert edge_value_function and basic_edge_weight_function

All 34 assertions in 20 test cases pass.
Tests vertexlist, incidence, neighbors, edgelist, and incidence-with-weight
views on a directed adjacency_list<vecS,vecS,directedS> wrapped in
graph_adaptor.
Two test cases on directed adjacency_list wrapped in graph_adaptor:
- CLRS 5-vertex graph (correct shortest paths 0→3:5 via 0→4→3)
- 4-vertex sanity-check graph

Fixes incorrect expected values for dist[3] and pred[3] that had assumed
the 0→2→1→3=9 path rather than the shorter 0→4→3=5 path.
graph_adaptor.hpp:
- Add call_in_edges() helpers in graph_bgl_adl namespace
- Add in_edges(graph_adaptor<G>, u) ADL functions (mutable + const)
  constrained on traversal_category convertible to bidirectional_graph_tag
  (covers both bidirectionalS and undirectedS)

test_bgl_bidirectional.cpp:
- static_assert bidirectional_adjacency_list<adapted_bidir_t>
- static_assert index_bidirectional_adjacency_list<adapted_bidir_t>
- static_assert bidirectional_adjacency_list<adapted_undir_t>
- in_edges correctness test for bidirectionalS (source/target IDs)
- dijkstra on bidirectionalS
- in_edges == out_edges degree test for undirectedS
- edgelist view on undirectedS (10 directed entries, 5 unique edges)
- dijkstra on undirectedS cross-checked against BGL's own dijkstra
Bug fix (affects all graph types):
- graph_adaptor.hpp: target_id/source_id now copy *uv.value() into a local
  variable instead of binding const& to it. CSR's csr_out_edge_iterator
  dereferences to a reference to its own m_edge member, so uv.value() (a
  temporary iterator copy) was producing a dangling reference.
- property_bridge.hpp: edge_key_extractor::operator() changed from
  decltype(auto) to auto to likewise avoid returning a dangling reference
  to a temporary iterator member.

test_bgl_csr.cpp:
- static_assert index_adjacency_list<adapted_csr_t>
- vertexlist view (5 vertices)
- incidence view (out-edge target sets for vertices 0 and 2)
- edgelist view (all 9 edges, sorted and compared)
- dijkstra_shortest_paths with hand-verified CLRS distances
- dijkstra cross-check against BGL's own dijkstra_shortest_paths
Implements graph::adaptors::filtered_graph<G, VertexPredicate, EdgePredicate>,
a non-owning adaptor that filters vertices and edges during traversal.

Design:
- filtered_graph delegates begin()/end()/size()/operator[] to the underlying
  graph so it satisfies forward_range (CPO _has_inner_value_pattern for vertices)
- edges(fg, u) ADL function returns subrange<filtering_iterator<...>> with
  self-contained predicate — avoids std::views::filter iterator dangling issue
  (filter_view iterators hold a back-pointer to their parent view)
- filtering_iterator stores predicate in std::optional with custom copy/move
  assignment (lambdas are not assignable) to satisfy semiregular constraint
- keep_all sentinel predicate accepts everything (zero overhead via [[no_unique_address]])
- filtered_vertices(fg) convenience function for lazy filtered vertex iteration

Tests: 5 test cases covering keep_all passthrough, vertex predicate,
edge predicate, filtered_vertices, and a Dijkstra placeholder.
All 4849 tests pass.
I/O subsystem (include/graph/io/):
- dot.hpp: write_dot()/read_dot() with std::format-based auto-labeling
- graphml.hpp: write_graphml()/read_graphml() lightweight XML handling
- json.hpp: write_json()/read_json() self-contained JGF-inspired format
- detail/common.hpp: shared concepts (formattable, has_vertex_value, has_edge_value)
- io.hpp: umbrella header

Generators (include/graph/generators/):
- erdos_renyi, barabasi_albert, grid, path generators
- Extracted from benchmark fixtures to public headers

Tests: 19 I/O tests + 6 generator tests (4874 total, all passing)
Updated bgl_migration_strategy.md to reflect implemented status.
New user guides:
- docs/user-guide/generators.md — path, grid, Erdős–Rényi, Barabási–Albert
- docs/user-guide/io.md — DOT, GraphML, JSON read/write with examples

Updated:
- README.md — highlights, feature table, test count (4874)
- docs/index.md — added I/O and generators links
- docs/getting-started.md — next steps links
- docs/status/metrics.md — added generator/IO counts, updated test count
- docs/status/implementation_matrix.md — added Generators, I/O sections,
  updated umbrella headers and namespace tables
New files:
- examples/bgl_adaptor_example.cpp — end-to-end Dijkstra on BGL graph
- docs/user-guide/bgl-adaptor.md — user guide (quick start, property
  bridging, supported types, API reference, limitations)

Updated:
- examples/CMakeLists.txt — conditionally build BGL example
- docs/index.md — added BGL adaptor guide link
- agents/bgl_migration_strategy.md — Section 12 references library adaptor
- agents/bgl_graph_adapt_plan.md — all phases marked complete
- Add bgl_keyed_vertex_iterator adaptor that wraps BGL void* iterators
  and yields pair<VD, monostate>, satisfying graph-v3's keyed_vertex_type
  concept so vertex_descriptor_view can be constructed
- Alias bgl_vertex_range to a sized std::ranges::subrange over the adaptor
- Add has_integral_vertex_id_v trait; vertices() uses if constexpr to
  return an iota range for vecS or a bgl_vertex_range for non-vecS
- Generalize make_vertex_map_property_fn / vertex_map_property_fn to
  accept any associative container (map, unordered_map, etc.)
- Add 11 test cases covering listS and setS: vertex iteration, edges,
  target_id, source_id, vertex_map_property_fn, and edge weights
- Update bgl-adaptor.md: listS/setS now supported; add Non-vecS section
  with map storage guidance; update Known Limitations
@pratzl pratzl merged commit 86b3ed6 into main Apr 30, 2026
11 checks passed
@pratzl pratzl deleted the bglws2 branch April 30, 2026 02:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant