First stable release. Every header outside melon/detail/ and
melon/experimental/ is frozen API for the 1.x series — see
API stability
for the exact scope of the guarantee. All changes below are relative to
1.0.0-alpha.1, the last package published on Conan Center.
The v1.0.0 tag was first cut on 2026-08-28 and re-pointed on 2026-09-05,
before any package was published from it, to a revision that also carries the
following renames. Code written against the earlier snapshot needs:
add_arc({u, v}, …) for add_arc(u, v, …) on a builder with properties;
maps::identity, maps::element<I...> and maps::function for
maps::identity_map, maps::element_map<I...> and maps::map;
melon/maps/constant.hpp and melon/maps/element.hpp for maps::true_map /
maps::false_map and maps::element; melon/numeric/ for semiring.hpp and
geometry.hpp; a mapping rather than a callable as
alias_method_sampler's probability map; and graph_ref_view,
graph_owning_view, graph_view_base, views::graph_all,
views::graph_all_t and graph_for for their undirected_graph_* twins,
which are gone along with melon/views/undirected_graph_view.hpp; and
melon/graph.hpp for melon/undirected_graph.hpp and
melon/borrowed_graph.hpp, whose contents now sit in the former; and
.r / .g / .b for std::get<0..2> on graphviz_printer::color, an
aggregate instead of a tuple so that color{255, 0, 0} no longer narrows
inside the standard library.
Breaking changes since 1.0.0-alpha.1
- The library namespace is
melon, no longerfhamonic::melon, and the
CMake target ismelon::melon. - The range-v3 dependency is gone: melon is dependency-free and builds on
C++23 standard library ranges. The toolchain floor is GCC 14 / Clang 18
with libstdc++ 14 (GCC 15 / C++26 recommended) and, on Windows, Visual
Studio 2022 17.11 (toolset v14.41). - Algorithms are move-only steppable ranges with a single lifecycle
contract: copying an algorithm object no longer compiles, and
preconditions are asserted in debug builds, never thrown. - Mappings are read through const access —
mappingrequires
const-readability, sostd::mapis not one — and algorithms store the
graphs and maps they are given as views (views::graph_all/
maps::mapping_all): lvalues by reference, rvalues by move. Both
reject const rvalues (asstd::views::alldoes) instead of silently
deep-copying into an owning view overconst Tthat models nothing. - The graph protocol is a customization-point layer that synthesizes
missing operations (out_neighbors,arcs, degrees, counts) from the
primitives a graph type exposes, and it is stricter than the alpha
concepts in two ways:arcs_entrieselements must be tuple-likes of the
shape(arc, (source, target)), and every range- or closure-returning
CPO — the undirectededgesandincidenceincluded — rejects rvalue
graphs at compile time; the result would dangle behind the temporary.
Rvalue support remains available through the borrowed-graph promise
(enable_borrowed_graphinmelon/graph.hpp). Custom graph types
written against the alpha concepts may need their protocol members
reshaped. - The undirected protocol follows suit:
nb_edgesisnum_edges
(has_nb_edgesishas_num_edges);incidence(g, v)yields
(edge, other endpoint)tuple-likes instead of bare edges, so a caller
never re-derives the far endpoint fromedge_endpoints; and a self-loop
is incident at both ends —incidencelists it twice, each time withv
as the other endpoint, anddegreecounts it twice. The last is part of
the concepts, not of any one container: a memberdegreemust agree with
the incidence range it summarises. A custom undirected graph listing a
loop once, or yielding edges alone, needs itsincidencereshaped. static_digraph,static_forward_digraphandmutable_digraphare
aliases of the default instantiation ofbasic_static_digraph<V, A>,
basic_static_forward_digraph<V, A>andbasic_mutable_digraph<V, A>:
the three containers are now class templates over their vertex and arc
handle types (std::unsigned_integral, both defaulting to
unsigned int),std::basic_string/std::stringstyle. A 64-bit arc
type lifts the 2^32 ceiling; a 16-bit type halves every array and map of
a small graph. The containersasserton a vertex or arc count the
handle type cannot represent instead of wrapping. Every existing
spelling of the names keeps compiling; a user-side forward declaration
(class static_digraph;) does not, and never was covered — the API
stability page now says so.static_digraph_builder::add_arctakes the endpoints as one
std::pair<vertex, vertex>—add_arc({u, v}, length)instead of
add_arc(u, v, length)— so a call shows where the topology stops and
the properties begin; three positional integers did not. A builder
without properties keeps the plainadd_arc(u, v). Newadd_arcs
appends a range of endpoint pairs, or of(pair, properties...)
tuple-likes such asstd::views::zip(endpoints, lengths), reserving up
front for sized ranges.melon/utility/semiring.hppmoved tomelon/numeric/semiring.hpp
(pure-math substrate, not graph tooling; the declared names are
unchanged), andmaps::true_map/maps::false_mapmoved out of
melon/mapping.hppintomelon/maps/constant.hppas the<true>/
<false>aliases of the newmaps::constant<V>.concurrent_dijkstrasis renamedcompeting_dijkstras, and its
relaxation steps are private, like every algorithm's.views::complete_digraphrequires unsigned vertex and arc types: signed
handles broke its wraparound-empty incidence subranges.shortest_path_semiring<T>::infty(andminimum_spanning_tree_semiring<T>'s)
isstd::numeric_limits<T>::infinity()whenTis IEEE floating point,
max()as before otherwise: unlikemax(),infis exact under further
arithmetic, so a "no path" value can no longer be improved by code
combining it with lengths. Observable wherever an unreached vertex's
dist()was compared againstmax().mutable_digraph's vertex and arc iterators are no longer
cross-comparable: the handle types share one id representation, so the
shared base's equality compared cursors from unrelated lists — and
answered true on equal ids. Each iterator now defines its own equality.priority_queueprobestop()andempty()on aconst Q, and
semiringprobesplus/lesson const values — matching how every
algorithm actually calls them, so a heap with non-const reads or a
mutable-lvalue-onlyplus_tis now rejected by the concept instead of
hard-erroring inside the algorithm that admitted it.
Other changes since 1.0.0-alpha.1
- New algorithms:
a_star(heuristic consistency asserted at every
examined arc in debug builds; deliberately no defaulted zero heuristic —
that instance is dijkstra),bellman_fordandbellman_ford_moore
(negative lengths, with opt-in negative-cycle detection and retrieval
through thedetect_negative_cyclestraits flag),
biobjective_dijkstra,connected_components(with
weakly_connected_components(g), which undirects a digraph and runs it),
network_voronoi,traversal_forest,network_simplex(below), and
bentley_ottmannpromoted out ofmelon/experimental/. network_simplex: exact minimum-cost flow by the primal network simplex,
in the implementation lineage of LEMON's — but with no renumbering, no
problem copy, and no materialized artificial root: it runs in the
graph's own id spaces, keeps every piece of state in the graph's own
maps (the root is as implicit as its virtual arcs, marked by a vertex
being its own parent in the basis tree), and reads capacities, costs and
supplies live through the given mappings. Steppable one pivot at a time,
reports its verdict through theoptimal()/infeasible()/
unbounded()predicates, and exposes the dual
potentials alongside the flow (flows_map()/potentials_map(), with
terminal move-out). Requiresnum_vertices/num_arcsand the map
factories; neither vertex nor arc ids need be integral — any copyable,
equality-comparable id type the factories and mappings accept runs, so a
mutable_digraphwith id holes from removals qualifies (the
entering-arc search walks the graph's ownarcs()range through a
resumable cursor), and so does a graph whose handles are structs. Arc
endpoints are delegated toarc_source/arc_targetwhere the graph
answers them, so an arc-list graph with map factories qualifies too. The
entering-arc pivot rule is selectable through the traits
(pivot_rules::block_search— the default —first_eligibleand
best_eligible, each carrying its own tuning constants; custom rules
plug in through a small search-context interface), along with an
arc_mixingflag providing LEMON's mixed sampling order as a strided
scan over random-access arc ranges (off by default; see the traits
documentation for when it pays).- New utilities:
numeric/bounded_value,numeric/rationaland
numeric/geometry,alias_method_sampler(its probability map is a
mapping: a vector indexed by the item or a graph's vertex/arc map passes
directly, callables need no wrapping, and the sampled value type deduces
decayed),make_static_digraph, andversion.hpp— the
MELON_VERSIONmacros both build systems parse. - New maps under
melon/maps/:maps::constant<V>(an empty map
answering the NTTPVfor every key),maps::element<I...>(a
std::getchain into the key),maps::transform(m, f)(a mapping
viewed through a value projectionf(m[k]), the base routed through
maps::mapping_all— lvalue referenced, rvalue owned, view passed
through; a reference-returning projection keeps the base's writability);
maps::identityandmaps::functionstay inmelon/mapping.hpp. - Map roles: every map an algorithm creates is requested under a role
(dijkstra_roles::heap_index,dinitz_roles::flow, … — one
<algorithm>_rolesstruct per algorithm), carried as a defaulted second
template parameter ofcreate_vertex_map/create_arc_map/
create_edge_map, ofvertex_map_t/arc_map_t/edge_map_tand of
has_vertex_map/has_arc_map/has_edge_map;melon::default_role
is what a request naming no role carries. A factory with one template
parameter answers every role with its standard map, so no container or
user graph changes; a two-parametercreate_vertex_map<T, Role>answers
per role and is probed first. Every forwarding view (graph_ref_view,
graph_owning_view,reverse,subgraph,undirect, thewith_*_maps
views) forwards the role it receives. Roles are extension
points with a weaker stability guarantee than the main API. - One wrapper for both protocols:
graph_ref_view,graph_owning_viewand
views::graph_allaccept directed and undirected graphs, and graphs
modelling both protocols, and forward
every protocol half the wrapped type models, as do thewith_*_maps
views andviews::reverse;graph_foris the one constructor
constraint. A type modelling bothgraphandundirected_graph— an
undirected container reading each edge as two arcs — therefore stays
both through the wrappers, anddijkstraandkruskalread the same
object.views::subgraphkeeps the directed half only, having no edge
filter. The forwarding itself is public:graph_view_interface<G, Stored>
(and the one-halfdirected_graph_view_interface/
undirected_graph_view_interface) is the base a user adaptor derives from
to forward everything and redeclare what it changes,view_interface
style.has_vertex_creation,has_is_valid_vertexand
has_vertex_removalare gated onhas_vertices, no longer ongraph. views::as_directed/views::as_undirected
(melon/views/graph_view.hpp): restrict such a graph to one half — the
identity on a graph with nothing to hide — for the caller who must pick,
before an overload set split ongraph_view/undirected_graph_view.views::with_vertex_maps,views::with_arc_mapsand
views::with_edge_maps(melon/views/with_maps.hpp): factory-enhancing
views that answer the map factories from caller-supplied lambdas and
forward everything else. A graph without factories runs every algorithm
from a single lambda ([]<typename T>(auto role, const auto & g) { … });
a graph with them can have particular maps redirected into storage the
caller already owns, Boost.Graph interior-property style. A lambda may
declare the bare form, the filled form (taking the default value) or
both, the missing one being derived; the first lambda serving a request
owns it, so role-specific lambdas go before the generic one; a request no
lambda serves — a generic lambda without an explicit<typename T>, a
mutablelambda — falls through to the wrapped graph's factory.
Pipe-composable; directed and undirected.updatable_d_ary_heap::index_map_typeand theheap_index_map_agrees
concept: each updatable-heap algorithmstatic_asserts that a traits
heap publishing the alias is built on the very map the graph answers for
the algorithm's heap-index role. The default traits ofdijkstra,
a_star,bidirectional_dijkstra,competing_dijkstrasand
network_voronoispell their heap's index map through the role-aware
alias; a custom traits struct hard-coding
vertex_map_t<static_digraph, std::size_t>still compiles over a
container, and fails thestatic_assert— rather than silently indexing
a private copy — over a view answering the role with another map type.- Bound adaptor closures (
g | views::subgraph(f)and thewith_*_maps
ones) are constrained on the adaptor producing a view rather than on
melon::graph, so undirected graphs pipe into them too. - Experimental, with no stability guarantee:
experimental::views::add_virtual_vertices
(melon/experimental/add_virtual_vertices.hpp) augments a graph with
countfresh vertices by extending the integral vertex id space past
its largest id — dense ids not required, arcs untouched, empty
incidence, the vertex-map factory covering them, stacked views minting
past each other's virtual ids;experimental::views::unify_sources
(melon/experimental/unify_sources.hpp) augments a dense-id graph with
a virtual root vertex and one virtual arc per given source — the
supersource construction of multi-source flow problems — by extending
the integer id spaces, its map factories covering the virtual elements
and the inward interface following the wrapped graph. - MSVC support: Visual Studio 2022 17.11 (toolset v14.41) and newer build
the library and pass the full test suite, exercised by an MSVC 17.11 /
C++23 CI job on Windows. One documented MSVC front-end limitation
remains for graphs that provide their map factories as free functions in
translation units with a file-scopeusing namespace melon— see the
installation page's MSVC note.detail/prefetch.hppemits real prefetch
hints under MSVC on x86-64. - Semirings may promise arithmetic absorption through an optional
infty_is_absorbingmember, read via thehas_absorbing_inftyvariable
template;bellman_forddrops its per-arc unreached-source guard when
the promise holds, making the floating-point arc sweep branchless. - Concept honesty — probes answer
falsewhere they used to hard-error,
and admit what the algorithms can actually use:graph<G>answersfalsefor a graph whose vertex or arc handles
are move-only (thearcs_entriessynthesizers constrain on
copy_constructiblehandles).- The map-creation requirement (
has_vertex_map/has_arc_map)
lives on the algorithms' class-level requires-clauses and default
traits, sostd::constructible_fromand CTAD probes on a graph
without map factories answerfalse. - The containers' and
complete_digraph's map factories are
constrained on what construction does with the value type
(default-init, plus fill-assign for the default-value form), and the
views' delegating factories on the wrapped graph's factory for the
exact value type requested. - Factory-created maps need only model
output_mapping: the
algorithms fill and reset through an internal helper that uses a
memberfill(value)when the map offers one and writes per key
otherwise, so a conforming map without.fillruns every algorithm. output_mappingno longer constrains the type of the write
expression and writes the probe's value from an rvalue with a
forwarded key: const-assignable proxies in the C++23vector<bool>
style (static_filter_mapis an output mapping, so a bit-packed
subgraph filter keepsdisable_vertex/enable_vertex), move-only
value types and rvalue-only-key subscripts are admitted; computed
maps stay rejected.- The
cartesian_point,cartesian_segmentandcartesian_line
concepts are arity-exact (std::tuple_sizeof 2, 2 and 3) over
cartesian_coordinateleaves — an==- and<-comparable scalar
that is not itself tuple-like — so the three categories are pairwise
disjoint andpoint_on_line(lineA, lineB)is a constraint failure
rather than a meaningless predicate. The extent checks
(point_on_segment,segments_intersectionand the overlaps) take a
common_cartesian_segment, whose endpoints share one point type, in
the spirit ofstd::ranges::common_range;segment_to_linekeeps
accepting mixed endpoints.
- Correctness fixes from the audits preceding this release, notably:
complete_digrapharc-id arithmetic past 2³² arcs,dinitzrecursion
overflow on million-vertex augmenting paths and equal-terminal looping,
biobjective_dijkstradominated-label yields,knapsack_bnbbound
overflow,rationalcomparison categories,disjoint_sets::mergestale
representatives,static_filter_map's const-assignable bit proxy,
alias_method_samplerboundary draws,bidirectional_dijkstrabinding
incidence ranges throughconst auto &(which fails for filter- and
transform-shaped ranges that are not const-iterable), and
mutable_digraphdefault-constructed iterators comparing unequal to the
end sentinel (a value-initialized incidence or vertex range walked a
null structure instead of being empty). - Consistency sweeps: noexcept clauses measure what accessors actually
return, the concept mirrors match the CPO detection they mirror
(priority_queueasksmovable+default_initializableinstead of
semiregular), and the synthesizedarcs()/arcs_entries()join the
same incidence direction on an equal-rank tie.