Add FixedGraph constexpr fixed-capacity graph container#202
Conversation
qxlsz
commented
Sep 20, 2025
- Allocation-free directed/undirected, weighted/unweighted graph.
- Algorithms: BFS/DFS, shortest paths (BFS/Dijkstra/Bellman-Ford), MST (Kruskal), SCC, topo sort, coloring, bipartite, Eulerian, cycle detection, centrality, density, diameter, clustering, complement/union/intersection.
- Utilities: has_node, find_node_index, remove_edge, edge_count, generators (create_complete_graph, create_cycle_graph), serialization.
- README updated with examples.
90efe4c to
62a9644
Compare
This adds a new template parameter to use a shared edge pool instead of per-node vectors, saving space when node degrees vary.
Bobobalink
left a comment
There was a problem hiding this comment.
I fear that Alex is going to be very resistant to merging this in, he has really high standards for what makes it into fixed-containers and I'm not sure this really fits the "vibe" of what goes in here...
| bool DIRECTED = true, | ||
| bool USE_MATRIX = false, | ||
| bool USE_POOL = false, |
There was a problem hiding this comment.
you should create separate "graph storage" classes with a minimal interface and then pass one of those as a template parameter into this class instead of mixing three disjoint implementations into one class
| adjacency_storage_.push_back({to, std::forward<Args>(args)...}); | ||
| } | ||
| // Update node's range | ||
| node_ranges_[from].second = insert_pos + 1; |
There was a problem hiding this comment.
won't this cause massive problems if I do, e.g.
add_edge(1, 2);
add_edge(2, 3);
add_edge(1, 4); // oops, now `1` has eaten the ->3 edge| } | ||
|
|
||
| // Shortest path using BFS (for unweighted graphs) | ||
| constexpr FixedVector<NodeIndex, MAX_NODES> shortest_path(NodeIndex start, NodeIndex end) const |
There was a problem hiding this comment.
All of these graph algorithms that return large structures (e.g. FixedVector, other graphs, etc.) would be significantly more useful if they instead took out<> parameters so the users aren't forced to incur a copy in many use-cases.
|
|
||
| // Serialize graph to binary format | ||
| template <typename OutputIterator> | ||
| constexpr OutputIterator serialize(OutputIterator out) const |
There was a problem hiding this comment.
Is there a strong justification for doing this (de)serialization by hand instead of using an existing format like flatbuffers or Avro? What is the use-case here?