How To Contribute an Algorithm #495
Becheler
started this conversation in
Doc & Onboarding
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
How to Contribue An Algorithm to Boost.Graph
Welcome, and thanks for thinking about adding an algorithm to Boost.Graph! 🎉
This guide is here to help your first algorithm contribution go smoothly. It's a companion to
CONTRIBUTING.md(which covers the mechanics of forking, building, and running tests) and walks through the design conversation that usually happens in the issue thread before any pull request is opened.Working on something smaller (a bug fix, an improvement to an existing algorithm, or a documentation update) ? Chances are you don't need this guide and that
CONTRIBUTING.mdor the issue templates have you covered.How algorithm contributions work
Open-source maintainers are busy people, and Boost.Graph is a large library that evolves carefully. To make the most of everyone's time (yours and the reviewers') algorithm contributions move through three phases, each ending with a clear deliverable that everyone can look at:
Two maintainers handle algorithm contributions, and they come in at different points:
The rest of this guide walks through each phase: what to do, what to share, and how to know you're ready for the next one.
Phase A Design
The goal of Phase A is to converge on a signature that everyone agrees with, before any production code is written. The deliverable at the end of this phase is a Compiler Explorer link with a working draft of the signature you and the maintainer have agreed on. No PR yet.
A.1 Open the feature-request issue
Open an issue and use the Feature Request template. The "I'd like to submit the implementation as a pull request" checkbox is your signal to the maintainers that the issue is also a design thread.
Two things make the rest of the workflow much smoother:
Your minimum viable signature should look very much like the cousin's: same parameter order, same conventions, same helpers (
graph::n_iterations, etc.).Open-ended brainstorming ("should BGL have spectral filters at all?") belongs in a Discussion, not an issue. The issue templates will redirect you there if needed 😉
A.2 Iterate in Compiler Explorer
The agreed medium for early design review is this Compiler Explorer skeleton: https://godbolt.org/z/fq1z9z9T8
Reviewers can then edit the same skeleton, save their own short link, and reply with counter-proposals. This is much faster than a PR and produces a record everyone can compile.
When using the skeleton, set the compiler flag to
-std=c++14: Boost.Graph still builds against C++14, and catching C++17-only constructs (likeif constexpror structured bindings) at this stage saves a round of feedback later.What a productive iteration looks like:
Most first-time contributions iterate quite a few times in the issue before that signal. It's expected and a sign the early review is working: it's the part of the work that's easiest to do collaboratively, so we do as much of it as possible here rather than in a PR review.
A.3 The minimum viable signature
A minimum viable signature has these properties:
(g, rank_map, done, damping, n, rank_map2), you should too, with new parameters inserted in the obvious positions.make_<adjective>_weight_map(g)) so the call site stays readable.niterations" is not exceptional, chances are the user can read the residual after the call and decide.In Phase A, the code in godbolt can use
autoeverywhere it makes sense. Don't bother with concept checks or explicit return types yet. The goal at this point is just to get something that compiles against real Boost, so that feedback is grounded in code that runs:You know Phase A is done when a maintainer signs off on the signature in the issue, typically with a message like "this looks good, please open a PR."
Phase B Working code
The goal of Phase B is to land the agreed signature into the real source tree, in the BGL idiom, with a minimal test that proves it does the right thing. The deliverable is a PR marked as Draft.
B.1 File layout and namespaces
include/boost/graph/<algorithm>.hpp.boost::graph::. Helpers, tag types, and implementation details go inboost::graph::<algorithm>_detail::, not in a top-levelboost::graph::detail(that would collide with other algorithms' helpers).boost::graph::, not in the_detailnamespace. If a user needs tocatchit, they need to be able to spell its type.test/<algorithm>_test.cppwhere you check the happy path, registered intest/Jamfile.v2. It should not be exhaustive at this point to facilitate review: make it short.B.2 C++14, not C++17
Boost.Graph builds against C++14. The following are not available to you:
if constexpr: use tag dispatch on traits instead.auto [a, b] = ...) : usestd::tieor named locals.std::optional: useboost::optional.std::variant: useboost::variant.A tag-dispatch replacement for
if constexprlooks like this:And the call site becomes:
B.3 Spell out the return type
Before opening the PR, every public function must have an explicit return type in its signature. Documentation generation and the public API reference both rely on it;
autoreturns are not acceptable on the public boundary.If the return type depends on a property map's value type, use
property_traits:B.4 Write a minimal test
A minimal test is enough code in
test/<algorithm>_test.cppto exercise the algorithm on a small graph and check the expected output. It doesn't need to cover edge cases or every graph type (that's Phase C). The point is to prove the implementation behaves as designed on a clear, hand-verifiable input.Register the new test in
test/Jamfile.v2and confirm it builds and passes withb2from inside thetest/directory.You know Phase B is done when CI is green on a draft PR (or your fork branch), the test passes, and the implementation matches the signature agreed in Phase A.
Phase C Magic Polish ✨
Phase C is everything that turns a working implementation into something we can confidently merge and maintain. None of these steps require new design decisions: they're about coverage, safety, and discoverability.
C.1 Add concept checks
BOOST_CONCEPT_ASSERTfor every template parameter, at the top of the function body. This is what catches a caller who passes aVertexListGraphwhere you needed anIncidenceGraph, with a readable diagnostic instead of a 200-line template instantiation error.Adding concepts last (rather than first) is deliberate: you don't yet know exactly which graph and map concepts you need until the body is written.
C.2 Expand test coverage
Phase B asserted the happy path on one small graph. Phase C broadens that:
adjacency_list. If the algorithm has meaningful behaviour oncompressed_sparse_row_graphor other graph types, test those too.iterator_property_map,function_property_map, and bundled properties if relevant, to make sure the algorithm really is property-map-generic and not accidentally specialised.C.3 Documentation
doc/<algorithm>.adocfollowing the AsciiDoc layout established in PR Doc migration #491.doc/templates/algorithm.adocshould get you startedC.4 Performance benchmarks (when relevant)
Performance benchmarks aren't required for every algorithm, but for algorithms with non-trivial complexity or competing implementation strategies they make review much easier.
A benchmark doesn't need to be elaborate to be worthy:
If your algorithm is essentially
O(V + E)with no interesting hidden constants, you can skip this and say so in the PR description.The boost-graph-benchmarks repository collects these until we agree on a long-term infrastructure. If you need your benchmark collected, ping @Becheler.
C.5 Mark the PR ready for review
Your draft PR has been open since Phase B. At this point, the action is to mark it as Ready for review (the green button at the bottom of the PR page).
Before you click it, a quick pass over the Phase C items:
CODEOWNERS will auto-assign @jeremy-murphy and @Becheler as reviewers, no need to ping them separately. This is the point where @jeremy-murphy joins the conversation if he has not before.
Appendix A worked example
Issue #493 (personalized PageRank) is a good worked example of this workflow that shows a full design loop: pseudo-code in the issue, reviewer pushes back on enums and visitor design, contributor narrows scope, parties agree on a minimum viable signature, then the implementation gets a Compiler Explorer link before any PR is opened.
Reading it end-to-end is the single best preparation for your own first algorithm contribution.
Good luck! 🍀
Beta Was this translation helpful? Give feedback.
All reactions