From 39e5cb41aafda2a203d3f3adab9569808a577709 Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Fri, 10 Apr 2026 17:56:16 -0400 Subject: [PATCH 1/2] D3128: remove Afforest, add Tarjan's SCC; update r4 revision history --- D3128_Algorithms/tex/revision.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/D3128_Algorithms/tex/revision.tex b/D3128_Algorithms/tex/revision.tex index 5fdfee8..8f9cc99 100644 --- a/D3128_Algorithms/tex/revision.tex +++ b/D3128_Algorithms/tex/revision.tex @@ -71,7 +71,7 @@ \subsection*{\paperno r4} \item Add time and space complexity to every algorithm section. \item New algorithms: \begin{itemize} - \item Afforest Connected Components. + \item Tarjan's Strongly Connected Components. \item Minimum Spanning Tree: Inplace Kruskal. \end{itemize} \item Replace raw container (range) predecessor and distance parameters with function objects From 138c81668a6f9456f8f6986099b046e11e9802f5 Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Sat, 11 Apr 2026 10:29:15 -0400 Subject: [PATCH 2/2] D3128: deduplicate weight concepts; add vertex_value_function; reorder property fn concepts - Move edge_value_function/basic_edge_weight_function/edge_weight_function to Common section only - Add vertex_value_function concept alongside edge_value_function - Reorder: vertex_property_fn_for/vertex_fn_value_t first, then distance/predecessor as aliases - Add predecessor_fn_value_t; simplify distance_fn_for/predecessor_fn_for to alias vertex_property_fn_for - Show concept prototypes inline with descriptive text --- .../src/shortest_paths_helpers.hpp | 55 ++----- D3128_Algorithms/tex/algorithms.tex | 153 +++++++----------- 2 files changed, 79 insertions(+), 129 deletions(-) diff --git a/D3128_Algorithms/src/shortest_paths_helpers.hpp b/D3128_Algorithms/src/shortest_paths_helpers.hpp index 31507cb..765069e 100644 --- a/D3128_Algorithms/src/shortest_paths_helpers.hpp +++ b/D3128_Algorithms/src/shortest_paths_helpers.hpp @@ -1,56 +1,35 @@ -// For exposition only: base concept for any 2-arg edge value function. -template -concept edge_value_function = // For exposition only - std::invocable && !std::is_void_v>; - +// General concept: a callable returning a mutable lvalue reference to any per-vertex property value // For exposition only -template -concept basic_edge_weight_function = // e.g. weight(g, uv) - edge_value_function, edge_t> && - strict_weak_order && - assignable_from, - invoke_result_t&, edge_t>>>; +template +concept vertex_property_fn_for = + invocable&, const vertex_id_t&> && + is_lvalue_reference_v&, const vertex_id_t&>>; +// Type alias: extracts the value type from a vertex property function's return type // For exposition only -template -concept edge_weight_function = // e.g. weight(g, uv) - is_arithmetic_v && - is_arithmetic_v&, edge_t>> && - basic_edge_weight_function, plus>; +template +using vertex_fn_value_t = remove_cvref_t< + invoke_result_t&, const vertex_id_t&>>; -// Type alias: extracts the distance value type from a distance function's return type +// Concept: a callable returning a mutable reference to a per-vertex distance value // For exposition only template -using distance_fn_value_t = remove_cvref_t< - invoke_result_t&, const vertex_id_t&>>; +concept distance_fn_for = vertex_property_fn_for; -// Concept: a callable returning a mutable reference to a per-vertex distance value +// Type alias: extracts the distance value type from a distance function's return type // For exposition only template -concept distance_fn_for = - invocable&, const vertex_id_t&> && - is_lvalue_reference_v&, const vertex_id_t&>>; +using distance_fn_value_t = vertex_fn_value_t; // Concept: a callable returning a mutable reference to a per-vertex predecessor value // For exposition only template -concept predecessor_fn_for = - invocable&, const vertex_id_t&> && - is_lvalue_reference_v&, const vertex_id_t&>>; - -// Concept: a callable returning a mutable lvalue reference to any per-vertex property value -// For exposition only -template -concept vertex_property_fn_for = - invocable&, const vertex_id_t&> && - is_lvalue_reference_v&, const vertex_id_t&>>; +concept predecessor_fn_for = vertex_property_fn_for; -// Type alias: extracts the value type from a vertex property function's return type +// Type alias: extracts the predecessor value type from a predecessor function's return type // For exposition only -template -using vertex_fn_value_t = remove_cvref_t< - invoke_result_t&, const vertex_id_t&>>; +template +using predecessor_fn_value_t = vertex_fn_value_t; // Null predecessor function — used when predecessor tracking is not needed // For exposition only diff --git a/D3128_Algorithms/tex/algorithms.tex b/D3128_Algorithms/tex/algorithms.tex index 8965ccf..7aae31e 100644 --- a/D3128_Algorithms/tex/algorithms.tex +++ b/D3128_Algorithms/tex/algorithms.tex @@ -139,10 +139,24 @@ \section{Common Algorithm Definitions} Common concepts used by algorithms are in this section, extending those in the Graph Container Interface. -\subsection{Edge Weight Concepts} -Edge weights are intrinsic numeric type for the current proposal, but could be any type in the future. +\subsection{Value Function and Edge Weight Concepts} + +Value function concepts constrain callables that extract per-vertex or per-edge values. +Edge weights are intrinsic numeric type (\lstinline{edge_weight_function}), but could be any type +for more general use (\lstinline{basic_edge_weight_function}). \begin{lstlisting} +// For exposition only: base concept for any 2-arg vertex value function. +template +concept vertex_value_function = + invocable && + (!is_void_v>); + +// For exposition only: base concept for any 2-arg edge value function. +template +concept edge_value_function = // For exposition only + std::invocable && !std::is_void_v>; + // For exposition only template concept basic_edge_weight_function = // e.g. weight(g, uv) @@ -202,21 +216,50 @@ \subsection{Vertex Property Function Concepts} This function-first design is more flexible than direct container access: property values may reside in vertex properties, in external containers, or in any custom storage. -The full definitions of all function concepts and helper types appear in the listing produced by -the \emph{Initialization} section below (from \tcode{shortest\_paths\_helpers.hpp}). +\subsubsection{\tcode{vertex_property_fn_for} and \tcode{vertex_fn_value_t}} +\tcode{vertex_property_fn_for} is the general concept for per-vertex property functions, +requiring a callable that returns a mutable lvalue reference to the stored value. +It is used directly by \tcode{connected\_components}, \tcode{kosaraju}, \tcode{tarjan\_scc}, +and \tcode{label\_propagation}. +\tcode{vertex_fn_value_t} extracts the corresponding value type. + +\begin{lstlisting} +// For exposition only +template +concept vertex_property_fn_for = + invocable&, const vertex_id_t&> && + is_lvalue_reference_v&, const vertex_id_t&>>; + +// For exposition only +template +using vertex_fn_value_t = remove_cvref_t< + invoke_result_t&, const vertex_id_t&>>; +\end{lstlisting} \subsubsection{\tcode{distance_fn_for} and \tcode{predecessor_fn_for}} -\tcode{distance_fn_for} constrains the \tcode{DistanceFn} parameter passed to -\tcode{dijkstra\_shortest\_paths}, \tcode{bellman\_ford\_shortest\_paths}, and \tcode{prim}. -\tcode{predecessor_fn_for} constrains the corresponding \tcode{PredecessorFn} parameter. -Both require the callable to return a mutable lvalue reference to the stored value. -\tcode{distance_fn_value_t} extracts the distance scalar type from the function's return -type. +\tcode{distance_fn_for} and \tcode{predecessor_fn_for} are concept aliases for +\tcode{vertex_property_fn_for}, giving semantic names to the distance and predecessor +function parameters of shortest-path and MST algorithms. +\tcode{distance_fn_value_t} and \tcode{predecessor_fn_value_t} are corresponding +type aliases for \tcode{vertex_fn_value_t}. -\subsubsection{\tcode{vertex_property_fn_for} and \tcode{vertex_fn_value_t}} -\tcode{vertex_property_fn_for} is the more general form used by -\tcode{connected\_components}, \tcode{kosaraju}, and \tcode{label\_propagation}. -\tcode{vertex_fn_value_t} extracts the corresponding value type. +\begin{lstlisting} +// For exposition only +template +concept distance_fn_for = vertex_property_fn_for; + +// For exposition only +template +using distance_fn_value_t = vertex_fn_value_t; + +// For exposition only +template +concept predecessor_fn_for = vertex_property_fn_for; + +// For exposition only +template +using predecessor_fn_value_t = vertex_fn_value_t; +\end{lstlisting} \subsubsection{\tcode{container_value_fn} Adaptor} \tcode{container_value_fn} adapts any subscriptable container into a property @@ -230,7 +273,7 @@ \subsubsection{\tcode{container_value_fn} Adaptor} \subsubsection{Legacy: \tcode{vertex_property_map_for} Concept} The container-subscript concept \tcode{vertex_property_map_for} is retained for -\tcode{afforest} and the \tcode{init\_shortest\_paths} helper functions, both of which take +the \tcode{init\_shortest\_paths} helper functions, which take subscriptable containers directly. It is satisfied by \tcode{std::vector} for index graphs and \tcode{std::unordered\_map,T>} for mapped graphs. @@ -294,7 +337,7 @@ \subsubsection{\tcode{vertex\_property\_map\_for} Concept} Requires that \tcode{m[uid]} is valid for \tcode{uid} of type \tcode{vertex\_id\_t} and the result is convertible to \tcode{vertex\_property\_map\_value\_t}. This concept constrains algorithm parameters that accept subscriptable containers directly, -such as \tcode{afforest} and the \tcode{init\_shortest\_paths} helpers. +such as the \tcode{init\_shortest\_paths} helpers. \subsection{Visitor Concepts and Classes} Visitors are optional member functions on a user-defined class that are called during the execution of an algorithm. @@ -1677,81 +1720,9 @@ \subsection{Connected Components} %\pnum\errors \end{itemdescr} -\subsection{Afforest Connected Components} -Find connected components of a graph using the Afforest algorithm. -Afforest is a sampling-based algorithm that first links vertices through a small number of -neighbor rounds before processing the remaining edges, making it well suited for -parallel execution. - -\begin{table}[ht] -\setcellgapes{3pt} -\makegapedcells -\centering -\begin{tabular}{|P{0.30\textwidth}|P{0.20\textwidth}|P{0.20\textwidth}|P{0.20\textwidth}|} -\hline - \multirowcell{2}{ - \textbf{Complexity} \\ - $\mathcal{O}(|V| + |E| \cdot \alpha(|V|))$ - } - & \textbf{Directed?} No & \textbf{Cycles?} Yes & \textbf{Throws?} No \\ - & \textbf{Multi-edge?} No & \textbf{Self-loops} Yes & \\ -\hline -\end{tabular} -\label{tab:algo_afforest} -\end{table} - -{\small - \lstinputlisting[firstline=21, lastline=30]{D3128_Algorithms/src/connected_components.hpp} -} - -\begin{itemdescr} - \pnum\mandates - \begin{itemize} - \item \tcode{G} satisfies \tcode{adjacency_list}. - \item \tcode{Component} satisfies \tcode{vertex_property_map_for}. - \item \tcode{vertex_property_map_value_t} is convertible to and from \tcode{vertex_id_t}. - \end{itemize} - \pnum\preconditions - \begin{itemize} - \item - For the two-graph overload, \lstinline{g_t} is the transpose of \lstinline{g}, - where edge \lstinline{uv} in \lstinline{g} implies edge \lstinline{vu} in \lstinline{g_t}. - \end{itemize} - \pnum\hardprecond - \begin{itemize} - \item - \lstinline{component} contains an entry for each vertex of \lstinline{g}. - \item - \lstinline{num_vertices(g) == num_vertices(g_t)} for the two-graph overload. - \end{itemize} - \pnum\effects - \begin{itemize} - \item - \lstinline{component[v]} is the connected component id of vertex \lstinline{v}. - \item - There is at least one connected component, with component id of \lstinline{0}, for \lstinline{num_vertices(g) > 0}. - \end{itemize} - %\pnum\result - %\pnum\returns - %\pnum\throws - \pnum\complexity - \begin{itemize} - \item \textbf{Time:} $\mathcal{O}(|V| + |E| \cdot \alpha(|V|))$, where $\alpha$ is the inverse Ackermann function. - \item \textbf{Space:} $\mathcal{O}(|V|)$ auxiliary --- component array only. - \end{itemize} - \pnum\remarks - \begin{itemize} - \item - \lstinline{neighbor_rounds} controls how many neighbors are sampled per vertex - before the full-edge pass. The default of 2 provides a good balance for most graphs. - \item - Afforest (Sampling-based Connected Components) is described in - Sutton, Sanders, Steil, \emph{An efficient parallel algorithm for graph - connected components}, IEEE International Conference on Parallel Processing - (ICPP), 2018. - \end{itemize} - %\pnum\errors -\end{itemdescr} +% Afforest Connected Components is intentionally excluded from this proposal. +% It is a parallel sampling-based algorithm that belongs in a future parallel-algorithms paper. +% Do not re-add it here. \subsection{Strongly Connected Components} \subsubsection{Kosaraju}