%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Background
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% In a thesis, every section starts a new page, hence \clearpage
\clearpage
\section{Background and related work}
\label{sec:background}

\subsection{Process mining}

To understand process mining it is necessary to start with the concept of \emph{event logs}.
An event log is a collection of recorded data for an information system.
Activities executed in the system leave records which are stored in the event log.
\emph{Process mining} describes methods of using the event log data to extract useful information.
The information can be used to discover previously unknown processes, to find bottlenecks and inefficiencies, to detect and understand anomalies, and to support redesign actions \cite{van2015extracting}.
In this thesis I look at \emph{process discovery}, which means finding the underlying process model
by reading the event log.
In process discovery, the model should be generated without any a-priori information, meaning that the algorithm should be unsupervised \cite{van2013discovering}.
The process model can be expressed as a directed graph or a \emph{Petri net}.
These models can be used for business intelligence (BI) solutions, or they can be compared to the real life
known models to check conformance \cite{van2013discovering}.

Discovering strictly sequential processes from event logs is straightforward. However, modern systems are increasingly concurrent, which complicates the issue.
Parallel systems generate events in an undetermined order based on how the processes are interleaved.
When the events are logged the order is realized resulting in a totally ordered sequential log \cite{van2004workflow}.
The challenge is having to discover and construct the parallelism from the event log.
Furthermore, the event log may be \emph{incomplete}, which means not all possible behaviour is present in the logs \cite{van2013discovering}.
Additionally, the event logs can be \emph{noisy} and contain random infrequent behaviour \cite{van2013discovering}.
It may be undesirable to present the infrequent behaviour in the models.
These characteristics give the task of process discovery challenging trade-offs.

\subsubsection{Event logs and traces}

\label{sec:eventtheory}

\begin{definition}
Let $A$ be the set of all \emph{events}.
$\sigma \in A^*$ is a \emph{trace} describing a sequence of events.
The event log $L \in \mathbb{B}(A^*)$ is a \emph{multi-set} of \emph{traces}.
\end{definition}

A process consists of a set of distinct \emph{activities}.
An activity is a well-defined step belonging to the process (for example, ``resize an image'').
Each event in the event log is a log entry documenting an execution of an activity.
In other words, $A$ is the vocabulary of events.
The event may also hold additional information about the process.
A workflow \emph{trace} contains a sequence of events documenting a single execution of the process (a \emph{process instance}).
This kind of single process execution is called a \emph{case} (later in this thesis also: \emph{submission}).
The event log can be seen as a \emph{multi-set} of \emph{traces}.
A multi-set (a \emph{bag}) is a set that allows multiple instances of the set's elements. \cite{van2015extracting}

In this thesis it is assumed that any concurrent execution of events can be recorded into
an ordered and sequential event log.
The concurrent execution generates randomly ordered sequences.
The parallelisms can be discovered by observing the different traces and their frequencies.
For example, for a process consisting of activities $a,b,c,d,e \in A$, one trace could be
$\langle a,b,c,d,e \rangle$ and another $\langle a,c,d,b,e \rangle$.
These different traces could be found in the event log a number of times, some more frequent than others.
In process discovery the task is to construct a model with sequential and parallel steps
that describes a process that can generate these traces \cite{van2013discovering}.
The frequency of a trace matters in process discovery, and this is why the event log is a multi-set.
Figure \ref{tab:multisettrace} illustrates the difference of the mathematical abstraction of a multi-set of traces and figure \ref{tab:interleaved} a real-life event log with interleaved traces in a physical log file.

\begin{figure}[htb]
    \centering
    % footprint table example
    \begin{subfigure}[h]{0.4\linewidth}
        \begin{center}
        \begin{tabular}{r | l}
        ID & trace\\
        \hline
        1 & $\langle a,b,c,d,e \rangle$ \\
        2 & $\langle a,c,d,b,e \rangle$ \\
        3 & $\langle a,b,c,d,e \rangle$ \\
        \end{tabular}
        \end{center}
        \caption{Event log as multi-set of traces}
        \label{tab:multisettrace}
    \end{subfigure}
    % directed graph example
    \begin{subfigure}[h]{0.4\linewidth}
        \begin{center}
        \begin{tabular}{r | l}
        ID & event\\
        \hline
        1 & a \\
        2 & a \\
        1 & b \\
        1 & c \\
        2 & c \\
        3 & a \\
        \end{tabular}
        \end{center}
        \caption{Interleaved event log (truncated)}
        \label{tab:interleaved}
    \end{subfigure}
    \caption{Event log illustrated}
\end{figure}

When dealing with discovering processes from event logs, there are two clear challenges: \emph{incompleteness} and \emph{noise}.
Discovering the model from the event log is difficult since one cannot assume that all the possible traces are present \cite{van2013discovering}.
This is because the order in which parallel processes finish is random.
For a set of $n$ concurrent processes, there are $n!$ possible orderings in the trace.
The number of sequences observed in the logs \cite{van2007business} is often much smaller than the number of all possible sequences.
Moreover, some sequences can be inherently more frequent than others.
Such behaviour can be seen as undesirable noise, but sometimes infrequent traces may also present important information.
This makes decisions about trade-offs necessary.
The model should describe the process accurately even when the event log is incomplete or noisy.

Van der Aalst et al. \cite{van2013discovering} describes four criteria that need to be balanced when generating a model from a log: fitness, precision, generalization, and simplicity.
\emph{Fitness} measures whether the model fits the log, meaning that the traces in the event log can be generated by the discovered model.
\emph{Precision} measures whether the model allows only the behaviour observed in the event log. The model should describe the traces in the log, but should exclude completely unrelated behaviour not seen in the traces.
\emph{Generalization} relates to the unseen behaviour. The model should be general enough that it describes the process while allowing the cases that were not observed in the specific set of sequences.
Lastly, \emph{simplicity} relates to the noisiness. The models should be as simple as possible and undesirable, rare, or exceptional behaviour should not be included if it increases the model complexity.

\subsubsection{Process models and discovery}
\label{sec:processmodelsdsc}

A simple way to describe a process model is a \emph{directed graph}. A directed graph is a set of \emph{nodes} that are connected together by \emph{edges}.

\begin{definition}
A directed graph $G = (\mathcal{N}, \mathcal{E})$ consists of the set $\mathcal{N}$ of nodes and the set $\mathcal{E} \subseteq \{ (x,y) | x,y \in \mathcal{N} \} $ of edges, which are ordered pairs of nodes.
\end{definition}

A process can be described as a directed graph by having a graph node for each activity of the process ($\mathcal{N} = A$). The graph edges describe the possible transitions between the activities.
In this model, any two parallel activities $a, b \in A$ will have directed arcs $(a,b)$ and $(b,a)$ between them.
A log is generated by traversing through the graph and visiting all nodes \textit{exactly once}.
This type of path is known as the \textit{Hamiltonian path} or a \textit{traceable path} \cite{garey1979computers}.
Figure \ref{fig:directedgraph} illustrates an example of a directed graph.
The graph shown has two nodes $c$ and $d$ which are parallel.
By following the directed arcs and visiting each node exactly once, the graph shown can generate exactly two distinct traces which are also Hamiltonian paths: $\langle a,b,c,d,e \rangle$ and $\langle a,b,d,c,e \rangle$.
In other words, a trace conforms to the model if and only if the trace is a Hamiltonian path over the directed graph.

\begin{figure}[htb]
\centering \includegraphics[width=0.7\linewidth]{gfx/figures/directedgraph.pdf}
\caption{An example of a directed graph}
\label{fig:directedgraph}
\end{figure}

A \emph{Petri net} \cite{rozenberg1998lectures} can be used as a more detailed process model. A Petri net consists of \emph{places}, \emph{transitions}, and directed arcs connecting them. In this thesis I focus on \emph{finite nets} where the sets forming a Petri net are finite.

\begin{definition}
A Petri net is a tuple $N = (S, T, F)$ which consists of:
\begin{enumerate}
    \item a set $S$ of \emph{places},
    \item a set $T$ of \emph{transitions} in a way that $S \cap T = \emptyset$
    \item a set $F$ (flow relation) of directed arcs: $F \subseteq (S \times T) \cup (T \times S)$
\end{enumerate}
\end{definition}

In a Petri net, the places and transitions $S \cup T$ are called the \emph{elements} of $N$.
For any element $x \in S \cup T$ its \emph{pre-set} ${}^\bullet x$ is all the elements that have a directed arc to $x$, that is ${}^\bullet x = \{y \in S \cup T | (y,x) \in F\}$. Similarly its \emph{post-set} $x^\bullet$ is defined as
$x^\bullet = \{y \in S \cup T | (x,y) \in F\}$.
A Petri net can be mapped to a directed graph by creating equivalent nodes for each place and directed edges for each transition.

Van der Aalst et al. \cite{van2013discovering, van2004workflow} define a subclass of Petri nets called a \emph{workflow net} to describe processes. A workflow net (WF-net) is a Petri net with some further restrictions to make it more suited for process discovery. In their description, a WF-net needs a single starting point (an input place) and a single ending point (an output place). Furthermore they define that a WF-net needs to be \emph{strongly connected}, meaning every node is on a directed path from the start to the end.

\begin{definition}
Let $N = (S, T, F)$ be a Petri net. $N$ is a workflow net \emph{iff}:
\begin{enumerate}
    \item $S$ contains an input place $i$ such that ${}^\bullet i = \emptyset$ (starting point)
    \item $S$ contains an output place $o$ such that $o^\bullet = \emptyset$ (ending point)
    \item $N$ is \textit{strongly connected}
\end{enumerate}
\end{definition}

With the definitions for event logs, traces and WF-nets, we can describe \textbf{process discovery} as an algorithm that maps any event log $L$ into a model such as a directed graph or a Petri net that describes the underlying process that generated the event log.

\subsubsection{\textalpha-algorithm}
\label{sec:alphaalgorithm}
Constructing concurrent process models from an ordered event log is a challenging task.
The event log is a linear and ordered list of events and does not directly express the dependencies between these events.
To find the dependencies, and thus the shape of the process model, it needs to be extracted with an algorithm.

The \textalpha-algorithm is a process discovery algorithm that reads ordered event logs.
The algorithm discovers parallelism by comparing the order of events in different traces.
In a trace, the activities that depend on another activity always come later in the trace.
However, the activities that are parallel and have no such dependency can come in any order regarding each other.
Thus, in different traces the parallel activities are ordered differently.
This is the main idea behind the \textalpha-algorithm.

A detailed mathematical description of the \textalpha-algorithm can be found in \cite{van2004workflow}.
The idea of the algorithm is:

\begin{enumerate}
    \item Find all the events that appear in event log $L$. I call this the \emph{vocabulary}. This corresponds to all the transitions $T_L$ in the WF-net.
    \item Find all the events that appear as the first event in any trace (the \emph{start transitions}).
    \item Find all the events that appear as the last event in any trace (the \emph{end transitions}).
    \item Find all pairs of sets of events $(A,B)$ that have a (causal) dependency in all the traces. This means that all events in $A$ always come before all the events in $B$ in all the traces.
    \item Reduce the set of pairs discovered in the previous step to only include the ``maximal pairs'' (see below).
    \item Create a place for each pair $(A,B)$ from the previous step. Additionally, create places for a starting point $i$ and an ending point $o$. This will be the set of places $S_L$.
    \item Connect the arcs (the flow relation $F_L$). All start transitions from step 2 will have $i$ as their input place and all end transitions from step 3 will have $o$ as their output place. All the places for each pair $(A,B)$ will have transitions in $A$ as their input node and transitions in $B$ as their output node.
    \item The result is a WF-net $\alpha(L) = ( S_L, T_L, F_L )$.
\end{enumerate}

In step 5, the set of ``maximal pairs'' means that there are no pairs which include subsets of another pair. For example, the pairs $\{(\{a\},\{b,c\}),(\{a\},\{b\}),(\{a\},\{c\})\}$ can be reduced into just $\{(\{a\},\{b,c\})\}$.

In essence, the \textalpha-algorithm tries to find arcs that form a WF-net describing the causal dependencies observed over all the traces in the event log.
For example, if activity $b$ comes after activity $a$ in all the traces, then it suggests a causal dependency $a \rightarrow b$.
On the other hand, if in some traces $a$ comes after $b$ and some others before, then it suggests that the activities do not depend on each other and are parallel.

There are some limitations to this algorithm.
The \textalpha-algorithm assumes that the event log is complete and has accurate ordering \cite{van2013discovering}. This means that all the events are present in the logs, and that the time-ordering in the traces corresponds to causal relations accurately. Furthermore, there can be different WF-nets that create similar traces \cite{van2013discovering}. In other words, different process models can create the same traces.
The algorithm is also not suited to dealing with non-local dependencies \cite{van2013discovering}.
For example, if $a \rightarrow b$, $b \rightarrow c$, and $a \rightarrow c$, this $a \rightarrow c$ dependency is said to be ``non-local'', since from the logs it would only appear that $b \rightarrow c$.

% ################################

\subsection{Machine learning}

The term \textit{machine learning} means the study and development of algorithms that give computers the ability to learn from data without being explicitly programmed for that data.
The traditional approach in programming is to explicitly define the steps the computer should take to solve a problem.
However, sometimes you know the input to a problem and what the solution should be, but not how to get to the solution.
Figures \ref{fig:traditionalvs} and \ref{fig:mlvs} illustrate this fundamental difference.
For example, we can look at the problem of computer vision.
As an input we could have a thousand photos of birds and a thousand photos of without birds.
For us humans it is easy to recognize a bird and decide which of these two groups an arbitrary photo belongs to.
What we don't know are the exact rules that make a photo a ``bird photo''.
It would be very difficult to program an algorithm that examines the pixels of a new photo and decides whether there is a bird in the image.
This situation is a good example of what machine learning algorithms excel in.

\begin{figure}[htb!]
    \centering
    \begin{subfigure}[h]{0.4\linewidth}
        \centering \includegraphics[width=\linewidth]{gfx/figures/traditionalvs.pdf}
        \caption{Traditional programming}
        \label{fig:traditionalvs}
    \end{subfigure}
    \begin{subfigure}[h]{0.4\linewidth}
        \centering \includegraphics[width=\linewidth]{gfx/figures/machinevs.pdf}
        \caption{Machine learning}
        \label{fig:mlvs}
    \end{subfigure}
    \caption{Illustration of machine learning}
\end{figure}

Machine learning is data driven and the focus is less on traditional programming instructions.
Machine learning algorithms focus on finding patterns and models in data,
which can then be used to process new data or make predictions.
Supervised learning is a subset of machine learning.
In supervised learning, the input for the computer is a set of \textit{training data} with predefined labels.
This training data is the ``known'' data points of the ``seen'' data.
Usually, these labels come from real world measurements or manual (human) labeling.
For example, in the computer vision problem described before, the training photos could be manually labeled by humans as ``bird'' and ``no bird''.
The supervised machine learning algorithm uses this labeled data to learn patterns in the \emph{training phase}. After the training, computer can then use the information learned to label new (previously unseen) data.
A separate set of data points called the \emph{test set} is used to evaluate the model performance.
The assumption is that the performance over the test set is an estimate of the performance over new data.

In classification tasks, the models try to predict a \emph{class} for an unknown datapoint. The classes are discrete and the number of classes is finite. In binary classification there are two possible classes, often labelled 1 and 0, or true and false, as seen in the bird photo example above. In regression tasks the predictions result in a real number instead of discrete values, such as when predicting a length of time.
Different models are used for these different tasks.
The model best suited for an application depends on the distribution of the possible values and other characteristics of the phenomenon being modeled.

In conclusion, Machine Learning is a set of algorithms and models that leverage a large dataset to estimate some feature of new datapoints.
In \textit{classification} tasks, this feature is chosen from a finite set of possible classes, whereas in \textit{regression} tasks the value estimated is a real number.

\subsubsection{Regression}

Regression algorithms use a set of training data to learn a model.
The training data is set of labelled data points.
The data set needed is often large and consists of thousands of points.
Each data point consists of a set of \emph{features} (the inputs) and a \emph{label} (the output).
The features are properties that are available for all the data points.
The label is the feature that is unknown and we want to estimate for new data.
In regression problems the label being estimated is a continuous value (a real number).

For example, regression could be used to estimate wine quality.
The features could be some measurable aspects of the wine such as the pH-value, the amount of sugar, or the year the wine was bottled.
The label would be a number ranging from 1 to 10 corresponding to the quality of the wine.
A training dataset could be generated by measuring the features of many wines and then having (human) wine tasters manually label them with their understanding of the wine quality.
This set of features and labels could then be used to train a regression model.
The model could then be used to estimate the quality of a previously unseen wine by measuring the same features and providing them as an input for the model.
The model would then output a number from 1 to 10 as the estimate for the wine quality.

Expressed mathematically, regression estimates an output value $r \in \mathbb{R}$, which is a real number \cite{alpaydin}.
The training set consists of $N \in \mathbb{N}$ feature vectors (inputs) $\mathbf{x}^t \in \mathbb{R}^d$ and $N$ output values $r^t$.
Here $d \in \mathbb{N}$ is the dimensionality of the data, that is, the number of features being used as inputs. Thus, the training data $\mathcal{D}$ can be expressed as follows:
$$\mathcal{D} = \{(\mathbf{x}^t, r^t)\}_{t=1}^N, \mathbf{x}^t \in \mathbb{R}^d, r^t \in \mathbb{R}$$
The regression algorithm (the learner) processes the training data and outputs a model $g(\mathbf{x})$ which estimates the output parameter $r$ for a new unseen feature vector $\mathbf{x} \in \mathbb{R}^d$.
$$g(\mathbf{x}) = r$$

The model $g(\mathbf{x})$ is chosen based on the data and domain knowledge.
The models can range from a simple linear models to complex models such as decision forests.
In theory any model $g: \mathbb{R}^d \rightarrow \mathbb{R}$ can work,
as long as a learning algorithm for the model exists.
In the case of features that are not real numbers, a mapping function is used that takes a different type of feature (such as a string or a boolean) and converts it into a real number.
In the ideal case, the model should fit the phenomenon (physical or other) being modeled in the machine learning application.
However, sometimes the underlying model is not known.
In these cases, multiple models can be used and compared based on the dataset in order to find the best performing one.

The model is evaluated over a separate test set.
Commonly, the test set is created by separating the training set into two distinct sets before the training phase.
$$\mathcal{D}_{test} = \{ (\mathbf{x}_*^t , r_*^t) \}_{t=1}^{N_{test}}$$
In essence, the model is tested with the inputs of a data point in the test set. The output value from the model is compared to the ``correct'' label in the test set data point.
The difference between the values is the \emph{error}.
The aim of machine learning is to minimize this error by choosing a good model for the application and the data, and tuning the model parameters until the desired (low) error is reached.
The error measures I use in this thesis are \textit{mean absolute error} (MAE) and \textit{root mean square error} (RMSE).
The mean absolute error is the average of all the individual errors of the test set data points.
Root mean square error is the square root or the average of squared errors.

$$E_{MAE}(g | \mathcal{D}_{test}) = \frac{1}{N_{test}} \sum_{t=1}^{N_{test}} (r_*^t - g(\mathbf{x}_*^t))$$

$$E_{RMSE}(g | \mathcal{D}_{test}) = \sqrt{ \frac{1}{N_{test}} \sum_{t=1}^{N_{test}} (r_*^t - g(\mathbf{x}_*^t))^2 }$$

All this is based on the assumption that the samples are \textit{independent and identically distributed} (iid) \cite{alpaydin}.
This means that the order of the samples in the sets does not matter and that the distribution of the features and the labels is the same in the training set, the test set, and for any unseen data point outside these sets.
If there is enough information in the training set, the model should be able to use the information to label new data points with the same performance as over the test set.
Thus, the performance over the test set can be used to estimate the performance of the model for unseen data.

There are many different regression learners that are based on different theories. The two models used in this thesis are Poisson Regression \cite{azurepoisson} and Boosted Decision Trees \cite{azurebdt}.

\subsubsection{Poisson regression}

The Poisson distribution model was derived to analyze counts of events within a specific time span \cite{osgood2000poisson}.
It analyzes the probability of observing a discrete number of events when given a ``mean rate'' of events happening.
The mean rate $\lambda$ describes the average number of events happening during the time span.
The Poisson model assumes that the events are independent from each other and they happen at random.
An example could be to model the probability of how many phone calls happen at a call center in a single day.
To model this with a Poisson distribution, knowing the average number of calls per day ($\lambda$) would need to be known.
When the mean rate $\lambda$ is low, the distribution is skewed towards the beginning.
As $\lambda$ increases, the distribution approaches the normal distribution \cite{osgood2000poisson}.
Figure \ref{fig:poissongraphs} illustrates the different shapes of Poisson distributions.
Poisson regression makes an assumption that the underlying variable follows a Poisson distribution.
It works in cases where the data is labelled by counts or probabilities of events.

\begin{figure}[htb]
\centering \includegraphics[width=0.8\linewidth]{gfx/figures/poissons.pdf}
\caption{Poisson distributions with different values of $\lambda$}
\label{fig:poissongraphs}
\end{figure}

\subsubsection{Boosted decision trees}

The second model used in this thesis is boosted decision trees (BDT).
A \textit{decision tree} is a model for supervised learning that is based on a sequence of splits which form a hierarchical tree \cite{alpaydin}.
The tree consists of internal decision nodes and the terminal leaves containing values.
To find the result of the regression model, the algorithm steps through the decision nodes starting from the root.
At each node a component of the feature vector is compared against a predetermined threshold value.
If the value is lower (or higher) than the threshold value, a decision is made and either the left or the right child node is chosen.
This is repeated until a terminal leaf node is reached at the bottom of the tree.
The terminal nodes contain the label values.
The value in the leaf reached by the iterative algorithm is the result of the regression model.

The boosted decision tree learner in Azure ML is based on LambdaMART \cite{azurebdt}.
LambdaMART is a set of algorithms that implement a \textit{forest} of regression trees \cite{lambdamart2010}.
Gradient boosting \cite{friedman2001greedy} is used to combine several weaker models to form a stronger model.
The forest consists of multiple decision trees.
The result of the regression given by the LambdaMART forest is a linear combination of the outputs of the trees.
The learner trains the thresholds at the decision nodes and the values at the terminal leaves of each tree, as well as the weights for the linear combination to minimize error over the training set.

% Talk about practical usage (strengths, limitations)
One strength of the boosted decision tree model is that it is highly interpretable and can be used for rule extraction \cite{alpaydin}. Each tree can be converted into a set of IF-THEN rules, and the weights of the linear combination correspond to the importance of each tree.
Because of these reasons, the domain expert can analyze the model to see which features are being used and whether the model seems to make sense.
Furthermore, the model can even provide information about the real world ruleset for the measured phenomenon.
In general, boosted decision trees work well when the components of the feature vectors are related. In the case of completely independent vectors, a BDT model will not be as effective \cite{azurebdt}.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Related work
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%\clearpage
\subsection{Related work}
\label{sec:relatedwork}

Process mining has gained interest in the recent years, since it offers possibilities of streamlining business processes and gaining business intelligence (BI) by finding bottlenecks and inefficiencies in the processes.
Process mining has many uses, such as process discovery \cite{van2016discovery, van2013discovering}, trace clustering \cite{de2016general}, and conformance checking \cite{chomyat2016process}. Furthermore, there's some research done in the area of detecting process anomalies automatically \cite{bezerra2009anomaly}.

Process discovery is in the heart of process mining, since most process mining methods rely on modeling the process and taking advantage of the model in some manner.
Because of this, process discovery is talked about in many papers related to process mining \cite{chomyat2016process, de2016general, van2013discovering, van2015extracting, van2016process,bezerra2009anomaly}.

Conformance checking means making sure the current process conforms to a previously determined set of rules or a model \cite{chomyat2016process}.
Conformance checking can be especially useful in sectors where conforming to regulations or other such rules is critical for the work.
Examples of such sectors are the financial sector, medical business, and government institutions.
Process mining can be used to ensure the regulations are being followed.

The main purpose of my thesis is to help visualize the processes and to show anomalies to the users or even send notifications about the anomalies automatically.
The definition of \textit{anomaly} is not consistent across research \cite{bezerra2009anomaly}.
An anomaly can be anything exceptional or abnormal in the behaviour of a system.
It can also describe an error, noise, or fraudulent behaviour.
Usual definitions include that an anomaly needs to be infrequent, unexpected, and something that deviates from the normal behaviour.
Precise definition is difficult, since the definition of what is considered ``normal'' differs between cases.
Bezerra et al. \cite{bezerra2009anomaly} presents how an established process mining tool ProM can be used to discover models and check their conformance.
Each trace gets assigned a conformance value (fitness) describing how well it fits the previously discovered model.
With this method, a threshold value for required model fitness can be assigned to find the anomalous traces.
However, there is little focus on detecting anomalies real-time.

The past event logs can also be used to build workload histograms \cite{getta2014mining}.
This method reads event logs with periodic patterns (such as the re-occuring submissions in the Microsoft store).
The workload information can be used to predict incoming workloads and to improve system performance by preparing against peak loads.
This method is labeled \textit{process enhancement}.
An example of process enhancement is detecting periods of low activity and using them to run background tasks.
This type of balancing decreases the idle time of a system and improves its capability to respond to peak loads \cite{getta2014mining}.


This chapter describes the benchmarking program, its input parameters, and the specification of the machines, that were used for the performance evaluation. Additionally, the results of the benchmark runs are analyzed (the results itself are presented in Appendix B) .

\section{Benchmark}

The performance evaluations is done with the benchmarking program. For each tested data structure (presented in \Cref{ch:numdb} and \Cref{ch:alt}), the benchmark runs for a specified amount of time. Then the throughput (operations per second) is calculated as the total count of iterations divided by the total time.

Instead of separately measuring the performance of every basic operation (\findop, \insertop, \removeop), the overall numeric database performance is evaluated. The numeric database retrieval operation consists of either lookup (in case the item with the specified key is in the database) or lookup, user function invocation, item removal and item insertion. The user function is much slower than the database operations. Therefore, the most effective numerical database is the one that calls the user function as rarely as possible.

The recursive computation of the $N$th Fibonacci number is chosen as the user function. The algorithm implementation is trivia and, having the exponential time complexity, it is extremely inefficient. This is the advantage from the perspective of the benchmark as its task is to simulate a very computational-heavy function. What is more, the time it takes to compute the function can be easily adjusted by the function argument.

\pagebreak

Generally, cache systems perform well only on skewed inputs, when there is a small subset of items that are accessed most of the time while other items are accessed much less often. In this benchmark, a numerical database is tested with a random input sequence that has normal distribution of values. The parameters of the distribution are as follows:
\begin{description}
\item[Mean $u$] equals zero. The data structures presented in this library are agnostic to the particular argument values and their performance is only affected by the frequency of items in the input sequence. So $u$ can be any number. Zero is any number.

\item [Standard deviation $\sigma$] is derived from $Area{\mhyphen}under{\mhyphen}curve$ parameter and the available memory. $Capacity$ is calculated as the available memory divided by the size of a single item. $Area{\mhyphen}under{\mhyphen}curve$ is a value from the interval $(0,1)$. It defines the ratio of accesses to the $Capacity$ most valuable items to the total count of accesses. With given $Capacity$ and $Area{\mhyphen}under{\mhyphen}curve$, $\sigma$ is calculated as follows:
\begin{equation}
 \sigma = \frac{Capacity}{2 \times Quantile(0.5 + \frac{Area{\mhyphen}under{\mhyphen}curve}{2})}
 \end{equation}
\end{description}

\section{Benchmark Parameters}
The benchmark has several input parameters:
\begin{description}
\item [minval, maxval]-- the range of values the Fibonacci function is called with. It is defined as a range to simulate functions which execution time depends on its arguments.
\item [available memory]-- the maximum amount of memory the numerical database uses.
\item [thread count]-- relevant for concurrent numerical databases. Sets the number of  threads to run in parallel.
\item[mean changing rate]-- adjusts the rate at which the mean of the distribution is changed. If larger than zero, it simulates input sequences with non-static distribution. It is measured in the \emph{delta-per-iteration} units~-- its value is added to the mean at every iteration, e.g. if the rate is $^1/_{100}$, than after 1000 iteration the mean will move by 10.
\item[area-under-curve]-- the parameter that affects the standard deviation of the distribution.
\end{description}

\section{Analysis of the Sequential Containers}

\label{sec:secanalysis}

The performance evaluation of the sequential containers has been done on the following machine:

\begin{description}
    \item [CPU] Intel\textsuperscript{\textregistered{}} Core\textsuperscript{\texttrademark{}} i5-6200U
    2.30GHz (2.80 GHz\footnote{with Intel\textsuperscript{\textregistered{}} Turbo Boost Technology})$ \times$ 2 cores
    \item [Memory] 8 GB DDR3 1600 MHz
    \item [OS] Linux\textsuperscript{\textregistered{}} Ubuntu\textsuperscript{\textregistered{}} 16.04 LTS 64-bit
    \item [Compiler] GCC 5.4, compilation flags: \texttt{-O3 -std=c++14}
    \end{description}

In this chapter there are several graphs (\Cref{f1}, \Cref{f2}, \Cref{f3}), that visualises data presented in \Cref{ch:bresult}. The graphs do not include all the data from the tables, e.g. there is no graph for LRU and LFU based numerical databases; only the most representative candidates have been chosen. The outcomes have confirmed some assumptions, stated in the previous chapters, while refuted others.

The weighted search tree proved to be the most effective container for the numerical database. However, no concurrent WST implementation is known, so its usage is limited to the sequential environment.

The combination of the hash table and the binary heap performs about 10\% slower than WST. However, its advantage over WST is the simpler structure, that made it possible to develop the concurrent version of this container, called \cndcname.

The benchmark proved splay tree inefficiency. It is outperformed by WST and the hash table on all workloads. Therefore it is not recommended to use it for a numerical database.

\emph{Least-recently-used} and \emph{Least-frequently-used} eviction policies do not achieve the same performance as the policy, based on the binary heap. Possibly, because they do not rely on the initial item priority, thus give no preference to items that are rarely accessed  but took long to be calculated and due to that must be kept in the database.

\emph{Priority aging} does not show any advantage over the static priority. However, further studies and tests are required here, as the benchmark does not simulate the worst-case input for the static priority scheme.

\begin{figure}[h]
\centering
    \label{f1}
    \begin{tikzpicture}
      \begin{axis}[
        legend pos=outer north east,
        xlabel = Memory {[KiB]},
        ylabel = Throughput {[op/s]},
        xmin = 0.85, xmax = 3.15,
        xtick={1,2,3},
        xticklabels={4, 16, 64},
        ymin = 0, ymax = 2700,
        ytick={250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500},
        ymajorgrids=true,
        grid style=dashed,
      ]
        \addplot+[densely dashed, color=black, mark = no] coordinates{(1, 588)(2, 588)(3, 588)};
        \addplot coordinates{(1, 2015)(2, 2411)(3, 2329)};
        \addplot coordinates{(1, 2505)(2, 2258)(3, 2211)};
        \addplot+[color=blue] coordinates{(1, 879)(2, 887)(3, 896)};
        \legend{Baseline,WST,Hash table,Splay tree}
      \end{axis}
      \end{tikzpicture}
\caption{Sequential containers comparison (variable memory size)}
\end{figure}

\begin{figure}
\centering
    \label{f2}
    \begin{tikzpicture}
      \begin{axis}[
        legend pos=outer north east,
        xlabel = \emph{area-under-curve},
        ylabel = Throughput {[op/s]},
        xmin = 0.65, xmax = 6.35,
        xtick={1,2,3,4,5,6},
        xticklabels={0.45, 0.55, 0.65, 0.75, 0.85, 0.95},
        ymin = 0, ymax = 3000,
        ytick={250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750},
        ymajorgrids=true,
        grid style=dashed,
      ]
        \addplot+[densely dashed, color=black, mark = no] coordinates{(1, 588)(2, 588)(3, 588)(4, 588)(5,588)(6,588)};
        \addplot coordinates{(1, 1199)(2, 1432)(3, 1709)(4, 1997)(5,2329)(6,2890)};
        \addplot coordinates{(1, 1183)(2, 1416)(3, 1655)(4, 1904)(5,2211)(6,2733)};
        \addplot+[color=blue] coordinates{(1, 658)(2, 698)(3, 747)(4, 801)(5,896)(6,1040)};
        \legend{Baseline,WST,Hash table,Splay tree}
      \end{axis}
    \end{tikzpicture}
\caption{Sequential containers comparison (variable \emph{area-under-curve} value)}
\end{figure}

\begin{figure}[!t]
\centering
    \label{f3}
    \begin{tikzpicture}
          \begin{axis}[
            legend pos=outer north east,
            xlabel = Mean changing rate,
            ylabel = Throughput {[op/s]},
            xmin = 0.80, xmax = 4.20,
            xtick={1,2,3,4},
            xticklabels={0, $^1/{100}$, $^1/{10}$, 1},
            ymin = 0, ymax = 3000,
            ytick={250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750},
            ymajorgrids=true,
            grid style=dashed,
          ]
            \addplot+[densely dashed, color=black, mark = no] coordinates{(1, 588)(2, 588)(3, 588)(4, 588)};
            \addplot coordinates{(1, 2461)(2, 2329)(3, 1161)(4, 330)};
            \addplot coordinates{(1, 2344)(2, 2211)(3, 1238)(4, 336)};
            \addplot+[color=blue] coordinates{(1, 957)(2, 896)(3, 565)(4, 311)};
            \legend{Baseline,WST,Hash table,Splay tree}
          \end{axis}
        \end{tikzpicture}
\caption{Sequential containers comparison (variable mean changing rate)}
\end{figure}

\section{Analysis of the Concurrent Containers}

\label{sec:conanalysis}

The performance evaluation of the concurrent containers has been performed on the following machine:

\begin{description}
    \item [CPU] Intel\textsuperscript{\textregistered{}} Xeon\textsuperscript{\textregistered{}} E5-2650 v4
    2.20GHz (2.90 GHz\footnote{with Intel\textsuperscript{\textregistered{}} Turbo Boost Technology}) $ \times $ 2 sockets $ \times $ 12 cores
    \item [Memory] 256 GB DDR4 2400 MHz
    \item [OS] Linux\textsuperscript{\textregistered{}} Ubuntu\textsuperscript{\textregistered{}} 16.04 LTS 64-bit
    \item [Compiler] GCC 5.4, compilation flags: \texttt{-O3 -std=c++14}
    \end{description}

Same as with the sequential containers, the complete benchmark data is presented in \Cref{ch:bresult}. \Cref{f4} shows the performance difference between the tested concurrent containers. \Cref{f5} demonstrates their scalability~-- the relative per-thread performance with increasing number of threads. For example, the graph shows that with 24 threads running simultaneously, the performance of one thread in \cndcname is 30\% lower than that in the single-threaded test.

As expected, the coarse-grained locking approach yields the very ineffective container. The observation that with 2 threads the performance is two times lower compared to the single-threaded test (note, the total, not the per-thread performance) can be explained by the high contantion on the single mutex. The process of locking/unlocking an open mutex is quite fast operation, but locking the already locked mutex implies, that the thread will be suspended and then resumed. This is quite heavy and complex operation from the perspective of an operational system.

The binning approach performs better than the previous one. However, \Cref{f5} clearly shows, that it does not scale very good for the bigger number of threads~-- at 24 threads, per-thread performance is only 10\% as high as the maximum.

\cndcname shows excellent scalability, even with 24 threads. The poor per-thread performance is rather explained by the huge memory overhead per item than by computational complexity~-- in addition to the overhead, introduced by the data structure itself, synchronization adds at least 60 bytes for each item. The further studies should be directed at lowering this overhead. For example, some synchronization can be performed in the lock-free fashion with no mutexes involved.

\begin{figure}
\centering
    \label{f4}
    \begin{tikzpicture}
          \begin{axis}[
            legend pos=outer north east,
            xlabel = Thread count,
            ylabel = Throughput {[op/s]},
            ylabel shift = 0.5 pt,
            xmin = 0, xmax = 26,
            xtick={1, 2, 4, 8, 16, 24},
            ymin = 0, ymax = 1400,
            ytick={100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300},
            yticklabels={1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000},
            ymajorgrids=true,
            grid style=dashed,
          ]
            \addplot coordinates{(1, 73.4)(2, 152.4)(4, 298.4)(8, 512.0)(16, 904.0)(24, 1292.0)};
            \addplot coordinates{(1, 234)(2, 123)(4, 120)(8, 127)(16, 124)(24, 127)};
            \addplot+[mark = triangle, mark options=solid]
                     coordinates{(1, 223)(2, 279)(4, 332)(8, 379)(16, 525)(24, 636)};

            \legend{\cndcname, Coarse + WST, Binning + WST}
          \end{axis}
        \end{tikzpicture}
\caption{Concurrent containers comparison (variable thread count)}
\end{figure}

\begin{figure}
\centering
    \label{f5}
    \begin{tikzpicture}
          \begin{axis}[
            legend pos=outer north east,
            xlabel = Thread count,
            ylabel = Relative performance per thread,
            xmin = 0, xmax = 26,
            xtick={1, 2, 4, 8, 16, 24},
            ymin = 0, ymax = 1.1,
            ytick={0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1},
            ymajorgrids=true,
            grid style=dashed]
              \addplot coordinates{(1, 1)(2, 1.03)(4, 0.97)(8, 0.87)(16, 0.77)(24, 0.70)};
              \addplot coordinates{(1, 1)(2, 0.26)(4, 0.127)(8, 0.067)(16, 0.033)(24, 0.02)};
              \addplot+[mark = triangle, mark options=solid]
                       coordinates{(1, 1)(2, 0.626)(4, 0.37)(8, 0.212)(16, 0.147)(24, 0.119)};
              \legend{\cndcname, Coarse + WST, Binning + WST}
          \end{axis}
    \end{tikzpicture}
    \caption{Concurrent containers scalability comparison}
\end{figure}


% !TEX root = main.tex
\section{Formalization of Unsafe Dataflow with dIMP}

In this section, we are going to formalize what we mean by a program having unsafe dataflow,
give a algorithm specification for computing if a program has unsafe dataflow and
prove that any algorithm conforming to that algorithm specification is sound.

We use the toy language IMP as presented in~\cite{sat}.
The lecture notes themselves heavily borrow from~\cite{fsopl} for the
presentation and semantics of IMP.

We call an algorithm that detects if a program has unsafe dataflow also a dataflow algorithm.
Dataflow is unsafe, if (user-controlled) values flow, without modification,
 from a set of sources to a set of sinks.

\subsection{Syntax of dIMP}
We extend the syntax of IMP a bit
and call the resulting language dIMP (for dataflow IMP):
\begin{align*}
    n \in  \:       & \Z\\
    \flaggedn{} \in \: & \StoreDomain = \{\flagged{} \mid n \in \Z\}\\
    X \in  \:       & \Loc = \{x, y, z, sum, \ldots\}\\
    a \Coloneqq \: &\literalint{} \mid X \mid \defaultsource \mid a_0+a_1 \mid \ldots\\
    t \Coloneqq \: & \btrue \mid \bfalse                                                \\
    b \Coloneqq \: & t \mid a_0 = a_1 \mid \neg b_0 \mid b_0 \land b_1 \mid \ldots \\
    c \Coloneqq \: &\skipcmd \mid \defaultstore \mid \defaultseq \mid \defaultif \mid \defaultwhile \mid \defaultsink\\
    f \Coloneqq \: & \textbf{c} \mid \textbf{t}\\
\end{align*}
Exactly which arithmetic and Boolean expressions are available in the language
is left unspecified, as it doesn't matter to the dataflow algorithm.
Stores are denoted with $\store \in \Sigma = \Loc \to \StoreDomain$.
Stores are function from locations to the set of tagged integer
values.

The intuition here is that for all $n \in \Z$,
each value is tagged by either \textbf{c} for clean or \textbf{t} for being tracked
as having unsafe dataflow.
If the tag is irrelevant in the current context, we write $\flaggedn{}$ for a tagged
value.
A tracked value originates from a source, and is preserved by value-preserving operations.
The command $\defaultsink$ is a special marker for the dataflow sink.
It aborts the program if a tracked value reaches the sink, thus indicating a policy
violation.
In real programs, the dataflow source would likely be a procedure reading input,
i.e.\ from a terminal, and the dataflow sink would likely be a procedure
printing the data to a terminal, or otherwise communicating with the outside world.

\iffalse
There is a new judgement of the form
\fbox{$\bigstep{a}{\sigma}{\flaggedn{}}$}:
\begin{align*}
    &\bsrule{EA-Num}{}{\bigstep{\literalint}{\store}{\clean}} \qquad
    \bsrule{EA-Loc}{}{\bigstep{X}{\store}{\store(X)}}\qquad
    \bsrule{EA-Plus}
    {\bigstep{a_0}{\store}{\flagged[n_0][0]}
    \qquad \bigstep{a_1}{\store}{\flagged[n_1][1]}}
    {\bigstep{a_0+a_1}{\store}{\clean[(n_0+n_1)]}}\\
    &\bsrule{EA-Minus}
    {\bigstep{a_0}{\store}{\flagged[n_0][0]}
    \qquad \bigstep{a_1}{\store}{\flagged[n_1][1]}}
    {\bigstep{a_0-a_1}{\store}{\clean[(n_0-n_1)]}} \qquad
    \bsrule{EA-Times}
    {\bigstep{a_0}{\store}{\flagged[n_0][0]}
    \qquad \bigstep{a_1}{\store}{\flagged[n_1][1]}}
    {\bigstep{a_0 \times a_1}{\store}{\clean[(n_0 \times n_1)]}}\\
    &\bsrule{EA-Source}{\bigstep{a}{\store}{\flagged}}
    {\bigstep{\source{a}}{\store}{\tracked}}
\end{align*}

The Judgement $\langle c, \sigma \rangle \downarrow \sigma'$ is replaced by
$\bigstep{c}{\sigma}{\excstore'}$
where $\excstore{}: (\Loc \to \StoreDomain) \cup \{\exception\}$.
The state $\exception$ indicates that the program was aborted due to a policy violation.
\\
Judgement \fbox{$\bigstep{c}{\sigma}{\excstore'}$}:
\begin{align*}
    &\bsrule{EC-Skip}{}{\bigstep{\skipcmd}{\store}{\store}}\qquad
    \bsrule{EC-Assign}{\bigstep{a}{\store}{\flaggedn{}}}
    {\bigstep{\defaultstore}{\store}{\store{}[X \mapsto \flaggedn{}]}}\\
    &\bsrule{EC-Seq}{\bigstep{c_0}{\sigma}{\store''} \qquad \bigstep{c_1}{\store''}{\excstore'}}
    {\bigstep{\defaultseq}{\store}{\excstore'}}\qquad
    \bsrule{EC-SeqAbrt}{\bigstep{c_0}{\sigma}{\exception}}
    {\bigstep{\defaultseq}{\store}{\exception}} \\
    &\bsrule{EC-IfT}{\bigstep{b}{\store}{\btrue}\qquad \bigstep{c_0}{\store}{\excstore'}}
    {\bigstep{\defaultif}{\store}{\excstore'}} \qquad
    \bsrule{EC-IfF}{\bigstep{b}{\store}{\bfalse}\qquad \bigstep{c_1}{\store}{\excstore'}}
    {\bigstep{\defaultif}{\store}{\excstore'}}\\
    &\bsrule{EC-WhileF}{\bigstep{b}{\sigma}{\bfalse}}
    {\bigstep{\defaultwhile}{\store}{\store}} \\
    &\bsrule{EC-WhileT}{\bigstep{b}{\sigma}{\btrue} \qquad \bigstep{c_0}{\store}{\store''}\qquad
    \bigstep{\defaultwhile}{\store''}{\excstore'}}
    {\bigstep{\defaultwhile}{\store}{\excstore'}}\\
    &\bsrule{EC-WhileTAbrt}{\bigstep{b}{\sigma}{\btrue} \qquad \bigstep{c_0}{\store}{\exception}}
    {\bigstep{\defaultwhile}{\store}{\exception}}\\
    &\bsrule{EC-Sink}{\bigstep{a}{\store}{\clean{}}}
    {\bigstep{\defaultsink}{\store}{\store}} \qquad
    \bsrule{EC-SinkAbrt}{\bigstep{a}{\store}{\tracked{}}}
    {\bigstep{\defaultsink}{\store}{\exception}}\\
\end{align*}

The judgement operations for Boolean expressions are modified to ignore the tracked-flag and work
just as in IMP. This is analogous to how $\textsc{EA-Plus}$ etc.\ work.
\fi

\subsection{Syntax and Semantics of SSA-dIMP}
To facilitate the dataflow analysis, we describe an SSA form on dIMP with a concrete
syntax and semantics.
We do not describe how to transform a dIMP program to an SSA-dIMP program, but
refer the reader to the literature, where different SSA construction algorithms are
described. Some even come with computer-verified correctness and minimality guarantees,
we refer the reader to~\cite{verifiedssa}.

The syntax for Boolean and arithmetic expressions in SSA-dIMP is the same as in dIMP.
However, the command syntax changes.
We now denote commands by $s$ (short for statement, or SSA-command) to highlight the differences
from the commands denoted by $c$ in dIMP.
\begin{align*}
    s \Coloneqq &\:\skipcmd \mid \defaultstore \mid \defaultssaseq \mid \defaultssaif\\
    &\mid \defaultssawhile  \mid \defaultsink \\
    \philist \Coloneqq &\: \defaultphilistn\\
\end{align*}
At every point where $\varphi$-nodes can placed in the control flow graph
of a dIMP program, the syntax of SSA-dIMP has an explicit list of $\varphi$-nodes.

\subsubsection*{The SSA Type System}
% TODO possible boolean type?
A program in SSA-dIMP is only valid if it conforms to the SSA properties.
To enforce that, we describe a simple type system.
Every well-typed expression has type $\tint$, thus the set of all types is $\Tau = \{ \tint \}$.
Let $\Gamma, \Delta: \Loc \partialf \Tau$ be partial maps with finite domain.
These are the type contexts.
$\Gamma$ keeps tracks of the type of the variables defined in the store before a
statement is executed, and $\Delta$ keeps track of the types of the
newly defined variables while executing that statement.

We will use $\dunion$ to be the union of maps,
where we assert that the domains of the maps are disjoint.

After giving the typing rules,
we state that type contexts $\Gamma$ and $\Delta$ are enough to prove that the program is indeed in SSA form.
The easiest way to get them is to run an SSA construction algorithm on a dIMP program.
It is a gap in the provided proofs that we do not show that every dIMP program
can be transformed in a valid SSA-dIMP program (especially, we omit showing that
$\varphi$-nodes will be placed exactly at the places they are allowed in the syntax
of SSA-dIMP).

The type system has the following judgments:
\\
Judgement \fbox{$\typestep{\Gamma}{a}{\tint}$}:
\begin{align*}
    &\trule{SSA-Num}{}{\typestep{\Gamma}{\overline{n}}{\tint}}\qquad
    \trule{SSA-Loc}{}{\typestep{\Gamma}{X}{\Gamma(X)}}\\
    &\trule{SSA-Source}{\typestep{\Gamma}{a}{\tint}}{\typestep{\Gamma}{\source{a}}{\tint}}\\
    &\trule{SSA-Plus}{\typestep{\Gamma}{a_0}{\tint}\qquad\typestep{\Gamma}{a_1}{\tint}}
    {\typestep{\Gamma}{a_0+a_1}{\tint}}\\
    &\ldots
\end{align*}
Judgement \fbox{$\typestmt{\Gamma}{b}$}:
\begin{align*}
    &\trule{SSA-Bool}{}{\typestmt{\Gamma}{t}}\qquad
    \trule{SSA-Eq}{\typestep{\Gamma}{a_0}{\tint}\qquad \typestep{\Gamma}{a_1}{\tint}}
    {\typestmt{\Gamma}{a_0 = a_1}}\\
    &\trule{SSA-Neg}{\typestmt{\Gamma}{b}}
    {\typestmt{\Gamma}{\neg b}}\qquad
    \trule{SSA-And}{\typestmt{\Gamma}{b_0}\qquad\typestmt{\Gamma}{b_1}}
    {\typestmt{\Gamma}{b_0 \land b_1}}\\
    &\ldots
\end{align*}
Judgement \fbox{$\typestep{\Gamma;\Delta_0;\Delta_1}{\philist}{\Delta}$}:
\begin{align*}
    &\trule{SSA-$\varphi$}{}{\typestep{\Gamma;\Delta_0;\Delta_1}{\defaultphilistn}{[X_1 \mapsto \type_1, \ldots, X_n \mapsto \type_n]}}\\
    &\text{(if for $i \in \{1, \ldots, n\}: X_i \notin \dom\Gamma \land \type_i = (\Gamma \dunion \Delta_0)(Y_i) = (\Gamma \dunion \Delta_1)(Z_i)
    \land \forall j \neq i: X_j \neq X_i$)}
\end{align*}
Note that this implies that this rule is only applicable if $Y_i$, $Z_i$ exist in the respective domains
of the partial functions.
\\
Judgement \fbox{$\typestep{\Gamma}{s}{\Delta}$}:
\begin{align*}
    &\trule{SSA-Skip}{}{\typestep{\Gamma}{\skipcmd}{\emptyset}}\qquad
    \trule{SSA-Assign}{\typestep{\Gamma}{a}{\tint}}{\typestep{\Gamma}{\defaultstore}{[X \mapsto \tint]}} \text{($X \notin \dom\Gamma$)}\\
    &\trule{SSA-Seq}{\typestep{\Gamma}{s_0}{\Delta_0}\qquad
    \typestep{\Gamma \dunion \Delta_0}{s_1}{\Delta_1}}{\typestep{\Gamma}{\defaultssaseq}{\Delta_0 \dunion \Delta_1}}\\
    &\trule{SSA-If}{\typestmt{\Gamma}{b}\qquad\typestep{\Gamma}{s_0}{\Delta_0}\qquad \typestep{\Gamma}{s_1}{\Delta_1}\qquad
    \typestep{\Gamma;\Delta_0;\Delta_1}{\philist}{\Delta}}
    {\typestep{\Gamma}{\defaultssaif}{\Delta}}\\
    &\trule{SSA-While}{\typestep{\Gamma;\emptyset;\Delta_1}{\philist}{\Delta}\qquad
    \typestmt{\Gamma \dunion \Delta}{b}\qquad\typestep{\Gamma \dunion \Delta}{s_0}{\Delta_1}}
    {\typestep{\Gamma}{\defaultssawhile}{\Delta}}\\
    &\trule{SSA-Sink}{\typestep{\Gamma}{a}{\tint}}{\typestep{\Gamma}{\sink{a}}{\emptyset}}\\
\end{align*}

Note that by this definition, the first argument of $\varphi$-nodes for \textbf{if} commands
corresponds to the variable after executing the \btrue{} branch, and the second argument to that
of the variable after executing the \bfalse{} branch.
For \textbf{while} commands, the first argument to the $\varphi$-node corresponds to the value
before executing $s_0$ the first time, and the second argument corresponds to the value
after executing the loop body.
The finite maps $\Gamma$ and $\Delta$ are natural outputs of an algorithm that converts a
dIMP program into SSA-dIMP form.
They prove that a (not necessarily minimal) SSA form was indeed achieved.
Inputs to the program are provided in the initially provided store, and $\Gamma$
has to contain types for all variables accessed by the program that don't
have a definition in the program.

\subsubsection*{The Semantics of SSA-dIMP}
Stores are now partial functions $\store : \Sigma \partialf \Loc$ to indicate that
variables have to be defined before they can be read.
When updating a store, we use the syntax
$\store \dunion [X \mapsto \flagged{}]$ to indicate that the store $\store$ does not
contain the variable $X$.
\autoref{thm:ssa-gamma-delta-disjoint} in combination with ~\autoref{thm:ssa-progress}
justify this notation.

Let $\excstore{}$ denote stores that represent an \exception{}
state or a partial function, i.e.\ $\excstore{} \in (\Loc \partialf \StoreDomain) \union \{\exception\}$
The state $\exception$ indicates that the program was aborted due to a policy violation.
This semantics is not necessarily meant to mirror what actually happens at runtime, i.e.\
in Java values don't have a flag attached whether a variable is tracked or not.
However, this does not mean that the semantics has only theoretical value - for example
Perl has a taint-checking feature, where user input is marked at runtime as tainted,
and if unchecked user input ends up in sinks such as SQL statements, the program aborts.
This is very similar to the semantics given here.

For $\varphi$-nodes, we introduce two judgements --- one that evaluates all the variable definitions
to the first argument, and one that evaluates them all to the second argument.
Both judgements are provided with a filter $\filter \subseteq \dom\sigma$ that specifies which variables
from the outer store should be kept.
The symbol $\store\restrict{\filter}$ denotes the restriction of the map $\store$
to the domain $\filter$.
In order to correctly model the execution of $\varphi$-nodes for \textbf{while} commands,
a second judgement is set up.
The regular command judgement only populates the variables defined by the $\varphi$-nodes
and then defers to a special while-command judgement that evaluates all loop executions,
evaluating the $\varphi$-nodes with the store after the loop body execution.
\\
Judgment \fbox{$\bigstep{a}{\sigma}{\flaggedn{}}$}:
\begin{align*}
    &\bsrule{EA-Num}{}{\bigstep{\literalint}{\store}{\clean}} \qquad
    \bsrule{EA-Loc}{}{\bigstep{X}{\store}{\store(X)}}\\
    &\bsrule{EA-Source}{\bigstep{a}{\store}{\flagged}}
    {\bigstep{\source{a}}{\store}{\tracked}}\\
    &\bsrule{EA-Plus}
    {\bigstep{a_0}{\store}{\flagged[n_0][0]}
    \qquad \bigstep{a_1}{\store}{\flagged[n_1][1]}}
    {\bigstep{a_0+a_1}{\store}{\clean[(n_0+n_1)]}}\\
    &\ldots\\
\end{align*}
\\
Judgement \fbox{$\bigsteppl{\philist}{\filter}{\store}{\store'}$}:
\begin{align*}
    &\bsrule{E$\Phi_1$-Assign}{}
    {\bigsteppl{\defaultphilistn}{\filter}{\store}{\storeassign{\store\restrict{\filter}}{X_1 \mapsto \store(Y_1),\ldots, X_n \mapsto \store(Y_n)}}}\\
\end{align*}
Judgement \fbox{$\bigsteppr{\philist}{\filter}{\store}{\store'}$}:
\begin{align*}
    &\bsrule{E$\Phi_2$-Assign}{}
    {\bigsteppr{\defaultphilistn}{\filter}{\store}{\storeassign{\store\restrict{\filter}}{X_1 \mapsto \store(Z_1),\ldots, X_n \mapsto \store(Z_n)}}}\\
\end{align*}
\\
Judgement \fbox{$\bigstepw{s}{\filter}{\store}{\excstore'{}}$}:
\begin{align*}
    &\bsrule{EW-WhileF}{\bigstep{b}{\store}{\bfalse}}
    {\bigstepw{\defaultssawhile}{\filter}{\store}{\store}}\qquad\\
    &\bsrule{EW-WhileTAbrt}{\bigstep{b}{\store}{\btrue} \qquad
    \bigstep{s_0}{\store}{\exception}}
    {\bigstepw{\defaultssawhile}{\filter}{\store}{\exception}}\\
    &\bsrule{EW-WhileT}{\bigstep{b}{\store}{\btrue} \enskip
    \bigstep{s_0}{\store}{\store''} \enskip
    \bigsteppr{\philist}{\filter}{\store''}{\store'''} \enskip
    \bigstepw{\defaultssawhile}{\filter}{\store'''}{\excstore'}}
    {\bigstepw{\defaultssawhile}{\filter}{\store}{\excstore'}}
\end{align*}
\\
Judgement \fbox{$\bigstep{s}{\store}{\excstore{}}$}:
\begin{align*}
    &\bsrule{EC-Skip}{}{\bigstep{\skipcmd}{\store}{\store}}\qquad
    \bsrule{EC-Assign}{\bigstep{a}{\store}{\flaggedn{}}}
    {\bigstep{\defaultstore}{\store}{\storeassign{\store}{X \mapsto \flaggedn{}}}} \\
    &\bsrule{EC-Seq}{\bigstep{s_0}{\sigma}{\store''} \qquad \bigstep{s_1}{\store''}{\excstore'}}
    {\bigstep{\defaultssaseq}{\store}{\excstore'}}\qquad
    \bsrule{EC-SeqAbrt}{\bigstep{s_0}{\sigma}{\exception}}
    {\bigstep{\defaultssaseq}{\store}{\exception}} \\
    &\bsrule{EC-IfT}{\bigstep{b}{\store}{\btrue}\qquad \bigstep{s_0}{\store}{\store''}
    \qquad \bigsteppl{\philist}{\dom\store}{\store''}{\store'}}
    {\bigstep{\defaultssaif}{\store}{\store'}}\\
    &\bsrule{EC-IfF}{\bigstep{b}{\store}{\bfalse}\qquad \bigstep{s_1}{\store}{\store''}
    \qquad \bigsteppr{\philist}{\dom\store}{\store''}{\store'}}
    {\bigstep{\defaultssaif}{\store}{\store'}}\\
    &\bsrule{EC-IfTAbrt}{\bigstep{b}{\store}{\btrue}\qquad \bigstep{s_0}{\store}{\exception}}
    {\bigstep{\defaultssaif}{\store}{\exception}} \qquad
    \bsrule{EC-IfFAbrt}{\bigstep{b}{\store}{\bfalse}\qquad \bigstep{s_1}{\store}{\exception}}
    {\bigstep{\defaultssaif}{\store}{\exception}} \\
    &\bsrule{EC-While}{\bigsteppl{\philist}{\dom\store}{\store}{\store''} \qquad
    \bigstepw{\defaultssawhile}{\dom\store}{\store''}{\excstore'}}
    {\bigstep{\defaultssawhile}{\store}{\excstore'}}\\
    &\bsrule{EC-Sink}{\bigstep{a}{\store}{\clean{}}}
    {\bigstep{\defaultsink}{\store}{\store}}\qquad
    \bsrule{EC-SinkAbrt}{\bigstep{a}{\store}{\tracked{}}}
    {\bigstep{\defaultsink}{\store}{\exception}}\\
\end{align*}

The judgement operations for Boolean expressions are modified to ignore the tracked-flag and work
just as in IMP. This is analogous to how $\textsc{EA-Plus}$ etc.\ work.

\subsubsection*{From dIMP to SSA-dIMP}
We show by example how the SSA construction works.
We consider the dIMP program shown in ~\autoref{fig:dimp-example}.
\begin{figure}[h]
    \begin{minted}[linenos]{pascal}
        I := X;
        Z := 1;
        while I > 0 do
            I := I - 1;
            if Z < 100 then
                Z := source Z * X
            else
                Z := Z
        ;
        sink Z
    \end{minted}
    \caption{The example dIMP program}
    \label{fig:dimp-example}
\end{figure}
After transformation, an equivalent SSA-dIMP program is shown in~\autoref{fig:ssa-dimp-example}.
%TODO same figure for both

\begin{figure}[h]
    \begin{minted}[escapeinside=||,mathescape=true,linenos]{pascal}
        I0 := X;
        Z0 := 1;
        while [Z3 := |$\varphi$|(Z0, Z2), I2 := |$\varphi$|(I0, I1)]; I2 > 0 do
            I1 := I2 - 1;
            if Z3 < 100 then
                Z1 := source Z3 * X
            else
                Z1 := Z3
            ;[Z2 := |$\varphi$|(Z1, Z1)]
        ;
        sink Z3
    \end{minted}
    \caption{The example program transformed to SSA-dIMP}
    \label{fig:ssa-dimp-example}
\end{figure}
The maps $\Gamma$ and $\Delta$ can be easily inferred, except for the while loop,
where the maps do not immediately can be inferred by using the rules.
Thus, as part of the transformation, we give the maps $\Delta$ and
$\Delta_1$ as in rule $\textsc{SSA-While}$ for the while loop in the example program:
$\Delta = [Z_3 \mapsto \tint, I_2 \mapsto \tint]$ and $\Delta_1 = [I_3 \mapsto \tint, Z_2 \mapsto \tint]$.

This SSA form is obviously not unique, as the variable naming is not canonical.
Furthermore, the number of $\varphi$-nodes in the example program is minimal,
but no such assertions is made by the typing rules.

\subsubsection*{Correctness Results}
We state that an SSA-dIMP program together with the SSA type derivation
is in fact in SSA form --- each variable is defined only once.
Furthermore, the structure of the bigstep derivation trees imply that
for every bigstep derivation, all variables are defined before they are used.
Proofs are omitted.
The first theorem is very easy to prove, and the second theorem is proved later in greater generality.

\begin{theorem}
    \label{thm:ssa-gamma-delta-disjoint}
    If $\typestep{\Gamma}{s}{\Delta}$ holds, then $\Gamma \cap \Delta = \emptyset$.
\end{theorem}

\begin{theorem}
    \label{thm:ssa-progress}
    If $\typestep{\Gamma}{s}{\Delta}$, $\dom\store = \Gamma$ and
    $\bigstep{s}{\store}{\store'}$, then $\store' = \store \dunion \store_0$
    and $\dom{\store_0} = \Delta$.
\end{theorem}

\subsection{Definition of Unsafe Dataflow}
\begin{definition}[Program]
    A \emph{program} in SSA-dIMP is a command $s$ with finite maps $\Gamma, \Delta$
    with $\typestep{\Gamma}{s}{\Delta}$.
    Complex programs are expressed by using the recursive nature of the definition of statements.
\end{definition}

\begin{definition}[Initial Store]
    An \emph{initial store} is a store $\store$ such that $\initialstore{}$ holds, with
    \begin{equation*}
        \initialstore{} \iff \forall X: \exists n: \store(X) = \clean[n]
    \end{equation*}
    This means that in an initial store all values are tagged as being clean.
\end{definition}

\begin{definition}[Unsafe Dataflow]
    A tuple $(s, \store, \Gamma, \Delta)$ of a program $s$ and initial store $\store{}$
    with $\dom{\store{}} = \Gamma$ and $\initialstore$
    has \emph{(unsafe) dataflow from a source to a sink} if
    $\bigstep{s}{\store{}}{\exception}$ holds.
    This means that the program may abort.
\end{definition}

\begin{definition}[Dataflow Algorithm]
    A \emph{dataflow algorithm} $\A(s, \Gamma, \Delta)$ computes, given a program $s$
    and an SSA type derivation $\typestep{\Gamma}{s}{\Delta}$,
    whether there exists a store $\store{}$
    such that $\initialstore$ and $(s, \store, \Gamma, \Delta)$ has unsafe dataflow from a source to a sink.
    We require $\A(s, \Gamma, \Delta) \in \{\text{POSSIBLE\_FLOW}, \text{NO\_FLOW}\}$.
\end{definition}

\begin{definition}[Soundness]
    A dataflow algorithm is \emph{sound} if for all tuples $(s, \store, \Gamma, \Delta)$ with $\initialstore$ that
    have unsafe dataflow it holds that $\A(s, \Gamma, \Delta) = \text{POSSIBLE\_FLOW}$.
\end{definition}

\begin{definition}[Completeness]
    A dataflow algorithm is \emph{complete} if for all tuples $(s, \store, \Gamma, \Delta)$ with $\initialstore$ that
    do not have unsafe dataflow it holds that $\A(s, \Gamma, \Delta) = \text{NO\_FLOW}$.
\end{definition}

\begin{definition}[False Positive]
    A program $s$ for which there exists no store $\store$ such that
    $(s, \initialstore, \Gamma, \Delta)$ with $\initialstore{}$ has unsafe dataflow,
     but for which $\A(s, \Gamma, \Delta) = \text{POSSIBLE\_FLOW}$ holds
    is called a \emph{false positive} of the algorithm.
\end{definition}
\begin{remark}
    In general, it is impossible to construct a dataflow algorithm that is both
    sound and complete.
    In practice, a dataflow algorithm may be neither sound nor complete.
    However, in the theoretical setting of this chapter, we are interested in
    sound dataflow algorithms.
    The \emph{trivially sound dataflow algorithm} $\A_0(s, \Gamma, \Delta) = \text{POSSIBLE\_FLOW}$
    is sound by definition, but not very interesting.
    We will not consider it further, but it is interesting to keep in mind,
    because it shows that just proving that a dataflow algorithm is sound does not
    mean it is useful.
\end{remark}

\subsection{A General Setting For Flow Analysis}
\label{sec:df-theory}
In this section, we refine the type system presented for SSA to be viable as a
general-purpose constraint system.
This constraint system can then be solved via fixed-point iteration.
The system is designed in a way that it can be easily adapted to different analyses.
We instantiate this system to determine if programs have unsafe dataflow.

Let $\lattice$ be a poset.
Let $\Gamma, \Delta: \Loc \partialf \lattice$ with finite domain.

For dataflow analysis, we have $\lattice = \{\lclean, \ltracked, \lunknown\}$.
Every variable encountered in the program is typed with an annotated type from \lattice.
Thus, it is either typed with $\lclean{}$ (the variable
is clean, i.e.\ does not contain a value originating from a dataflow source), $\lunknown{}$
(it is unknown whether the variable contains a value originating from a source) or $\ltracked{}$
(the variable contains a tracked value from a dataflow source).
We define the following poset structure:
\begin{figure}[h]
    \centering
    \begin{tikzpicture}
        \node (u) at (0, 1) {$\lunknown$};
        \node (c) at (-1, 0) {$\lclean$};
        \node (t) at (1, 0) {$\ltracked$};
        \draw[->] (c) -- (u);
        \draw[->] (t) -- (u);
    \end{tikzpicture}
\end{figure}

We introduce the following judgements:
\\
Judgement \fbox{$\typestep{\Gamma}{a}{L}$}:
\begin{align*}
    &\trule{DF-Num}{}{\typestep{\Gamma}{\overline{n}}{\lclean}}\qquad
    \trule{DF-Loc}{}{\typestep{\Gamma}{X}{\Gamma(X)}}\\
    &\trule{DF-Source}{\typestep{\Gamma}{a}{L}}
    {\typestep{\Gamma}{\source{a}}{\ltracked}}\\
    &\trule{DF-Plus}{\typestep{\Gamma}{a_0}{L_0}\qquad\typestep{\Gamma}{a_1}{L_1}}
    {\typestep{\Gamma}{a_0+a_1}{\lclean}}\\
    &\ldots
\end{align*}
Judgement \fbox{$\typestmt{\Gamma}{b}$}:
\begin{align*}
    &\trule{DF-Bool}{}{\typestmt{\Gamma}{t}}\qquad
    \trule{DF-Eq}{\typestep{\Gamma}{a_0}{L_0}\qquad \typestep{\Gamma}{a_1}{L_1}}
    {\typestmt{\Gamma}{a_0 = a_1}}\\
    &\trule{DF-Neg}{\typestmt{\Gamma}{b}}
    {\typestmt{\Gamma}{\neg b}}\qquad
    \trule{DF-And}{\typestmt{\Gamma}{b_0}\qquad\typestmt{\Gamma}{b_1}}
    {\typestmt{\Gamma}{b_0 \land b_1}}\\
    &\ldots
\end{align*}
\\
Judgement \fbox{$\typestep{\Gamma;\Delta_0;\Delta_1}{\philist}{\Delta}$}:
\begin{align*}
    &\trule{DF-$\varphi$}{}{\typestep{\Gamma;\Delta_0;\Delta_1}{\defaultphilistn}{[X_1 \mapsto L_1, \ldots, X_n \mapsto L_n]}}\\
    &\text{(if for $i \in \{1, \ldots, n\} \exists L_i: X_i \notin \dom\Gamma \land (\Gamma \dunion \Delta_0)(Y_i) \sqsubseteq L_i \land (\Gamma \dunion \Delta_1)(Z_i) \sqsubseteq L_i
    \land \forall j \neq i: X_j \neq X_i$)}
\end{align*}
Note that this implies that this rule is only applicable if $Y_i$, $Z_i$ exist in the respective
domains of the partial functions, and if $L_i$ satisfying the constraints exists as well.\\
Judgement \fbox{$\typestep{\Gamma}{s}{\Delta}$}:
\begin{align*}
    &\trule{DF-Skip}{}{\typestep{\Gamma}{\skipcmd}{[]}}\qquad
    \trule{DF-Assign}{\typestep{\Gamma}{a}{L}}
    {\typestep{\Gamma}{\defaultstore}{[X \mapsto L]}} \text{($X \notin \dom\Gamma$)}\\
    &\trule{DF-Seq}{\typestep{\Gamma}{s_0}{\Delta_0}\qquad
    \typestep{\Gamma \cup \Delta_0}{s_1}{\Delta_1}}{\typestep{\Gamma}{\defaultssaseq}{\Delta_0 \cup \Delta_1}}\\
    &\trule{DF-If}{\typestmt{\Gamma}{b}\qquad\typestep{\Gamma}{s_0}{\Delta_0}\qquad \typestep{\Gamma}{s_1}{\Delta_1}\qquad
    \typestep{\Gamma;\Delta_0;\Delta_1}{\philist}{\Delta}}
    {\typestep{\Gamma}{\defaultssaif}{\Delta}}\\
    &\trule{DF-While}{\typestep{\Gamma;\emptyset;\Delta_1}{\philist}{\Delta}\qquad
    \typestmt{\Gamma \cup \Delta}{b}\qquad\typestep{\Gamma \cup \Delta}{s_0}{\Delta_1}}
    {\typestep{\Gamma}{\defaultssawhile}{\Delta}}\\
    &\trule{DF-Sink}{\typestep{\Gamma}{a}{L}}{\typestep{\Gamma}{\sink{a}}{[]}}\\
\end{align*}

\begin{definition}[Concretization Function, ~\cite{abstractinterpretation}]
    Let $\gamma:\lattice \to \P(\StoreDomain)$ be the concretization function in the abstract interpretation framework,
    as presented in~\cite{abstractinterpretation}.
    The concretization function is defined by
    \begin{align*}
        &\gamma:\lattice \to \P(\StoreDomain)\\
        &\gamma(L) = \begin{cases}
            \{\flagged{} \mid \flagged{} \in \StoreDomain \land f = \textbf{t}\} & \text{if }L = \ltracked\\
            \{\flagged{} \mid \flagged{} \in \StoreDomain \land  f = \textbf{c}\} & \text{if }L = \lclean\\
            \StoreDomain & \text{if }L = \lunknown\\
        \end{cases}
    \end{align*}
\end{definition}

\begin{definition}[Store-Matching]
    A store $\store$ \emph{matches a description} $\Gamma: \Loc \partialf \lattice$ if it holds that
    \begin{equation*}
        \matches{\store}{\Gamma} \longeq \dom\store = \dom\Gamma \land \forall X: \sigma(X) \in \gamma(\Gamma(X))
    \end{equation*}
\end{definition}

First, we justify why the semantics contains disjoint unions when updating stores.
Then we prove some lemmas needed to establish the soundness of our dataflow analysis.
We omit the easy proofs.

\begin{theorem}
    \label{thm:gamma-delta-disjoint}
    If $\typestep{\Gamma}{s}{\Delta}$ holds, then $\dom\Gamma \cap \dom\Delta = \emptyset$.
\end{theorem}

\begin{lemma}
    \label{lem:gamma-arithm}
    Let $\E$ be a derivation of $\bigstep{a}{\sigma}{\flaggedn{}}$.
    If $\typestep{\Gamma}{a}{L}$ and $\matches{\store}{\Gamma}$, then $\flaggedn{} \in \gamma(L)$.
\end{lemma}

The following lemma and theorem are very similar to the classic preservation lemma
used to prove the soundness of type systems.

\begin{lemma}
    \label{thm:preservation-phi}
    Let $\bigsteppl{\Phi}{\Theta}{\sigma''}{\sigma'}$ (or $\bigsteppr{\Phi}{\Theta}{\sigma''}{\sigma'}$),
    such that $\store'' = \store \dunion \store_0''\dunion \store{\_}$, $\matches{\store}{\Gamma}$,
    $\matches{\store_0''}{\Delta_1}$ (or $\matches{\store_0''}{\Delta_2}$) and $\Theta = \dom\store$.
    Let $\typestep{\Gamma;\Delta_0;\Delta_1}{\Phi}{\Delta}$ by the DF rules.
    Then there exists a $\store_0$ such that $\store' = \store \dunion \store_0$
    and $\matches{\store_0}{\Delta}$.
\end{lemma}

\begin{theorem}
    \label{thm:preservation}
    Suppose $\bigstep{s}{\store}{\store'}$ by $\E$, $\matches{\store}{\Gamma}$,
    and let $\typestep{\Gamma}{s}{\Delta}$ by $\D$ and the DF rules.
    Then there exists a $\store_0$ such that $\store' = \store \dunion \store_0$
    and $\matches{\store_0}{\Delta}$.
\end{theorem}
\begin{proof}
    We prove the theorem by induction over the derivation $\E$.\\
    \textbf{Case 1:}
    \textsc{EC-Skip}: Trivial, as $\Delta = \emptyset$.\\
    \textbf{Case 2:}
    \textsc{EC-Sink}: Trivial, as $\Delta = \emptyset$.\\
    \textbf{Case 3:}
    \begin{align*}
        &\E = \bsrule{EC-Seq}{\overset{\E_0}{\bigstep{s_0}{\sigma}{\store''}}
         \qquad \overset{\E_1}{\bigstep{s_1}{\store''}{\store'}}}
        {\bigstep{\defaultssaseq}{\store}{\store'}}\\
        &\D = \trule{DF-Seq}{\overset{\D_0}{\typestep{\Gamma}{s_0}{\Delta_0}}\qquad
        \overset{\D_1}{\typestep{\Gamma \cup \Delta_0}{s_1}{\Delta_1}}}
        {\typestep{\Gamma}{\defaultssaseq}{\Delta_0 \cup \Delta_1}}
    \end{align*}
    By assumption we have that $\matches{\store}{\Gamma}$.
    Thus, we can apply the IH on $\E_0$ with $\D_0$.
    With the IH we get $\store'' = \store \dunion \store''_0$ and $\matches{\store''_0}{\Delta_0}$
    with $\matches{\store''}{\Gamma \union \Delta_0}$.
    Thus, we can apply the IH on $\E_1$ with $\D_1$.
    Then we get that $\store' = \store'' \dunion \store'_0$ and $\matches{\store'_0}{\Delta_1}$.
    With that, we have $\store' = \store \dunion \store''_0 \dunion \store'_0$.
    We can set $\store_0 = \store''_0 \dunion \store'_0$, and we obviously
    have that $\matches{\store_0}{\Delta_0 \union \Delta_1}$.\\
    \textbf{Case 4:}
    \begin{align*}
        &\E = \bsrule{EC-IfT}{
        \overset{}{\bigstep{b}{\store}{\btrue}}\qquad
        \overset{\E_0}{\bigstep{s_0}{\store}{\store''}}
        \qquad
        \overset{\E_1}{\bigsteppl{\philist}{\dom\store}{\store''}{\store'}}}
        {\bigstep{\defaultssaif}{\store}{\store'}}\\
        &\D = \trule{DF-If}{
        \overset{}{\typestmt{\Gamma}{b}}\qquad
        \overset{\D_0}{\typestep{\Gamma}{s_0}{\Delta_0}}\qquad \typestep{\Gamma}{s_1}{\Delta_1}\qquad
        \overset{\D_1}{\typestep{\Gamma;\Delta_0;\Delta_1}{\philist}{\Delta}}}
        {\typestep{\Gamma}{\defaultssaif}{\Delta}}
    \end{align*}
    By IH on $\E_0$ with $\D_0$, we get that $\store'' = \store \dunion \store''_0$ and
    $\matches{\store''_0}{\Delta_0}$.
    The result then follows from~\autoref{thm:preservation-phi} on $\E_1$ with $\D_1$.\\
    \textbf{Case 5:}
    $\E$ uses \textsc{EC-IfF}: analogous.\\
    \textbf{Case 6:}
    \begin{align*}
        &\E = \bsrule{EC-Assign}{\overset{\E_0}{\bigstep{a}{\store}{\flaggedn{}}}}
        {\bigstep{\defaultstore}{\store}{\storeassign{\store}{X \mapsto \flaggedn{}}}}\\
        &\D = \trule{DF-Assign}{\overset{\D_0}{\typestep{\Gamma}{a}{L}}}
        {\typestep{\Gamma}{\defaultstore}{[X \mapsto L]}}
    \end{align*}
    We apply~\autoref{lem:gamma-arithm} on $\E_0$ with $\D_0$,
    and as $\flaggedn{} \in \gamma(L)$, we have that $\matches{[X \mapsto \flaggedn{}]}{[X \mapsto L]}$.
    The side-condition of \textsc{DF-Assign} implies that the union in the \textsc{EC-Assign}
    rule is actually disjoint.
    \\
    \textbf{Case 7:}\\
    \begin{align*}
        &\E = \bsrule{EC-While}{\overset{\E_0}{\bigsteppl{\philist}{\dom\store}{\store}{\store''}}\qquad
        \overset{\E_2}{\bigstepw{\defaultssawhile}{\dom\store}{\store''}{\excstore'}}}
        {\bigstep{\defaultssawhile}{\store}{\store'}}\\
        &\D = \trule{DF-While}{\overset{\D_0}{\typestep{\Gamma;\emptyset;\Delta_1}{\philist}{\Delta}}\qquad
        \overset{\D_1}{\typestmt{\Gamma \cup \Delta}{b}}\qquad
        \overset{\D_2}{\typestep{\Gamma \cup \Delta}{s_0}{\Delta_1}}}
        {\typestep{\Gamma}{\defaultssawhile}{\Delta}}
    \end{align*}
    By applying~\autoref{thm:preservation-phi} on $\E_0$ with $\D_0$, we get that
    $\store'' = \store \dunion \store_0$ and $\matches{\store_0}{\Delta}$.
    Thus, $\matches{\store''}{\Gamma \union \Delta}$.
    We prove the statement by an inner induction over the while derivation $\E^w$:
    \begin{claim}
        Let $\bigstepw{\defaultwhile}{\filter}{\store_w}{\store_w'}$ by $\E^w$,
         $\store_w = \store_w^0 \dunion \store_w^1$
        such that $\matches{\store_w^0}{\Gamma}$, $\Theta = \dom\store^0_w$, $\matches{\store_w^1}{\Delta}$
        and let $\typestep{\Gamma}{\defaultwhile}{\Delta}$ by $\D$ and the DF rules.
        Then we have that there exists a $\store_0$ such that $\store_w' = \store_w^0 \dunion \store_0$,
        and $\matches{\store_0}{\Delta}$.
    \end{claim}
    \begin{claimproof}
        \emph{Subcase 1:}
        \begin{align*}
            \E^w = \bsrule{EW-WhileF}{
            \overset{}{\bigstep{b}{\store_w}{\bfalse}}}
            {\bigstepw{\defaultssawhile}{\filter}{\store_w}{\store_w}}
        \end{align*}
        Trivial, taking $\store_0 = \store_w^1$.\\
        \emph{Subcase 2:}
        \begin{align*}
            \E^w = \bsrule{EW-WhileT}{\overset{}{\bigstep{b}{\store_w}{\btrue}} \enskip
            \overset{\E^w_0}{\bigstep{s_0}{\store_w}{\store''}} \enskip
            \overset{\E^w_1}{\bigsteppr{\philist}{\filter}{\store''}{\store'''}} \enskip
            \overset{\E^w_2}{\bigstepw{\defaultssawhile}{\filter}{\store'''}{\excstore'}}}
            {\bigstepw{\defaultssawhile}{\filter}{\store_w}{\store_w'}}
        \end{align*}
        By the outer IH on $\E^w_0$ with $\D_2$, we get that
        $\sigma'' = \sigma_w \dunion \sigma_w'' = \sigma_w^0 \dunion \sigma_w^1 \dunion \sigma_w''$
        and $\matches{\sigma_w''}{\Delta_1}$.
        By~\autoref{thm:preservation-phi} we get that $\store''' = \store_w^0 \dunion \store_0'''$ and
        $\matches{\store_0'''}{\Delta}$.
        With that we can apply the inner IH on $\E^2_w$ with $\D$ to get the result on $\sigma_w'$.
    \end{claimproof}
    We finish the proof by applying the claim on $\E^2$ with $\D$.
\end{proof}

\begin{definition}[Safe Sink]
    Let $s, \Gamma, \Delta$ be such that $\typestep{\Gamma}{s}{\Delta}$ (by $\D$).
    A sink in $\D$ is \emph{safe}, if the type of its argument is $\lclean$.
\end{definition}

We then have the following (general) soundness property of the dataflow analysis:
\begin{theorem}[Soundness of the DF rules]
    \label{thm:df-soundness}
    Let $s$ be a program in SSA form, $\typestep{\Gamma}{s}{\Delta}$ (by $\D$)
    and let $\store$ be a store with $\matches{\store}{\Gamma}$.
    Let $\E$ be the bigstep derivation of $\bigstep{s}{\store}{\excstore{}'}$.
    Assume that all sinks in $\D$ are safe.
    Then $\excstore{}' \neq \exception$.
\end{theorem}
\begin{proof}
    Proof by induction over the derivation $\E$.
    The cases \textsc{EC-Skip}, \textsc{EC-Sink}, \textsc{EC-Assign}, \textsc{EC-IfT} and \textsc{EC-IfF}
    are trivially clear, as they never evaluate to \exception.\\
    \textbf{Case 1:}
    \begin{align*}
        \E = \bsrule{EC-SinkAbrt}{\overset{}{\bigstep{a}{\store}{\tracked{}}}}
        {\bigstep{\defaultsink}{\store}{\exception}}\\
        \D = \trule{DF-Sink}{\overset{}{\typestep{\Gamma}{a}{L}}}
        {\typestep{\Gamma}{\sink{a}}{\emptyset}}
    \end{align*}
    However, because all sinks are safe, we have $L = \lclean$.
    Furthermore, as $\store : \Gamma$ this is a contradiction to ~\autoref{lem:gamma-arithm},
    so this case cannot happen.\\
    \textbf{Case 2:}
    \begin{align*}
        &\E = \bsrule{EC-SeqAbrt}{\overset{\E_0}{\bigstep{s_0}{\sigma}{\exception}}}
        {\bigstep{\defaultssaseq}{\store}{\exception}}\\
        &\D = \trule{DF-Seq}{\overset{\D_0}{\typestep{\Gamma}{s_0}{\Delta_0}}\qquad
        \overset{}{\typestep{\Gamma \cup \Delta_0}{s_1}{\Delta_1}}}
        {\typestep{\Gamma}{\defaultssaseq}{\Delta_0 \cup \Delta_1}}
    \end{align*}
    By IH on $\E_0$ with $\D_0$ we get that in $\bigstep{s_0}{\store}{\excstore{}'}$
    we have that $\excstore{}' \neq \exception$ holds, so this case cannot happen.
    The cases for \textsc{EC-IfTAbrt} and \textsc{EC-IfFAbrt} are proved analogous.\\
    \textbf{Case 3:}
    \begin{align*}
        &\E = \bsrule{EC-Seq}{\overset{\E_0}{\bigstep{s_0}{\sigma}{\store''}} \qquad
        \overset{\E_1}{\bigstep{s_1}{\store''}{\excstore'}}}
        {\bigstep{\defaultssaseq}{\store}{\excstore'}}\\
        &\D = \trule{DF-Seq}{\overset{\D_0}{\typestep{\Gamma}{s_0}{\Delta_0}}\qquad
        \overset{\D_1}{\typestep{\Gamma \cup \Delta_0}{s_1}{\Delta_1}}}
        {\typestep{\Gamma}{\defaultssaseq}{\Delta_0 \cup \Delta_1}}
    \end{align*}
    By~\autoref{thm:preservation} on $\E_0$ with $\D_0$ we get that $\matches{\store''}{\Gamma \cup \Delta_0}$.
    Then we apply the IH on $\E_1$ with $\D_1$ and get that $\excstore{}' \neq \exception$.\\
    \textbf{Case 4:}
    \begin{align*}
        &\E = \bsrule{EC-While}{\bigsteppl{\philist}{\dom\store}{\store}{\store''} \qquad
        \overset{\E_0}{\bigstepw{\defaultssawhile}{\dom\store}{\store''}{\excstore'}}}
        {\bigstep{\defaultssawhile}{\store}{\excstore'}}\\
        &\D = \trule{DF-While}{\overset{\D_0}{\typestep{\Gamma;\emptyset;\Delta_1}{\philist}{\Delta}}\qquad
        \typestmt{\Gamma \cup \Delta}{b}\qquad
        \overset{\D_1}{\typestep{\Gamma \cup \Delta}{s_0}{\Delta_1}}}
        {\typestep{\Gamma}{\defaultssawhile}{\Delta}}
    \end{align*}
    \begin{claim}
        Let $\store_w = \store_{w0} \dunion \store_{w1}$ with
        $\matches{\store_{w0}}{\Gamma}$ and $\matches{\store_{w1}}{\Delta}$,
         $\dom\Gamma = \filter$ and
        $\bigstepw{\defaultssawhile}{\filter}{\store_w}{\excstore{}'_w}$ by $\E^w$.
        Let $\typestep{\Gamma \union \Delta}{s_0}{\Delta_1}$ by $\D^w_0$
        and $\typestep{\Gamma;\emptyset;\Delta_1}{\philist}{\Delta}$ by $\D^w_1$.
        Then if all sinks in $\E^w$ are safe, $\excstore{}'_w \neq \exception$.
    \end{claim}
    \begin{claimproof}
        The case \textsc{EW-WhileF} is trivial, as it never evaluates to \exception.\\
        \emph{Subcase 1:}
        \begin{align*}
            \E^w = \bsrule{EW-WhileTAbrt}{\bigstep{b}{\store_w}{\btrue} \qquad
            \overset{\E_0}{\bigstep{s_0}{\store_w}{\exception}}}
            {\bigstepw{\defaultssawhile}{\filter}{\store_w}{\exception}}
        \end{align*}
        By applying the outer IH on $\E_0$ with $\D^w_0$ we get that for
        $\bigstep{s_0}{\store_w}{\excstore{}'}$ it actually holds that $\excstore{}' \neq \exception$,
        so this case cannot occur.\\
        \emph{Subcase 2:}
        \begin{align*}
            \E^w = \bsrule{EW-WhileT}{\overset{}{\bigstep{b}{\store_w}{\btrue}} \enskip
            \overset{\E^w_0}{\bigstep{s_0}{\store_w}{\store''}} \enskip
            \overset{\E^w_1}{\bigsteppr{\philist}{\filter}{\store''}{\store'''}} \enskip
            \overset{\E^w_2}{\bigstepw{\defaultssawhile}{\filter}{\store'''}{\excstore'_w}}}
            {\bigstepw{\defaultssawhile}{\filter}{\store_w}{\store_w'}}
        \end{align*}
        By~\autoref{thm:preservation} on $\E^w_0$ with $\D^w_0$, we get that $\store'' = \store_w \dunion \store''_0$
        and $\matches{\store''_0}{\Delta_1}$, thus $\matches{\store''}{\Gamma \union \Delta \dunion \Delta_1}$.
        By~\autoref{thm:preservation-phi} on $\E^w_1$ with $\D_1^w$ it follows that $\store''' = \store_{w0} \dunion \store'''_0$
        with $\matches{\store'''_0}{\Delta}$.
        Thus, $\matches{\store'''}{\Gamma \union \Delta}$ and we can apply the inner IH on $\E^w_2$.
        That implies that $\excstore{}'_w \neq \exception$.
    \end{claimproof}
    We apply the claim on $\E_0$ with $\D_0$ and $\D_1$.
\end{proof}
\iffalse
\begin{corollary}
    Let $s$ be a program in SSA form with
    $\typestep{\Gamma}{s}{\Delta}$ (by $\D$ with the DF rules).
    Let $\sigma$ be a store with $\initialstore{}$
    and $\matches{\store}{\Gamma}$.
    Let $\E$ be the bigstep derivation of
    $\bigstep{s}{\store}{\excstore{}'}$.
    If all sinks in $\D$ are safe, then $\excstore{}' \neq \exception$.
\end{corollary}
\fi

We now describe a sound dataflow algorithm schema $\A(s, \Gamma_\text{ssa}, \Delta_\text{ssa})$.
This algorithm schema can be seen as a general specification for sound dataflow algorithms.
As soon as an algorithm satisfies this schema, it is sound.
In the next section, we will see an instantiation of this algorithm schema in QL.

First, define $\Gamma$ by $\Gamma(X) = \lclean$ for all $X \in \dom\Gamma_\text{ssa}$.
Then, compute a finite map $\Delta$ and a derivation tree $\D$
such that $\typestep{\Gamma}{s}{\Delta}$ (by $\D$) holds.
Output \text{POSSIBLE\_FLOW} if $\D$ contains a derivation of form
\begin{equation*}
    \trule{DF-Sink}{\typestep{\Gamma}{a}{\ltracked}}{\typestep{\Gamma}{\sink{a}}{\emptyset}}
\end{equation*}
or
\begin{equation*}
    \trule{DF-Sink}{\typestep{\Gamma}{a}{\lunknown}}{\typestep{\Gamma}{\sink{a}}{\emptyset}}
\end{equation*}

In the absence of these derivations, output \text{NO\_FLOW}.
\begin{corollary}
    \label{cor:soundness-df}
    The algorithm schema $\A(s, \Gamma_\text{ssa}, \Delta_\text{ssa})$ describes a sound dataflow algorithm.
\end{corollary}
\begin{proof}
    We prove the corollary by contraposition.
    If the algorithm outputs \text{POSSIBLE\_FLOW}, there is nothing to prove.

    If the algorithm outputs \text{NO\_FLOW}, we have to show that no store $\sigma$
    with $\initialstore{}$ exists such that the program aborts.
    As we have $\matches{\store}{\Gamma}$ by construction of $\Gamma$,
    we can apply~\autoref{thm:df-soundness}.
    Thus, in this case the program cannot program, and the algorithm schema
    is indeed sound.
\end{proof}

The difference between $\ltracked$ and $\lunknown$ at an unsafe sink
is not reflected in the soundness theorem,
but it can be used to tailor the warnings given to the user.
If a sink is marked with $\ltracked$, that sink will abort the program, if it is ever
executed. Such a sink almost always constitutes an error of the programmer.

A sink that is marked with $\lunknown$ might, or might not, abort the program depending on control flow.
There is also the possibility that no control flow path exists at which the sink aborts
the program. In this case, marking the sink as unsafe happens only because the analysis
is not fine-grained enough to detect this.

Thus, the annotated types can be used to show sinks with $\ltracked$ with a higher
priority than sinks with $\lunknown$.

With a different operational semantics where a sink would output the value,
as well as its flag, we could formally make a distinction
if a sink will always get a tainted value, or if that only might happen in some cases.
With that, we could add \text{HAS\_FLOW} to the possible outputs of the algorithm,
and make a distinction between $\ltracked$ and $\lunknown$ at sinks.
This would allow for a stronger soundness theorem.
Currently, both $\ltracked$ and $\lunknown$ get mapped to the algorithm output POSSIBLE\_FLOW.

Furthermore, algorithmic improvements could reduce the number of sinks marked with
$\lunknown$, but not the number of sinks marked with $\ltracked$.