\documentclass[10pt]{article}

\usepackage{amsthm}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{stmaryrd}
\usepackage{tikz}
\usepackage{comment}
\usetikzlibrary{shapes, arrows.meta, positioning}

\tikzstyle{block} = [draw, fill=white, rectangle]
\newtheorem{theorem}{Theorem}[section]
\newtheorem{lemma}{Lemma}[section]
\newtheorem{definition}{Definition}[section]

\newcommand{\code}[1]{\texttt{#1}}
\newcommand{\Z}{\mathbb{Z}}  % integers
\newcommand{\N}{\mathbb{N}}  % naturals
\newcommand{\B}{\mathbb{B}}  % booleans
% stream with elements of a given type
\newcommand{\stream}[1]{\ensuremath{\mathcal{S}_{#1}}}
% finite stream with elements of a given type (zero almost everywhere)
\newcommand{\streamf}[1]{\ensuremath{\overline{\mathcal{S}_{#1}}}}
\newcommand{\zm}{\ensuremath{z^{-1}}} % stream delay operator
\newcommand{\I}{\mathcal{I}}  % stream integration
\newcommand{\D}{\mathcal{D}}  % stream derivative
\newcommand{\distinct}{\mathit{distinct}}  % distinct operator
\newcommand{\q}{\ensuremath{\mathcal{Q}}}  % query
% multiset of elements with given type
\newcommand{\multiset}[1]{\mathit{multiset}_{#1}}
% set with elements of given type
\newcommand{\set}[1]{\mathit{set}_{#1}}
\newcommand{\id}{\ensuremath{\mathit{id}}} % identity function
\newcommand{\isset}{\mbox{isset}}
\newcommand{\ispositive}{\mbox{ispositive}}
\newcommand{\defn}{\stackrel{\textrm{\scriptsize def}}{=}}
\newcommand{\map}{\mbox{map}}

\title{Streaming Differential Datalog}

\begin{document}
\maketitle

\section{Basic notation}

\begin{comment}
\subsection{Types}

$\N$ is the set of natural numbers, while $\Z$ is the set of integers.

Our language will deal with a set of base types $B$ that includes
$\N$, $\Z$, \code{string}, $\B$ (Booleans), $\mathbf{unit}$.

Derived types include: tuples, vectors (lists), functions.

$$T = B \;|\; T \times T \;|\; T^* \;|\; T \rightarrow T$$

%% We also highlight two special derived types: $\multiset{T}$: finite
%% multisets of elements of type $T$, and $\set{T}$: sets of elements of
%% type $T$.  We call these two particular types \emph{collections}.

A typing context is a map that assigns types to variable names.
$\Gamma = x_1 : T_1, x_2 : T_2, \ldots, x_m : T_m$, where $T_i$ is the
type of variable $x_i$.
\end{comment}

\subsection{Monoids and groups}

A monoid $(M, 0_M, +_M)$ is a set $M$ with a distinguished element
$0_M \in M$ and a binary associative operation $+_M : M \times M
\rightarrow M$, such that $a +_M 0 = 0 +_M a = a$ for any $a \in M$.
When clear from the context we drop the index $_M$.  A commutative
monoid has the property that $a + b = b + a$ for all $a, b \in M$.  A
group is a monoid where every element $a \in M$ has a complement $-a
\in M$ such that $a + (-a) = 0$.

$\id$ is the identity function on any set $\id: T \rightarrow T$,
defined by $\id(x) \defn x$.

\subsection{Multisets}

Given a monoid (group) $B$, the set of functions between $A$ and $B$
form a monoid (group): M = $A \rightarrow B$, defined by $0_M = (x
\mapsto 0_B)$ and $f +_M g = x \mapsto f(x) +_B g(x)$.  If $B$ is a
monoid (group), we denote the \emph{finite} functions between $A$ and
$B$ as $B[A]$; these are functions where $f(x) \not= 0_B$ for at most
a finite number of values of $x \in A$.  Such a function can be
denoted by enumerating the inputs that map to non-zero values: $\{ x_1
\mapsto b_1, \dots, x_n \mapsto b_n \}$.  The values in $B[A]$ can
also be thought as being key-value maps with keys in $A$ and values in
$B$.

In particular, \emph{multisets} with elements of type $A$ are the
functions $\Z[A]$.  Multiset union is just addition in the $\Z[A]$
monoid.  Note that multisets elements can have negative weights.
Multisets form a vector space, since $\Z$ with addition is a group.
The zero is the empty multiset $\{\} = \phi$.  Given a multiset $m \in
\Z[A]$ and a value $v \in A$, we overload the array index notation
$m[v]$ to denote the \emph{weight} of the element $v$ in $m$.  When $c
\in \Z$, and $v \in A$ we also write $c \cdot v$ for the multiset $\{
v \mapsto c \}$.  We say that $x \in m$ iff $m[x] > 0$.

The ``distinct'' function $\distinct: \Z[D] \rightarrow \Z[D]$
projects a multiset into an underlying set (but \emph{the result is
  still a multiset}).  The definition of distinct is given by
$\distinct(m) \defn \{ x \mapsto 1 \;|\; m[x] > 0 \} = \{ x \mapsto 1
\;|\; x \in m \} = \sum_{x \in m} 1 \cdot x$.  The distinct
function is idempotent: $\distinct = \distinct \circ \distinct$.
Since our algebraic operations are cleaner over a vector space, we
prefer to work with multisets and project them down to sets when
necessary rather than working with sets.

We say that a multiset is also a ``set'' if the weight of every
element is either zero or one: $\isset : \Z[D] \rightarrow \B$,
given by $\isset(s) \defn (s = \distinct(s))$

We say that a multiset is positive if the weight of every element is
positive: $\ispositive : \Z[D] \rightarrow \B$, given by

$$\ispositive(s) \defn \left\{
\begin{array}{ll}
  \mbox{true} & \mbox{ if } s[x] \geq 0, \forall x \in D \\
  \mbox{false} & \mbox{ otherwise}
\end{array}
\right.$$

Note that for any $m \in \Z[D]$ we have: $\isset(\distinct(m))$ and
$\ispositive(\distinct(m))$.  We also write $m \geq 0$ when $m$ is
positive.  We also say that $m \supseteq n$ or $m \geq n$ for $m, n
\in \Z[D]$ iff $m - n \geq 0$.

We call a function (query) between multisets ``linear'' if it commutes
with addition: $\q: \Z[I] \rightarrow \Z[O]$ has the property that
$\q(a +_{\Z[I]} b) = \q(a) +_{\Z[O]} \q(b)$ for any $a, b \in \Z[I]$.
This implies that for a linear query $\q(0_{\Z[I]}) = 0_{\Z[O]}$.

We call a function $f : \Z[D] \rightarrow \Z[T]$ ``positive'' if
$\forall x \in \Z[T], x \geq 0 \rightarrow f(x) \geq 0$.  We use the
same notation as for multisets: $\ispositive{f}$.

\subsection{Streams}

Given a monoid $T$, streams $\stream{T}$ of values of type $T$ are
functions $\N \rightarrow T$.  We often think of the index in $\N$ as
being time; if $s \in \stream{T}$ is a stream of values of type $T$,
the notation $s[t] = s(t) \in T$ denotes the value of the element of
the stream $s$ ``at time'' $t \in \N$.  To simplify some proofs we
define that $s[-1] = 0_T$.

Functions on monoids can be ``lifted'' to operate on streams: given
$f: I \rightarrow O$ we can extend it on streams pointwise: $f :
\stream{I} \rightarrow \stream{I}$ given by $o[t] = f(i)[t] = f(i[t])$.

We depict the streams as arrows, and the pointwise application of a
function to stream as a box, as in the following diagram:

\begin{tikzpicture}[auto,node distance=1cm,>=latex]
    \node [] (input) {$i$};
    \node [block, right of=input] (f) {$f$};
    \node [right of=f] (output) {$o$};
    \draw [->] (input) -- (f);
    \draw [->] (f) -- (output);
\end{tikzpicture}

This works also for functions with multiple inputs, e.g.  a function
$f: A \times B \rightarrow C$ can be lifted to operate on streams $f:
\stream{A} \times \stream{B} \rightarrow \stream{C}$ computing
pointwise on time: $f(a, b)[t] = f(a[t], b[t])$ for $t \in \N$.

\begin{tikzpicture}[auto,node distance=.5cm,>=latex]
  \node [] (input1) {$a$};
  \node [below of=input1] (midway) {};
  \node [below of=midway] (input2) {$b$};
  \node [block, right of=midway] (f) {$f$};
  \node [right of=f, node distance=2cm] (output) {$f(a,b)$};
  \draw [->] (input1) -| (f);
  \draw [->] (input2) -| (f);
  \draw [->] (f) -- (output);
\end{tikzpicture}

The $\zm: \stream{T} \rightarrow \stream{T}$ \emph{delay operator} is
a function from streams to streams, defined as
$$(\zm(s))[t] = \left\{
\begin{array}{ll}
  0_T & \mbox{ if } t = 0 \\
  s[t - 1] & \mbox{ for } t > 0.
\end{array}
\right.
$$

\begin{tikzpicture}[auto,node distance=1cm,>=latex]
    \node [] (input) {$i$};
    \node [block, right of=input] (z) {$\zm$};
    \node [right of=z] (output) {$o$};
    \draw [->] (input) -- (z);
    \draw [->] (z) -- (output);
\end{tikzpicture}

We write $z^{-k}$ for $\underbrace{\zm \circ \ldots \circ \zm}_{k
  \mbox{ times}}$ .

We call a function $f$ over streams \textbf{memoryless} if it has the
property: $f \circ \zm = \zm \circ f$.

\begin{definition}
Given a monoid $M$, \textbf{integration} is an operation from streams to
streams, $\I : \stream{M} \rightarrow \stream{M}$.  The integral of a
stream $S$ is defined using an equation: $\I(s) \defn \zm(\I(s)) + s$.
(Using the notation used for digital filters this equation can be also
written as $\I(s) = s / (1 - \zm)$).  The element of $\I(s)$ at time
$t$ is the (prefix) sum of all elements of $s$ at times up to $t$:
$\I(s)[t] = \sum_{i \leq t} s[t]$, where the sum uses the addition of
the underlying monoid $M$.  The digital filter for $\I$ is given in
the following figure:

\begin{tikzpicture}[auto,>=latex]
    \node [] (input) {$s$};
    \node [block, shape=circle, right of=input, inner sep=0pt] (plus) {$+$};
    \node [right of=plus, node distance=2cm] (output) {$\I(s)$};
    \node [block, below of=plus, node distance=1cm] (z) {$z^{-1}$};
    \draw [draw,->] (input) -- (plus);
    \draw [->] (plus) -- node (o) {} (output);
    \draw [->] (o) |- (z);
    \draw [->] (z) -- (plus);
\end{tikzpicture}
\end{definition}

\begin{definition}
Given a group $M$, \textbf{differentiation} is an operation from
streams to streams $\D : \stream{M} \rightarrow \stream{M}$, defined
as $\D(s) \defn s - \zm(s)$ (we need $M$ to be group in order to have
subtraction).  An element of $\D(s)$ (at time $t$) is the difference
between the previous element (time $t-1$) of $s$ and the current (time
$t$) element of $S$.  Using the notation for digital filters $\D(s) =
s(1 - \zm)$.

\begin{tikzpicture}[auto,>=latex]
    \node [] (input) {$s$};
    \node [block, shape=circle, right of=input,node distance=2cm] (plus) {};
    \node [right of=plus] (output) {$\D(s)$};
    \draw [draw,->] (input) -- node (i) {} (plus);
    \node [block, below of=i, node distance=1cm] (z) {$\zm$};
    \draw [->] (plus) -- (output);
    \draw [->] (i) -- (z);
    \draw [->] (z) -| node[near end,right] {$-$} (plus);
\end{tikzpicture}
\end{definition}

\begin{lemma}
For a stream $s$ over a commutative group we have $\D(\I(s)) = s$.
\end{lemma}
\begin{proof}
  We can prove this algebraically: $\D(\I(s)) = \I(s) - \zm(\I(s)) =
  (\zm(\I(s)) + s) - \zm(\I(s)) = s$, by substituting the definitions
  of $\D$ and $\I$ and using the commutativity of the group.
\end{proof}

If $I$ and $O$ are monoids, we call an operator $f: \stream{I}
\rightarrow \stream{O}$ over streams \textbf{linear} if $\forall t \in
\N . f(a +_I b)[t] = (f(a) +_O f(b))[t]$.  Notice that this is a
different kind of linearity than the linearity of operators between
multisets: this is linearity in the time dimension.  The following
observation is trivial: the stream operator produced by lifting a
linear function between monoids $f: I \rightarrow O$ is also linear.
The operator $\zm$ is linear.

\begin{lemma}
  The composition of two linear stream operators is linear.
\end{lemma}
\begin{proof}
  For suitable monoids $I, O, P$, consider two linear operators $f:
  \stream{I} \rightarrow \stream{O}$ and $g: \stream{O} \rightarrow
  \stream{P}$.
$$
\begin{aligned}
  g(f(a +_I b))[t] &= g(f(a) +_O f(b))[t] & \mbox{ linearity of }f \\
  &= (g(f(a)) +_P g(f(b)))[t] & \mbox{ linearity of }g. \\
\end{aligned}
$$
\end{proof}

\begin{lemma}
  The composition of two memoryless stream operators is memoryless.
\end{lemma}
\begin{proof}
  For suitable sets $I, O, P$, consider two memoryless operators $f:
  \stream{I} \rightarrow \stream{O}$ and $g: \stream{O} \rightarrow
  \stream{P}$.
$$
\begin{aligned}
  \zm(g(f(i))) &= g(\zm(f(i))) & \mbox{ since $g$ is memoryless} \\
  &= g(f(\zm(i))) & \mbox{ since $f$ is memoryless}.
\end{aligned}
$$
\end{proof}

\begin{lemma}
  When computing over a commutative group, the operators $\I$, $\D$,
  and $\zm$ are memoryless and linear.
\end{lemma}
\begin{proof}
  $\D$ is the composition of three linear and memoryless operators.
  For $\zm$ the proof is trivial.  Let us prove the statement for $\I$.
  $$
\begin{aligned}
  \zm(\I(i))[t] &= \zm(\sum_{k \leq t} i[k]) & \mbox{ definition of }\I \\
  &= \sum_{k \leq t-1} i[k] & \mbox{ definition of }\zm \\
  &= \sum_{k \leq t} \zm(i[k]) & \mbox{ commutativity }\zm \\
  &= \I(\zm(i))[t] & \mbox{ definition of }\I. \\
  (\I(a + b))[t] &= \sum_{k \leq t}(a + b)[t] & \mbox{ definition of }\D \\
  &= \sum_{k \leq t} a[k] + \sum_{k \leq t} b[k] & \mbox{ commutativity, linearity of + } \\
  &= \I(a)[t] + \I(b)[t] & \mbox{ definition of }\I.
\end{aligned}
$$
\end{proof}

Two streams can be combined into a single stream of pairs: $\times:
\Z[I] \times \Z[J] \rightarrow \Z[I \times J]$, defined by $(a \times
b)[t] = (a[t], b[t])$.  The inverse operation can project a stream of
pairs into two separate streams.  This enables us to treat programs
that handle multiple input streams as a program with a single input
stream.

\subsection{Loops as streams}

We introduce two new operators: one that can create a new stream from
a scalar value, and one to convert a stream to a scalar value.  This
is a translation of the schema proposed in~\cite{abadi-fossacs15} into
the language of streams.

The Kroneker delta function $\delta_0 : T \rightarrow \stream{T}$
produces a stream from a scalar value.  The stream is
defined:

$$\delta_0(v)[t] \defn \left\{
\begin{array}{ll}
  v & \mbox{if } t = 0 \\
  0_T & \mbox{ otherwise}
\end{array}
\right.
$$

We diagram the $\delta_0$ operator using a dotted arrow as input, since
the input is a scalar value.

\begin{tikzpicture}[auto,node distance=1cm,>=latex]
    \node [] (input) {$i$};
    \node [block, right of=input] (delta) {$\delta_0$};
    \node [right of=delta] (output) {$o$};
    \draw [->,dotted] (input) -- (delta);
    \draw [->] (delta) -- (output);
\end{tikzpicture}

Let us denote with $\streamf{T}$ streams that are almost everywhere
(a.e.)  $0_T$ (only a finite number of values in the stream have a
non-zero value).  We define a function $\int : \streamf{T} \rightarrow
T$ as $\int(s) \defn \sum_{t \geq 0} s[t]$.

We can also extend the set $T$ with an ``infinite'' value $\top$:
$\overline{T} \defn T \cup \{ \top \}$, and define $\int{s} \defn
\top$ for streams $s \in \stream{T} \setminus \streamf{T}$.

\begin{tikzpicture}[auto,node distance=1cm,>=latex]
    \node [] (input) {$i$};
    \node [block, right of=input] (S) {$\int$};
    \node [right of=delta] (output) {$o$};
    \draw [->] (input) -- (S);
    \draw [->, dotted] (S) -- (output);
\end{tikzpicture}

\subsection{Clock domains}

So far we had the tacit assumption that ``time'' is common for all
streams in a program.  For example, when we perform an operation
between two streams, we assume that they use the same ``clock''.
However, the $\delta_0$ operator creates streams with a ``new'' clock,
so a computation can have multiple clock domains.  To be precise we
should label all stream operators with the clock domain they belong
to, and we should make sure only that streams within the same clock
domain are combined.  We will use a superscript $\cdot^t$ to indicate
a clock domain.  The $\delta_0^t$ operator creates a new clock domain.
If not clear from the context, operators such as $\zm, \D, \I,
\delta_0, \int$ should be labeled with the clock domain they operate
on: $\zm_t, \D^t, \I^t, \delta_0^t, \int^t$.

\subsection{Streams over multisets}

In the rest of this text we consider only streams over multisets
$\stream{\Z[T]}$, for some type of element $T$: at each time moment
the value of the stream is a multiset.  Since multisets form a vector
space, addition and subtraction on streams over multisets of the same
type are well-defined.

\begin{definition}
A stream over a multiset is \textbf{monotone} if $s[t] \geq s[t-1],
\forall t \in \N$.
\end{definition}

\begin{lemma}
Given a positive stream $s$ over a group, the stream $\I(s)$ is
monotone.
\end{lemma}
\begin{proof}
  Let us compute $\I(s)[t + 1] - \I(s)[t] = \sum_{i \leq t+1}s[i] -
  \sum_{i \leq t}s[i] = s[t+1] \geq 0$, by commutativity.
\end{proof}

\begin{lemma}
Given a monotone stream $s$ over a group, the elements of the stream
$\D(s)$ are positive.
\end{lemma}
\begin{proof}
  By the definition of monotonicity $s[t+1] \geq s[t]$.  By definition
  of $\D$ we have $\D(s)[t+1] = s[t+1] - s[t] \geq 0$.
\end{proof}

\section{A semantics of Datalog in terms of streams}

\subsection{Datalog operator implementations}

We show how various Datalog operators can be implemented using these
primitives.  We follow e.g.,~\cite{green-pods07}.

\paragraph{Union} $\cup: \Z[I] \times \Z[I] \rightarrow \Z[I]$.  $i_1
\cup i_2 \defn \sum_{x \in i_1 \cup i_2} (i_1[x] + i_2[x]) \cdot x$.
In the following diagram we use dotted lines to indicate scalar
values.

\begin{tikzpicture}[auto,node distance=.5cm,>=latex]
  \node [] (input1) {$i_1$};
  \node [below of=input1] (midway) {};
  \node [below of=midway] (input2) {$i_2$};
  \node [block, shape=circle, right of=midway, inner sep=0in, node distance=1cm] (plus) {$+$};
  \node [block, right of=plus, node distance=1.5cm] (distinct) {$\distinct$};
  \node [right of=distinct, node distance=1.5cm] (output) {$o$};
  \draw [->,dotted] (input1) -| (plus);
  \draw [->,dotted] (input2) -| (plus);
  \draw [->,dotted] (plus) -- (distinct);
  \draw [->,dotted] (distinct) -- (output);
\end{tikzpicture}

The $\distinct$ node is necessary to provide the set semantics of
Datalog.  We have $\isset(i_1) \land \isset(i_2) \Rightarrow
\isset(i_1 \cup i_2)$ and $\ispositive(i_1) \land \ispositive(i_2)
\Rightarrow \ispositive(i_1 \cup i_2)$.

\paragraph{Projection} In this case the inputs and outputs have some
additional structure: $I = \Z[A_0 \times A_1]$, $O = \Z[A_0]$.  The
projection on $A_0$ is defined as: $\pi_{A_0}(i) = \distinct(\sum_{x
  \in A_0} (\sum_{x' \in i, x'|_0 = x} i[t]) \cdot x)$, where $x'|_0$
is defined as the first component of $x'$.  Note that the inner
sum is defined over weights, so it is a value in $\Z$, while the outer
sum is defined over tuples, so it is in $\Z[A_0]$.

\begin{tikzpicture}[auto,>=latex]
  \node [] (input) {$i$};
  \node [block, right of=input, node distance=1cm] (pi) {$\pi$};
  \node [block, right of=pi, node distance=1.5cm] (distinct) {$\distinct$};
  \node [right of=distinct, node distance=1.5cm] (output) {$o$};
  \draw [->] (input) -- (pi);
  \draw [->] (pi) -- (distinct);
  \draw [->] (distinct) -- (output);
\end{tikzpicture}

We have $\isset(i) \Rightarrow \isset(\pi_A(i))$ and $\ispositive(\pi_A)$.

\paragraph{Filtering} Let us assume that we have a predicate $P: I
\rightarrow \B$; we identify ``false'' with 0 and ``true'' with 1.
The filtering a collection $i$ with predicate $P$ is implemented as:
$\sigma_P(i) = \sum_{x \in i} P(x) i[x] \cdot x$.

\begin{tikzpicture}[auto,node distance=1cm,>=latex]
  \node [] (input) {$i$};
  \node [block, right of=input] (P) {$\sigma_P$};
  \node [right of=P] (output) {$o$};
  \draw [->] (input) -- (P);
  \draw [->] (P) -- (output);
\end{tikzpicture}

We have $\isset(i) \Rightarrow \isset(\sigma_P(i))$ and
$\ispositive(\sigma_P)$.

\paragraph{Mapping}

Given a function $f : T \rightarrow S$, the map operator lifts the
function to operate on multisets $\map(f) : \Z[T] \rightarrow \Z[S]$,
defined as $(\map(f))(i) \defn \sum_{x \in i} i[x] \cdot f(x)$.  When
unambiguous, we omit the ``map'' and instead of $map(f)$ we write just
$f$ denote the lifted function.

It turns out that mapping is a model for 4 Datalog operations: maps,
flatmaps, and group-bys, and aggregations.  Note that $\ispositive(f)
\Rightarrow \ispositive(\map(f))$.  From the point of view of
Differential Datalog all these boxes are just positive
transformations.

\code{Flatmap} is transformation that consumes a (multi)set where each
element is a multiset. Given a function $f : T \rightarrow \Z[S]$, we
define $\mbox{flatmap}(f)(i) \defn \sum_{x \in i} i[x] \cdot f(x)$.
The DDlog \code{Flatmap} operator is defines as $\mbox{flatmap}(\id)$.
Note that $\ispositive(\code{Flatmap})$.

\code{group-by} is a transformation that consumes a multiset and
produces collection of groups, where each group is (roughly) a
multiset.  More precisely, consider an arbitrary type of keys $K$, and
a function that computes a key for a value $k: I \rightarrow K$.  Then
we can define $\mbox{groupby}(k): \Z[I] \rightarrow \Z[I][K]$, as
$\mbox{groupby}(k)(i) = \sum_{x \in i} \{ k(x) \mapsto 1 \cdot i \}$.
Note that $\ispositive(\mbox{groupby}(k))$.

Finally, aggregation in DDlog is nothing but a function that
transforms a group into a scalar value.  (In fact, it does not even
have a special notation.)  Formally, given a function $a: \Z[I]
\rightarrow O$, aggregation is $\map(a)$.  Group-by combined with
aggregation is defined as $\mbox{group-by-aggregate}(k, a) = \map(a)
\circ \map(\mbox{groupby}(k))$ (assuming suitable functions $k$ and
$a$ with types defined as above).

\paragraph{Negation} Datalog negation is defined as set difference:
$\setminus: \Z[I] \times \Z[I] \rightarrow \Z[I]$, where $i_1
\setminus i_2 = \distinct(i_1 - i_2)$.  Note that we have $\forall
i_1, i_2, \ispositive(i_1 \setminus i_2)$ due to the application of
the $\distinct$ operator.  A Datalog antijoin is defined as a pair of
projections (that bring valuations to the same schema) followed by a
negation.

\subsection{Fixed points}

This is the essential part of this formalism.

Let us consider a language that consists of the relational algebra
together with stratified negation and recursive definitions.  Let us
consider a query $\q$ in this language.  Let us assume that the query
defines a function $\q : I \rightarrow O$, where $I$ and $O$ are sets
with elements from a fixed universe.  We can naturally ``lift'' the
semantics of $\q$ to compute on $\stream{I} \rightarrow \stream{O}$
pointwise: $q(i)[t] = q(i[t]), \forall t \geq 0, \mbox { for } i \in
\stream{I}$.  Since we only support streams of multisets, we need to
treat $I$ and $O$ as multisets in the stream computation.  Note that
the semantics of Datalog promises that once an input is a set, the
output is also a set.

\begin{theorem}
Consider a recursive datalog query of the form: $o = i \cup \q(o)$,
where $\q$ is a relational query.  The following filter implements the
Datalog set semantics of $o$:

\begin{tikzpicture}[auto,>=latex]
  \node [] (input) {$i$};
  \node [block, right of=input] (delta) {$\delta(i)$};
  \node [block, shape=circle, right of=input, node distance=2cm, inner sep=0in] (plus) {$+$};
  \node [block, right of=plus, node distance=1.5cm] (distinct) {$\distinct$};
  \node [block, right of=distinct,node distance=2cm] (D) {$\D$};
  \node [block, right of=D, node distance=2cm] (S) {$\int$};
  \node [right of=S] (output)  {$o$};
  \node [block, below of=plus, node distance=1cm] (f) {$\q$};
  \draw [->, dotted] (input) -- (delta);
  \draw [->] (delta) -- (plus);
  \draw [->] (plus) -- (distinct);
  \draw [->] (distinct) -- node (o) {$o'$} (D);
  \draw [->] (D) -- node (do) {$do$} (S);
  \draw [->, dotted] (S) -- (output);
  \node [block, below of=o, node distance=1.3cm] (z) {$\zm$};
  \draw [->] (o) -- (z);
  \draw [->] (z) -- (f);
  \draw [->] (f) -- (plus);
\end{tikzpicture}
\end{theorem}
\begin{proof}
  TODO: this proof should relate some of the standard semantics of
  fixed-point computations to the stream semantics.
\end{proof}

Since $\q$ is a relational query, we have that $i \geq 0 \Rightarrow
\q(i) \geq 0$.  We can prove using induction over time that the stream
$o'$ (the output of the $\distinct$ block) is monotone.  Thus the
stream defined by the output of $\D$ block is positive.  If there is a
$t$ such that $o'[t + 1] = o'[t]$, if follows that $o'[t + k] = o'[t]$
for all $k \geq 0$, which implies that the stream $do$ is 0 a.e., and
thus $o$ is well-defined.  Moreover, we can prove that $\isset(o)$.

Let us notice that the combination $\int \circ \D$ applied to a
monotone stream will produce that fixed-point value of the input
stream (if it exists).  Under this circumstance the output of the
$\int$ corresponds to its first $0$ input.

\section{Differential Datalog}

\begin{definition}
Consider a traditional datalog program $\q: I \rightarrow O$, where
$I$ and $O$ are multiset types.  When this program is considered as a
Differential Datalog program it's semantics is a function $\q:
\stream{I} \rightarrow \stream{O}$, defined by the following diagram:
$\D \circ \q \circ \I$.
\end{definition}

Notice that, while the original program computes on multisets, the
DDlog program computes on streams of multisets.

We have to add one important restriction, however: since the $\q$
program computes on sets, we must require that output of the $\I$
operator to always be a set!  Since the inputs to the program are
arbitrary streams, this constraint is not automatically satisfied.

\begin{tikzpicture}[auto,node distance=1cm,>=latex]
    \node [] (input) {$i$};
    \node [block, right of=input] (I) {$\I$};
    \node [block, right of=I] (q) {$\q$};
    \node [block, right of=q] (D) {$\D$};
    \node [right of=D] (output) {$o$};
    \draw [->] (input) -- (I);
    \draw [->] (I) -- (q);
    \draw [->] (q) -- (D);
    \draw [->] (D) -- (output);
\end{tikzpicture}

Note that the definition uses the ``lifted'' implementation of the
program $\q$, operating over streams.

Also note that if program $\q$ contains a fixed-point sub-query, then
the implementation of $\q$ contains a block that computes over a
stream of streams!  We will denote a stream where each element is a
stream with a double arrow.  Then the previous query $o = i \cup
\q(o)$ provides the following DDlog program:

\begin{tikzpicture}[auto,>=latex]
  \node [] (input) {$i$};
  \node [block, right of=input] (I) {$\I$};
  \node [block, right of=I] (delta) {$\delta^t(i)$};
  \node [block, shape=circle, right of=I, node distance=2cm, inner sep=0in] (plus) {$+^t$};
  \node [block, right of=plus, node distance=1.5cm] (distinct) {$\distinct^t$};
  \node [block, right of=distinct,node distance=2cm] (D) {$\D^t$};
  \node [block, right of=D] (S) {$\int^t$};
  \node [block, right of=S] (D2) {$\D$};
  \node [right of=D2] (output)  {$o$};
  \node [block, below of=plus, node distance=1cm] (f) {$\q^t$};
  \draw [->] (input) -- (I);
  \draw [->] (I) -- (delta);
  \draw [->, double] (delta) -- (plus);
  \draw [->, double] (plus) -- (distinct);
  \draw [->, double] (distinct) -- node (o) {} (D);
  \draw [->, double] (D) -- (S);
  \draw [->] (S) -- (D2);
  \draw [->] (D2) -- (output);
  \node [block, below of=o, node distance=1.1cm] (z) {$\zm_t$};
  \draw [->, double] (o) -- (z);
  \draw [->, double] (z) -- (f);
  \draw [->, double] (f) -- (plus);
\end{tikzpicture}

Note that we have annotated the inner loop with a superscript ${}^t$
(used as a subscript for $\zm_t$) to indicate the clock domain of
these stream operators.

\section{Term-rewriting transformations}

To implement efficiently a DDlog program the compiler makes use of a
series of term-rewriting transformations.  We list here some of them.

\subsection{A compilation strategy}

DDlog programs can be expressed in general as a composition of a
sequence of \emph{fold operators over streams}.  The general scheme
of a fold over a stream is given by the following diagram:

\begin{tikzpicture}[auto,node distance=1cm,>=latex]
    \node [] (input) {$i$};
    \node [block, right of=input] (f) {$f$};
    \node [right of=I] (output) {$o$};
    \node [block, below of=f] (z) {$\zm$};
    \draw [->] (input) -- (f);
    \draw [->] (f) -- (output);
    \draw [<-] (z.east) -- ++(.3,0) |- node[below right]{$S$} ([yshift=1mm]f.south east);
    \draw [->] (z.west) -- ++(-.3,0) |- ([yshift=1mm]f.south west);
\end{tikzpicture}

$f$ is a function $f: I \times S \rightarrow O \times S$.  $S$ is the
\emph{state} maintained (incrementally) to compute $f$.  $i$ is an
incremental input change to $f$.  $o$ is a change in the output, a
function of the current input and the previous version of the state
accumulated so far $S$.  The next state $S$ is a function of the
previous state and the current input.  Assuming $S$ is a monoid, the
initial value of the state is $0_S$.

In an implementation we want the following properties for such a
diagram:
\begin{itemize}
  \item The cost of computing $f(i, s)$ is proportional to the size of
    $i$, but weakly dependent on the size of $s$ (for the most common
    case both $i$ and $s$ are multisets, and the size of $m$ can be
    defined as the number of elements with non-zero weight; ``weakly
    dependent'' could be an e.g. logarithmic cost).
  \item $S$ does not grow ``too large'' (e.g., the size of $S$ should
    not be a function of the time elapsed $t$).
\end{itemize}

\subsection{Linear queries}

\begin{theorem}
If $\q$ is a linear query, we have: $\q \circ \I = \I \circ \q$ and
$\D \circ \q = \q \circ \D$.
\end{theorem}
\begin{proof}
$$
\begin{aligned}
  ((\q \circ \I)(i))[t] &= \q(\sum_{i \leq t} i[t]) & \mbox{by definition of }\I \\
  &= \sum_{k \leq t} \q(i[k]) & \mbox{by linearity of }\q \\
  &= \I(\q(i))[t] & \mbox{by definition of }\I. \\
  ((\D \circ \q)(i))[t] &= \q(i[t]) - \q(i[t-1]) & \mbox{by definition of }\D \\
  &= \q(i[t] - i[t-1]) & \mbox{by linearity of }\q \\
  &= \q(\D(i)))[t] & \mbox{by definition of }\D.
\end{aligned}
$$
\end{proof}

Using this observation it follows that for linear programs $\q$ the
DDlog implementation is the same as the Datalog implementation:

$\D(\q(\I(i))) = \q(\D(\I(i))) = \q(i)$.

\subsection{Bi-linear queries}

Consider a bi-linear query of two inputs: $\q : \Z[I] \times
\Z[J] \rightarrow \Z[O]$ with the properties: $\q(a + b, c) = \q(a,
c) + \q(b, c)$ and $\q(a, c + d) = \q(a, c) + \q(a, d)$.  Cartesian
products and joins have this property.  For such a query we have the
following property:

\begin{theorem}
  If $\q$ is a bi-linear query, we have:
  $$
  \begin{aligned}
    \q(\I(a), \I(b)) &= \zm(\q(\I(a)), \I(b))& \mbox{ ``previous''
      version of }\q \\
    &+ \q(\I(\zm(a)), b)& \mbox{ uses previous version of left input}\\
    &+ \q(a, \I(\zm(b)))& \mbox{ uses previous version of right input} \\
    &+ \q(a, b) & \mbox{ only based on latest changes}.
  \end{aligned}
$$
\end{theorem}
\begin{proof}
  The proof is based on algebraic manipulations starting from the
  definition of $\I(a) = \zm(\I(a)) + a$ using the memoryless properties.
\end{proof}

\begin{tikzpicture}[auto,>=latex]
  \node [] (input1) {$i_1$};
  \node [below of=input1, node distance=2cm] (input2) {$i_2$};
  \node [block, right of=input1] (I1) {$\I$};
  \node [block, circle, below of=I1, inner sep=0cm] (ab) {$\times$};
  \node [block, right of=input2] (I2) {$\I$};
  \draw [->] (input1) -- node[name=i1tap] {} (I1);
  \draw [->] (input2) -- node[name=i2tap,below] {} (I2);
  \draw [<-] (ab.west) -- ++(0,.05) -| (i1tap);
  \draw [<-] (ab.west) -- ++(0,-.05) -| (i2tap);
  \node [block, right of=I1] (ZI1) {$\zm$};
  \node [block, right of=I2] (ZI2) {$\zm$};
  \draw [->] (I1) -- (ZI1);
  \draw [->] (I2) -- (ZI2);
  \node [block, right of=ZI1, circle, inner sep=0cm] (DI1) {$\times$};
  \node [block, right of=ZI2, circle, inner sep=0cm] (DI2) {$\times$};
  \draw [->] (ZI1) -- (DI1);
  \draw [->] (ZI2) -- (DI2);
  \node [block, circle, right of=ab, inner sep=0cm, node distance=2cm] (sum) {$+$};
  \draw [->] (ab) -- (sum);
  \node [block, circle, right of=sum, inner sep=0cm, node
    distance=2cm] (final) {$+$};
  \draw [->] (DI1) -- (sum);
  \draw [->] (DI2) -- (sum);
  \draw [->] (sum) -- node[name=mid] {} (final);
  \node [block, below of=mid] (zz) {$\zm$};
  \node [right of=final] (output) {$o$};
  \draw [->] (final) -- (output);
  \draw [->] (final) |- (zz);
  \draw [->] (zz) -- (mid);
  \draw [->] (i1tap) -- (DI2);
  \draw [->] (i2tap) -- (DI1);
\end{tikzpicture}

In the DDlog Rust implementation the collection $\I(\zm(a))$ is
usually represented as an arrangement.

\subsection{Recursion}

TODO

\hrule
\hrule
\pagebreak

From now on this is WIP.

\begin{comment}
\subsection{DDlog types}

\[\frac{\code{A}: T, \code{B}: S}{\code{(A,B)}: T \times S}\]
\[\frac{\code{A}: T, \code{B}: S}{\code{function(x:A):B}: A \rightarrow B}\]
\[\frac{\code{T1}: T_1, \code{T2}: T_2}{\code{T1 | T2} : T_1 \oplus T_2}\]
\[\frac{\code{T1}: T_1, \code{T2}: T_2}{\code{Constructor\{f1: T1, f2:
    T2\}} : \string \rightarrow T_1 \oplus T_2}\]
\end{comment}

\subsection{DDlog collections}

DDlog programs consume and produce streams of data.  The outside world
inputs/outputs streams feed to/from DDlog collections.  A DDlog
transaction defines a time step for all the input streams.  On each
transaction commit DDlog updates all output streams.  DDlog programs
only operate on streams.  Some input and output streams are fed
directly to DDlog programs, while others are processed, as described
in this section.

\subsubsection{\code{input stream IS[D]}}

\begin{tikzpicture}[auto, node distance=4cm,>=latex]
    \node [] (input) {};
    \node [block, right of=input] (block) {\id};
    \node [block, shape=ellipse, right of=block] (ddlog) {DDlog};
    \draw [draw,->] (input) -- node {$IS$} (block) node [below,pos=0.5] {input stream};
    \draw [->] (block) -- node {$\code{IS}$}(ddlog) node [below,pos=0.5] {internal stream};
\end{tikzpicture}

A DDlog declaration of \code{input stream IS[D]} declares a (DDlog
internal) stream $\code{IS} \in \stream{\Z[\code{D}]}$, where the
stream's elements are multisets with elements of type \code{D}.  Given
a stream of input values $IS \in \stream{\Z[D]}$, the contents of the
DDlog stream \code{IS} is exactly $IS$.  $\id$ is the identity
function on streams $\id(x) = x$.

\subsubsection{\code{output stream OS[D]}}

\begin{tikzpicture}[auto, node distance=4cm,>=latex]
    \node [block, shape=ellipse] (ddlog) {DDlog};
    \node [block, right of=ddlog] (block) {\id};
    \node [right of=block] (output) {};
    \draw [draw,->] (ddlog) -- node {\code{OS}} (block) node [below,pos=0.5] {internal stream};
    \draw [->] (block) -- node {$OS$}(output) node [below,pos=0.5] {output stream};
\end{tikzpicture}

As shown in the previous diagram, a DDlog declaration of \code{output
  stream OS[D]} declares an (output) stream $OS \in
\stream{\Z[\code{D}]}$.  The contents of the output stream $OS$ is
exactly the contents of the stream \code{OS}.

\subsubsection{\code{input multiset IM[D]}}

\begin{tikzpicture}[auto, node distance=4cm,>=latex]
    \node [] (input) {};
    \node [block, right of=input] (block) {$\I$};
    \node [block, shape=ellipse, right of=block] (ddlog) {DDlog};
    \draw [draw,->] (input) -- node {$IM$} (block) node [below,pos=0.5] {input stream};
    \draw [->] (block) -- node {$\code{IM}$}(ddlog) node [below,pos=0.5] {internal stream};
\end{tikzpicture}

A DDlog declaration of \code{input multiset IM[D]} declares a stream
$\code{IM} \in \stream{\Z[\code{D}]}$.  Given a stream of input values
$IM \in \stream{\Z[\code{D}]}$, the contents of \code{IM} is given by
$\code{IM} = \I(MI)$, the integral of the stream of inputs.

\subsubsection{\code{output multiset OM[D]}}

\begin{tikzpicture}[auto, node distance=4cm,>=latex]
    \node [block, shape=ellipse] (ddlog) {DDlog};
    \node [block, right of=ddlog] (block) {$\D$};
    \node [right of=block] (output) {};
    \draw [draw,->] (ddlog) -- node {\code{OM}} (block) node [below,pos=0.5] {internal stream};
    \draw [->] (block) -- node {$OM$}(output) node [below,pos=0.5] {output stream};
\end{tikzpicture}

A DDlog declaration of \code{output multiset OM[D]} declares a stream
$OM \in \stream{\Z[\code{D}]}$.  The contents of the (output) stream
$OM$ is given by $OM = \D(\code{OM})$, the derivative of the stream
\code{OM}.

\subsubsection{\code{input relation IR[D]}}

\begin{tikzpicture}[auto, node distance=4cm,>=latex]
    \node [] (input) {};
    \node [block, right of=input] (distinct) {$\distinct$};
    \node [block, right of=distinct] (I) {$\I$};
    \node [block, shape=ellipse, right of=I] (ddlog) {DDlog};
    \draw [draw,->] (input) -- node {$IR$} (block) node [below,pos=0.5] {input stream};
    \draw [draw,->] (distinct) -- (I);
    \draw [->] (I) -- node {$\code{IR}$}(ddlog) node [below,pos=0.5] {internal stream};
\end{tikzpicture}

A DDlog declaration of \code{input relation IR[D]} declares a stream
$\code{IR} \in \stream{\Z[\code{D}]}$.  The elements of the stream
\code{IR} are defined by $\code{IR} = \distinct(\I(IR))$.

\subsubsection{\code{output relation OR[D]}}

\begin{tikzpicture}[auto, node distance=4cm,>=latex]
    \node [block, shape=ellipse] (ddlog) {DDlog};
    \node [block, right of=ddlog] (D) {$\D$};
    \node [block, right of=D] (distinct) {$\distinct$};
    \node [right of=distinct] (output) {};
    \draw [draw,->] (ddlog) -- node {\code{OR}} (D) node [below,pos=0.5] {internal stream};
    \draw [draw,->] (D) -- (distinct);
    \draw [->] (distinct) -- node {$OR$}(output) node [below,pos=0.5] {output stream};
\end{tikzpicture}

A DDlog declaration of \code{output relation OR[D]} declares a stream
$OR \in \stream{\Z[\code{D}]}$.  The elements of the stream are $OR$ are defined
by $OR = \D(\distinct(\code{OR}))$.

\subsection{DDlog operators}

All DDlog operators: join, group-by, aggregate, projection, etc., are
just particular instances of functions over multisets.  When computing
over streams DDlog just applies these functions to the streams
pointwise.  In this section we describe the semantics of these
operators over a multi-set; the semantics over streams is just lifted
pointwise.

\subsection{DDlog syntax}

A Datalog rule is a term of the form:

\begin{eqnarray*}
  rule &::=& atom \code{ :- } \mathit{RHSClauses}. \\
  atom &::=& C[X] \mbox{ where $C$ is a collection and $X$ is a tuple
    of names} \\
  \mathit{RHSClauses} &::=& \mathit{RHSClause} \\
  &|& \mathit{RHSClause}, \mathit{RHSClauses} \\
  \mathit{RHSClause} &::=& \code{not } atom \\
  &|& expr   \\
  &|& \code{var } name = expr \\
  &|& \code{var } name = \code{FlatMap}( expr ) \\
  &|& \code{var } name = expr \code{.groupby}( expr ) \\
\end{eqnarray*}

\bibliographystyle{plain}
\bibliography{model}

\end{document}


\documentclass{article}

\usepackage{amsmath}
\usepackage{graphicx}
\usepackage{tabularx}
\usepackage{multicol}

% Geometry
\usepackage{geometry}
\geometry{letterpaper, left=15mm, top=30mm, right=15mm, bottom=20mm}

% Fancy Header
\usepackage{fancyhdr}
\renewcommand{\footrulewidth}{0.4pt}
\pagestyle{fancy}
\fancyhf{}
\chead{CSC 360 - Analysis of Algorithms}
\lfoot{CALU Fall 2021}
\rfoot{RDK}

% Add vertical spacing to tables
\renewcommand{\arraystretch}{1.4}

% Macros
\newcommand{\definition}[1]{\underline{\textbf{#1}}}

\newenvironment{rcases}
  {\left.\begin{aligned}}
  {\end{aligned}\right\rbrace}

% Begin Document
\begin{document}

\section*{Notes - Week 1 - August 25, 2021}

\begin{itemize}

    \item An \definition{algorithm} is a finite step by step process to solve a problem
    \begin{itemize}
        \item \definition{finite} it must terminate given \textbf{any} input
    \end{itemize}

    \item What is the Analysis of Algorithms?
    \begin{itemize}
        \item How long does it take to run?
        \item How much space does it use?
    \end{itemize}

    \item Most research is on the time it takes an algorithm to run. Memory is "cheap".

    \item Typically concerned with large data sets.
    \begin{itemize}
        \item Most algorithms will seem fast in small data sets
        \item Large data sets simulate real situations
    \end{itemize}

    \item We always analyze an algorithm before we write it. \definition{Analysis}

    \item Trying it out is referred to as \definition{Measuring}.

    \item \definition{Big O Notation} refers to the time complexity of a statement, notated as $O(x)$ where $x$ is the amount of statements the algorithm executes, based on the variable $n$.
    \begin{itemize}
        \item $O(n^2)$
        \item $O(log(n))$
        \item $O(1)$
        \item etc
    \end{itemize}

\end{itemize}

\subsection*{The Selection Problem}

\begin{itemize}

    \item We have $n$ numbers, in an array, no guarantee of sorting.

    \item We want the $k^t^h$ largest number.

    \item Algorithm $(0)$: $O(n^2)$ complexity

    \item Algorithm $(1)$: $O(nlog(n))$ complexity

    \item New Algorithm:
    \begin{enumerate}
        \item Read the first $k$ numbers into a separate array
        \item Sort the new array
        \item Read the rest of the numbers. If they're smaller, replace the largest number in the array with an insertion.
    \end{enumerate}

    \item Is this new algorithm faster?
    \begin{itemize}
        \item Some of the time
        \item depends on how large $k$ is relative to $n$
    \end{itemize}

    \item Example: Find the $5^t^h$ largest number in an array of size $1,000,000$
    \begin{itemize}
        \item $n = 1,000,000$
        \item $k = 5$
        \item Using $nlog(n)$ sort, it's approximately $20,000,000$ statements
        \item Using new algorithm, it's about $5log(5) + 500,000 + 5(500,000) ~= 3,000,000$ statements
    \end{itemize}

    \item As $k$ approaches $n$, the new algorithm approaches the original time complexity of $nlog(n)$.

\end{itemize}

\end{document}


\section{Result}

\newcommand{\e}[1]{\times 10^{#1}}

The frequency we set on the signal generator is $f=34498 \pm 1$Hz.
The room temperature is $23 \pm 1 ^\circ C$.

\subsection{Measurements for resonance method}

The data are presented in Table~\ref{d1} with the calculation for $L_{10+i}-L_i$.

\begin{table}[H] \small
    \centering
    \begin{tabular}{|c|c|c|c|c|c|}
    \hline
        \multicolumn{2}{|c|}{$L_i[\times 10^{-3} m]\pm[0.01\times 10^{-3} m]$} &
        \multicolumn{2}{|c|}{$L_i[\times 10^{-3} m]\pm[\times 10^{-3} m]$} &
        \multicolumn{2}{|c|}{$L_{10+i}-L_i[\e{-3}m]$}\\\hline
        1  & 29.37 & 11 &  80.44 & 1  & 51.07 \\\hline
        2  & 34.49 & 12 &  85.48 & 2  & 50.99 \\\hline
        3  & 39.60 & 13 &  90.01 & 3  & 50.41 \\\hline
        4  & 44.74 & 14 &  95.65 & 4  & 50.91 \\\hline
        5  & 49.83 & 15 & 100.82 & 5  & 50.99 \\\hline
        6  & 54.90 & 16 & 105.93 & 6  & 51.03 \\\hline
        7  & 60.06 & 17 & 111.12 & 7  & 51.06 \\\hline
        8  & 65.24 & 18 & 116.20 & 8  & 50.96 \\\hline
        9  & 70.37 & 19 & 121.32 & 9  & 50.95 \\\hline
        10 & 75.38 & 20 & 126.39 & 10 & 51.01 \\\hline
    \end{tabular}
    \caption{Data for the resonance method}\label{d1}
\end{table}

The average value of $\Delta L$ can be calculated from the results presented in Table~\ref{d1} as

\[
    \overline{\Delta L}=\frac{1}{10}\sum_{i=1}^{10}\Delta L_i=(50.94\pm
    0.05)\times 10^{-3} m,\quad u_{r,\Delta}=0.10\%
\]

Then the wavelength $\lambda$ can be calculated by

\[
        \lambda=\frac{2\Delta L}{n}=\frac{2\times50.94\times 10^{-3}
        }{10}=(10.19 \pm0.01)\times 10^{-3} m,\quad u_{r,\lambda}=0.10\%.
\]

The speed of sound in air $v$ is

\[
    v=\lambda f = (10.19 \pm 0.01)\times 10^{-3} m \cdot 34498 Hz  = 351.45 \pm
    0.4 m/s,\quad u_{r,v}=0.11\%.
\]

\subsection{Measurements for phase comparison method}

The experiment data  are shown in Table~\ref{d2} with the calculation for $L_{6+i}-L_i$.

\begin{table}[H] \small
    \centering
    \begin{tabular}{|c|c|c|c|c|c|}
    \hline
        \multicolumn{2}{|c|}{$L_i[\times 10^{-3} m]\pm[0.01\times 10^{-3} m]$} &
        \multicolumn{2}{|c|}{$L_i[\times 10^{-3} m]\pm[0.01\times 10^{-3} m]$} &
        \multicolumn{2}{|c|}{$L_{6+i}-L_i[\e{-3}m]$}\\\hline
        1 & 23.57 & 7  &  84.39 & 1 & 60.82 \\\hline
        2 & 33.78 & 8  &  94.51 & 2 & 60.73 \\\hline
        3 & 43.97 & 9  & 104.62 & 3 & 60.65 \\\hline
        4 & 54.17 & 10 & 114.76 & 4 & 60.59 \\\hline
        5 & 64.11 & 11 & 124.72 & 5 & 60.61 \\\hline
        6 & 74.24 & 12 & 134.92 & 6 & 60.68 \\\hline
    \end{tabular}
    \caption{Data for the phase comparison method}\label{d2}
\end{table}

The average value of $\Delta L$ is calculated  based on the results presented in Table~\ref{d2} as

\[
    \overline{\Delta L}=\frac{1}{6}\sum_{i=1}^{6}\Delta L_i=(60.68\pm 0.8)\times
    10^{-3} m,\quad u_{r,\Delta L}=3\%.
\]

Hence, the wavelength $\lambda$ can be calculated as

\[
    \lambda=\frac{\Delta L}{n}=\frac{60.68 \e{-3}}{6}=(10.11 \pm 0.13)\times
    10^{-3} m,\quad u_{r,\lambda}=1.3\%.
\]

The speed of sound in air $v$ is

\[
    v=\lambda f = (10.11 \pm 0.13) \times 10^{-3} m \cdot 34498 Hz  = 348.889
    \pm 0.4 m/s,\quad u_{r,v}=0.11\%.
\]

\subsection{Measurements for time difference method (liquid)}

We obtain the speed of sound in water from Table~\ref{d3} by linear fitting (See Figure \ref{tl}).

\begin{table}[H] \small
    \centering
    \begin{tabular}{|c|c|c|}
    \hline
        & $t_i[\e{-6}s] \pm 0.2 [\e{-6} s]$  & $L_i[\times 10^{-3} m] \pm 0.01 [\e{-3} m]$ \\\hline
        1  & 113.8 & 160.00 \\\hline
        2  & 120.6 & 170.00 \\\hline
        3  & 127.4 & 180.00 \\\hline
        4  & 134.2 & 190.00 \\\hline
        5  & 141.2 & 200.00 \\\hline
        6  & 148.2 & 210.00 \\\hline
        7  & 153.8 & 220.00 \\\hline
        8  & 160.6 & 230.00 \\\hline
        9  & 167.4 & 240.00 \\\hline
        10 & 174.2 & 250.00 \\\hline
        11 & 181.0 & 260.00 \\\hline
        12 & 186.8 & 270.00 \\\hline
    \end{tabular}
    \caption{Data for Figure \ref{tl}}
    \label{d3}
\end{table}

\begin{figure}[H]
    \centering
    \includegraphics[width=12cm]{fig/tl}
    \caption{Fitting curve for $L\ vs.\ t$. }\label{tl}
\end{figure}

\begin{quote}
\centering
Goodness of fit:\\
  SSE: 3.331e-06                \\
  R-square: 0.9998              \\
  Adjusted R-square: 0.9997     \\
  RMSE: 0.0005771
\end{quote}

From the slope of the fitting curve we can deduce the $v_{water}$
\[
    v_{water}=1502 \pm 16 m/s.
\]


% \makeatletter
% \newcommand\prev{\the\tikz@lastxsaved,\the\tikz@lastysaved}
% \makeatother

The remainder of the text is just commented examples.

\clearpage

\subsection{Snake}

\begin{tcblisting}{gallery}
\begin{codi}[tetragonal]
  \obj{          & \ker a   & \ker b   & \ker c   &   \\
                 & A        & B        & C        & 0 \\
        |(0')| 0 & A'       & B'       & C'       &   \\
                 & \coker a & \coker b & \coker c &   \\ };

  \mor   (ker a) ->   (ker b) ->   (ker c);
  \mor (coker a) -> (coker b) -> (coker c);
  \mor       A  f :-> B  g :-> C -> 0;
  \mor 0' -> A' f':-> B' g':-> C';

  \mor[near start] (ker a) -> A a:-> A' -> (coker a);
  \mor[near start] (ker b) -> B b:-> B' -> (coker b);
  \mor[near start] (ker c) -> C c:-> C' -> (coker c);

  \draw[/codi/arrows/crossing over, ->, rounded corners, >=stealth]
    (ker c) -- ++( 0.6,0) -- ++(0,-1.55)
            -- ++(-3.2,0) -- ++(0,-1.45) -- (coker a);
\end{codi}
\end{tcblisting}

\clearpage

\subsection{The fourth associahedron}

\begin{tcblisting}{gallery}
\begin{codi}
% From the LaTeX preamble:
%   \usepackage{newunicodechar}
%   \newunicodechar{ı}{\mathbf 1}
%   \newunicodechar{×}{\otimes}

  \foreach [count=\n] \o in {
      ((w×x)×y)×x,
      (w×(x×y))×x,
      w×((x×y)×x),
      w×(x×(y×x)),
      (w×x)×(y×x)
    } \obj (\n) at (72*\n:7em) {\o};

  \mor 1 "a_{w,x,y}×ı_z": -> 2
           "a_{w,x×y,z}": -> 3
         "ı_w×a_{x,y,z}": -> 4;
  \mor *   "a_{w×x,y,z}": -> 5
           "a_{w,x,y×z}": -> *;
\end{codi}
\end{tcblisting}

\clearpage

\subsection{Pullback \& pushout}

\begin{tcblisting}{gallery}
\begin{codi}[hexagonal]
  \obj{ |(pb)| A \times_Z B & B \\
               A            & Z \\ };
  \obj[above left=of pb] {Q};

  \mor[swap] pb p_1:-> A f:-> Z;
  \mor        * p_2:-> B g:-> *;

  \mor[swap]:[bend right] Q q_1:-> A;
  \mor      :[bend left]  * q_2:-> B;
  \mor [mid]:[dashed]     *   u:-> pb;
\end{codi}
\end{tcblisting}

\begin{tcblisting}{gallery}
\begin{codi}[hexagonal]
  \obj{ Z &                   B \\
        A & |(po)| A \sqcup_Z B \\ };
  \obj[below right=of po] {Q};

  \mor[swap] Z f:-> A i_1:-> po;
  \mor       * g:-> B i_2:-> *;

  \mor[swap]:[bend right]  A j_1:-> Q;
  \mor      :[bend left]   B j_2:-> *;
  \mor [mid]:[dashed]     po   u:-> *;
\end{codi}
\end{tcblisting}

\clearpage

\subsection{Complexes sequence}

\begin{tcblisting}{gallery}
\begin{codi}
  \obj (M) {   & \vdots  & \vdots  & \vdots  &   \\
             0 & A_{n+1} & B_{n+1} & C_{n+1} & 0 \\
             0 & A_{n}   & B_{n}   & C_{n}   & 0 \\
             0 & A_{n-1} & B_{n-1} & C_{n-1} & 0 \\
               & \vdots  & \vdots  & \vdots  &   \\ };

  \foreach \n/\row in {n+1/2, n/3, n-1/4}
    \mor (M-\row-1) -> (A_{\n}) "\alpha_{\n}":-> (B_{\n})
                                 "\beta_{\n}":-> (C_{\n}) -> (M-\row-5);

  \foreach \l/\col/\q in {A/2/, B/3/', C/4/''}
    \mor (M-1-\col) -> (\l_{n+1}) "\partial\q_{n+1}":-> (\l_{n})
                                  "\partial\q_{n}"  :-> (\l_{n-1}) -> (M-5-\col);
\end{codi}
\end{tcblisting}

\clearpage

\subsection{Braid}

% TODO: there's a bug here. If one does \begin{codi}[ l/.style={bend left}
% TODO: (note the space before l) then it's not recognized. Investigate.
\begin{tcblisting}{gallery}
\begin{codi}[l/.style={bend left}, r/.style={bend right} ]
  \obj [ hexagonal=horizontal side 6em angle 45, remove characters=H_\{q+\} ] {
    H_{q+2}(X)   & H_{q+2}(X,Y) & H_{q+1}(Y,Z) & H_{q}(Z)     \\
    H_{q+2}(Y)   & H_{q+2}(X,Z) & H_{q+1}(Y)   & H_{q+1}(X,Z) \\
    H_{q+2}(Y,Z) & H_{q+1}(Z)   & H_{q+1}(X)   &              \\
  };

  \mor :[blue]  2Y  -> 2X  l,-> 2XY   -> 1Y  -> 1X;
  \mor :[green] 2Y  -> 2YZ r,-> 1Z    -> 1Y  -> 1YZ l,-> Z;
  \mor :[cyan]  2X  -> 2XZ   -> 1Z  r,-> 1X  -> 1XZ   -> Z;
  \mor :[red]   2YZ -> 2XZ   -> 2XY l,-> 1YZ -> 1XZ;
\end{codi}
\end{tcblisting}

\clearpage

\subsection{Hammock}

\begingroup\catcode`~=12
\begin{tcblisting}{gallery}
\begin{codi}[x=4em, y=-3em, node distance=1 and 1,
    sim/.style={sloped, auto,
      edge node={node[every edge quotes][/velos/install quote
        handler,"\sim", anchor=south, outer sep=-.15em]}
    },
    ~>/.style={->, sim},
    <~/.style={<-, sim},
    ../.style={line width=.25ex, dash pattern=on 0sp off .75ex, line cap=round},
    remove characters=_\{\},
    expand=full,
  ]

  \foreach [count=\c] \col in {1, 2, 3, n}
  \foreach [count=\r] \row in {K_{\col}, C_{0\col}, \vdots, C_{m\col}, L_{\col}}
    \obj [name/.expanded={\ifnum\r=3 vdots\col\fi}] at (\c,\r) {\row};

  \obj  [left=of vdots1] {X};
  \obj [right=of vdotsn] {Y};

  \foreach \col in {1, 2, 3, n}
    \mor (K\col) ~> (C0\col) ~> (vdots\col) ~>  (Cm\col) ~> (L\col);

  \foreach \row in {K, C0, Cm, L} {
    \mor (\row1) -> (\row2) <~ (\row3) .. (\row n);
    \mor X <~ + -> Y;
  }
\end{codi}
\end{tcblisting}
\endgroup


\section{Automated Variance Reduction Methods for Global Solutions}
\label{sec:GlobalVR}

Variance reduction methods for global solutions are designed to obtain an even
distribution of error across several tallies or a tally map that spans the
entire problem phase-space.
The previous section detailed several methods that automate variance reduction
for localized tallies. However, for global solutions these methods do not work
well. The global tally suffers from a large range in variance across the
physical problem space, and the solution is dependent on the flux distribution
throughout the problem.

This section describes several methods that provide
automated variance reduction for global solutions or multiple tallies. The
general principle that these methods follow is that by distributing particles
evenly throughout the Monte Carlo problem, a global tally will have
approximately the same sample size in each region, resulting in a uniform
variance across the tally. This often requires a forward deterministic solution
to determine the density of forward particles throughout the problem, and
subsequently using that forward distribution to aid in generating an
importance map. This
section summarizes the theory behind a number of existing global variance
reduction methods. The section is concluded with a summary of how the
methods performed and in which problems they performed well.

\subsection{Cooper's Isotropic Weight Windows}
\label{subsec:CooperGlobal}

Cooper and Larsen developed a weight window technique to reduce the variance of
Monte Carlo global solutions \cite{cooper_automated_2001} using a calculation of
the forward flux from solutions obtained from diffusion, quasidiffusion
\cite{miften_quasi-diffusion_1993}, or pure
Monte Carlo. In their work, Cooper
and Larsen utilized a forward solution to the transport equation to generate
weight window values to uniformly distribute particles throughout the problem.
By doing so, the variance in the
scalar flux remained relatively constant throughout the problem for a
problem-wide tally, rather than
rising significantly with increasing distance from the forward source. Cooper's
``isotropic'' weight windows (named because they were not dependent on $\hat\Omega$ )
dependent on $\vec{r}$ are given by:
\begin{subequations}
\label{coopers}
\begin{equation}
  \bar{ww}(\vec{r}) = \frac{\phi(\vec{r})}{\max \phi(\vec{r})} \:,
  \label{eq:coopertarget}
\end{equation}
\begin{equation}
  ww(\vec{r})_{top} = \rho \bar{ww}(\vec{r}) \:,
\end{equation}
and
\begin{equation}
  ww(\vec{r})_{bottom} = \frac{\bar{ww}(\vec{r})}{\rho} \:,
\end{equation}
where $\rho$ is the weight window scaling factor.
\end{subequations}
Note that by setting the weight window target value to be inversely
proportional to the total flux in the cell, the density of particles throughout
the problem ends up as roughly constant. Also note from Eq. \
\eqref{eq:coopertarget} that the weight windows are depend on space only.

In practice, Cooper's algorithm iteratively switches between solving the
diffusion equation with transport correctors (Eddington factors described by
\cite{goldin_quasi-diffusion_1964}), and Monte Carlo solutions; this process is
known as quasidiffusion \cite{goldin_quasi-diffusion_1964,
miften_quasi-diffusion_1993}. An initial
quasidiffusion solution is used to generate weight windows, and then after a
relatively short runtime, the Monte Carlo solution is used to
generate updated Eddington factors for
the quasidiffusion solution.

Because Cooper's method depends on Monte Carlo to generate the Eddington
factors for the quasidiffusion problem, this method is limited by the iterative
switch between the quasidiffusion solution and the Monte Carlo solution. The
frequency with which this switching happens is entirely up to the user, but may
drastically affect the efficiency of the method. Further, Cooper notes that we
do not know at what point in time (for which number of N particles) the Monte
Carlo solution becomes more accurate than the quasidiffusion solution, which is
an important issue in choosing solution parameters.

\subsection{Becker's Global Weight Windows}
\label{subsec:BeckerGlobal}

Becker, in addition to developing the local VR method discussed in Section
\ref{sec:beckerlocal}, developed a global space-energy
weight correction method both with (Section \ref{sec:AngleVR}) and
without directional biasing \cite{becker_hybrid_2007, becker_hybrid_2009}.
\label{eq.beckerglobal}
Becker's global method uses a formulation of the space-dependent
contributon flux, as with the local weight windows described in Section
\ref{sec:beckerlocal}. For reference, those are
defined in Eqs.\ \eqref{eq:beckerconributon} and
\eqref{eq:beckerconributonspace}.

Becker defines the spatially-dependent
contributon flux parameter as
$B(\vec{r})$, where
\begin{equation}
  B(\vec{r}) = \tilde{\phi^c}(\vec{r}).
\end{equation}
Becker's method defines a different adjoint source
distribution depending on the response desired for the calculation.
To optimize the flux the adjoint source is defined as:
\begin{subequations}
\begin{equation}
  q^{\dagger}(\vec{r},E) = \frac{1}{\phi(\vec{r},E)}.
\end{equation}
If the detector response is desired then
\begin{equation}
  q^{\dagger}(\vec{r},E) = \frac{\sigma_d(\vec{r},E)}
  {\int_0^{\infty} \phi(\vec{r},E) \sigma_d(\vec{r},E) dE},
\end{equation}
can be used instead.
\end{subequations}
The space- and energy-dependent weight windows are then a function of the
contributon flux, where
\begin{equation}
  \bar{w}(\vec{r},E) = \frac{B(\vec{r})}{\phi^{\dagger}(\vec{r},E)} \:.
\label{eq:beckerglobalww}
\end{equation}

The process followed by Becker's global method uses two deterministic
calculations to generate weight windows for the Monte Carlo calculation. First,
the forward flux is calculated deterministically and used to construct the
adjoint source distribution. After the adjoint solution
is run, the contributon flux is calculated. The contributon flux and the adjoint
flux are then used to construct the weight windows.

Becker's method aims to distribute response evenly throughout the problem.
However, like FW-CADIS
(discussed below in Section \ref{subsec:FWCADIS}),
the global response weight windows are proportional to the forward response,
\begin{equation}
  \bar{w}(\vec{r},E) \propto \frac{\int \sigma(\vec{r},E) \phi (\vec{r},E) dE}
                                  {\sigma (\vec{r},E)}
\end{equation}
rather than the forward flux as in Cooper's method, where
$\bar{w}(\vec{r},E) \propto \phi(\vec{r},E)$ .

In implementation, both Becker and Cooper's global methods
undersampled the source (in comparison to FW-CADIS, which will be described in
Section \ref{subsec:FWCADIS}) for a specified calculation
time. However, Becker's method sampled $\sim$1/3 the number of particles that
Cooper's method did. Notably, Becker's method did obtain better relative
uncertainties for low flux-regions in the problem.

\subsection{FW-CADIS}
\label{subsec:FWCADIS}

In 2007, Peplow, Blakeman, and Wagner \cite{peplow_advanced_2007} proposed three
methods by which variance reduction could be decreased in global mesh tallies in
deep-penetration radiation transport problems. The first method, using a CADIS
calculation where the adjoint source is defined at the problem boundary, aimed
at moving particles outward to the problem edges.
The second method used standard CADIS, but instead
defined each cell as equally important, so the adjoint source was defined
equally throughout the problem phase-space. The last method, called Forward-Weighted
CADIS (FW-CADIS), distributed the adjoint source across mesh cells as an inverse
relation to the forward response of the cell. In their work, Peplow et al.\ found
that the first method had large uncertainties in areas of the problem far
from the boundary; the second method performed slightly, but not significantly,
better than analog; and the third method had the most uniform uncertainty
distribution.

FW-CADIS
\cite{wagner_forward-weighted_2007,wagner_forward-weighted_2009,wagner_forward-weighted_2010}
built off of the work by Cooper and the CADIS method.
Like Becker's method, FW-CADIS uses a forward deterministic calculation to
determine the source distribution for the adjoint calculation. Unlike Becker's
method, which used contributon fluxes to construct weight windows,
the CADIS method uses adjoint fluxes as the basis of the weight window values.
Similar to
Cooper's method, however, FW-CADIS uses the forward calculation to determine how to
evenly distribute particles throughout the problem. Like CADIS, FW-CADIS uses
the adjoint solution from the deterministic calculation to generate consistent
source biasing, weight windows, and particle birth weights.

The adjoint source for the adjoint calculation is dependent on the
desired response for the system. The generic description for the adjoint source
is given by Eq. \eqref{eq:adjointsourcesimple} and more specific parameters are
given by Eqs. \eqref{eq:FWCadglobaldose}-\eqref{eq:FWCadglobalflux2}. First, we
can describe a general form of the adjoint source definition for all
phase-space, $P$, as:
\begin{equation}
  { q^{\dagger}} (P)=\frac{\sigma_d(P)}{R}.
\label{eq:adjointsourcesimple}
\end{equation}
Thus the adjoint source is dependent on the detector (or tally)
cross-section and whatever response is being calculated in the system. Depending
on whether the response is a flux or a dose rate, the adjoint source will
differ. For example,
the adjoint source for the spatially dependent global dose, $\int
\phi(\vec{r},E)\sigma_d(\vec{r},E) dE$ is:
\begin{subequations}
\begin{equation}
  { q^{\dagger} }(\vec { r } ,E)= \frac { \sigma _{ d }(\vec { r } ,E) }
       { \int { \sigma _{ d }(\vec { r } ,E)\phi (\vec { r } ,E,) } dE }.
\label{eq:FWCadglobaldose}
\end{equation}
The adjoint source for the spatially dependent total flux $\int \phi(\vec{r},E)
dE $ is:
\begin{equation}
  { q^{\dagger} }(\vec { r }) = \frac { 1 }{ \int { \phi (\vec { r } ,E) } dE }.
\label{eq:FWCadglobalflux}
\end{equation}
Last,
the adjoint source for the energy- and spatially- dependent flux
$\phi(\vec{r},E)$ is:
\begin{equation}
  { q^{\dagger} }(\vec { r } ,E) = \frac { 1 }{\phi (\vec { r } ,E) }.
\label{eq:FWCadglobalflux2}
\end{equation}
\end{subequations}

The process followed by FW-CADIS is to initially run a deterministic forward
calculation to obtain the forward response. This solution is used to create the
source distribution for the adjoint
problem. A second deterministic calculation is run to obtain the adjoint
solution. The adjoint solution is then used to generate variance reduction
parameters in the same manner as CADIS.

\subsection{Other Notable Methods}

Baker and Larsen showed that the exponential transform can be used to generate
VR parameters for global low-variance solutions in Monte Carlo
\cite{baker_localexponential_1993}. In this work, Baker used a forward diffusion
solution to generate parameters for a combination of VR techniques: implicit
capture and weight cutoff, geometry splitting / rouletting with implicit
capture and weight cutoff, and the exponential transform combined with
implicit capture and a weight cutoff. The exponential transform method was then
compared to the other combinations of VR techniques to quantify its success.
In their work, Baker and Larsen found that
the exponential transform approach did not work well for highly
scattering problems, where geometry
splitting and Russian roulette were generally better options. Their work did not
focus on generating weight window values, nor was it tested on deep-penetration
shielding problems.

While the aforementioned methods in this and the previous sections use
deterministically-obtained solutions to generate importance maps, it should be
noted that not all methods use this approach. Booth and Hendricks' methods used
initial Monte Carlo calculations to reduce the relative error in tallies. Two
methods in the global variance reduction realm are notable in that they too use
Monte Carlo estimates of the flux to generate variance reduction parameters
\cite{van_wijk_easy_2011, davis_comparison_2011}.
Van Wijk et al. \cite{van_wijk_easy_2011} developed an automated weight
window generator that used a Monte
Carlo calculation of the forward flux to generate weight window values. The
weight window target values could be determined based on either a flux-centered
scheme like Cooper's (Eq. \eqref{eq:coopertarget})
or by using a ratio of the square roots of the fluxes. The
second method is a combination of Cooper's weight window target values and
knowing that the relative error in a region
is proportional to the square root of the number
of particles.
Van Wijk et al.\ applied their methods to a PWR facility and observed a FOM
increase by a factor of $>$200 when compared to analog Monte Carlo. However, as
with other Monte Carlo-generated VR parameters, for deep-penetration problems
this approach relies on adequate sampling of all phase-space, which could be
computationally prohibitive.

The Method of Automatic Generation of Importances by Calculation (MAGIC) method
was proposed in parallel by Davis and Turner \cite{davis_comparison_2011}.
As with Van Wijk's method, the MAGIC method uses an analog forward Monte Carlo
--potentially with several iterations--calculation to generate weight windows.
The initial
Monte Carlo runs used to generate the importance map took less time to converge
by
using multigroup (rather than continuous energy) cross section data as well
as energy cutoffs. MAGIC
converged on a finalized importance map by iteratively running several
lower-fidelity
Monte Carlo calculations.

Davis and Hendricks compared three variants of MAGIC
to FW-CADIS in ITER fusion energy systems.
These three variants used different weight window adjustments for importances:
weight windows in cells based on existing weight information, weight windows in
mesh cells based on flux information, and weight windows in cells based on
population density.
It was concluded that the most effective method for variance
reduction of those proposed in the paper
was MAGIC's weight window in mesh cells based on flux
information. In this case, FW-CADIS' FOM was 65\% that of MAGIC's. This compared
similarly to Van Wijk's method, where the flux-based results continued improving
the FOM as the computational time increased.
The authors did not make it clear how many iterations were required, on average,
to generate the finalized weight window map or if the time to iteratively
generate the importance map was included in the FOM.
While FW-CADIS' FOM was lower
than MAGIC's, FW-CADIS had the highest fraction of cell voxels with very low
relative errors.

Peplow et al.\ \cite{peplow_comparison_2012} compared the performance of
Cooper's method, Van Wijk's method, Becker's method, and FW-CADIS
across a number of shielding calculations. For a simple shielding
problem, FW-CADIS had the shortest runtime, which included the forward and
adjoint deterministic runtimes, and had a FOM 80x higher than the analog
calculation, and more than 3x higher than the next best hybrid method. Van Wijk's method was
the only method other than FW-CADIS to pass all statistical convergence checks
for the problem, but its reported FOM was lower than either Becker's method or
FW-CADIS. In a second deep penetration shielding problem, FW-CADIS was the
only method
that passed all statistical convergence checks. FW-CADIS also had the highest
reported FOM for this problem. The timing for all of the methods were
comparable. Peplow et al.\ also ran two ``challenge'' problems. As with the first
two problems, FW-CADIS outperformed the other methods and passed all statistical
checks. Becker's method was
consistently comparable to FW-CADIS in reported FOMs, but only passed all of the
statistical checks in a single challenge problem. Becker's method also performed
relatively better than the other methods in deep-penetration challenge problems.

The ubiquity and continued development of global variance reduction methods
illustrates the need and desire for them in the nuclear engineering community.
Some of the
methods discussed in this section--including Becker's global weight windows,
Cooper's weight windows, Van Wijk's method, and FW-CADIS--have
been applied to large application problems and compared to other methods.
All of the methods reduce the time to a ``good'' solution--thus improving the
final FOM--when
compared to analog Monte Carlo. When compared against one another, FW-CADIS
consistently outperforms the other methods.


\chapter{Overview of the {\tt berry} module}
\label{ch:berry}

The {\tt berry} module of {\tt postw90} is called by setting {\tt
  berry = true} and choosing one or more of the available options for
{\tt berry\_task}. The routines in the {\tt berry} module which
compute the $k$-space Berry curvature and orbital magnetization are
also called when {\tt kpath = true} and {\tt kpath\_task = \{curv,morb\}},
or when {\tt kslice = true} and {\tt kslice\_task = \{curv,morb\}}.

\section{Background: Berry connection and curvature}

The Berry connection is defined in terms of the cell-periodic Bloch
states $\vert u_{n{\bf k}}\rangle=e^{-i{\bf k}\cdot{\bf r}}\vert
\psi_{n{\bf k}}\rangle$ as
%
\begin{equation}
{\bf A}_n({\bf k})=\langle u_{n{\bf k}}\vert i\bm{\nabla}_{\bf k}\vert
u_{n{\bf k}}\rangle,
\end{equation}
%
and the Berry curvature is the curl of the connection,
%
\begin{equation}
\bm{\Omega}_n({\bf k})=\bm{\nabla}_{\bf k}\times {\bf A}_n({\bf k})=
-{\rm Im}
\langle \bm{\nabla}_{\bf k} u_{n{\bf k}}\vert \times
\vert\bm{\nabla}_{\bf k} u_{n{\bf k}}\rangle.
\end{equation}
%
These two quantities play a central role in the description of several
electronic properties of crystals~\cite{xiao-rmp10}.  In the following
we will work with a matrix generalization of the Berry connection,
%
\begin{equation}
{\bf A}_{nm}({\bf k})=\langle u_{n{\bf k}}\vert i\bm{\nabla}_{\bf k}\vert
u_{m{\bf k}}\rangle={\bf A}_{mn}^*({\bf k}),
\end{equation}
%
and write the curvature as an antisymmetric tensor,
%
\begin{equation}
\label{eq:curv}
\Omega_{n,\alpha\beta}({\bf k}) =\epsilon_{\alpha\beta\gamma}
\Omega_{n,\gamma}({\bf k})=-2{\rm Im}\langle
\nabla_{k_\alpha} u_{n\bf k}\vert \nabla_{k_\beta} u_{n\bf k}\rangle.
\end{equation}

\section{{\tt berry\_task=kubo}: optical conductivity and joint
  density of states }

The Kubo-Greenwood formula for the optical conductivity of a crystal
in the independent-particle approximation reads
%
\begin{equation}
\sigma_{\alpha\beta}(\hbar\omega)=\frac{ie^2\hbar}{N_k\Omega_c}
\sum_{\bf k}\sum_{n,m}
\frac{f_{m{\bf k}}-f_{n{\bf k}}}
     {\varepsilon_{m{\bf k}}-\varepsilon_{n{\bf k}}}
\frac{\langle\psi_{n{\bf k}}\vert v_\alpha\vert\psi_{m{\bf k}}\rangle
      \langle\psi_{m{\bf k}}\vert v_\beta\vert\psi_{n{\bf k}}\rangle}
{\varepsilon_{m{\bf k}}-\varepsilon_{n{\bf k}}-(\hbar\omega+i\eta)}.
\end{equation}
%
Indices $\alpha,\beta$ denote Cartesian directions, $\Omega_c$ is the
cell volume, $N_k$ is the number of $k$-points used for sampling the
Brillouin zone, and $f_{n{\bf k}}=f(\varepsilon_{n{\bf k}})$ is the
Fermi-Dirac distribution function. $\hbar\omega$ is the optical
frequency, and $\eta>0$ is an adjustable smearing parameter with units
of energy.

The off-diagonal velocity matrix elements can be expressed in terms of
the connection matrix~\cite{blount-ssp62},
%
\begin{equation}
\langle\psi_{n{\bf k}}\vert {\bf v} \vert\psi_{m{\bf k}}\rangle=
-\frac{i}{\hbar}(\varepsilon_{m{\bf k}}-\varepsilon_{n{\bf k}})
{\bf A}_{nm}({\bf k})\,\,\,\,\,\,\,\,(m\not= n).
\end{equation}
%
The conductivity becomes
%
\begin{align}
\label{eq:sig-bz}
\sigma_{\alpha\beta}(\hbar\omega)&=
\frac{1}{N_k}\sum_{\bf k}\sigma_{{\bf k},\alpha\beta}(\hbar\omega)\\
\label{eq:sig-k}
\sigma_{{\bf k},\alpha\beta}(\hbar\omega)&=\frac{ie^2}{\hbar\Omega_c}\sum_{n,m}
(f_{m{\bf k}}-f_{n{\bf k}})
\frac{\varepsilon_{m{\bf k}}-\varepsilon_{n{\bf k}}}
{\varepsilon_{m{\bf k}}-\varepsilon_{n{\bf k}}-(\hbar\omega+i\eta)}
A_{nm,\alpha}({\bf k})A_{mn,\beta}({\bf k}).
\end{align}

Let us decompose it into Hermitian (dissipative) and anti-Hermitean
(reactive) parts. Note that
%
\begin{equation}
\label{eq:lorentzian}
\overline{\delta}(\varepsilon)=\frac{1}{\pi}{\rm Im}
\left[\frac{1}{\varepsilon-i\eta}\right],
\end{equation}
%
where $\overline{\delta}$ denotes a ``broadended''
delta-function. Using this identity we find for the Hermitean part
%
\begin{equation}
\label{eq:sig-H}
\sigma_{{\bf k},\alpha\beta}^{\rm H}(\hbar\omega)=-\frac{\pi e^2}{\hbar\Omega_c}
\sum_{n,m}(f_{m{\bf k}}-f_{n{\bf k}})
(\varepsilon_{m{\bf k}}-\varepsilon_{n{\bf k}})
A_{nm,\alpha}({\bf k})A_{mn,\beta}({\bf k})
\overline{\delta}(\varepsilon_{m{\bf k}}-\varepsilon_{n{\bf k}}-\hbar\omega).
\end{equation}
%
Improved numerical accuracy can be achieved by replacing the
Lorentzian (\ref{eq:lorentzian}) with a Gaussian, or other shapes. The
analytical form of $\overline{\delta}(\varepsilon)$ is controlled by
the keyword {\tt [kubo\_]smr\_type}.

The anti-Hermitean part of Eq.~(\ref{eq:sig-k}) is given by
%
\begin{equation}
\label{eq:sig-AH}
\sigma_{{\bf k},\alpha\beta}^{\rm AH}(\hbar\omega)=\frac{ie^2}{\hbar\Omega_c}
\sum_{n,m}(f_{m{\bf k}}-f_{n{\bf k}})
{\rm Re}\left[ \frac{\varepsilon_{m{\bf k}}-\varepsilon_{n{\bf k}}}
                    {\varepsilon_{m{\bf k}}-\varepsilon_{n{\bf k}}
                     -(\hbar\omega+i\eta)}
\right]
A_{nm,\alpha}({\bf k})A_{mn,\beta}({\bf k}).
\end{equation}
%
Finally the joint density of states is
%
\begin{equation}
\label{eq:jdos}
\rho_{cv}(\hbar\omega)=\frac{1}{N_k}\sum_{\bf k}\sum_{n,m}
f_{n{\bf k}}(1-f_{m{\bf k}})
\overline{\delta}(\varepsilon_{m{\bf k}}-\varepsilon_{n{\bf k}}-\hbar\omega).
\end{equation}

Equations~(\ref{eq:lorentzian}--\ref{eq:jdos}) contain the parameter
$\eta$, whose value can be chosen using the keyword\\ {\tt
  [kubo\_]smr\_fixed\_en\_width}. Better results can often be achieved
by adjusting the value of $\eta$ for each pair of states, i.e.,
$\eta\rightarrow \eta_{nm\bf k}$. This is done as follows (see
description of the keyword {\tt adpt\_smr\_fac})
%
\begin{equation}
\eta_{nm{\bf k}}=\alpha\vert \bm{\nabla}_{\bf k}
(\varepsilon_{m{\bf k}}-\varepsilon_{n{\bf k}})\vert \Delta k.
\end{equation}

The energy eigenvalues $\varepsilon_{n\bf k}$, band velocities
$\bm{\nabla}_{\bf k}\varepsilon_{n{\bf k}}$, and off-diagonal Berry
connection ${\bf A}_{nm}({\bf k})$ entering the previous four
equations are evaluated over a $k$-point grid by Wannier
interpolation, as described in Refs.~\cite{wang-prb06,yates-prb07}.
After averaging over the Brillouin zone, the Hermitean and
anti-Hermitean parts of the conductivity are assembled into the
symmetric and antisymmetric tensors
%
\begin{align}
\sigma^{\rm S}_{\alpha\beta}&=
{\rm Re}\sigma^{\rm H}_{\alpha\beta}+i{\rm Im}\sigma^{\rm AH}_{\alpha\beta}\\
\sigma^{\rm A}_{\alpha\beta}&=
{\rm Re}\sigma^{\rm AH}_{\alpha\beta}+i{\rm Im}\sigma^{\rm H}_{\alpha\beta},
\end{align}
%
whose independent components are written as a function of frequency
onto nine separate files.

\section{{\tt berry\_task=ahc}: anomalous Hall conductivity}

The antisymmetric tensor $\sigma^{\rm A}_{\alpha\beta}$ is odd under
time reversal, and therefore vanishes in non-magnetic systems, while
in ferromagnets with spin-orbit coupling it is generally nonzero.  The
imaginary part ${\rm Im}\sigma^{\rm H}_{\alpha\beta}$ describes
magnetic circular dichroism, and vanishes as $\omega\rightarrow
0$. The real part ${\rm Re}\sigma^{\rm AH}_{\alpha\beta}$ describes
the anomalous Hall conductivity (AHC), and remains finite in the
static limit.

The intrinsic dc AHC is obtained by setting $\eta=0$ and $\omega=0$ in
Eq.~(\ref{eq:sig-AH}). The contribution from point ${\bf k}$ in the
Brillouin zone is
%
\begin{equation}
\sigma^{\rm AH}_{{\bf k},\alpha\beta}(0)=\frac{2e^2}{\hbar\Omega_c}
\sum_{n,m}f_{n\bf k}(1-f_{m\bf k})
{\rm Im}\langle \nabla_{k_\alpha} u_{n\bf k}\vert u_{m\bf k}\rangle
\langle u_{m\bf k}\vert\nabla_{k_\beta} u_{n\bf k}\rangle,
\end{equation}
%
where we replaced $f_{n\bf k}-f_{m\bf k}$ with
$f_{n\bf k}(1-f_{m\bf k})-f_{m\bf k}(1-f_{n\bf k})$.

This expression is not the most convenient for {\it ab initio}
calculations, as the sums run over the complete set of occupied and
empty states. In practice the sum over empty states can be truncated,
but a relatively large number should be retained to obtain accurate
results. Using the resolution of the identity $1=\sum_m \vert u_{m\bf
  k}\rangle \langle u_{m\bf k}\vert$ and noting that the term
$\sum_{n,m}f_{n\bf k}f_{m\bf k}(\ldots)$ vanishes identically, we
arrive at the celebrated formula for the intrinsic AHC in terms of the
Berry curvature,
%
\begin{align}
\label{eq:ahc}
\sigma^{\rm AH}_{\alpha\beta}(0)&=\frac{e^2}{\hbar}
\frac{1}{N_k\Omega_c}\sum_{\bf k}(-1)\Omega_{\alpha\beta}({\bf k}),\\
%\sum_n (-1)f_{n\bf k}\Omega_{n,\alpha\beta}({\bf k}).
\label{eq:curv-occ}
\Omega_{\alpha\beta}({\bf k})&=\sum_n f_{n\bf k}\Omega_{n,\alpha\beta}({\bf k}).
\end{align}
%
Note that only {\it occupied} states enter this expression.  Once we
have a set of Wannier functions spanning the valence bands (together
with a few low-lying conduction bands, typically) Eq.~(\ref{eq:ahc})
can be evaluated by Wannier interpolation as described in
Refs.~\cite{wang-prb06,lopez-prb12}, with no truncation involved.

\section{{\tt berry\_task=morb}: orbital magnetization}

The ground-state orbital magnetization of a crystal is given
by~\cite{xiao-rmp10,ceresoli-prb06}
%
\begin{align}
\label{eq:morb}
{\bf M}^{\rm orb}&=\frac{e}{\hbar}
%\int_{\rm BZ}\frac{d{\bf k}}{(2\pi)^3}
\frac{1}{N_k\Omega_c}\sum_{\bf k}{\bf M}^{\rm orb}({\bf k}),\\
\label{eq:morb-k}
{\bf M}^{\rm orb}({\bf k})&=
\sum_n\,\frac{1}{2}f_{n{\bf k}}\,
{\rm Im}\,\langle \bm{\nabla}_{\bf k}u_{n{\bf k}}\vert
\times
\left(H_{\bf k}+\varepsilon_{n{\bf k}}-2\varepsilon_F\right)
\vert \bm{\nabla}_{\bf k}u_{n{\bf k}}\rangle,
\end{align}
%
where $\varepsilon_F$ is the Fermi energy. The Wannier-interpolation
calculation is described in Ref.~\cite{lopez-prb12}. Note that the
definition of ${\bf M}^{\rm orb}({\bf k})$ used here differs by a
factor of $-1/2$ from the one in Eq.~(97) and Fig.~2 of that work.

\section{Needed matrix elements}

%The basic idea of the implementation in the {\tt berry} module is to
%calculate the needed Berry-type quantities very efficiently at
%arbitrarily points in the BZ by Wannier interpolation, once certain
%Wannier matrix elements have been tabulated.

All the quantities entering the formulas for the optical conductivity
and AHC can be calculated by Wannier interpolation once the
Hamiltonian and position matrix elements $\langle {\bf 0}n\vert H\vert
{\bf R}m\rangle$ and $\langle {\bf 0}n\vert {\bf r}\vert {\bf
  R}m\rangle$ are known~\cite{wang-prb06,yates-prb07}.  Those matrix
elements are readily available at the end of a standard MLWF
calculation with {\tt wannier90}. In particular, $\langle {\bf
  0}n\vert {\bf r}\vert {\bf R}m\rangle$ can be calculated by Fourier
transforming the overlap matrices in Eq.~(1.7),
%
$$\langle u_{n{\bf k}}\vert u_{m{\bf k}+{\bf b}}\rangle.
$$
%
Further Wannier matrix elements are needed for the orbital
magnetization~\cite{lopez-prb12}. In order to calculate them using
Fourier transforms, one more piece of information must be taken from
the $k$-space {\it ab-initio} calculation, namely, the matrices
%
$$\langle u_{n{\bf k}+{\bf b}_1}\vert
H_{\bf k}\vert u_{m{\bf k}+{\bf b}_2}\rangle
$$
%
over the {\it ab-initio} $k$-point mesh~\cite{lopez-prb12}.  These are
evaluated by {\tt pw2wannier90}, the interface routine between {\tt
  pwscf} and {\tt wannier90}, by adding to the input file {\tt
  seedname.pw2wan} the line
%
$${\tt
%\begin{quote}
write\_uHu = .true.
%\end{quote}
}
$$

%A note on the implementation: the optical conductivity and orbital
%magnetization are implemented in the {\tt berry} module in the manner
%described in Refs.~\cite{yates-prb07} and \cite{lopez-prb12}
%respectively. As for the AHC, it is currently implemented using the
%``trace formulation'' of Ref.~\cite{lopez-prb12}, rather than the
%original formulation of Ref.~\cite{wang-prb06} (the two are
%equivalent, and should produce identical results to within numerical
%accuracy).


\chapter{Introduction}
\label{chp:introduction}

% %
% HEADER
% %
INSERT HERE AN EXPANSION OF THE ABSTRACT

% %
% RELATED WORKS
% %
Elasticity is a key feature for DSP systems that is attracting many research efforts.
%
Most approaches that enable elasticity exploit best-effort threshold-based policies based on the utilization of either the system nodes or the operational abstraction, e.g. containers or data stream processing operators.
%
Other works, e.g., [1,2,8], use more complex policies to determine the scaling decisions, exploiting optimization theory [1], control theory [2], or queueing theory [8].

To the best of our knowledge, only one
work [5] has so far exploited RL techniques to drive the auto-scaling decisions in
DSP systems. Heinze et al. [5] propose a simple RL approach that learns from
experience when to acquire and release computing nodes so to efficiently process
the incoming workload. The per-operator auto-scaler populates a lookup table
that associates the utilization of the node on which the operator is executed with
the action to perform (i.e., scale in, scale out, or do nothing). The adaptation
goal is to keep the system utilization within a specific range; the SARSA learning
algorithm [12] is used to update the lookup table.

A larger number of works has exploited RL techniques to drive elasticity in
the Cloud computing context, as surveyed in [9]. Most of them use the simple Q-
learning RL algorithm (described in Sec. 5), which suffers from slow convergence,
as we also show in Section 6. Tesauro et al. [13] observe that RL approaches
can suffer from poor scalability in systems with a large state space, because
the lookup table has to store a separate value for every possible state-action
pair. Moreover, the performance obtained during the on-line training may be
unacceptably poor, due to the absence of domain knowledge or good heuristics.
To overcome these issues, they combine RL with a model of the system, defined
using queuing theory, which computes the initial deployment decisions and drives
the exploration actions. They use the SARSA learning algorithm, which however
suffers from slow convergence as Q-learning.

The goal of the Operator Manager is to take scaling decisions as to minimize
a long-term cost function which accounts for the operator downtime and for the
monetary cost to run the operator. The latter comprises: (i) the cost for running
the number of instances during the next time slot, and (ii) possibly a penalty
in case of SLA violation. In particular, we consider a constraint on the operator
response time, so that a penalty is paid every time the response time exceeds a
given threshold T SLA.

Since decisions are taken periodically, we consider a slotted time system with
fixed-length time intervals of length $\Delta t$, with the i-th time slot corresponding
to the time interval [i$\Delta t$, (i + 1)$\Delta t$] (see Fig. 2). We denote by k i the number
of parallel instances at the beginning of slot i, and by $\lambda$ i the average tuple rate
during slot i-1 (the previous slot). At the beginning of slot i the Operator-
Manager makes the decision a i on whether modify or keep the current instance
configuration.

% %
% REMAINDER
% %
The remainder of this thesis is organized as follows.
%
In Chapter~\ref{chp:smart-elasticity} we introduce the context of containers orchestrations, thus focusing on resource management, containerization and elasticity.
%
In Chapter~\ref{chp:reinforcement-learning} we give the necessary background notions about reinforcement learning, focusing on the Q-Learning technique and its comparison with respect to other techniques.
%
In Chapter~\ref{chp:kubernetes} we describe the technological environment of our work, that is focused on Kubernetes. In particular we describe its architecture and how it implements elasticity.
%
In Chapter~\ref{chp:implementation} we introduce the concept of smart elasticity, showing how we implemented it leveraging Q-Learning as an auto-scaling service in the Kuberntes environment.
%
In Chapter~\ref{chp:evaluation} we show the experimental results of the proposed smart elasticity technique.
%
In Chapter~\ref{chp:conclusions} we sum up our work, giving its conclusions and pointing out some promising future improvements.


\acrshort{bert} was proposed by~\textcite{devlin2019bert:} and obtained state-of-the-art results on a variety of NLP-related tasks, including sentence classification and next-word predictions. The model is predicated on the concept of transformers, which were released in 2017 and provided a method for ensuring that the sequential nature of text data was accounted for~\parencite{transformers:}. Priorly, the primary method for encoding spatial word relationships was through the use of Recurrent Neural Networks (RNN). They input tokens sequentially and create a new latent state based on the previous $n-1$ tokens combined with the recently inputted $n$th token. The general input process is depicted in~\Cref{fig:rnn}.

\begin{figure}[h]
\centering
\includegraphics[width=0.8\textwidth]{fig/rnn.png}
\caption{RNN sequencing example (displays sequential input handling and state updating)~\parencite{olah_2015}}
\label{fig:rnn}
\end{figure}

Many problems hindered this approach, including a lack of concrete connection between distant words of a sequence. Additionally, as only a single hidden state was stored after each token was added, the weight (or visibility) of the beginning of the input could often become hidden and difficult for the model to recover~\parencite{hochreiter1997long}.

For example, if a model is being trained to translate from English to Spanish, it can be reasonably assumed that the initial words of the English input have a strong correlation to the correct beginning tokens of the Spanish output. However, the model only contains the final latent state of the input, making it difficult to correctly decipher the beginning of the Spanish translation. Transformers were created to offer an alternative to this process, and they rely on a concept called attention and involve two components, an encoder and a decoder~\parencite{transformers:}. As \acrshort{bert} relies exclusively on encoders, they will be discussed.

\subsubsection{Encoders}
An encoder consists of two sub-layers, a self-attention layer that calculates the relation of each token to other tokens in the same input and a traditional feed-forward network. Self-attention is the concept of helping the model comprehend the relationships of words to other tokens in the input. For example, consider the sequence: \\

\textbf{The money has gone missing. Where is it?} \\

For a human, it would be easy to understand that \textbf{it} is referring to the \textbf{money}. But for a machine, it can be much more difficult to gather these types of contextual clues, especially if the corresponding words are separated~\parencite{hochreiter1997long}. Thus, self-attention generates “scores” for each input token with every other token which helps it understand the hidden/distant relationships. \\

The encoder takes the raw embedding sequence as input which is passed to the self-attention layer. The embeddings are slightly modified before being fed to the model, however. It is important for the computer to have some sense of the spatial relationships between words (the relative distances) to help with the positional aspect of the sequence. Thus, the model utilizes learned positional embeddings, which are the same size as the word embeddings themselves~\parencite{devlin2019bert:}. These positional vectors are added to the token vectors to create the real input:

\begin{figure}[h]
\centering
\includegraphics[width=0.8\textwidth]{fig/positional_encodings.png}
\caption{The basic addition of positional encodings to the input vectors before being fed to the model~\parencite{alammar_2018}.
}
\label{fig:positional_encodings}
\end{figure}

This layer then utilizes three matrices to generate a key, value, and query for each input token. For \acrshort{bert}, the embedding vectors are of length $768$, and each of these matrices has dimensions $768 \times 64$. For each token, the embedding vector is multiplied by the three matrices to get the key, query, and value vectors which each have a length of $64$. Then, the dot-product between the query vector and each token’s key is calculated to generate a score.

\begin{figure}[h]
\centering
\includegraphics[width=0.8\textwidth]{fig/first_encoder_step.jpg}
\caption{Initial score generation for first token by taking a dot-product between the query vector and the key vectors for each token~\parencite{karim_2019}.)
}
\label{fig:first_encoder_step}
\end{figure}

The scores are then normalized with a $softmax$ function, defined by:
\begin{equation}
\label{eq:softmax}
S(y_i) = \frac{e^{y_i}}{\sum_{j\in y}e^{y_j}},
\end{equation}

\Cref{eq:softmax} takes a list of numbers and normalizes them into a probability distribution based on the exponential values of the inputs~\parencite{bengio_goodfellow_courville_2017}. These normalized scores are multiplied with the corresponding value vectors, which then are summed element-wise to get a final score for the token:

\begin{figure}[H]
\centering
\includegraphics[width=0.8\textwidth]{fig/second_encoder_step.jpg}
\caption{The SoftMax function is applied to the initial score, then multiplied with the value vectors. The results are then summed to generate a final output for the first token~\parencite{karim_2019}.
}
\label{fig:second_encoder_step}
\end{figure}

This process is performed for each input token and is vectorized for faster computation. Transformers are able to utilize this process multiple times per encoder to generate what is known as multi-headed attention. In the case of \acrshort{bert}, this process is done $8$ separate times, each with a different key, query, and value matrix to get $8$ vectors of length $64$ for each input token. This makes the attention layer even more powerful and allows for more concrete connections to be encoded between words~\parencite{transformers:}. However, the feed-forward layer is not expecting each token to have multiple associated vectors, thus these outputs must be combined first before sending. To alleviate this problem, the vectors are all concatenated together to create a vector of length 512 $(8 \times 64)$, then multiplied with another parameter matrix of dimensions $512 \times 768$, to return to the original embedding size of $768$~\parencite{devlin2019bert:}, which is outlined here:

\begin{figure}[H]
\centering
\includegraphics[width=0.8\textwidth]{fig/multi-head.jpg}
\caption{The outputs are concatenated as above then multiplied with the weighted matrix that is updated throughout training to get a final output with a 768 long vector for each token.
}
\label{fig:multi_head_attention}
\end{figure}

The overall attention process can be summarized as the following:
\begin{equation}
\label{eq:attention}
Attention\left(Q, K, V\right) = softmax\left(\frac{QK^\top}{\sqrt{d_k}}\right)V,
\end{equation}

\Cref{eq:attention} outlines the attention function for a $(Q,K,V)$ value tuple. The results of the query and key product are divided by the square root of the size of the vectors (8 for~\acrshort{bert}) to normalize the outputs before applying softmax~\parencite{transformers:}.

This attention layer output is then passed to the fully-connected feed-forward neural network, which takes inputs of length 768 and returns an output of identical size based on a non-linear activation function as such:

\begin{figure}[H]
\centering
\includegraphics[width=0.8\textwidth]{fig/full_neural.png}
\caption{A sample fully-connected feed forward network with a hidden layer}
\label{fig:neural-network}
\end{figure}

The workings of a neural network have been extensively documented throughout machine learning literature, thus they will not be discussed in detail. However, the basic premise is very similar to the workings of \acrshort{rfs}, where a dot-product is calculated with learned weights, and then passed through an activation function, such as $\sigma$~\parencite{lecun2015deep}.

\subsubsection{General Working}
\acrshort{bert} employs 12 of these encoders, with both self-attention and feed-forward components, stacked on top of each other. Because the model is being used for classification, another final neural network is placed on top that takes the outputs of the encoders and generates a single probability for the entry~\parencite{sun2019finetune}.