Skip to content

Commit 1a12990

Browse files
committed
Reworked section 3.5, including adding exercises
1 parent c062b0a commit 1a12990

File tree

1 file changed

+104
-53
lines changed

1 file changed

+104
-53
lines changed

ALP_Tutorial.tex

Lines changed: 104 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -371,72 +371,123 @@ \subsection{Numerical Linear Algebra}
371371

372372
\subsection{Semirings and Algebraic Operations}
373373

374-
A key feature of GraphBLAS (and ALP) is that operations are defined over semirings rather than just the conventional arithmetic operations. A semiring consists of a pair of operations (an “addition” and a “multiplication”) along with their identity elements, which generalize the standard arithmetic (+ and $\times$). GraphBLAS allows using different semirings to, for example, perform computations like shortest paths or logical operations by substituting the plus or times operations with min, max, logical OR/AND, etc. In GraphBLAS, matrix multiplication is defined in terms of a semiring: the “add” operation is used to accumulate results, and the “multiply” operation is used when combining elements.
375-
ALP lets you define and use custom \textbf{semirings} by specifying:
374+
A key feature of GraphBLAS and ALP is that operations are defined over generic algebraic structures rather than over the conventional arithmetic operations only. An example of an algebraic structure is a \emph{semiring}. Loosely speaking, a semiring formalises what we understand as standard linear algebra. Intuitively, a semiring consists of a pair of operations, an ``addition'' and a ``multiplication'', along with their identity elements. The additive and multiplicative operations may differ from standard arithmetic ($+$ and $\times$). The multiplicative operation together with its identity -- which we call $\textbf{1}$ -- forms a monoid. The additive operation together with its identity -- $\mathbf{0}$ -- forms a commutative monoid, meaning that the order of addition shall not change the result ($a+b=b+a$). Formally speaking there are more requirements to monoids and semirings that ALP is aware of and exploits -- however, for the purposes of this tutorial, the preceding intuitive description suffices.
376375

376+
GraphBLAS allows using different semirings to, for example, perform computations like shortest paths or logical operations by substituting the plus or times operations with min, max, logical OR/AND, and so on. This is usually done structurally, by replacing the plus-times semirings with another, such as e.g.\ a min-plus semiring to compute shortest paths. This is why, as you saw in the previous subsection, GraphBLAS primitives explicitly take algebraic structures as a mandatory argument. ALP additionally allows expressing algebraic structures as C++ types, and introduces an algebraic type trait system:
377377

378378
\begin{itemize}
379-
\item \textbf{A binary monoid:} an associative, commutative ``addition'' operation with an identity element. Examples:
379+
\item \textbf{commutative monoids:} an associative and commutative operation with an identity element. Examples:
380380
\begin{itemize}
381-
\item \texttt{(+}, 0\texttt{)} — the usual addition over numbers
382-
\item \texttt{(min}, $+\infty$\texttt{)} — useful for computing minima
381+
\item \texttt{(+, 0)} — the usual addition over numbers:
382+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
383+
grb::Monoid< grb::operators::add< T >, grb::identities::zero >
384+
\end{lstlisting}
385+
or, more simply,
386+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
387+
grb::monoids::plus< T >
388+
\end{lstlisting}
389+
\item \texttt{(min, $\infty$)} — useful for computing minima:
390+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
391+
grb::Monoid< grb::operators::min< T >, grb::identities::infinity > // or simply
392+
grb::monoids::min< T >
393+
\end{lstlisting}
394+
\item \texttt{($\land$, true)} — logical semiring for Boolean algebra:
395+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
396+
grb::Monoid< grb::operators::logical_and >, grb::identities::logical_true > // or
397+
grb::monoids:land< T >
398+
\end{lstlisting}
383399
\end{itemize}
400+
For all the above examples, the following \emph{type traits} are \texttt{true}:
401+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
402+
grb::is_monoid< grb::monoid::plus< T > >::value
403+
grb::is_commutative< grb::monoid::min< T > >::value
404+
// and so on
405+
\end{lstlisting}
384406

385-
\item \textbf{A binary multiplicative operator:} a second operation (not necessarily arithmetic multiplication), with its own identity element. Examples:
386-
\begin{itemize}
387-
\item \texttt{(*}, 1\texttt{)} — standard multiplication
388-
\item \texttt{(AND}, \texttt{true}\texttt{)} — logical semiring for Boolean algebra
389-
\end{itemize}
390-
\end{itemize}
391-
392-
A semiring is a mathematical structure consisting of a set equipped with two binary operations satisfying certain axioms.
393-
Many common semirings are provided or can be constructed.
394-
For instance, the plus-times semiring uses standard addition as the accumulation (monoid)
395-
and multiplication as the combination operator – this yields ordinary linear algebra over real numbers.
396-
One can also define a \texttt{min-plus} semiring (useful for shortest path algorithms, where "addition"
397-
is min and "multiplication" is numeric addition). ALP’s design allows an “almost unlimited variety of operators
398-
and types” in semirings.
399-
400-
In code, ALP provides templates to construct these. For example, one can define:
407+
% \item \textbf{general monoids:} an operation with an identity element. Example:
408+
% \begin{itemize}
409+
% \item \texttt{($\times$, 1)} — standard multiplication:
410+
%\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
411+
%grb::Monoid< grb::operators::mul< T >, grb::identities::one > // or
412+
%grb::monoids::times< T >
413+
%\end{lstlisting}
414+
\item \textbf{general binary operators}: binary operators without any additional structure. Examples:
401415
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
402-
using Add = grb::operators::add<double>;
403-
using AddMonoid = grb::Monoid<Add, grb::identities::zero>;
404-
using Mul = grb::operators::mul<double>;
405-
using PlusTimes = grb::Semiring<Mul, AddMonoid>;
406-
PlusTimes plusTimesSemiring;
416+
grb::operators::mul< double > // f(x, y) = x * y
417+
grb::operators::subtract< int > // f(i, j) = i - j
418+
grb::operators::zip< char, int > // f(c, i) = {c, i}, an std::pair< char, int >
407419
\end{lstlisting}
408-
Here we built the plus-times semiring for \texttt{double}: we use the provided addition operator and its identity (zero) to make a monoid, then combine it with the multiply operator to form a semiring. ALP comes with a library of predefined operator functors (in \texttt{grb::operators}) and identities (in \texttt{grb::identities}) for common types. You can also define custom functor structs if needed. In many cases, using the standard \texttt{plusTimesSemiring} (or simply passing operators/monoids directly to functions) is sufficient for basic algorithms.
409-
410-
\subsection{Primitive Operations (mxv, eWiseMul, dot, etc.)}
411-
412-
Using the above containers and semirings, ALP provides a set of primitive functions in the \texttt{grb} namespace to manipulate the data. These functions are free functions (not class methods) and typically take the output container as the first parameter (by reference), followed by input containers and an operator or semiring specification. The most important primitives include:
413-
414-
\textbf{grb::set} – Assigns all elements of a container to a given value. For example, \texttt{grb::set(x, 1.0)} will set every entry of vector \texttt{x} to $1.0$ (making all indices present with value 1.0). This is useful for initialization (if called on an empty vector, it will insert all indices with that value). There is also \texttt{grb::setElement(container, value, index[, index2])} to set a single element: for a vector, you provide an index; for a matrix, a row and column. For example, \texttt{grb::setElement(y, 3.0, n/2)} sets $y_{n/2} = 3.0$.
415-
\newline
416-
417-
\textbf{grb::mxv} – Perform matrix-vector multiplication on a semiring. The call \texttt{grb::mxv(u, A, v, semiring)} computes $u = A \otimes v$ (where $\otimes$ denotes matrix-vector multiply under the given semiring). For the plus-times semiring, this corresponds to the usual linear algebra operation $u_i = \sum_j A_{ij} \times v_j$ (summing with + and multiplying with $\times$). The output vector \texttt{u} must be pre-allocated to the correct size (number of rows of $A$). By default, ALP’s \texttt{mxv} adds into the output vector (as if doing $u += A \times v$). If you want to overwrite \texttt{u} instead of accumulate, you may need to explicitly set \texttt{u} to the identity element (e.g. zero) beforehand or use descriptors (advanced options) – but for most use cases, initializing $u$ to 0 and then calling mxv is sufficient to compute $u = A x$. For example, \texttt{grb::mxv(y, A, x, plusTimesSemiring)} will compute $y_i = \sum_j A_{ij} x_j$ using standard arithmetic (assuming \texttt{y} was zeroed initially).
418-
\newline
420+
These too define algebraic type traits:
421+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
422+
grb::is_operator< OP >::value // true for all above operators
423+
grb::is_monoid< OP >::value // false for all above operators
424+
grb::is_associative< grb::operators::mul< T > >::value // true
425+
grb::is_commutative< grb::operators::subtract< T >::value // false
426+
// ...
427+
\end{lstlisting}
428+
\item \textbf{semirings}: simplified, a commutative ``additive'' monoid combined with a ``multiplicative'' monoid. Examples:
429+
\begin{itemize}
430+
\item the plus-times semiring: standard linear algebra
431+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
432+
grb::Semiring<
433+
grb::operators::add< T >, grb::operators::mul< T >,
434+
grb::identities::zero, grb::identities::one
435+
> // or
436+
grb::semirings::plusTimes< T >
437+
\end{lstlisting}
438+
\item the Boolean semiring: perhaps the second most common semiring
439+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
440+
grb::Semiring<
441+
grb::operators::logical_or< bool >, grb::operators::logical_and< bool >,
442+
grb::identities::logical_false, grb::identities::logical_true
443+
> // or
444+
grb::semirings::boolean
445+
\end{lstlisting}
446+
\item the min-plus semiring: useful for, e.g., shortest paths
447+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
448+
grb::Semiring<
449+
grb::operators::min< T >, grb::operators::add< T >,
450+
grb::identities::infinity, grb::identities::zero
451+
> // or
452+
grb::semirings:::minPlus< T >
453+
\end{lstlisting}
454+
\end{itemize}
455+
For all of the above semirings, we have the following:
456+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
457+
grb::is_semiring< S >::value // true
458+
grb::is_monoid< S >::value // false
459+
grb::is_operator< S >::value // false
460+
\end{lstlisting}
461+
We may furthermore extract the additive and multiplicative monoids and operators from semirings:
462+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false ]
463+
grb::semirings::boolean mySemiring;
464+
auto myAddM = mySemiring.getAdditiveMonoid();
465+
auto myMulM = mySemiring.getMultiplicativeMonoid();
466+
auto myAddOp = mySemiring.getAdditiveOperator();
467+
auto myMulOp = myMulM.getOperator();
468+
\end{lstlisting}
469+
Finally, we may also extract and instantiate identities from semirings:
470+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false, morekeywords=constexpr ]
471+
grb::semirings::plusTimes< int > mySemiring;
472+
constexpr int myZero = mySemiring.template getZero< int >();
473+
double castFromZero = mySemiring.template getZero< double >();
474+
constexpr int myOne = mySemiring.getMultiplicativeMonoid().template getIdentity();
475+
\end{lstlisting}
476+
\end{itemize}
419477

420-
\textbf{grb::dot} – Compute the dot product of two vectors. This is essentially a special case of a matrix-vector multiply or a reduce operation. ALP provides \texttt{grb::dot(result, u, v, semiring)} to compute a scalar result = $u^T \otimes v$ under a given semiring. For the standard plus-times semiring, \texttt{grb::dot(alpha, u, v, plusTimesSemiring)} will calculate $\alpha = \sum_i (u_i \times v_i)$ (i.e. the dot product of $u$ and $v$). If you use a different monoid or operator, you can compute other pairwise reductions (for example, using a \texttt{min} monoid with logical multiplication could compute something like an “AND over all i” if that were needed). In most cases, you'll use dot with the default arithmetic semiring for inner products. The output \texttt{alpha} is a scalar (primitive type) passed by reference, which will be set to the resulting value.
421-
\newline
478+
The design of ALP allows the definition of custom operators and identities, and therefore allows a virtually unlimited variety of algebraic structures. The most useful operators, monoids, and semirings are predefined in the namespaces \texttt{grb::operators}, \texttt{grb::monoids}, and \texttt{grb::semirings}, respectively. Let us now employ these algebraic structures to show-case how these amplify the expressiveness of standard linear algebraic primitives.\vspace{.5\baselineskip}
422479

423-
\textbf{grb::apply} – Apply a binary operator out-of-place between two scalars and store result in a third scalar.
424-
The function \texttt{grb::apply}\,(z, x, s, op) applies the binary functor \texttt{op} to scalar \texttt{x}
425-
and scalar \texttt{s} and writes the result into scalar \texttt{z}.
426-
For example, \texttt{grb::apply}\,(z, x, s, grb::operators::mul<double>()) computes $z = x \times s$.
427-
Note: some backends like nonblocking or hyperdag may rely on \texttt{grb::apply} to infer data dependencies,
428-
therefore pure C++ should be avoided and implementations should ensure all dependencies are explicit.
429-
\newline
430-
\textbf{grb::eWiseApply} – Apply a binary operator element-wise between two containers (out-of-place vector/matrix update).
431-
The function \texttt{grb::eWiseApply}\,(z, x, y, op) applies the binary functor \texttt{op} to corresponding elements of \texttt{x} and \texttt{y} and writes the results into \texttt{z}; both inputs and the output are containers of matching dimensions.
432-
For example, \texttt{grb::eWiseApply}\,(z, x, y, grb::operators::mul<double>()) computes $z_i = x_i \times y_i$ for indices where the operation is defined.
433-
In summary, both \texttt{grb::apply}\,() and \texttt{grb::eWiseApply}\,() require a binary operator and perform out-of-place elementwise updates (one with a scalar, the other with a second container).
480+
\noindent \textbf{Exercise 9} (warm-up): given a \texttt{grb::Vector< double > x}, write an ALP/GraphBLAS function that computes the squared 2-norm of $x$ (i.e., compute $\sum_i x_i^2$) using \texttt{grb::dot}. \textbf{Hint:} consider starting from the code of exercise 8. \textbf{Question}: which semiring applies here?\vspace{.5\baselineskip}
434481

435-
\paragraph{API usage notes:} All the above operations require that output parameters be passed by reference, since they are modified in place (e.g., \texttt{y} in \texttt{grb::mxv(y, A, x, ...)} is updated with the result). Input objects are typically passed by const-reference. You should ensure that the output container is allocated with the correct size beforehand – ALP will not automatically resize vectors or matrices on operation calls if dimensions mismatch. If dimensions do not agree (e.g., you try to multiply an $m\times n$ matrix with a vector of length not $n$),
436-
the function will return an error code to indicate the misuse. In fact, most ALP primitives return a status code of type \texttt{grb::RC} (with \texttt{grb::SUCCESS} indicating success). For clarity, our code examples will omit explicit error handling, but in a real program you may check the returned code of each operation.
482+
\noindent \textbf{Exercise 10}: ALP and GraphBLAS allow for the use of \emph{improper} semirings -- semirings that are mathematically not true semirings but are still useful in practice. In ALP, improper semirings are made up of 1) an commutative ``additive'' monoid and 2) \emph{any} binary ``multiplicative'' operator. All primitives that take a semiring may also take a pair of such an additive monoid and multiplicative operator-- for example, \texttt{grb::dot( alpha, x, y, plusTimes )} is semantically equivalent to
483+
\begin{lstlisting} [language=C++, basicstyle=\ttfamily\small, showstringspaces=false, morekeywords=constexpr ]
484+
grb::dot( alpha, x, y, plusTimes.getAdditiveMonoid(), plusTimes.getMultiplicativeOperator() );
485+
\end{lstlisting}
486+
Take note of \texttt{grb::operators::abs\_diff< double >}. What does this binary operator compute? Use this operator and the notion of improper semirings to compute the $1$-norm difference between two vectors $x$ and $y$ using a single call to \texttt{grb::dot}. \textbf{Hint:} start off from the code from the previous exercise.\vspace{.5\baselineskip}
437487

438-
In the next section, we will put these concepts together in a concrete example.
488+
\noindent \textbf{Exercise 11}: consider a square matrix \texttt{grb::Matrix< double > G} the matrix representation of an edge-weighted graph $G$. Consider \texttt{grb::Vector< double > s} (source) a vector of matching dimension to $G$ with a single value zero ($0$) at an index of your choosing. \textbf{Question}: normally, under a plusTimes semiring, $Gs$ would return a zero vector. However, what interpretation would $Gs$ have under the minPlus semiring? Use this interpretation to compute the shortest path to any other vertex reachable from your chosen source. Then, extend the approach to compute the shortest path two hops away from your chosen source.\vspace{.25\baselineskip}
439489

490+
\textbf{Bonus question}: what interpretation could $G^ks$ have under the maxTimes semiring?
440491

441492
\section{Solution to Exercise 8}\label{sec:simple_example}
442493

0 commit comments

Comments
 (0)