Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions D3128_Algorithms/src/dijkstra_heap_tags.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Heap-selector tag: use std::priority_queue with lazy deletion (default).
// Heap entries may grow to O(E); stale entries are skipped at pop time.
struct use_default_heap {};

// Heap-selector tag: use an indexed d-ary heap with true decrease-key.
// Heap size is bounded by O(V); no stale pops.
// @tparam Arity Children per node (default 4, matching Boost's d_ary_heap_indirect).
template <size_t Arity = 4>
struct use_indexed_dary_heap {
static constexpr size_t arity = Arity;
};
2 changes: 2 additions & 0 deletions D3128_Algorithms/src/dijkstra_shortest_dists.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ template <adjacency_list G,
class Visitor = empty_visitor,
class Compare = less<distance_fn_value_t<DistanceFn, G>>,
class Combine = plus<distance_fn_value_t<DistanceFn, G>>,
class Heap = use_default_heap,
class Alloc = allocator<byte>>
requires distance_fn_for<DistanceFn, G> &&
basic_edge_weight_function<G, WF, distance_fn_value_t<DistanceFn, G>, Compare, Combine>
Expand All @@ -17,4 +18,5 @@ constexpr void dijkstra_shortest_distances(
Visitor&& visitor = empty_visitor(),
Compare&& compare = less<distance_fn_value_t<DistanceFn, G>>(),
Combine&& combine = plus<distance_fn_value_t<DistanceFn, G>>(),
Heap heap_tag = Heap{},
const Alloc& alloc = Alloc());
2 changes: 2 additions & 0 deletions D3128_Algorithms/src/dijkstra_shortest_dists_multi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ template <adjacency_list G,
class Visitor = empty_visitor,
class Compare = less<distance_fn_value_t<DistanceFn, G>>,
class Combine = plus<distance_fn_value_t<DistanceFn, G>>,
class Heap = use_default_heap,
class Alloc = allocator<byte>>
requires distance_fn_for<DistanceFn, G> &&
convertible_to<range_value_t<Sources>, vertex_id_t<G>> &&
Expand All @@ -19,4 +20,5 @@ constexpr void dijkstra_shortest_distances(
Visitor&& visitor = empty_visitor(),
Compare&& compare = less<distance_fn_value_t<DistanceFn, G>>(),
Combine&& combine = plus<distance_fn_value_t<DistanceFn, G>>(),
Heap heap_tag = Heap{},
const Alloc& alloc = Alloc());
2 changes: 2 additions & 0 deletions D3128_Algorithms/src/dijkstra_shortest_paths.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ template <adjacency_list G,
class Visitor = empty_visitor,
class Compare = less<distance_fn_value_t<DistanceFn, G>>,
class Combine = plus<distance_fn_value_t<DistanceFn, G>>,
class Heap = use_default_heap,
class Alloc = allocator<byte>>
requires distance_fn_for<DistanceFn, G> &&
predecessor_fn_for<PredecessorFn, G> &&
Expand All @@ -20,4 +21,5 @@ constexpr void dijkstra_shortest_paths(
Visitor&& visitor = empty_visitor(),
Compare&& compare = less<distance_fn_value_t<DistanceFn, G>>(),
Combine&& combine = plus<distance_fn_value_t<DistanceFn, G>>(),
Heap heap_tag = Heap{},
const Alloc& alloc = Alloc());
2 changes: 2 additions & 0 deletions D3128_Algorithms/src/dijkstra_shortest_paths_multi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ template <adjacency_list G,
class Visitor = empty_visitor,
class Compare = less<distance_fn_value_t<DistanceFn, G>>,
class Combine = plus<distance_fn_value_t<DistanceFn, G>>,
class Heap = use_default_heap,
class Alloc = allocator<byte>>
requires distance_fn_for<DistanceFn, G> &&
predecessor_fn_for<PredecessorFn, G> &&
Expand All @@ -22,4 +23,5 @@ constexpr void dijkstra_shortest_paths(
Visitor&& visitor = empty_visitor(),
Compare&& compare = less<distance_fn_value_t<DistanceFn, G>>(),
Combine&& combine = plus<distance_fn_value_t<DistanceFn, G>>(),
Heap heap_tag = Heap{},
const Alloc& alloc = Alloc());
2 changes: 2 additions & 0 deletions D3128_Algorithms/src/mst.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ template <adjacency_list G,
class WF = function<distance_fn_value_t<WeightFn, G>(const remove_reference_t<G>&,
const edge_t<G>&)>,
class CompareOp = less<distance_fn_value_t<WeightFn, G>>,
class Heap = use_default_heap,
class Alloc = allocator<byte>>
requires distance_fn_for<WeightFn, G> &&
is_arithmetic_v<distance_fn_value_t<WeightFn, G>> &&
Expand All @@ -43,4 +44,5 @@ auto prim(G&& g,
PredecessorFn&& predecessor,
WF&& weight_fn = [](const auto& gr, const edge_t<G>& uv) { return edge_value(gr, uv); },
CompareOp compare = less<distance_fn_value_t<WeightFn, G>>(),
Heap heap_tag = Heap{},
const Alloc& alloc = Alloc());
75 changes: 59 additions & 16 deletions D3128_Algorithms/tex/algorithms.tex
Original file line number Diff line number Diff line change
Expand Up @@ -748,8 +748,24 @@ \subsection{Dijkstra Shortest Paths and Shortest Distances}
%\caption{Algorithm Example}
\end{table}

Note that complexity may be $\mathcal{O}(|E| + |V|\log{|V|)}$ for certain implementations that use a Fibonacci heap
instead of a binary heap implemented with \tcode{std::priority_queue}.
Two heap-selector tag types control the internal priority queue strategy and are passed as the
\tcode{Heap} template argument:
{\small
\lstinputlisting[texcl=false]{D3128_Algorithms/src/dijkstra_heap_tags.hpp}
}

The \tcode{Heap} template parameter selects the internal priority queue strategy at compile time.
Two heap-selector tags are provided:
\begin{itemize}
\item \tcode{use_default_heap} (default) --- uses \tcode{std::priority_queue} with lazy deletion.
Stale entries are skipped at pop time; the heap may grow to $\mathcal{O}(|E|)$ in the worst case.
Recommended for sparse graphs ($|E|/|V| \lesssim 4$), grid-like topologies, and path graphs.
\item \tcode{use_indexed_dary_heap<Arity>} --- uses an indexed $d$-ary heap with true decrease-key.
Heap size is bounded by $\mathcal{O}(|V|)$; no stale pops.
Recommended for dense or hub-heavy graphs ($|E|/|V| \gtrsim 8$).
\tcode{Arity=8} is the recommended setting on x86\_64 for high-$|E|/|V|$ workloads;
\tcode{Arity=4} matches Boost's \tcode{d_ary_heap_indirect}.
\end{itemize}

\subsubsection{Dijkstra Shortest Paths}

Expand Down Expand Up @@ -844,9 +860,12 @@ \subsubsection{Dijkstra Shortest Paths}
\end{itemize}
\pnum\complexity
\begin{itemize}
\item \textbf{Time:} $\mathcal{O}((|E| + |V|)\log{|V|})$ based on using the binary heap in \tcode{std::priority_queue}.
\item \textbf{Space:} $\mathcal{O}(|V|)$ auxiliary --- priority queue and bookkeeping arrays.
\item An implementation may choose to use a Fibonacci heap for a time complexity of $\mathcal{O}(|E| + |V|\log{|V|})$.
\item \textbf{Time:} $\mathcal{O}((|E| + |V|)\log{|V|})$ with \tcode{use_default_heap}
(binary heap via \tcode{std::priority_queue}).
With \tcode{use_indexed_dary_heap<d>} the heap size is bounded by $\mathcal{O}(|V|)$
and each operation costs $\mathcal{O}(\log_{d}{|V|})$.
\item \textbf{Space:} $\mathcal{O}(|V|)$ auxiliary for \tcode{use_indexed_dary_heap};
up to $\mathcal{O}(|E|)$ for \tcode{use_default_heap} due to lazy deletion.
\end{itemize}
\pnum\remarks
\begin{itemize}
Expand All @@ -858,6 +877,11 @@ \subsubsection{Dijkstra Shortest Paths}
the same way (see §\textit{Vertex Property Function Concepts}).
\item Pass \lstinline{_null_predecessor} as \lstinline{predecessor} when predecessor tracking
is not needed (avoids storing results).
\item The \lstinline{Heap} template parameter selects the internal heap implementation.
Pass \tcode{use_default_heap\{\}} (default) for sparse or grid-like graphs;
pass \tcode{use_indexed_dary_heap<Arity>\{\}} for dense or hub-heavy graphs
where many edges trigger distance relaxation.
\tcode{use_indexed_dary_heap<8>} is recommended on x86\_64 for high-$|E|/|V|$ workloads.
\item The optional \lstinline{alloc} parameter supplies an allocator used for
the internal priority queue. Defaults to \tcode{std::allocator<std::byte>}.
Provide a custom allocator (e.g.~a pool allocator) to control the memory
Expand Down Expand Up @@ -953,9 +977,12 @@ \subsubsection{Dijkstra Shortest Distances}
%\pnum\returns \lstinline{void} \\
\pnum\complexity
\begin{itemize}
\item \textbf{Time:} $\mathcal{O}((|E| + |V|)\log{|V|})$ based on using the binary heap in \tcode{std::priority_queue}.
\item \textbf{Space:} $\mathcal{O}(|V|)$ auxiliary --- priority queue and bookkeeping arrays.
\item An implementation may choose to use a Fibonacci heap for a time complexity of $\mathcal{O}(|E| + |V|\log{|V|})$.
\item \textbf{Time:} $\mathcal{O}((|E| + |V|)\log{|V|})$ with \tcode{use_default_heap}
(binary heap via \tcode{std::priority_queue}).
With \tcode{use_indexed_dary_heap<d>} the heap size is bounded by $\mathcal{O}(|V|)$
and each operation costs $\mathcal{O}(\log_{d}{|V|})$.
\item \textbf{Space:} $\mathcal{O}(|V|)$ auxiliary for \tcode{use_indexed_dary_heap};
up to $\mathcal{O}(|E|)$ for \tcode{use_default_heap} due to lazy deletion.
\end{itemize}
\pnum\remarks
\begin{itemize}
Expand All @@ -964,6 +991,11 @@ \subsubsection{Dijkstra Shortest Distances}
\item \tcode{DistanceFn} must satisfy \tcode{distance_fn_for<DistanceFn,G>}. Wrap a
\tcode{std::vector} or \tcode{std::unordered_map} with \tcode{container_value_fn}
(see §\textit{Vertex Property Function Concepts}).
\item The \lstinline{Heap} template parameter selects the internal heap implementation.
Pass \tcode{use_default_heap\{\}} (default) for sparse or grid-like graphs;
pass \tcode{use_indexed_dary_heap<Arity>\{\}} for dense or hub-heavy graphs
where many edges trigger distance relaxation.
\tcode{use_indexed_dary_heap<8>} is recommended on x86\_64 for high-$|E|/|V|$ workloads.
\item The optional \lstinline{alloc} parameter supplies an allocator used for
the internal priority queue. Defaults to \tcode{std::allocator<std::byte>}.
Provide a custom allocator (e.g.~a pool allocator) to control the memory
Expand Down Expand Up @@ -2168,7 +2200,7 @@ \subsection{Prim Minimum Spanning Tree}
\end{table}

{\small
\lstinputlisting[firstline=28,lastline=46]{D3128_Algorithms/src/mst.hpp}
\lstinputlisting[firstline=28,lastline=48]{D3128_Algorithms/src/mst.hpp}
}

\begin{itemdescr}
Expand Down Expand Up @@ -2220,14 +2252,25 @@ \subsection{Prim Minimum Spanning Tree}
\end{itemize}
\pnum\complexity
\begin{itemize}
\item \textbf{Time:} $\mathcal{O}(|E|\log{|V|})$.
\item \textbf{Space:} $\mathcal{O}(|V|)$ auxiliary --- priority queue and bookkeeping arrays.
\item \textbf{Time:} $\mathcal{O}(|E|\log{|V|})$ with \tcode{use_default_heap}.
With \tcode{use_indexed_dary_heap<d>} the heap size is bounded by $\mathcal{O}(|V|)$
and each operation costs $\mathcal{O}(\log_{d}{|V|})$.
\item \textbf{Space:} $\mathcal{O}(|V|)$ auxiliary for \tcode{use_indexed_dary_heap};
up to $\mathcal{O}(|E|)$ for \tcode{use_default_heap} due to lazy deletion.
\end{itemize}
\pnum\remarks
\begin{itemize}
\item Only produces a spanning tree for the connected component containing \lstinline{seed}.
For disconnected graphs, call \lstinline{prim} once per component with a seed vertex from each component.
\item The \lstinline{Heap} template parameter selects the internal heap implementation
(forwarded to \lstinline{dijkstra_shortest_paths}).
Pass \tcode{use_default_heap\{\}} (default) for sparse or grid-like graphs;
pass \tcode{use_indexed_dary_heap<Arity>\{\}} for dense or hub-heavy graphs.
See the Dijkstra Shortest Paths section for guidance on arity selection.
\item The optional \lstinline{alloc} parameter supplies an allocator used for
the internal priority queue (forwarded to \lstinline{dijkstra_shortest_paths}).
Defaults to \tcode{std::allocator<std::byte>}.
\end{itemize}
\pnum\remarks Only produces a spanning tree for the connected component containing \lstinline{seed}.
For disconnected graphs, call \lstinline{prim} once per component with a seed vertex from each component.
The optional \lstinline{alloc} parameter supplies an allocator used for
the internal priority queue (forwarded to \lstinline{dijkstra_shortest_paths}).
Defaults to \tcode{std::allocator<std::byte>}.
%\pnum\errors
\end{itemdescr}

Loading