From 777ec002b6bccad8e259e9ec286b3973a18a4f6e Mon Sep 17 00:00:00 2001 From: Phil Ratzloff Date: Fri, 10 Apr 2026 16:02:22 -0400 Subject: [PATCH] D3130: add vertex and edge pattern sections for automatic container adjustment --- .../tex/container_interface.tex | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/D3130_Container_Interface/tex/container_interface.tex b/D3130_Container_Interface/tex/container_interface.tex index d1caf0a..85c4887 100644 --- a/D3130_Container_Interface/tex/container_interface.tex +++ b/D3130_Container_Interface/tex/container_interface.tex @@ -769,3 +769,148 @@ \section{Using Existing Data Structures} Useful defaults have been created using types and containers in the standard library, with the ability to override them for external data structures. This is described in more detail in the paper for Graph Library Containers. + +\subsection{Recognized Vertex Patterns} + +When a graph type \tcode{G} is itself a \tcode{forward_range} whose elements are also ranges, the +GCI CPOs can detect and adapt to the storage strategy automatically. Two broad categories of vertex +container are recognized, each producing a different descriptor and vertex-id strategy. + +\subsubsection{Random-Access Vertex Pattern} +When \tcode{G} satisfies \tcode{random_access_range} and its elements satisfy \tcode{forward_range}, +the vertices are assumed to reside in a contiguous or random-access container such as +\tcode{std::vector} or \tcode{std::deque}. + +\begin{itemize} + \item \tcode{vertex_id_t} defaults to an integral type (index into the range). + \item \tcode{find_vertex(g, uid)} uses indexed access: \tcode{begin(vertices(g)) + uid}, + giving $\mathcal{O}(1)$ lookup. + \item \tcode{out_edges(g, u)} returns the inner range at that index. +\end{itemize} + +Examples of standard containers matching this pattern: +\begin{itemize} + \item \tcode{vector>} --- vertices in a \tcode{vector}, edges as \tcode{int} target ids. + \item \tcode{vector>>} --- vertices in a \tcode{vector}, edges as weighted pairs in a \tcode{list}. + \item \tcode{deque>} --- vertices in a \tcode{deque}, edges in a \tcode{forward_list}. +\end{itemize} + +\subsubsection{Associative Vertex Pattern} +When \tcode{G} is an associative container (\tcode{std::map} or \tcode{std::unordered_map}) +whose mapped values are forward ranges, vertices are keyed by an arbitrary id type rather than +a dense index. + +\begin{itemize} + \item \tcode{vertex_id_t} defaults to the \tcode{key_type} of the container. + \item \tcode{find_vertex(g, uid)} uses \tcode{g.find(uid)}, giving + $\mathcal{O}(\log |V|)$ for \tcode{map} or amortized $\mathcal{O}(1)$ for + \tcode{unordered_map}. + \item \tcode{out_edges(g, u)} extracts the \tcode{.second} member (the mapped edge + range) from the key-value pair. +\end{itemize} + +Examples of standard containers matching this pattern: +\begin{itemize} + \item \tcode{map>} --- sparse vertex ids in a sorted \tcode{map}, edges as target ids. + \item \tcode{unordered_map>>} --- hash-based vertex lookup, weighted edges. +\end{itemize} + +\subsubsection{Edge Container Patterns} +The edge range returned by \tcode{out_edges(g, u)} is the inner range stored at (or +referenced by) each vertex. Any standard container satisfying \tcode{forward_range} +whose element type matches a recognized edge element pattern (described below) is +accepted automatically. The library does \emph{not} maintain a fixed list of containers; +it relies on concept-based detection. + +Table~\ref{tab:edge_container_patterns} groups the standard containers by category and +summarises their trade-offs when used as edge containers. + +\begin{table}[h!] +\begin{center} +\resizebox{\textwidth}{!} +{\begin{tabular}{l l L{7.5cm}} +\hline + \textbf{Category} & \textbf{Container} & \textbf{Characteristics} \\ +\hline + Sequence & + \tcode{vector} & + Random-access, cache-friendly, amortized $\mathcal{O}(1)$ push-back. \\ + & + \tcode{deque} & + Random-access, stable references on push-back. \\ + & + \tcode{list} & + Bidirectional, $\mathcal{O}(1)$ splice, stable iterators. \\ + & + \tcode{forward_list} & + Forward-only, minimal overhead, $\mathcal{O}(1)$ push-front. \\ +\hdashline + Ordered associative & + \tcode{set} & + Sorted, automatic deduplication, $\mathcal{O}(\log n)$ lookup; element is the edge itself. \\ + & + \tcode{map} & + Sorted by target id, $\mathcal{O}(\log n)$ lookup, no parallel edges; \tcode{.first} is + target id, \tcode{.second} is edge value. \\ +\hdashline + Unordered associative & + \tcode{unordered_set} & + Hash-based deduplication, amortized $\mathcal{O}(1)$ insert/lookup. \\ + & + \tcode{unordered_map} & + Hash-based by target id, amortized $\mathcal{O}(1)$ lookup, no parallel edges; + \tcode{.first} is target id, \tcode{.second} is edge value. \\ +\hline +\end{tabular}} +\caption{Recognized Edge Container Patterns} +\label{tab:edge_container_patterns} +\end{center} +\end{table} + +For associative containers whose \tcode{value_type} is a \tcode{pair} +(i.e.\ \tcode{map} and \tcode{unordered_map}), the key is +treated as the target vertex id and the mapped type as the edge value. This means that +\tcode{target_id(g,uv)} returns \tcode{.first} and \tcode{edge_value(g,uv)} returns +\tcode{.second}, following the same pair convention described below. + +For set-like containers (\tcode{set}, \tcode{unordered_set}), each element is the edge +itself. If the element is integral it serves as the target id directly; if it is a +\tcode{pair} or \tcode{tuple} the element-level rules below apply. + +\subsubsection{Edge Element Patterns} +Within each vertex's edge range the GCI recognizes the following element forms and +automatically provides \tcode{target_id(g,uv)} and, where applicable, +\tcode{edge_value(g,uv)}: + +\begin{table}[h!] +\begin{center} +{\begin{tabular}{l L{8.5cm}} +\hline + \textbf{Edge Element Type} & \textbf{Automatic CPOs} \\ +\hline + \tcode{integral} & \tcode{target_id(g,uv)} returns the value directly. + No \tcode{edge_value}. \\ + \tcode{pair} & \tcode{target_id(g,uv)} returns \tcode{.first}; + \tcode{edge_value(g,uv)} returns \tcode{.second}. \\ + \tcode{tuple} & \tcode{target_id(g,uv)} returns \tcode{get<0>(uv)}; + remaining elements accessible via \tcode{edge_value}. \\ + custom struct & + The user overrides \tcode{target_id(g,uv)} and optionally + \tcode{edge_value(g,uv)} for the type. \\ +\hline +\end{tabular}} +\caption{Recognized Edge Element Patterns} +\label{tab:edge_element_patterns} +\end{center} +\end{table} + +\noindent +These vertex and edge patterns combine freely: any recognized vertex container can hold +any recognized edge container, and any recognized edge container can hold any recognized +edge element type. For example, +\tcode{vector>>} is a random-access graph with weighted edges, +\tcode{vector>} is a random-access graph with sorted deduplicated unweighted edges, +\tcode{vector>} is a random-access graph with $\mathcal{O}(\log n)$ edge lookup by target, +and \tcode{map>} is an associative graph with unweighted edges. +When the element type does not match a recognized pattern, the user must override the +appropriate CPOs for the graph type.