From dfbba38819050fe588ef3868c5bf05d281016cd3 Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Sun, 25 May 2025 15:32:27 -0400 Subject: [PATCH 01/31] Feedback from AndrzejK Mandates only applies to statically checked compile-time items New "Hardened preconditions" clause added. Many items in mandates and precondications are moved into that. Thows clauses removed. Weight function name changed from "w" to "weight" to reflect code. Rename "seed" to "source" to match statements. Summarize changes in Revisions --- D3128_Algorithms/src/mis.hpp | 2 +- D3128_Algorithms/src/mst.hpp | 4 +- D3128_Algorithms/src/prim.hpp | 4 +- D3128_Algorithms/src/visitor_vertex.hpp | 10 +- D3128_Algorithms/tex/algorithms.tex | 203 +++++++++++------------- D3128_Algorithms/tex/revision.tex | 8 + D3129_Views/tex/views.tex | 50 +++--- tex/P1709-preamble.tex | 3 + tex/conventions.tex | 2 +- 9 files changed, 137 insertions(+), 149 deletions(-) diff --git a/D3128_Algorithms/src/mis.hpp b/D3128_Algorithms/src/mis.hpp index 51ba25e..b893468 100644 --- a/D3128_Algorithms/src/mis.hpp +++ b/D3128_Algorithms/src/mis.hpp @@ -1,3 +1,3 @@ template requires output_iterator> -void maximal_independent_set(G&& g, Iter mis, vertex_id_t seed); +void maximal_independent_set(G&& g, Iter mis, vertex_id_t source); diff --git a/D3128_Algorithms/src/mst.hpp b/D3128_Algorithms/src/mst.hpp index 5e3dcb2..c78c558 100644 --- a/D3128_Algorithms/src/mst.hpp +++ b/D3128_Algorithms/src/mst.hpp @@ -13,7 +13,7 @@ void kruskal(IELR&& e, OELR&& t, CompareOp compare); template -void prim(G&& g, Predecessor& predecessor, Weight& weight, vertex_id_t seed = 0); +void prim(G&& g, Predecessor& predecessor, Weight& weight, vertex_id_t source = 0); template init_dist, - vertex_id_t seed = 0); + vertex_id_t source = 0); diff --git a/D3128_Algorithms/src/prim.hpp b/D3128_Algorithms/src/prim.hpp index 546285b..551c06a 100644 --- a/D3128_Algorithms/src/prim.hpp +++ b/D3128_Algorithms/src/prim.hpp @@ -1,7 +1,7 @@ template -void prim(G&& g, Predecessor& predecessor, Weight& weight, vertex_id_t seed = 0) {} +void prim(G&& g, Predecessor& predecessor, Weight& weight, vertex_id_t source = 0) {} template init_dist, - vertex_id_t seed = 0) {} \ No newline at end of file + vertex_id_t source = 0) {} \ No newline at end of file diff --git a/D3128_Algorithms/src/visitor_vertex.hpp b/D3128_Algorithms/src/visitor_vertex.hpp index e95ad56..c95ca28 100644 --- a/D3128_Algorithms/src/visitor_vertex.hpp +++ b/D3128_Algorithms/src/visitor_vertex.hpp @@ -1,25 +1,25 @@ template concept has_on_initialize_vertex = // For exposition only - requires(Visitor& v, vertex_info, vertex_reference_t, void> vdesc) { + requires(Visitor& v, vertex_info, void> vdesc) { { v.on_initialize_vertex(vdesc) }; }; template concept has_on_discover_vertex = // For exposition only - requires(Visitor& v, vertex_info, vertex_reference_t, void> vdesc) { + requires(Visitor& v, vertex_info, void> vdesc) { { v.on_discover_vertex(vdesc) }; }; template concept has_on_start_vertex = // For exposition only - requires(Visitor& v, vertex_info, vertex_reference_t, void> vdesc) { + requires(Visitor& v, vertex_info, void> vdesc) { { v.on_start_vertex(vdesc) }; }; template concept has_on_examine_vertex = // For exposition only - requires(Visitor& v, vertex_info, vertex_reference_t, void> vdesc) { + requires(Visitor& v, vertex_info, void> vdesc) { { v.on_examine_vertex(vdesc) }; }; template concept has_on_finish_vertex = // For exposition only - requires(Visitor& v, vertex_info, vertex_reference_t, void> vdesc) { + requires(Visitor& v, vertex_info, void> vdesc) { { v.on_finish_vertex(vdesc) }; }; diff --git a/D3128_Algorithms/tex/algorithms.tex b/D3128_Algorithms/tex/algorithms.tex index 0e571a1..2a9e226 100644 --- a/D3128_Algorithms/tex/algorithms.tex +++ b/D3128_Algorithms/tex/algorithms.tex @@ -271,7 +271,7 @@ \subsubsection{Multi-Source Breadth-First Search} \begin{itemdescr} %\pnum\mandates % \pnum -\preconditions + \hardprecond \begin{itemize} \item \lstinline{0 <= source < num_vertices(graph)} for the single-source version. @@ -290,10 +290,6 @@ \subsubsection{Multi-Source Breadth-First Search} \end{itemize} %\pnum\result %\pnum\returns \lstinline{void} \\ - \pnum\throws - \begin{itemize} - \item \tcode{out_of_range} is thrown when \tcode{source} is not in the range \tcode{0 <= source < num_vertices(g)}. - \end{itemize} \pnum\complexity \begin{itemize} \item $\mathcal{O}((|E| + |V|)\log{|V|})$ based on using the binary heap in \tcode{std::priority_queue}. @@ -347,7 +343,7 @@ \subsubsection{Single Source Depth-First Search} \begin{itemdescr} %\pnum\mandates % \pnum -\preconditions + \hardprecond \begin{itemize} \item \lstinline{0 <= source < num_vertices(graph)}. @@ -369,10 +365,6 @@ \subsubsection{Single Source Depth-First Search} \end{itemize} %\pnum\result %\pnum\returns \lstinline{void} \\ - \pnum\throws - \begin{itemize} - \item \tcode{out_of_range} is thrown when \tcode{source} is not in the range \tcode{0 <= source < num_vertices(g)}. - \end{itemize} \pnum\complexity \begin{itemize} \item $\mathcal{O}(|V| + |E|)$. @@ -430,13 +422,17 @@ \subsubsection{Multi-Source Topological Sort} \begin{itemdescr} %\pnum\mandates - \pnum\preconditions + \pnum\hardprecond \begin{itemize} + \item \lstinline{size(predecessors) >= size(vertices(g))} \item \lstinline{0 <= source < num_vertices(graph)} for the single-source version. \item \lstinline{0 <= source < num_vertices(graph)}, for each \lstinline{source} in \lstinline{sources}, for the multi-source version. + \end{itemize} + \pnum\preconditions + \begin{itemize} \item \lstinline{predecessors[i] = i} for \lstinline{0 <= i < num_vertices(g)}. \end{itemize} @@ -450,14 +446,6 @@ \subsubsection{Multi-Source Topological Sort} \end{itemize} %\pnum\result %\pnum\returns \lstinline{void} \\ - \pnum\throws - \begin{itemize} - \item An \tcode{out_of_range} exception is thrown in the following cases: - \begin{itemize} - \item \lstinline{size(predecessor) < size(vertices(g))} - \item \lstinline{source} is not in the range \lstinline{0 <= source < num_vertices(graph)}. - \end{itemize} - \end{itemize} \pnum\complexity \begin{itemize} \item $\mathcal{O}((|E| + |V|)\log{|V|})$ based on using the binary heap in \tcode{std::priority_queue}. @@ -564,18 +552,20 @@ \subsubsection{Dijkstra Shortest Paths} integral values.} \begin{itemdescr} - \pnum\mandates + \pnum\hardprecond \begin{itemize} + \item \lstinline{size(distances) >= size(vertices(g))} + \item \lstinline{size(predecessor) >= size(vertices(g))} \item \lstinline{0 <= source < num_vertices(graph)} for the single-source version. \item \lstinline{0 <= source < num_vertices(graph)}, for each \lstinline{source} in \lstinline{sources}, for the multi-source version. - \item - The weight function \lstinline{w} must return a non-negative value. \end{itemize} \pnum\preconditions \begin{itemize} + \item + The weight function \lstinline{weight} must return a non-negative value. \item \lstinline{distances[i] = shortest_path_infinite_distance()} for \lstinline{0 <= i < num_vertices(g)}. \item @@ -602,17 +592,6 @@ \subsubsection{Dijkstra Shortest Paths} \end{itemize} %\pnum\result %\pnum\returns \lstinline{void} \\ - \pnum\throws - \begin{itemize} - \item An \tcode{out_of_range} exception is thrown in the following cases: - \begin{itemize} - \item \lstinline{size(distances) < size(vertices(g))} - \item \lstinline{size(predecessor) < size(vertices(g))} - \item \lstinline{source} is not in the range \lstinline{0 <= source < num_vertices(graph)}. - \item The weight function returns a negative value. This check is not made if the weight - value type is an unsigned integral type. - \end{itemize} - \end{itemize} \pnum\complexity \begin{itemize} \item $\mathcal{O}((|E| + |V|)\log{|V|})$ based on using the binary heap in \tcode{std::priority_queue}. @@ -641,18 +620,19 @@ \subsubsection{Dijkstra Shortest Distances} } \begin{itemdescr} - \pnum\mandates + \pnum\hardprecond \begin{itemize} + \item \lstinline{size(distances) >= size(vertices(g))} \item \lstinline{0 <= source < num_vertices(graph)} for the single-source version. \item \lstinline{0 <= source < num_vertices(graph)}, for each \lstinline{source} in \lstinline{sources}, for the multi-source version. - \item - The weight function \lstinline{w} must return a non-negative value. \end{itemize} \pnum\preconditions \begin{itemize} + \item + The weight function \lstinline{weight} must return a non-negative value. \item \lstinline{distances[i] = shortest_path_infinite_distance()} for \lstinline{0 <= i < num_vertices(g)}. \end{itemize} @@ -672,16 +652,6 @@ \subsubsection{Dijkstra Shortest Distances} \end{itemize} %\pnum\result %\pnum\returns \lstinline{void} \\ - \pnum\throws - \begin{itemize} - \item An \tcode{out_of_range} exception is thrown in the following cases: - \begin{itemize} - \item \lstinline{size(distances) < size(vertices(g))} - \item \lstinline{source} is not in the range \lstinline{0 <= source < num_vertices(graph)}. - \item The weight function returns a negative value. This check is not made if the weight - value type is an unsigned integral type. - \end{itemize} - \end{itemize} \pnum\complexity \begin{itemize} \item $\mathcal{O}((|E| + |V|)\log{|V|})$ based on using the binary heap in \tcode{std::priority_queue}. @@ -746,8 +716,10 @@ \subsubsection{Bellman-Ford Shortest Paths} } \begin{itemdescr} - \pnum\mandates + \pnum\hardprecond \begin{itemize} + \item \lstinline{size(distances) >= size(vertices(g))} + \item \lstinline{size(predecessor) >= size(vertices(g))} \item \lstinline{0 <= source < num_vertices(graph)} for the single-source version. \item @@ -787,14 +759,6 @@ \subsubsection{Bellman-Ford Shortest Paths} vertex id in the cycle is returned. \lstinline{find_negative_cycle} can be called to get the vertex ids of the cycle. \end{itemize} - \pnum\throws - \begin{itemize} - \item An \tcode{out_of_range} exception is thrown in the following cases: - \begin{itemize} - \item \lstinline{size(distances) < size(vertices(g))} - \item \lstinline{source} is not in the range \lstinline{0 <= source < num_vertices(graph)}. - \end{itemize} - \end{itemize} \pnum\complexity $\mathcal{O}(|E| \cdot |V|)$. Complexity may also be affected when visitor events are called. \\ \pnum\remarks \begin{itemize} @@ -821,8 +785,9 @@ \subsubsection{Bellman-Ford Shortest Distances} } \begin{itemdescr} - \pnum\mandates + \pnum\hardprecond \begin{itemize} + \item \lstinline{size(distances) >= size(vertices(g))} \item \lstinline{0 <= source < num_vertices(graph)} for the single-source version. \item @@ -849,28 +814,20 @@ \subsubsection{Bellman-Ford Shortest Distances} \end{itemize} %\pnum\result \pnum\returns - \begin{itemize} - \item \lstinline{optional} If no negative weight cycle is found, - there is no associated vertex id. If a negative weight cycle is found, a - vertex id in the cycle is returned. \lstinline{bellman_ford_shortest_paths} must be used - to get the predecessors if it is importantant to get the vertex ids of the cycle - using \lstinline{find_negative_cycle}. - \end{itemize} -\pnum\throws \begin{itemize} - \item An \tcode{out_of_range} exception is thrown in the following cases: - \begin{itemize} - \item \lstinline{size(distances) < size(vertices(g))} - \item \lstinline{source} is not in the range \lstinline{0 <= source < num_vertices(graph)}. - \end{itemize} + \item \lstinline{optional} If no negative weight cycle is found, + there is no associated vertex id. If a negative weight cycle is found, a + vertex id in the cycle is returned. \lstinline{bellman_ford_shortest_paths} must be used + to get the predecessors if it is importantant to get the vertex ids of the cycle + using \lstinline{find_negative_cycle}. \end{itemize} \pnum\complexity $\mathcal{O}(|E| \cdot |V|)$. Complexity may also be affected when visitor events are called. \\ - \pnum\remarks - \begin{itemize} - \item Duplicate sources do not affect the algorithm's complexity or correctness. - \item Unlike Dijkstra's algorithm, Bellman-Ford allows negative edge weights. - Performance constraints limit this to smaller graphs. - \end{itemize} + \pnum\remarks + \begin{itemize} + \item Duplicate sources do not affect the algorithm's complexity or correctness. + \item Unlike Dijkstra's algorithm, Bellman-Ford allows negative edge weights. + Performance constraints limit this to smaller graphs. + \end{itemize} %\pnum\errors \end{itemdescr} @@ -936,7 +893,7 @@ \subsection{Triangle Counting} %\pnum\mandates \pnum\preconditions \begin{itemize} - \item The outgoing edges of a vertex are ordered by target\_id. + \item The outgoing edges of a vertex are ordered by target\_id, such that target\_id > source\_id. \end{itemize} %\pnum\effects %\pnum\result @@ -944,10 +901,6 @@ \subsection{Triangle Counting} \begin{itemize} \item Number of triangles \end{itemize} - \pnum\throws - \begin{itemize} - \item A \tcode{graph_error} is thrown when the target\_id for an outgoing edge is less than the target\_id of the previous edge. - \end{itemize} \pnum\complexity $\mathcal{O}(N^3)$ \\ \pnum\remarks \begin{itemize} @@ -1003,7 +956,10 @@ \subsection{Label Propagation} %\pnum\returns %\pnum\throws \pnum\complexity $\mathcal{O}(M)$ \\ - \pnum\remarks User is responsible for initial vertex labels. + \pnum\remarks + \begin{itemize} + \item User is responsible for initial vertex labels. + \end{itemize} %\pnum\errors \end{itemdescr} @@ -1039,14 +995,21 @@ \subsection{Label Propagation} \item \lstinline{rng} is a random number generator for vertex voting order. \item - \lstinline{max_iters} is the maximum number of iterations of the label propagation, or equivalently the maximum distance a label will propagate from its starting vertex. + \lstinline{max_iters} is the maximum number of iterations of the label propagation, or equivalently + the maximum distance a label will propagate from its starting vertex. + \end{itemize} + \pnum\effects + \begin{itemize} + \item \lstinline{label[uid]} is the label assignments of vertex id \lstinline{uid} discovered by label propagation. \end{itemize} - \pnum\effects \lstinline{label[uid]} is the label assignments of vertex id \lstinline{uid} discovered by label propagation. \\ %\pnum\result %\pnum\returns %\pnum\throws \pnum\complexity $\mathcal{O}(M)$ \\ - \pnum\remarks User is responsible for initial vertex labels. + \pnum\remarks + \begin{itemize} + \item User is responsible for initial vertex labels. + \end{itemize} %\pnum\errors \end{itemdescr} @@ -1227,13 +1190,18 @@ \subsubsection{Kosaraju's SCC} \begin{itemdescr} %\pnum\mandates - \pnum\preconditions + \pnum\hardprecond \begin{itemize} \item - \lstinline{g_t} is the transpose of \lstinline{g}. Edge \lstinline{uv} in \lstinline{g} implies edge \lstinline{vu} in \lstinline{g_t}. \lstinline{num_vertices(g)} equals \lstinline{num_vertices(g_t)}. + \lstinline{num_vertices(g) == num_vertices(g_t)}. \item \lstinline{size(component) >= num_vertices(g)}. \end{itemize} + \pnum\preconditions + \begin{itemize} + \item + \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\effects \begin{itemize} \item @@ -1276,7 +1244,7 @@ \subsubsection{Tarjan's SCC} \begin{itemdescr} %\pnum\mandates - \pnum\preconditions + \pnum\hardprecond \begin{itemize} \item \lstinline{size(component) >= num_vertices(g)}. @@ -1296,7 +1264,7 @@ \subsubsection{Tarjan's SCC} \section{Maximal Independent Set} \subsection{Maximal Independent Set} -Find a maximally independent set of vertices in a graph starting from a seed vertex. An independent vertex set indicates no pair of vertices in the set are adjacent. +Find a maximally independent set of vertices in a graph starting from a source vertex. An independent vertex set indicates no pair of vertices in the set are adjacent. \begin{table}[h] \setcellgapes{3pt} @@ -1319,19 +1287,23 @@ \subsection{Maximal Independent Set} {\small \lstinputlisting{D3128_Algorithms/src/mis.hpp} } +\phil{The mandates condition should be part of the requires clause.} \begin{itemdescr} %\pnum\mandates - \pnum\preconditions + \pnum\mandates \begin{itemize} \item - \lstinline{0 <= seed < num_vertices(graph)}. + The \tcode{value_type} for the \lstinline{mis} output iterator is convertible to \lstinline{vertex_id_t}. + \end{itemize} + \pnum\hardprecond + \begin{itemize} \item - \lstinline{mis} output iterator can be assigned vertices of type \lstinline{vertex_id_t} when dereferenced. + \lstinline{0 <= source < num_vertices(graph)}. \end{itemize} \pnum\effects \begin{itemize} \item - Output iterator \lstinline{mis} contains maximal independent set of vertices containing \lstinline{seed}, + Output iterator \lstinline{mis} contains maximal independent set of vertices containing \lstinline{source}, which is a subset of \lstinline{vertices(graph)}. \\ \end{itemize} %\pnum\result @@ -1429,8 +1401,8 @@ \subsection{Kruskal Minimum Spanning Tree} %\pnum\mandates \pnum\preconditions \begin{itemize} - \item - \lstinline{e} is an \lstinline{edgelist}. + %\item + % \lstinline{e} is an \lstinline{edgelist}. \item \lstinline{compare} operator is a valid comparison operation on two edge values of type \lstinline{range_value_t::value_type} which returns a bool. @@ -1476,23 +1448,28 @@ \subsection{Prim Minimum Spanning Tree} \lstinputlisting[firstline=13,lastline=29]{D3128_Algorithms/src/mst.hpp} } +\phil{The mandates condition should be part of the requires clause.} \begin{itemdescr} - %\pnum\mandates - \pnum\preconditions + \pnum\mandates \begin{itemize} \item - \lstinline{0 <= seed < num_vertices(g)}. + \lstinline{compare} operator is a valid comparison operation on two edge values of type \lstinline{edge_value_t} which returns a bool. + \end{itemize} + \pnum\hardprecond + \begin{itemize} \item - Size of \lstinline{weight} and \lstinline{predecessor} is greater than or equal to \lstinline{num_vertices(g)}. + \lstinline{0 <= source < num_vertices(g)}. \item - \lstinline{compare} operator is a valid comparison operation on two edge values of type \lstinline{edge_value_t} which returns a bool. + \lstinline{size(weight) >= to num_vertices(g)}. + \item + \lstinline{size(predecessor >= to num_vertices(g)}. \end{itemize} \pnum\effects \begin{itemize} \item - \lstinline{predecessor[v]} is the parent vertex of \lstinline{v} in a tree rooted at \lstinline{seed} and \lstinline{weight[v]} is the value of the edge between \lstinline{v} and \lstinline{predecessor[v]} in the tree. When \lstinline{compare} is \lstinline{<} and \lstinline{init_dist==+inf}, \lstinline{predecessor} represents a minimum weight spanning tree. + \lstinline{predecessor[v]} is the parent vertex of \lstinline{v} in a tree rooted at \lstinline{source} and \lstinline{weight[v]} is the value of the edge between \lstinline{v} and \lstinline{predecessor[v]} in the tree. When \lstinline{compare} is \lstinline{<} and \lstinline{init_dist==+inf}, \lstinline{predecessor} represents a minimum weight spanning tree. \item - If \lstinline{predecessor} and \lstinline{weight} are not initialized by user, and the graph is not fully connected, \lstinline{predecessor[v]} and \lstinline{weight[v]} will be undefined for vertices not in the same connected component as \lstinline{seed}. + If \lstinline{predecessor} and \lstinline{weight} are not initialized by user, and the graph is not fully connected, \lstinline{predecessor[v]} and \lstinline{weight[v]} will be undefined for vertices not in the same connected component as \lstinline{source}. \end{itemize} %\pnum\result %\pnum\returns @@ -1520,7 +1497,7 @@ \subsection{Prim Minimum Spanning Tree} \subsection{Dijkstra's Shortest Paths and Shortest Distances} %Dijkstra's algorithm \cite{REF_} is a single-source, shortest paths algorithm for non-negative weights. It finds the shortest paths - %and their weighted distances to all vertices connected to a single seed vertex. + %and their weighted distances to all vertices connected to a single source vertex. \begin{lstlisting} template @@ -1544,8 +1521,8 @@ \subsection{Prim Minimum Spanning Tree} edge_weight_function constexpr void dijkstra_shortest_paths( G&& g, // graph - vertex_id_t seed, // starting vertex_id - Distance& distance, // out: distance[uid] of vertex_id uid from seed + vertex_id_t source, // starting vertex_id + Distance& distance, // out: distance[uid] of vertex_id uid from source Predecessor& predecessor, // out: predecessor[uid] of vertex_id uid in path EVF weight_fn = [](edge_reference_t uv) // weight_fn(uv) -> 1 { return ranges::range_value_t(1); }, @@ -1565,18 +1542,18 @@ \subsection{Prim Minimum Spanning Tree} \hline \textit{Constraints} & Values returned by \tcode{weight_fn} must be non-negative. \\ \hline - \textit{Preconditions} & \tcode{seed >= 0 & & seed < size(vertices(g))} \\ + \textit{Preconditions} & \tcode{source >= 0 & & source < size(vertices(g))} \\ & \tcode{size(distance) >= size(vertices(g))}; caller must pre-extend with \tcode{dijkstra_infinite_distance()} \\ & \tcode{size(predecessor) >= size(vertices(g))}; caller must pre-extend \\ & \tcode{distance[i] = dijkstra_infinite_distance()} for \tcode{i < size(vertices(g))} \\ \hline - \textit{Postconditions} & \tcode{distance[seed] == 0} \\ - & \tcode{predecessor[seed] == seed}. \\ + \textit{Postconditions} & \tcode{distance[source] == 0} \\ + & \tcode{predecessor[source] == source}. \\ \hline - \textit{\effects} & \tcode{distance[uid]} will be the shortest, weighted distance of vertex\_id \tcode{uid} from \tcode{seed}. \\ - & If \tcode{uid} is not connected to \tcode{seed} by any edges then it will have a value of \tcode{dijkstra_infinite_distance()}. \\ + \textit{\effects} & \tcode{distance[uid]} will be the shortest, weighted distance of vertex\_id \tcode{uid} from \tcode{source}. \\ + & If \tcode{uid} is not connected to \tcode{source} by any edges then it will have a value of \tcode{dijkstra_infinite_distance()}. \\ & \\ - & \tcode{predecessor[uid]} will have the preceding vertex\_id of \tcode{uid} in the weighted shortest path to \tcode{seed} \\ + & \tcode{predecessor[uid]} will have the preceding vertex\_id of \tcode{uid} in the weighted shortest path to \tcode{source} \\ & when \tcode{distance[uid] != dijkstra_infinite_distance()}. \\ \hline \end{tabular}} @@ -1588,7 +1565,7 @@ \subsection{Prim Minimum Spanning Tree} \phil{Describe the pros and cons of different kinds of queues} The default weight function \tcode{weight_fn} returns a value of 1. When that is used, \tcode{distance[uid]} will have the shortest number of edges - between vertex \tcode{uid} and vertex \tcode{seed}. The distance from \tcode{seed} to itself is zero. + between vertex \tcode{uid} and vertex \tcode{source}. The distance from \tcode{source} to itself is zero. If the caller wishes to use a different queue other than \tcode{priority_queue}, the queue will need to have elements of \tcode{weighted_vertex} which is used internally by the algorithm. @@ -1619,8 +1596,8 @@ \subsection{Prim Minimum Spanning Tree} edge_weight_function constexpr void dijkstra_shortest_distances( G&& g, // graph - vertex_id_t seed, // starting vertex_id - Distance& distance, // out: distance[uid] of vertex_id uid from seed + vertex_id_t source, // starting vertex_id + Distance& distance, // out: distance[uid] of vertex_id uid from source EVF weight_fn = [](edge_reference_t uv) // weight_fn(uv) -> 1 { return ranges::range_value_t(1); }, Q q = Q() diff --git a/D3128_Algorithms/tex/revision.tex b/D3128_Algorithms/tex/revision.tex index 93bdfa5..41205fd 100644 --- a/D3128_Algorithms/tex/revision.tex +++ b/D3128_Algorithms/tex/revision.tex @@ -50,3 +50,11 @@ \subsection*{\paperno r3} \item Update the breadth-first search and topological sort algorithms to be in line with changes made to the Dijkstra and Bellman-Ford algorithms, such as adding a visitor parameter and overloads for multiple sources. \end{itemize} + +\subsection*{\paperno r4} +\begin{itemize} + \item Added the \textit{Hardened preconditions} section to the algorithms for C++26 which helped to reword + the other clauses so they conform to expectations of the standard. Statements incorrectly included in + the \textit{Mandates} and \textit{Preconditions} sections were moved to the \textit{Hardened preconditions} + section and the \textit{Throws} claus was removed, simplifying and clarifying the defintions. +\end{itemize} diff --git a/D3129_Views/tex/views.tex b/D3129_Views/tex/views.tex index 5a204fa..d4125d1 100644 --- a/D3129_Views/tex/views.tex +++ b/D3129_Views/tex/views.tex @@ -366,7 +366,7 @@ \subsection{Common Types and Functions for ``Search'' } template auto depth(S search) -> integral; @@ -402,13 +402,13 @@ \subsection{Common Types and Functions for ``Search'' } \subsection{Depth First Search Views} -Depth First Search views iterate over the vertices and edges from a given seed vertex, returning a \tcode{vertex_info} or \tcode{edge_info} on each iteration when it is first encountered, depending on the function used. +Depth First Search views iterate over the vertices and edges from a given source vertex, returning a \tcode{vertex_info} or \tcode{edge_info} on each iteration when it is first encountered, depending on the function used. Table \ref{tab:dfs} shows the functions and their return values. %The \tcode{alloc} parameter shown in the following examples is optional and defaults to \tcode{std::allocator}. It is used for containers %that are internal to the view. The \tcode{bool} argument has no particular meaning. -% basic_edges_dfs(g,seed,evf) implies the use of Sourced type internally to have source_id in the call call to evf(eid) +% basic_edges_dfs(g,source,evf) implies the use of Sourced type internally to have source_id in the call call to evf(eid) \phil{Consider adding an enum bitset of events matching the visitor events, and creating Overloads that accept the bitset. The returned type would be a subclass of \tcode{vertex_info} or \tcode{edge_info} @@ -424,14 +424,14 @@ \subsection{Depth First Search Views} \hline \textbf{Example} & \textbf{Return} \\ \hline - \tcode{for(auto\&\& [v] : vertices_dfs(g,seed))} & \tcode{vertex_info} \\ - \tcode{for(auto\&\& [v,val] : vertices_dfs(g,seed,vvf))} & \tcode{vertex_info} \\ + \tcode{for(auto\&\& [v] : vertices_dfs(g,source))} & \tcode{vertex_info} \\ + \tcode{for(auto\&\& [v,val] : vertices_dfs(g,source,vvf))} & \tcode{vertex_info} \\ \hdashline - \tcode{for(auto\&\& [v,uv] : edges_dfs(g,seed))} & \tcode{edge_info} \\ - \tcode{for(auto\&\& [v,uv,val] : edges_dfs(g,seed,evf))} & \tcode{edge_info} \\ + \tcode{for(auto\&\& [v,uv] : edges_dfs(g,source))} & \tcode{edge_info} \\ + \tcode{for(auto\&\& [v,uv,val] : edges_dfs(g,source,evf))} & \tcode{edge_info} \\ \hdashline - \tcode{for(auto\&\& [u,v,uv] : sourced_edges_dfs(g,seed))} & \tcode{edge_info} \\ - \tcode{for(auto\&\& [u,v,uv,val] : sourced_edges_dfs(g,seed,evf))} & \tcode{edge_info} \\ + \tcode{for(auto\&\& [u,v,uv] : sourced_edges_dfs(g,source))} & \tcode{edge_info} \\ + \tcode{for(auto\&\& [u,v,uv,val] : sourced_edges_dfs(g,source,evf))} & \tcode{edge_info} \\ \hline \end{tabular}} \caption{depth\_first\_search View Functions} @@ -442,14 +442,14 @@ \subsection{Depth First Search Views} \subsection{Breadth First Search Views} \phil{NetworkX provides an optional depth\_limit parameter for bfs. Add? } -Breadth First Search views iterate over the vertices and edges from a given seed vertex, returning a \tcode{vertex_info} +Breadth First Search views iterate over the vertices and edges from a given source vertex, returning a \tcode{vertex_info} or \tcode{edge_info} on each iteration when it is first encountered, depending on the function used. Table \ref{tab:bfs} shows the functions and their return values. %The \tcode{alloc} parameter shown in the following examples is optional and defaults to \tcode{std::allocator}. It is used for containers %that are internal to the view. The \tcode{bool} argument has no particular meaning. -% basic_edges_bfs(g,seed,evf) implies the use of Sourced type internally to have source_id in the call call to evf(eid) +% basic_edges_bfs(g,source,evf) implies the use of Sourced type internally to have source_id in the call call to evf(eid) \phil{Consider adding an enum bitset of events matching the visitor events, and creating Overloads that accept the bitset. The returned type would be a subclass of \tcode{vertex_info} or \tcode{edge_info} @@ -466,14 +466,14 @@ \subsection{Breadth First Search Views} \textbf{Example} & \textbf{Return} \\ \hline \hdashline - \tcode{for(auto\&\& [v] : vertices_bfs(g,seed))} & \tcode{vertex_info} \\ - \tcode{for(auto\&\& [v,val] : vertices_bfs(g,seed,vvf))} & \tcode{vertex_info} \\ + \tcode{for(auto\&\& [v] : vertices_bfs(g,source))} & \tcode{vertex_info} \\ + \tcode{for(auto\&\& [v,val] : vertices_bfs(g,source,vvf))} & \tcode{vertex_info} \\ \hdashline - \tcode{for(auto\&\& [v,uv] : edges_bfs(g,seed))} & \tcode{edge_info} \\ - \tcode{for(auto\&\& [v,uv,val] : edges_bfs(g,seed,evf))} & \tcode{edge_info} \\ + \tcode{for(auto\&\& [v,uv] : edges_bfs(g,source))} & \tcode{edge_info} \\ + \tcode{for(auto\&\& [v,uv,val] : edges_bfs(g,source,evf))} & \tcode{edge_info} \\ \hdashline - \tcode{for(auto\&\& [u,v,uv] : sourced_edges_bfs(g,seed))} & \tcode{edge_info} \\ - \tcode{for(auto\&\& [u,v,uv,val] : sourced_edges_bfs(g,seed,evf))} & \tcode{edge_info} \\ + \tcode{for(auto\&\& [u,v,uv] : sourced_edges_bfs(g,source))} & \tcode{edge_info} \\ + \tcode{for(auto\&\& [u,v,uv,val] : sourced_edges_bfs(g,source,evf))} & \tcode{edge_info} \\ \hline \end{tabular}} \caption{breadth\_first\_search View Functions} @@ -482,14 +482,14 @@ \subsection{Breadth First Search Views} \end{table} \subsection{Topological Sort Views} -Topological Sort views iterate over the vertices and edges from a given seed vertex, returning a \tcode{vertex_info} or +Topological Sort views iterate over the vertices and edges from a given source vertex, returning a \tcode{vertex_info} or \tcode{edge_info} on each iteration when it is first encountered, depending on the function used. Table \ref{tab:topo_sort} shows the functions and their return values. %The \tcode{alloc} parameter shown in the following examples is optional and defaults to \tcode{std::allocator}. It is used for containers %that are internal to the view. The \tcode{bool} argument has no particular meaning. -% basic_edges_topological_sort(g,seed,evf) implies the use of Sourced type internally to have source_id in the call call to evf(eid) +% basic_edges_topological_sort(g,source,evf) implies the use of Sourced type internally to have source_id in the call call to evf(eid) \phil{Consider adding an enum bitset of events matching the visitor events, and creating Overloads that accept the bitset. The returned type would be a subclass of \tcode{vertex_info} or \tcode{edge_info} @@ -505,14 +505,14 @@ \subsection{Topological Sort Views} \hline \textbf{Example} & \textbf{Return} \\ \hline - \tcode{for(auto\&\& [v] : vertices_topological_sort(g,seed))} & \tcode{vertex_info} \\ - \tcode{for(auto\&\& [v,val] : vertices_topological_sort(g,seed,vvf))} & \tcode{vertex_info} \\ + \tcode{for(auto\&\& [v] : vertices_topological_sort(g,source))} & \tcode{vertex_info} \\ + \tcode{for(auto\&\& [v,val] : vertices_topological_sort(g,source,vvf))} & \tcode{vertex_info} \\ \hdashline - \tcode{for(auto\&\& [v,uv] : edges_topological_sort(g,seed))} & \tcode{edge_info} \\ - \tcode{for(auto\&\& [v,uv,val] : edges_topological_sort(g,seed,evf))} & \tcode{edge_info} \\ + \tcode{for(auto\&\& [v,uv] : edges_topological_sort(g,source))} & \tcode{edge_info} \\ + \tcode{for(auto\&\& [v,uv,val] : edges_topological_sort(g,source,evf))} & \tcode{edge_info} \\ \hdashline - \tcode{for(auto\&\& [u,v,uv] : sourced_edges_topological_sort(g,seed))} & \tcode{edge_info} \\ - \tcode{for(auto\&\& [u,v,uv,val] : sourced_edges_topological_sort(g,seed,evf))} & \tcode{edge_info} \\ + \tcode{for(auto\&\& [u,v,uv] : sourced_edges_topological_sort(g,source))} & \tcode{edge_info} \\ + \tcode{for(auto\&\& [u,v,uv,val] : sourced_edges_topological_sort(g,source,evf))} & \tcode{edge_info} \\ \hline \end{tabular}} \caption{topological\_sort View Functions} diff --git a/tex/P1709-preamble.tex b/tex/P1709-preamble.tex index 32f2997..a4c12c3 100644 --- a/tex/P1709-preamble.tex +++ b/tex/P1709-preamble.tex @@ -130,6 +130,7 @@ \newcommand{\constraints}{\Fundesc{Constraints}} \newcommand{\mandates}{\Fundesc{Mandates}} \newcommand{\preconditions}{\Fundesc{Preconditions}} +\newcommand{\hardprecond}{\Fundesc{Hardened preconditions}} \newcommand{\effects}{\Fundesc{Effects}} \newcommand{\sync}{\Fundesc{Synchronization}} \newcommand{\postconditions}{\Fundesc{Postconditions}} @@ -140,6 +141,8 @@ \newcommand{\remarks}{\Fundesc{Remarks}} \newcommand{\errors}{\Fundesc{Error conditions}} +%%\newcommand{\concept}[1]{\textit{#1}} + %% \usepackage[⟨options⟩]{fancyhdr} \usepackage{fancyhdr} \pagestyle{fancy} diff --git a/tex/conventions.tex b/tex/conventions.tex index 1d37902..2607e5b 100644 --- a/tex/conventions.tex +++ b/tex/conventions.tex @@ -19,7 +19,7 @@ \section{Naming Conventions} \hline \tcode{V} & \tcode{vertex_t} & & Vertex descriptor \\ & \tcode{vertex_reference_t} & \tcode{u,v} & Vertex descriptor reference. \tcode{u} is the source (or only) vertex. \tcode{v} is the target vertex. \\ - \tcode{VId} & \tcode{vertex_id_t} & \tcode{uid,vid,seed} & Vertex id. \tcode{uid} is the source (or only) vertex id. \tcode{vid} is the target vertex id. \\ + \tcode{VId} & \tcode{vertex_id_t} & \tcode{uid,vid,source} & Vertex id. \tcode{uid} is the source (or only) vertex id. \tcode{vid} is the target vertex id. \\ \tcode{VV} & \tcode{vertex_value_t} & \tcode{val} & Vertex Value, value or reference. This can be either the user-defined value on a vertex, or a value returned by a function object (e.g. \tcode{VVF}) that is related to the vertex. \\ \tcode{VR} & \tcode{vertex_range_t} & \tcode{ur,vr} & Vertex Range \\ \tcode{VI} & \tcode{vertex_iterator_t} & \tcode{ui,vi} & Vertex Iterator. \tcode{ui} is the source (or only) \\ From 24aa23faba8fd1372a1f4212a95a30ba136fdd58 Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Mon, 26 May 2025 11:33:27 -0400 Subject: [PATCH 02/31] Update hardended preconditions and preconditions Hardened preconditions should be O(1). In the case where there are multiple sources, they should be specified as preconditions. Remove ranges:: prefix in common type names for clarity Add Remarks for Connected Components and Strongly Connected Components Remove stale, commented-out text --- D3128_Algorithms/src/alg_comprehensive.hpp | 34 +- D3128_Algorithms/src/connected_components.hpp | 14 +- D3128_Algorithms/src/lp.hpp | 6 +- D3128_Algorithms/src/mst.hpp | 10 +- D3128_Algorithms/src/pagerank.hpp | 16 +- D3128_Algorithms/src/prim.hpp | 10 +- D3128_Algorithms/src/prototypes.cpp | 2 +- .../src/shortest_paths_helpers.hpp | 2 +- D3128_Algorithms/tex/algorithms.tex | 293 +++++------------- .../src/concepts_target_edge_range.hpp | 4 +- .../src/concepts_vertex_range.hpp | 4 +- .../src/edgelist_concepts.hpp | 8 +- .../src/edgelist_types.hpp | 2 +- D3131_Containers/src/compressed_graph.hpp | 36 +-- .../src/compressed_graph_gvoid.hpp | 12 +- D3131_Containers/tex/containers.tex | 4 +- D9903/src/degree.hpp | 4 +- tex/specification.tex | 40 +-- 18 files changed, 189 insertions(+), 312 deletions(-) diff --git a/D3128_Algorithms/src/alg_comprehensive.hpp b/D3128_Algorithms/src/alg_comprehensive.hpp index 1f9667e..4bc30f2 100644 --- a/D3128_Algorithms/src/alg_comprehensive.hpp +++ b/D3128_Algorithms/src/alg_comprehensive.hpp @@ -125,15 +125,15 @@ void breadth_first_search(ExecutionPolicy&& policy, * BFS: multiple source */ template -requires std::ranges::forward_range +requires std::forward_range void breadth_first_search(const G& graph, S&& sources, P&& predecessors, D&& distances); template -requires std::ranges::forward_range +requires std::forward_range void breadth_first_search(const G& graph, S&& sources, P&& predecessors, D&& distances, Q&& q); template -requires std::ranges::forward_range +requires std::forward_range void breadth_first_search( ExecutionPolicy&& policy, const G& graph, S&& sources, P&& predecessors, D&& distances); @@ -143,7 +143,7 @@ template -requires std::ranges::forward_range +requires std::forward_range void breadth_first_search(ExecutionPolicy&& policy, const G& graph, S&& sources, @@ -179,7 +179,7 @@ void dijkstra_shortest_paths(const G& graph, D&& distances); template -requires std::ranges::forward_range +requires std::forward_range void dijkstra_shortest_paths(const G& graph, S&& sources, P&& predecessors, D&& distances); /* @@ -240,7 +240,7 @@ void dijkstra_shortest_paths(const G& graph, */ template -requires weight_function> && std::ranges::forward_range +requires weight_function> && std::forward_range void dijkstra_shortest_paths( const G& graph, S&& sources, W&& w, P&& predecessors, D&& distances) {} @@ -251,7 +251,7 @@ template -requires weight_function> && std::ranges::forward_range +requires weight_function> && std::forward_range void dijkstra_shortest_paths(const G& graph, S&& sources, W&& w, @@ -299,11 +299,11 @@ void bellman_ford_shortest_paths(ExecutionPolicy&& e, D&& distances); template -requires std::ranges::forward_range +requires std::forward_range void bellman_ford_shortest_paths(const G& graph, S&& sources, P&& predecessors, D&& distances); template -requires std::ranges::forward_range +requires std::forward_range void bellman_ford_shortest_paths( ExecutionPolicy&& e, const G& graph, S&& sources, P&& predecessors, D&& distances); @@ -403,7 +403,7 @@ void bellman_ford_shortest_paths(const G& graph, */ template -requires weight_function> && std::ranges::forward_range +requires weight_function> && std::forward_range void bellman_ford_shortest_paths( const G& graph, S&& sources, W&& w, P&& predecessors, D&& distances) {} @@ -414,7 +414,7 @@ template -requires weight_function> && std::ranges::forward_range +requires weight_function> && std::forward_range void bellman_ford_shortest_paths(const G& graph, S&& sources, W&& w, @@ -424,7 +424,7 @@ void bellman_ford_shortest_paths(const G& graph, Combine&& comb) {} template -requires weight_function> && std::ranges::forward_range +requires weight_function> && std::forward_range void bellman_ford_shortest_paths(ExecutionPolicy&& e, const G& graph, S&& sources, @@ -440,7 +440,7 @@ template -requires weight_function> && std::ranges::forward_range +requires weight_function> && std::forward_range void bellman_ford_shortest_paths(ExecutionPolicy&& e, const G& graph, S&& sources, @@ -594,7 +594,7 @@ template -requires weight_function> && std::ranges::forward_range +requires weight_function> && std::forward_range void delta_stepping_shortest_paths(ExecutionPolicy&& e, const G& graph, S&& sources, @@ -610,7 +610,7 @@ template -requires weight_function> && std::ranges::forward_range +requires weight_function> && std::forward_range void delta_stepping_shortest_paths(ExecutionPolicy&& e, const G& graph, S&& sources, @@ -627,7 +627,7 @@ template -requires weight_function> && std::ranges::forward_range +requires weight_function> && std::forward_range void delta_stepping_shortest_paths(ExecutionPolicy&& e, const G& graph, S&& sources, @@ -645,7 +645,7 @@ template -requires weight_function> && std::ranges::forward_range +requires weight_function> && std::forward_range void delta_stepping_shortest_paths(ExecutionPolicy&& e, const G& graph, S&& sources, diff --git a/D3128_Algorithms/src/connected_components.hpp b/D3128_Algorithms/src/connected_components.hpp index fdbec99..6c326d2 100644 --- a/D3128_Algorithms/src/connected_components.hpp +++ b/D3128_Algorithms/src/connected_components.hpp @@ -9,9 +9,9 @@ void articulation_points(G&& g, Iter cut_vertices); * Hopcroft-Tarjan Biconnected Components */ template -requires ranges::forward_range> && - integral>> + forward_range OuterContainer> +requires forward_range> && + integral>> void biconnected_components(G&& g, OuterContainer& components); @@ -19,7 +19,7 @@ void biconnected_components(G&& g, * Connected Components */ template + random_access_range Component> void connected_components(G&& g, Component& component); @@ -28,7 +28,7 @@ void connected_components(G&& g, */ template + random_access_range Component> void strongly_connected_components(G&& g, GT&& g_t, Component& component); @@ -37,7 +37,7 @@ void strongly_connected_components(G&& g, * Tarjan Strongly Connected Components */ template -requires ranges::random_access_range> && integral> + random_access_range Component> +requires random_access_range> && integral> void strongly_connected_components(G&& g, Component& component); diff --git a/D3128_Algorithms/src/lp.hpp b/D3128_Algorithms/src/lp.hpp index 7e98cd1..dd0449b 100644 --- a/D3128_Algorithms/src/lp.hpp +++ b/D3128_Algorithms/src/lp.hpp @@ -2,7 +2,7 @@ * Label Propagation Algorithm */ template void label_propagation(G&& g, @@ -11,11 +11,11 @@ void label_propagation(G&& g, T max_iters = numeric_limits::max()); template void label_propagation(G&& g, Label& label, - ranges::range_value_t