\section{Linearity, Affinity, and Borrows at Work}
\label{motivation}

\lstMakeShortInline[keepspaces,basicstyle=\small\ttfamily]@

\lang{} supports the resource-passing style
common in functional encodings of session types (e.g.,
\cite{DBLP:journals/jfp/Padovani17}; see also
\cref{sec:session-linearity} in the supplement) as well as other
functional resource handling. But it really shines
when manipulating mutable resources like buffers or connection pools
using a mix of functional and imperative programming styles.
%
To support this usage pattern of linearity, \lang{} relies on
the notion of borrowing \cite{DBLP:conf/popl/BoylandR05}. Our first
example of linear arrays demonstrates simple borrowing and
imperative programming; the second example demonstrates reborrowing
and the interaction between closures and borrowing by implementing a
Sudoko solver based on a hybrid copy-on-write data structure; the
third example demonstrates advanced uses
of regions with iterators on linear values and the low-level
primitives needed to implement them.
Further examples are available in \cref{sec:extra-example}.

\subsection{Imperative programming with linear arrays}
\label{sec:imper-progr}

\begin{figure}[tp]
  \centering
  \begin{minipage}{0.5\linewidth}
\begin{lstlisting}
module Array : sig
  type ('a : 'k) t : lin
  val create : ('a : un) => int * 'a -> 'a t
  val free : ('a : aff) => 'a t -> unit
  val length : &('a t) -> int
  val get : ('a : un) => &('a t) * int -> 'a
  val set : ('a : aff) => &!('a t) * int * 'a -> unit
  val map : (&'a -> 'b) * &('a t) -> 'b t
  val iter : ('a -> unit) * 'a t -> unit
end
\end{lstlisting}
%  val map : ('a -> 'b) * 'a t -> 'b t (* destructive *)
%  val map_copy : (&'a -> 'b) * &('a t) -> 'b t (* copying *)
  \vspace{-15pt}
  \caption{Linear arrays}
  \label{ex:array}
  \label{sig:array}
  \vspace{-10pt}
\end{minipage}~
\begin{minipage}{0.5\linewidth}
\begin{lstlisting}
let mk_fib_array n =
  let a = create (n, 1) in
  for i = 2 to n - 1 do
    let x = get (&a, i-1) + get (&a, i-2) in(*@\label{ex:array:get}*)
    set (&!a, i, x)(*@\label{ex:array:set}*)
  done;
  a(*@\label{ex:array:return}*)
# mk_fib_array : int -> int Array.t
\end{lstlisting}
  \vspace{-5pt}
  \caption{An array of Fibonacci numbers}
  \label{ex:fibo}
  \vspace{-10pt}
\end{minipage}

\end{figure}

The API for mutable linear arrays (\cref{sig:array})
aims to safely handle manual allocation and
deallocation of arrays that may contain affine or linear elements.
A program would first use @create (n, v)@ to create
an array of size @n@ initialized with value
@v@. The value @v@ must be unrestricted as it is duplicated to
initialize all array elements.
To @free@ an array the elements must be affine. Thanks to subkinding,
the type of @free@ is pleasingly simple: any type @'a@ whose kind is
less than or equal to @aff@ is acceptable.
The @length@ function is always applicable.
The @get@ function is only applicable
if the element type is unrestricted as one element is duplicated.
To @set@ an array element displaces the previous content, which must
be at least affine.

The @map@ function can transform arrays with arbitrary elements. In
particular, it can turn unrestricted elements into linear (affine)
ones. It takes a borrow of the input array and returns a newly created
output array. As @free@ing requires affine elements, we provide the
@iter@ function which takes a
suitable finalizer and an array with arbitrary elements, which is
consumed. Indeed such an iteration is the only way to free an array
with linear elements. A real-life
API would provide a combination of @map@ and @iter@ as a
``destructive'' map that consumes its input array. Assuming a uniform
representation, such a destructive map might be implemented by
in-place update.

To manage the different kinds of accessing the array we distinguish between constructors, destructors,
observers, and mutators.
Constructors and destructors like @create@ and @free@ manipulate the whole
array. %As with channels in \cref{sec:session-linearity},
The constructor
@create@ yields a linear resource which is consumed by @free@.
During the lifetime of the array resource @a@, we can split
off \emph{shared borrows} @&a@ that provide a read-only
view or \emph{exclusive borrows} @&!a@ for read-write views.
Observer functions such as @length@ and @get@ expect a shared borrow
argument, mutator functions such as @set@ expect
an exclusive borrow.

Each borrow is tied to a region whose lifetime is properly
contained in the lifetime of the resource.
In a region, we can split off as many shared borrows of a resource as
we like, but we can take only one exclusive borrow. In a
subsidiary region, we can take shared borrows of any
borrow or we can take an exclusive borrow of an exclusive borrow from an
enclosing region. Borrows are confined to their regions. Inside the region,
shared borrows are unrestricted (@un@) whereas exclusive
borrows are affine (@aff@).

Using the API
we can create an
array of Fibonacci numbers in an imperative coding style, as shown
in \cref{ex:fibo}.
%
After
creation of the array, the presence of a borrow in the for loop
prevents access to the ``raw'' resource inside the loop's
body. In particular, the resource cannot be freed through a
borrow. \cref{ex:array:get} contains two shared borrows
in the same expression which forms a region by itself (recall that
shared borrows are unrestricted and may thus be duplicated). These borrows
are split off the exclusive borrow used in \cref{ex:array:set} which
belongs to the next enclosing region corresponding to the loop body.
The whole array can be returned in \cref{ex:array:return} because  the
borrows are no longer in scope.
%
More precisely, here is is an annotated excerpt with regions explicitly
marked by braces @{| ... |}@:
\begin{lstlisting}[firstnumber=3]
  for i = 2 to n - 1 do {|
    let x = {| get (&a, i-1) + get (&a, i-2) |} in(*@\label{ex:array:region:get}*)
    set (&!a, i, x)
  |} done;
\end{lstlisting}

One region consists of the header expression of the @let@ in
\cref{ex:array:region:get}. It is contained in another region
spanning the body of the @for@ loop. \lang guarantees that borrows
never escape the smallest enclosing region. It employs a system of
\emph{indexed kinds} like @aff_r@ and @un_r@ where
$r$ is a positive integer that corresponds to the lexical nesting
depth of regions. For instance, the type of @&!a@ in
\cref{ex:array:set} has kind @aff_1@ whereas the type of
@&a@ in \cref{ex:array:region:get} has kind
@un_2@ and the typing of the inner region is such that types with
kind indexes greater than or equal to $2$ cannot escape.
In the example, borrows cannot escape  because they are consumed
immediately by @get@ and @set@.

\input{motivation-persistent}

\subsection{Iterators and regions}
\label{tuto:vector}

% We have seen that borrows are limited to a region.
In the examples so far, regions do not appear in type signatures.
But for certain programming idioms, we want to extend the scope of a
region across a function boundary.
For instance, how should we fold on an array of linear objects?
Here is a first attempt at the type of a fold function:
\begin{lstlisting}[numbers=none]
val fold : ('a:'k) => ('a -> 'b -{'k}> 'b) -> 'a Array.t -> 'b -{lin}> 'b
\end{lstlisting}
This type puts no restrictions on the element type of the array, but
it requires the @fold@ function to consume the array and all its
elements. The last function arrow is linear because the array type (from
\cref{sec:imper-progr}) is linear.

If we want to work on borrows of linear and affine resources, then the
typing gets more involved because
we must make sure those borrows are not leaked in the result.
We obtain the following signature for @bfold@, the borrowing fold operation:
\begin{lstlisting}[numbers=none]
val bfold : ('b:'k),('k <= lin_r) => (&(aff_r1,'a) -> 'b -{aff_r1}> 'b) -> &('k_1,'a Array.t) -> 'b -{'k_1}> 'b
\end{lstlisting}

The folded function receives a shared borrow of the element in the array.
The typing of the callback ensures
that this borrow is neither captured nor returned by the function.
%
This encapsulation is implemented with a universally quantified \emph{kind index variable} $r$.
The signature prescribes the type @&(aff_r1,'a)@ for the
shared borrow of the resource with an affine kind at region nesting $r+1$. The return
type of the callback is constrained to kind @'k <= lin_r@. The
important part of this constraint is the $_r$ index, which ensures
that the callback cannot return the borrowed argument from the more
deeply nested scope.
%
The input of the fold is a shared borrow of the array,
which ensures that we have the right to share borrows of the inner content and
make multiple concurrent folds.

As an easy example, we fold over an array of files
@all_files : File.t Array.t@ to compute the sum of their sizes:
\begin{lstlisting}[numbers=none]
let total_size_of files = bfold (fun f s -> File.size f + s) files 0
let total_size = total_size_of &all_files
\end{lstlisting}

This approach is not sufficient if we want to mutate the elements of
the array during iteration.
To this end, we need to take an exclusive borrow of the structure to iterate
on:
\begin{lstlisting}[numbers=none]
val iter_mut : (&!(aff_r1,'a) -> unit) -> &!('k_1,'a Array.t) -> unit
\end{lstlisting}

While the distinction between mutable and immutable iteration functions
seems unfortunate, it is typical of
programming with borrows and is also present in the Rust standard library.
It enables the programmer to explicitly state how different iterations
may be composed and optimized.
It also enables different implementations such as
using parallel iterations in the immutable case.
\lang's region variables ensure that the content iterated on can never
be leaked outside of the iteration function.
This pattern is essential in many use cases of linearity such
as pools of linear objects (see \cref{tuto:pool}).

To close this discussion, let's see which primitives are needed to implement
functions like @bfold@ and @iter_mut@. The naive sequential implementations of
both functions boil down to a loop over the index range of the array:
\begin{flushleft}\vspace{-\baselineskip}
  \begin{minipage}[t]{0.49\linewidth}
\begin{lstlisting}
let rec bfold_helper f a z i =
  if i < 0 then z
  else bfold_helper f &&a (f (get_sb &&a i) z) (i-1)
let bfold f a z =
  let l = length &&a - 1 in
  bfold_helper f &&a z l
\end{lstlisting}
  \end{minipage}
  \begin{minipage}[t]{0.49\linewidth}
\begin{lstlisting}
let rec iter_helper f a i =
  if i < 0 then ()
  else (f (get_eb &&!a i); iter_helper f &&!a (i-1))
let iter_mut f a =
  let l = length &&a - 1 in
  iter_helper f &&!a l
\end{lstlisting}
  \end{minipage}
\end{flushleft}
Observe that we are proposing two different primitives
\begin{itemize}
\item
  @get_sb : &('k, 'a Array.t) -> int -{'k}> &('k, 'a)@ \\to get a
  shared borrow from a shared borrow of an array and
\item
  @get_eb : &!('k, 'a Array.t) -> int -{'k}> &!('k, 'a) (* Unsafe! *)@
\\to get an
  exclusive borrow from an exclusive borrow of  an array.
\end{itemize}
These primitives have the same underlying implemention (the same as
@get@ from \cref{sec:imper-progr}). Their types arise from the
intuition that the borrow of a structure should entitle to borrows of
its substructures, roughly, the borrow of an array could be considered as
array of borrows.
However, only @get_sb@ is safe: the shared borrow of the array entitles us to
obtain shared borrows for the elements \emph{in the same region} as
the shared borrow for the array freezes the array inside the
region. This freeze extends to the elements because
lifetime of the array fully overlaps with the lifetime of its
elements.
Considering @get_eb@, we see that we may obtain \emph{two different
exclusive borrows} of the same array element inside a region. Clearly,
the exclusive borrow for the element should live in a nested region
where the array is not accessible. Hence, the safe alternative is
to use a different function for obtaining borrows of elements
\begin{lstlisting}[numbers=none]
with_eborrow : ('b:'k),('k <= lin_r) => &!('k_1,'a Array.t) -> int -> (&!(aff_r1,'a) -> 'b) -{'k_1}> 'b
\end{lstlisting}
Hence, the helper function for @iter_mut@ should read like this
\begin{lstlisting}
let rec iter_helper f a i =
  if i < 0 then ()
  else (with_eborrow &!a i f; iter_helper f &!a (i-1))
\end{lstlisting}
which also explains the occurrence of @aff_r1@ in the type of
@iter_mut@.

We conclude that borrows of datastructures create the need for
differently typed access functions that are tailored for different use
cases. The argumentation whether such an access function is safe is
sometimes subtle and gives rise to nonobvious types.

\lstDeleteShortInline@

%%% Local Variables:
%%% mode: latex
%%% TeX-master: "main"
%%% End:


\subsection{Sharpe ratio}


\chapter{Questions difficulty}
During the first pilot family and friends were asked to play the game and provide feedback. With the help of the 83 games played, we were able to get information about some important aspects of the game: which questions are selected by the users, are they answering randomly or by thinking, how much time they take to answer the questions. This feedback was really useful to understand how difficult the game was and what kind of improvement has to be made. More analysis about this pilot will be done in section \ref{sec:pilot1}. One of the first issue was that the questions were generated completely randomly and there was no concern about how difficult they were, we mostly used parameters that we thought would make sense and not too difficult. We had two main reasons for wanting to be able to change the difficulty at will.\\
The first and most obvious reason is that it makes the game more enjoyable, getting hard questions and failing over and over is  not amusing and the same goes if you only get easy question which offer no challenge at all. The second reason is that by being able to toy with the difficulty, we can test hypotheses and improve our understanding of memory: if we think that some parameter is a central part of what makes an element memorable we can then consider it when modifying questions' difficulty and see whether or not this affects the results when games are played.\\\\
It was therefore important to add some modularity to the question generation process and decide what parameters could be played with to influence the difficulty. Note that older events are obviously harder than recent events so we did not take into account the creation date of a post when discussing the difficulty of a question. We approached the problem from two angles, the selection of items and the generation of the question itself.\\\\
Some items will be harder to remember than others no matter the way the question is then generated. For instance, finding out precisely when something was posted is hard if it is in the middle of a lot of other posts because it was posted during a period of heavy usage of Facebook. On the other hand, isolated posts are really memorable because they are often about something so noteworthy that it made the user go on Facebook and talk about it when they were in the middle of a low usage period.\\\\
The way items are used when generating questions is also something that increases and decreases difficulty. The choice of other alternatives in a multiple choice questions has a lot of influence on the difficulty and the size of the proposed time periods on a time question has also an influence.

\section{Clustering}
\subsection{Why do we need clustering}
Clustering is a standard data analysis technique. ``[It] is the task of grouping a set of objects in such a way that objects in the same group (called a cluster) are more similar (in some sense or another) to each other than to those in other groups (clusters).''\cite{clustering} It is often used in data mining to perform pattern recognition as it allows to find similar items in a data set. The reason we are using it is that we want to find sets of similar posts or similar pages which are then hard to compare to each other. This is of great help when generating ordering questions as three elements belonging to a same cluster are then harder to order than those in different clusters.
\subsection{Algorithm choice}
There are a lot of different algorithms which can achieve clustering. They all have different behaviors and required inputs. Some of the most common algorithms are k-means and DBSCAN.\\
K-means ``aims to partition $n$ observations into $k$ clusters in which each observation belongs to the cluster with the nearest mean''\cite{kmeans}. The algorithm works quite well when the number of clusters is known in advance and provides a centroid for each cluster, which is the mean value for each cluster.\\
``Density-based spatial clustering of applications with noise (DBSCAN) [...] groups together points that are closely packed together (points with many nearby neighbors), marking as outliers points that lie alone in low-density regions (whose nearest neighbors are too far away).''\cite{dbscan} This algorithm does not provide centroids but has the nice property to discover the right number of cluster by itself based on the density distribution of the dataset.\\\\
Figure \ref{fig:clustComp} shows a visual representation of the results of different variations of k-means and DBSCAN when applied to the same datasets. One can see that k-means works well when the number of expected clusters is the same as the number of clusters that the data set actually has. However, when the data set has a different number of cluster or their shape is such that one cannot enclose them in separate circles, the results are less than convincing. On the other hand DBSCAN behaves well in all those cases.\\
In our application, we do not know the number of clusters in advance, it is something we would like the algorithm to help us discover, therefore the choice was to use DBSCAN.

\begin{figure}
\centering
{\includegraphics[width=6in]{images/cluster_comparison.png}}
\caption{Comparison of multiple clustering techniques from the Apache maths Commons documentation\cite{apachecluster}}
\label{fig:clustComp}
\end{figure}
\newcommand\minpts{\mathit{minPts}}
\section{How does DBSCAN work}
\subsection{General notions}
Besides the data set, DBSCAN works with two parameters as inputs, $\epsilon$ and $\minpts$. $\epsilon$ can be seen as a density measure, it is the distance between two points which we would consider acceptable for them to be in the same cluster. $\minpts$ is the minimum number of points in a cluster.\\
Let's introduce a few notions\cite{dbscan}:
\begin{itemize}
	\item A \emph{core point} is a point which is surrounded by at least $\minpts$ points within a distance of $\epsilon$. Those points are said to be \emph{directly reachable} from this \emph{core point}. By definition, no point is \emph{directly reachable} from a non-core point.
	\item A point $q$ is said to be \emph{reachable} from a core point $p$ if there exists a sequence of points, all \emph{directly reachable} from the previous one, which starts at $p$ and ends at $q$. All those points must be \emph{core points} except $q$.
	\item All non-core, non-reachable points are \emph{outliers}
	\item Two points $p$ and $q$ are \emph{density connected} if there is a point $o$ from which they are both \emph{reachable}
\end{itemize}

And then the points in a cluster satisfy the following properties\cite{dbscan}:
\begin{itemize}
	\item All points within the cluster are mutually density-connected.
	\item If a point is \emph{reachable} from any point in a cluster, it is part of the cluster as well.
\end{itemize}

Figure \ref{fig:reachExample} illustrates those definitions.

\begin{figure}
\centering
{\includegraphics[width=3.5in]{images/reach_example.png}}
\caption{This figure taken from the Wikipedia article on DBSCAN \cite{dbscan} shows an example where $\minpts=4$. $\epsilon$ is represented by the circles. The points in red are \emph{core points}, the ones in yellow are \emph{reachable} and the one in blue is an outlier. The cluster would be comprised of points in red and yellow.}
\label{fig:reachExample}
\end{figure}

\subsection{The algorithm itself}

Let's first define the $\epsilon$-\emph{neighborhood} of a point as the set of points which are at a distance less than $\epsilon$ from this point. The algorithm works as follows\cite{dbscan}:
\begin{enumerate}
	\item \label{initdbscan} Pick a point $P$ from the dataset that was not visited yet and mark $P$ as visited. If no such point exists, the algorithm is completed.
	\item Let $N$ be the $\epsilon$-\emph{neighborhood} of this point. If $N$ contains at least $\minpts$ points, $P$ is a \emph{core point}. In that case create a new cluster $C$ containing only $P$ and carry on to \ref{preloopdbscan}, otherwise go back to \ref{initdbscan}.
	\item\label{preloopdbscan} All the points in $N$ should obviously be part of cluster $C$ as they are neighbors of a \emph{core point} ($P$) and are at a distance less than $\epsilon$ from this point. We must include them in the cluster, but if those points are also \emph{core points} we must also include their neighborhoods and so on (forming sequences of \emph{core points} to find all the \emph{reachable} points). To achieve this, we will put all the points we have to visit in a set we will call $V$. First, put all the points from $N$ in $V$ then go to \ref{loopdbscan}.
	\item \label{loopdbscan} Pick a point $P'$ from $V$ that was not visited yet and mark $P'$ as visited. If no such point exists, go to \ref{initdbscan}.
	\item If $P'$ does not belong to any cluster yet, add $P'$ to cluster $C$.
	\item If the $\epsilon$-\emph{neighborhood} of $P'$ contains at least $\minpts$ points ($P'$ is then a \emph{core point}), add the $\epsilon$-\emph{neighborhood} of $P'$ to $V$. Go to \ref{loopdbscan}.
\end{enumerate}

At the end, all the points which are not in any cluster are \emph{outliers}.

\subsection{Parameters selection}\label{subsec:paramselect}

As for all clustering algorithm, we must select the input parameters carefully as they have a big impact on the algorithm's behavior and results. In the case of DBSCAN, the two parameters are $\epsilon$ and $\minpts$. The selection of those parameters is not an exact science and depends on the problem to solve. In our case, we are still in the really early stage of out understanding of the problem (our clusters relate to questions difficulty which we do not fully master yet), we needed some basic parameters to start experimenting with.\\
For $\minpts$, it is generally advised to use at least the dimension of the values plus 1 but no less than 3\cite{dbscan}. In out case we will be clustering geolocation data (dimension 2), temporal data (dimension 1) or simple numerical values (dimension 1) so a cluster size of 3 seemed to fit the purpose well (it is also the number of elements we need in the ordering questions).\\
For $\epsilon$, it depends a lot on the kind of data we are clustering. The general advice is that ``The value for $\epsilon$ can then be chosen by using a k-distances graph, plotting the distance to the $k = \minpts$ nearest neighbor. Good values of $\epsilon$ are where this plot shows a strong bend.''\cite{dbscan} This simply means that we can use a data sample, for each point compute the maximum distance to its 3 closest neighbors and plot those distance. Where the plot shows a strong bend should be the right value for $\epsilon$. The value chosen for every type of data is specified in section \ref{sec:qdiff}.

\section{Questions creation with difficulty}\label{sec:qdiff}
In this section we will discuss the process of creating questions with a certain difficulty. As mentioned before, there are two aspect to the problem: the items selection and the generation of the question itself. The selection part consists on assigning a difficulty score for each type of question to each item, so that when generating a question one can know which items to use. Those scores were chosen so that they are between 0 and 1 for any type of question so that we have a common baseline. The generation part simply consists of the logic we use to generate the question once we selected the items.
\subsection{Multiple Choice Questions}
We have two kind of multiple choice questions, the ones about posts and the ones about pages. The ones about posts always ask who of the displayed people reacted or commented on a post, therefore the difficulty of these questions is directly linked to the relation with those people. The questions about pages ask which page was liked, the intuition we used here is that pages with the least likes are the most recognizable because they are often related to a really particular interest of the user that is not usual and they are aware of it. Also showing choices that have a low number of likes makes it easy for the user to discard them as not liked because they have a high chance to be subjects the player do not even know about.
\subsubsection{Items selection}
For the questions about the posts, we first counted how many times each person reacted on any one of the user's posts. Then each post's difficulty was decided based on how frequent the people who reacted on that particular post reacted to the user's posts over all. The less they did, the higher the difficulty score. The reason behind this scoring logic is that it seems that some posts get reactions from people the user does not know (friends of friends for instance) and it makes the question hard when the right answer is someone the player is not even sure they know at all. More precisely, let $\mathit{max}$ be the total number of reactions for the person who made the most reactions over all of the user's posts and let $\mathit{maxForPost}$ be the total number of reactions for the person with the most overall reactions among the people who reacted on the considered post. Then the difficulty score $\mathit{diffScore}$ is : $$\mathit{diffScore} = 1 - \frac{\mathit{maxForPost}}{\mathit{max}}$$\\
For the questions about the pages, we considered the logarithm of the number of likes as the distribution of the number of likes is a power law distribution (the rank is proportional to the logarithm of the number of likes). Then, as we considered highly liked pages as being the hardest, we decided to assign the score as follows: let $\mathit{max}$ be the number of likes of the page with the most number of likes among the pages liked by this user and let $\mathit{pageLikes}$ be the number of likes for the considered page, then the difficulty score $\mathit{diffScore}$ is: $$\mathit{diffScore} = \frac{\log(\mathit{pageLikes})}{\log(\mathit{max})}$$
\subsubsection{Question generation}
In the question generation process, the choice to make is the proposed alternatives. For the posts questions, the harder the question the less reactions will the proposed alternatives have. For the pages questions, the harder the question, the most likes will the proposed alternatives have.
\subsection{Timeline questions}
The difficulty of such a question resides in the period in which a post is made and the precision asked. The heuristic we used for this question is that if a post comes from a period of very dense activity it is not a particularly memorable one so it would generate a hard question. If it comes from a period of non dense activity it must be a memorable one due to its isolation and therefore it will generate an easy question.
\subsubsection{Scoring the items}
To assign a score we decided to use DBSCAN in order to know about the periods of dense activity. A cluster represent such a period and therefore an item which is in a cluster will get score 1.0 and an item which is not in a cluster will get score 0.5.\\
As for the parameters used for the clustering, we decided to use 3 for $\minpts$ for the reasons mentioned in section \ref{subsec:paramselect}. The choice of $\epsilon$ is based on a 3-distances graph we made using the data from a user who had a lot of posts. The distances are computed in milliseconds. Figure \ref{fig:postTime} shows the resulting graph. The value chosen for $\epsilon$ was 1010391000 milliseconds which is approximately 11.69 days.
\begin{figure}
\centering
{\includegraphics[width=3.5in]{images/post_time_knn.pdf}}
\caption{3-distances graph for post time}
\label{fig:postTime}
\end{figure}
\subsubsection{Generating the question}
The parameter we can choose when generating a question is the length of the time periods proposed to the user. Without difficulty this length is chosen to be proportional to how long in the past the event happened. When incorporating the difficulty we decided to reduce it based on the difficulty: the harder the question has to be, the smaller the time period has to be. We still take into account the date of the event as we have to compensate for the fact that older events are harder to remember.

\subsection{Geolocation Questions}
On this type of question we have nothing to do while generating the question, the selection of an item suffices. Therefore we only need to generate a score for each item. We do it in the same way as for the timeline questions: we cluster the items, an item which is in a cluster will get score 1.0 and an item which is not in a cluster will get score 0.5. The reason for this is that clusters will represent places where the user lives, has lived or goes often so it is easy for them to locate these events as they know the area well. On the other hand the ones outside of a cluster are isolated places and the area is often not known well by the user.\\
For the parameters we used for the DBSCAN clustering, we chose $\minpts$ to be 3 for the reasons expressed in section \ref{subsec:paramselect}. We did not use a 3-distances graph for the choice of $\epsilon$ because there was no user with a satisfying amount of data. So we simply tried different values to see their effect on the clustering and finally decided an $\epsilon$ of 2. This distance is a euclidean distance in the latitude and longitude space.

\subsection{Ordering Questions}
For the ordering questions, as for the geolocation questions, only the items picking matters as there is nothing else to decide when generating the question. There are two types of questions. The first kind is the new question about ordering reactions on a post according to their number on that post. And the second is the questions are the ones about ordering pages according to their number of likes or the time when the user liked the page.
\subsubsection{Reactions ordering}
In this case the difficulty of the question comes from how different the numbers of each reaction are from one another. A good measure for this is the standard deviation, the higher the standard deviation the easiest the question will be. To make sure that this score is between 0 and 1 we first normalize the number of reactions relative to the one with the highest number of reactions, then compute the standard deviation. If we note the standard deviation of the normalized values $\sigma_n$ the difficulty score $\mathit{diffScore}$ will be $$\mathit{diffScore} = 1 - 2 \sigma_n$$ which is between 0 and one as the standard deviation of the normalized values will be between 0 and 0.5.
\subsubsection{Ordering pages}\label{subsubsec:orderpages}
This is an exception to the standard scheme of picking items only based on their score. The difficulty here lies in the similarity between the items, so when we want to generate a hard question we want to select similar items. To decide on the similarity of items we use DBSCAN clustering. We can generate two kind of questions, the hard ones, when the items are selected in the same cluster and the easy ones where the items are selected at random.\\
For the DBSCAN parameters selection we decided to use 3 for $\minpts$ for the reasons mentioned in section \ref{subsec:paramselect}. For the choice of $\epsilon$ we generated 3-distances graphs using the data from a user with a high number of liked pages.\\
For page like times the distances are expressed in milliseconds. Figure \ref{fig:plikeTime} show the resulting graph, we decided to use the value 7709211000 milliseconds for $\epsilon$ which corresponds to approximately 89.22 days.\\
Finally for page like numbers the distances expressed are the distances between the logarithms of the page likes number. As mentioned earlier the number of likes on a page is a power law distribution so using the logarithm of this number makes also sens when clustering. The resulting graph is shown on figure \ref{fig:plikesNumber}. The chosen value for $\epsilon$ is then 0.43349.

\begin{figure}
\centering
{\includegraphics[width=3.5in]{images/page_like_time_knn.pdf}}
\caption{3-distances graph for page like time}
\label{fig:plikeTime}
\end{figure}
\begin{figure}
\centering
{\includegraphics[width=3.5in]{images/page_likes_number_knn.pdf}}
\caption{3-distances graph for page likes number}
\label{fig:plikesNumber}
\end{figure}

\section{Difficulty selection}
The last problem to tackle is choosing the difficulty level we want the questions to be when generating a game board. Thanks to the stats module (see section \ref{sec:stats}) we have easily access to the success rate of a user on any type of question. This success rate being a number between 0 and 1.0 we decided to use this as a measure of required difficulty on any type of question. This means that in the cases where we are trying to generate a question which is not an ordering of pages (we did not compute a score for those, see section \ref{subsubsec:orderpages}) we can simply choose items which score is at least as high as the success rate. This success rate is then also used in the question generation process as a parameter.


    \filetitle{jforecast}{Forecast with judgmental adjustments (conditional forecasts)}{model/jforecast}

	\paragraph{Syntax}\label{syntax}

\begin{verbatim}
F = jforecast(M,D,Range,...)
\end{verbatim}

\paragraph{Input arguments}\label{input-arguments}

\begin{itemize}
\item
  \texttt{M} {[} model {]} - Solved model object.
\item
  \texttt{D} {[} struct {]} - Input data from which the initial
  condition is taken.
\item
  \texttt{Range} {[} numeric {]} - Forecast range.
\end{itemize}

\paragraph{Output arguments}\label{output-arguments}

\begin{itemize}
\itemsep1pt\parskip0pt\parsep0pt
\item
  \texttt{F} {[} struct {]} - Output struct with the judgmentally
  adjusted forecast.
\end{itemize}

\paragraph{Options}\label{options}

\begin{itemize}
\item
  \texttt{'anticipate='} {[} \emph{\texttt{true}} \textbar{}
  \texttt{false} {]} - If true, real future shocks are anticipated,
  imaginary are unanticipated; vice versa if false.
\item
  \texttt{'currentOnly='} {[} \emph{\texttt{true}} \textbar{}
  \texttt{false} {]} - If \texttt{true}, MSE matrices will be computed
  only for the current-dated variables, not for their lags or leads.
\item
  \texttt{'deviation='} {[} \texttt{true} \textbar{}
  \emph{\texttt{false}} {]} - Treat input and output data as deviations
  from balanced-growth path.
\item
  \texttt{'dtrends='} {[} \emph{\texttt{@auto}} \textbar{} \texttt{true}
  \textbar{} \texttt{false} {]} - Measurement data contain deterministic
  trends.
\item
  \texttt{'initCond='} {[} \emph{\texttt{'data'}} \textbar{}
  \texttt{'fixed'} {]} - Use the MSE for the initial conditions if found
  in the input data or treat the initical conditions as fixed.
\item
  \texttt{'meanOnly='} {[} \texttt{true} \textbar{}
  \emph{\texttt{false}} {]} - Return only mean data, i.e.~point
  estimates.
\item
  \texttt{'plan='} {[} plan {]} - Simulation plan specifying the
  exogenised variables and endogenised shocks.
\item
  \texttt{'vary='} {[} struct \textbar{} \emph{empty} {]} - Database
  with time-varying std deviations or cross-correlations of shocks.
\end{itemize}

\paragraph{Description}\label{description}

When adjusting the mean and/or std devs of shocks, you can use real and
imaginary numbers ot distinguish between anticipated and unanticipated
shocks:

\begin{itemize}
\item
  any shock entered as an imaginary number is treated as an anticipated
  change in the mean of the shock distribution;
\item
  any std dev of a shock entered as an imaginary number indicates that
  the shock will be treated as anticipated when conditioning the
  forecast on the reduced-form tunes.
\item
  the same shock or its std dev can have both the real and the imaginary
  part.
\end{itemize}

\paragraph{Description}\label{description-1}

\paragraph{Example}\label{example}


% !TEX root = thesis.tex

\chapter{Extrusion}
\label{ch:extrusion}

Extrusion is a commonly used technique in GIS to construct simple 3D models.
Starting from a planar partition of polygons and a height interval associated to each of them, it generates a set of space-partitioning box-shaped polyhedra by considering that each polygon exists all along its related interval.
For instance, a set of building footprints and associated heights is extruded into a set of simple prismatic buildings.
Based on the fundamental operations on generalised and combinatorial maps discussed in \refch{ch:operations-background}, this chapter presents a generalisation of this technique to higher dimensions: an $(n-1)$-dimensional cell complex and a set of associated intervals per $(n-1)$-cell is thus transformed into an $n$-dimensional cell complex.

The chapter starts by presenting some background on 2D-to-3D extrusion and an intuitive description of dimension-independent extrusion in \refse{se:extrusion-background}.
Afterwards, \refse{se:extrusion-algos} describes an dimension-independent extrusion algorithm.
 % that can create $n$-dimensional cell complexes from $(n-1)$-dimensional space partitions.
% by assigning one or more intervals to each $(n-1)$-cell
\refse{se:extrusion-implementation} describes how this algorithm was implemented based on the implementation of combinatorial maps in CGAL.\@
\refse{se:extrusion-experiments} summarises experiments using this implementation, which created consistent objects in up to 6D by combining publicly available GIS datasets.
\refse{se:extrusion-generalisation} describes how extrusion can be used not only directly, but as a base to create dimension-independent generalisation operations.
Finally, \refse{se:extrusion-conclusions} concludes the chapter with the main findings and the possibilities to use extrusion for higher-dimensional datasets.

Most of this chapter is based on the paper:
\begin{itemize}
\paperijgisextrusion%
\end{itemize}

\section{Background}
\label{se:extrusion-background}

Extrusion is most commonly used in GIS\footnote{This contrasts with the use of the term `extrusion' in other fields.
For instance, in geometric modelling, extrusion is a well-known operation in which all of the objects in the model are `dragged' along a predefined path given by a curve, more akin to an actual (physical) extrusion process, but whose output topology can be computed without any geometric computations.} in order to create simple 3D city models with box-shaped buildings.
In such a process, a user takes a set of building footprints, optionally subdivided into parts of similar height, and extrudes them using intervals that extend from the ground level to the building height at the location of each polygon.
This process thus creates simple 3D representations of each building, where a building is represented by one or more box-shaped polyhedra.
\reffig{fig:3dtop10nl} shows an example of such a model over a triangulated terrain (\ie\ a 2D simplicial complex embedded in 3D).
\begin{figure*}
\centering
\includegraphics[width=\linewidth]{figs/3dtop10nl}
\caption[A view of the 3D TOP10NL dataset]{A view of the 3D TOP10NL dataset\protect\footnotemark\ in the area of Valkenburg, the Netherlands.}
\label{fig:3dtop10nl}
\end{figure*}
\footnotetext{\url{https://www.pdok.nl/nl/producten/pdok-downloads/basis-registratie-topografie/top10nl-3d}}

Such an extrusion process is appealing largely because of its simplicity.
All the information that is required for the previous example is notoriously easy to obtain: building footprints are widely available---including in open datasets such as OpenStreetMap\footnote{\url{http://www.openstreetmap.org/}}---or can be easily obtained from satellite imagery, while the height information can be acquired with techniques like airborne laser scanning or photogrammetry.
Not coincidentally, this type of 3D models are commonly generated in practice and often appear in standards such as CityGML \citep{CityGML2}, where it is defined as the level of detail (LOD) 1.

Moreover, it is easy to ensure that extruded models are generated in a topologically consistent manner~\citep{Ledoux11a}.
If the input forms a planar partition---or is processed to form a planar partition, \eg\ using the method described in \refse{se:pprepair}---and the extrusion direction is orthogonal to the planar partition, \emph{the output polyhedra are guaranteed not to overlap}.

While not every possible 3D shape can be generated using extrusion---the top and bottom faces will always be horizontal, and the side faces connecting them will always be vertical---, a remarkable number of shapes can be constructed using this type of method \citep{Ferrucci93}.
This is especially true when simple extensions to the method are considered, such as multiple intervals per 2-cell, possibly overlapping 2-cells in the input, or an arbitrary extrusion direction.

Viewed at a more fundamental level, shown in \reffig{fig:extrusion}, extrusion `lifts' a 2D cell complex to form a 3D cell complex.
In order to form a valid cell complex as defined in \refse{ss:algebraic-topology}, cells must not overlap, but instead they should form a structure of cells of dimension from 0 to 3, where $i$-cells ($\forall i > 0$) are bounded by sets of $(i-1)$-cells.
The extruded cells must therefore take into account the incidence and adjacency relationships between cells, splitting cells of every dimension at the places where the common boundaries of higher-dimensional cells start and end.
\begin{figure}[tbp]
\centering
\subfloat[]{
\includegraphics[width=0.5\linewidth]{figs/extrusion-1}
\label{subfig:extrusion-1}}
% \quad
\subfloat[]{
\includegraphics[width=0.5\linewidth]{figs/extrusion-2}
\label{subfig:extrusion-2}}
\caption[Extrusion from 2D to 3D]{(a) A 2D cell complex, where each 2-cell is associated with a height, is extruded to generate (b) a 3D cell complex. Note how the extrusion of vertex $v$ in (a) causes the generation of several vertices and edges.
In particular, the vertex $v^\prime$ in (b), which is at the height of the top face of the back left polyhedron.
This vertex needs to be used in the representation of the all 4 edges, 5 faces and 3 volumes that are incident to it, not only in those that are part of the back left polyhedron. This ensures that the cells in (b) are pairwise disjoint and have the expected correct topology.}
\label{fig:extrusion}
\end{figure}

Extrusion, in the sense of its GIS definition as exposed in the previous paragraph, has a natural extension to higher dimensions.
A dimension-independent extrusion operation thus `lifts' an $(n-1)$-dimensional cell complex, to an $n$-dimensional cell complex by assigning one or more intervals to each $(n-1)$-cell, \ie\ a subset of 1D Euclidean space\footnote{This is equivalent to one or more edges in \citet{Lienhardt04} or 1-dimensional polyhedra in \citet{Ferrucci93}.}, along which this cell is defined.
For instance, just as a polygon representing the footprint of a building is commonly extruded using an interval $(0, height)$, a polyhedron representing a building can be extruded along the time interval $(construction, destruction)$.
As \reffig{fig:Frauenkirche} shows, extrusion using multiple unconnected intervals is also a possible use case.
\marginpar{
\captionsetup{type=figure}
\centering
\includegraphics[width=\marginparwidth]{figs/Frauenkirche}
\caption[The Frauenkirche in Dresden]{The Frauenkirche in Dresden, Germany, was originally built in 1743, destroyed during the bombing of Dresden in 1945, and reconstructed in 2005.
A simple 4D model of the building could be made by extruding a 3D model of it along the interval $(1743, 1945) \cup (2005, \infty)$.
Photograph by David M\"uller in Wikimedia Commons.
}
\label{fig:Frauenkirche}
}

In the related literature, there are two methods that can be used for a similar purpose.
The Cartesian product, a more general operation defined for generalised maps in \citet{Lienhardt04}, generates a combinatorial structure equivalent to the extrusion of all the objects along a single interval by computing the Cartesian product of the original (unextruded) cell complex with an edge.
However, since such an operation is limited to a single interval (which is the same for all the input objects), the output cannot be directly applied for modelling real-world datasets.
A related possibility, presented by \citet{Ferrucci93}, is to first pre-process all the intervals (for all cells), splitting them into fragments at the other intervals' endpoints so that each fragment intersects another one if and only if they have the same endpoints, and then computing the output purely combinatorially for each possible combination of fragment and for each input cell.
While this allows us to model real-world objects, the process of splitting the input intervals might greatly increase the number of output cells since two intersecting intervals are split even if their corresponding cells are far away from each other.
The method presented in this chapter follows a similar approach, but instead process the input intervals for each input cell separately based on the incidence relationships with other cells, thus generating fewer total intervals, a smaller number of cells and a considerably smaller combinatorial structure.

\section{A dimension-independent extrusion algorithm}
\label{se:extrusion-algos}

The dimension-independent extrusion algorithm requires two input arguments: an $(n-1)$-dimensional space partition of $(n-1)$-polytopes embedded into $(n-1)$-dimensional space, stored as an $(n-1)$-dimensional generalised map $G$; and a map of extrusion intervals $\rho$\footnote{I originally referred to these as \emph{ranges} and thus used variations of $R$ and $\rho$ (rho).
While a kind anonymous reviewer correctly suggested that it is more precise to refer to them as \emph{intervals}, $\rho$ is more distinctive than iota ($\iota$) and upsilon ($\upsilon$), and so it remains as $\rho$ here.} that links each $(n-1)$-cell $c$ in $G$ to a set $R$ of 1-dimensional intervals, where every interval $r$ in $R$ is represented as a pair of values $(r_{\min}, r_{\max})$ where $c$ is extruded along the $n$-th dimension.
The intervals in $\rho$ for the cells of lower dimension do not need to be given, since they can be computed by the algorithm based on their incidence relationships to the $(n-1)$-cells.
Note that, as \reffig{fig:extrusion-intervals} shows, multiple intervals for the same cell are possible.
\begin{figure}[tbp]
\centering
\subfloat[]{
\includegraphics[width=0.5\linewidth]{figs/intervals-1}
\label{subfig:extrusion-intervals-1}}
% \quad
\subfloat[]{
\includegraphics[width=0.5\linewidth]{figs/intervals-2}
\label{subfig:extrusion-intervals-2}}
\caption[The extrusion intervals of the lower-dimensional cells]{All the cells are given extrusion intervals based on the intervals for the $(n-1)$-cells.
Note how it is possible to have multiple intervals per cell both in the input, \eg\ the purple square on the right is extruded along two intervals, and in the output, \eg\ the two edges $v^{(0,1)}$, $v^{(1.5,2)}$ and $v^{(2,3)}$ are the result of the extrusion of a single vertex $v$ whose extrusion interval was not directly given.}
\label{fig:extrusion-intervals}
\end{figure}

There are two cases in which a cell has multiple intervals.
One of these is that for an $(n-1)$-dimensional cell, multiple intervals may be explicitly provided in the input (\eg\ the example previously given in \reffig{fig:Frauenkirche}).
The other case is that for a lower-dimensional cell, multiple extrusion intervals may be passed to it by several adjacent higher-dimensional cells.

The result of the extrusion algorithm is an $n$-dimensional generalised map $G^{\prime}$ representing a $n$-dimensional cell complex containing a set of prismatic $n$-polytopes, the $n$-dimensional analogue of a set of prisms, which also form a $n$-dimensional space partition.
It is important to note that the output map $G^\prime$ creates entirely new structures, \ie\ it does not reuse the darts or embeddings of $G$, since the $(n-1)$-simplices in $G$ are similar but not identical to the $n$-simplices in the base of $G^\prime$.
These differ in terms of the highest-dimensional involution $\alpha_{n-1}$ and---importantly for an implementation---in the total number of involutions per dart.

As \reffigs{fig:trianglecomplex} and~\ref{fig:blockscomplex} show, the cells in the new $n$-dimensional cell complex in $G^\prime$ have a direct relation to and can be expressed in terms of the $(n-1)$-cells in $G$ and their extrusion intervals in $\rho$.
This property is used in order to define the cells of the output cell complex, which are equivalent to the embeddings in $G^\prime$.
These consist of:
\begin{itemize}
\item
`Base' and `top' $(n-1)$-cells (\ie\ facets), which are constructed from every $(n-1)$-cell $c$ in $G$ at the $r_{\min}$ and $r_{\max}$ end points of every interval in $\rho(c)$.
\item
A series of prismatic facets linking corresponding $(n-2)$-cells (\ie\ ridges) $c$ of the above mentioned $r_{\min}$ and $r_{\max}$ facets for every interval, such that every one of these facets corresponds to the extrusion of the ridge along an interval in $\rho(c)$.
\end{itemize}

\begin{figure}[tb]
\centering
\subfloat[]{
\includegraphics[width=0.45\linewidth]{figs/trianglecomplex-1}
\label{subfig:trianglecomplex-1}}
\quad
\subfloat[]{
\includegraphics[width=0.45\linewidth]{figs/trianglecomplex-2}
\label{subfig:trianglecomplex-2}}
\caption[Extruding the embeddings]{Extruding the embeddings of an $i$-cell $c$ along a single interval $r = (a,b)$ such that $a,b \in \mathbb{R}, a \neq b$, generates the embeddings of three cells: two $i$-cells $c^{a}$ and $c^{b}$, and an $(i+1)$-cell $c^{r} = c^{(a,b)}$ lying between them.}
\label{fig:trianglecomplex}
\end{figure}

\begin{figure}[tb]
\centering
\subfloat[]{
\includegraphics[width=0.45\linewidth]{figs/blockscomplex-1}
\label{subfig:blockscomplex-1}}
\quad
\subfloat[]{
\includegraphics[width=0.45\linewidth]{figs/blockscomplex-2}
\label{subfig:blockscomplex-2}}
\caption[Extruding a 2D cell complex]{Extruding a 2D cell complex using an interval that is defined per 2-cell.
The facet $f_0$ is to be extruded along the interval $r_0 = (a,c)$ and $f_1$ along $r_1 = (a,b)$.
Note how the vertices and edges incident to multiple facets in the input are extruded along the intervals of these facets, generating a series of cells connecting the end points of their intervals.}
\label{fig:blockscomplex}
\end{figure}

For the combinatorial structure, the algorithm takes advantage of the fact that the darts in the generalised map $G$ can be extruded largely independently based on querying the combinatorial structure of $G$ and simple 1D geometric queries along the $n$-th dimension.
Intuitively, the extrusion of a single $(n-1)$-simplex in $G$ consists of layers of $n$-simplices that are `stacked'
% \footnote{Not in the sense of a stack as a data structure, but as a pile of simplices arranged vertically along the $n$-th dimension.}
so as to form one part of the prism-shaped output.
Each new layer corresponds to a new $n$-simplex that shares all but one of the nodes with the $n$-simplex below it.

The extrusion algorithm is thus divided into three parts that are performed sequentially and explained in detail in the following sections: (1) propagating the input intervals to all the cells in the input cell complex, (2) generating the new embeddings (\ie\ the attributes and geometry) for each input cell, and (3) generating the combinatorial structure (\ie\ the darts and involutions) and linking each dart to its correct embeddings for every dimension.

\subsection{Propagating the extrusion intervals to all cells}
\label{ss:propagation}

While the extrusion intervals are defined only for the $(n-1)$-cells, the cells of every dimension need to be extruded, and therefore the extrusion intervals need to be propagated from the $(n-1)$-cells to the cells of lower dimension.
This is done recursively in decreasing dimension, using the incidence relationships between every $i$-cell and the $(i-1)$-cells on its boundary to pass the intervals of the former to the latter, using the same map of extrusion intervals $\rho$.
Because incidence is a transitive relation, an interval attached to a particular lower dimensional cell thus indicates that it is incident to an $(n-1)$-cell that will be extruded along that interval.

As $(i-1)$-cells can be on the boundary of multiple $i$-cells, several intersecting intervals can be passed to the map of extrusion intervals of a lower dimensional cell.
In order to generate non-intersecting cells, these need to be split into a set of non-intersecting intervals as shown in \reffig{fig:intersectingintervals}, each of which will represent the incidence of this cell to an equal set of higher-dimensional cells along the entirety of the interval.
\marginpar{
\captionsetup{type=figure}
\centering
\includegraphics[width=\marginparwidth]{figs/intersectingintervals}
\caption[Propagating the extrusion intervals]{The extrusion intervals from the cells incident to the middle vertex of \reffig{fig:extrusion-intervals} in (a), are passed on to it, resulting in a new set of non-intersecting intervals in (b).}
\label{fig:intersectingintervals}
}
A sketch of a simple process to do this is shown in \refalgo{algo:propagateintervals}, which assumes that the sets of intervals are kept sorted.
Note that this is essentially a one dimensional analogue of other operations used in GIS, \eg\ vector map overlays \citep[\S{}2.3]{deBerg08} and time-composites in spatio-temporal modelling \citep{Langran88}.
% \begin{figure}
\begin{algorithm}[tb]
\small
\SetKwInOut{Input}{Input}
\SetKwInOut{Output}{Output}
\DontPrintSemicolon\Input{generalised map $G$ of the input cell complex,\\
map $\rho$ with the extrusion intervals of the $(n-1)$-cells in $G$}
\Output{map $\rho$ with the extrusion intervals of all the cells in $G$}
\For{$i \leftarrow n-1$ \KwTo$0$}{
  \ForEach{$i$-cell $c$ in $G$}{
    \ForEach{$(i-1)$-cell $b$ on the boundary of $c$}{
      \ForEach{extrusion interval $r = (r_{\min}, r_{\max}) \in \rho(c)$}{
        Find the intervals $R^\prime \subseteq \rho(b)$ whose interiors intersect with $r$ \;
        \If{$r_{\min}$ is in the interior of an interval $r^\prime = (r_{\min}^\prime, r_{\max}^\prime) \in R^\prime$}{
          Remove $r^\prime$ from $\rho(b)$ \;
          Add $(r_{\min}^\prime, r_{\min})$ to $\rho(b)$ \;
          Add $(r_{\min}, r_{\max}^\prime)$ to $\rho(b)$ \;
        }
        \If{$r_{\min}$ is outside all intervals in $R^\prime$}{
          Add a new interval in $R^\prime$ from $r_{\min}$ to the minimum of the lowest interval in $R^\prime$ \;
        }
        \If{$r_{\max}$ is in the interior of an interval $r^\prime = (r_{\min}^\prime, r_{\max}^\prime) \in R^\prime$}{
          Remove $r^\prime$ from $\rho(b)$ \;
          Add $(r_{\min}^\prime, r_{\max})$ to $\rho(b)$ \;
          Add $(r_{\max}, r_{\max}^\prime)$ to $\rho(b)$ \;
        }
        \If{$r_{\max}$ is outside all intervals in $R^\prime$}{
          Add a new interval in $R^\prime$ from the maximum of the highest interval in $R^\prime$ to $r_{\max}$ \;
        }
        \ForEach{empty interval $(r_{\min}^\prime, r_{\max}^\prime)$ between consecutive intervals in $R^\prime$}{
          Add $(r_{\min}^\prime, r_{\max}^\prime)$ to $\rho(b)$ \;
        }
      }
    }
  }
}
\caption{\textsc{PropagateRanges}}\label{algo:propagateintervals}
\end{algorithm}
% \end{figure}

Considering what happens when a single new interval is passed to a cell in the incremental process shown in \refalgo{algo:propagateintervals}, the total number of intervals of that cell can increase from $j$ to $2j+1$ in the worst case, which happens when the new interval starts before and ends after all other intervals and these are all not contiguous (\ie\ they are all separated by empty intervals).
However, when taking into account $r$ intervals passed to the same cell, the total number of intervals for the cell can only increase to $2r-1$.
As each extrusion interval is bounded by two values, $r$ intervals lead to at most $2r$ boundary values and thus the number of intervals cannot be higher than $2r-1$.

Assuming that a new interval can be added to a cell in $O(\log r)$ time, \eg\ by maintaining a sorted list or an augmented red-black tree with the endpoints of the intervals, the total time to construct the ordered set of all intervals for a cell $c$ is $O(r \log r)$, where $r$ is the number of intervals that are passed onto $c$.
The overall computational complexity of this step depends on the incidence relationships between the cells in the complex.

\subsection{Generating the new embeddings}
\label{ss:embeddings}

Intuitively, when a single $i$-cell is extruded along a single interval $r = (r_{\min}, r_{\max})$, three new cells are generated: two $i$-cells that correspond to the end points of the interval $r_{\min}$ and $r_{\max}$, and a prismatic $(i+1)$-cell along all of $r$, \ie\ lying between the two $i$-cells.
For instance, extruding a polygon results in `top' and `bottom' polygonal faces and a polyhedron that lies between the two polygons.

Analogously, considering the \emph{embedding} structures that store the necessary attributes for each cell, such that an $i$-dimensional embedding ($i$-embedding) structure keeps the attributes of an $i$-cell, \emph{extruding an $i$-dimensional embedding results in two $i$-embeddings and one $(i+1)$-embedding}.
In the case of linear geometries, extruding a point entails the creation of two additional points, one with an appended $r_{\min}$ coordinate, and one with an $r_{\max}$ one.

With multiple intervals, this same procedure can then be used by applying it per embedding and per interval.
Notice that some embeddings are shared by multiple intervals (when the minimum of an interval is equal to the maximum of another), but these only need to be created once.

The extrusion algorithm for the embeddings receives the set of input embeddings $E$ and the map of extruded intervals $\rho$ which, being the output of \textsc{PropagateRanges} (\refalgo{algo:propagateintervals}), now contains a set of non-intersecting intervals for the cells of every dimension, and it returns an entirely new set of extruded embeddings $E^{\prime}$, as well a function $ex(e, v) \rightarrow E^\prime$ linking an input embedding $e \in E$ and an interval or end point of an interval $v$ to an extruded (output) embedding $e^{\prime} \in E^{\prime}$.
For instance, given an interval $r = (r_{\min}, r_{\max}) \in \rho(e)$, $v$ can be $r$, $r_{\min}$ or $r_{\max}$, reflecting the fact that extruding an $i$-embedding results in two $i$-embeddings (respectively for $r_{\min}$ and $r_{\max}$) and one $(i+1)$-embedding (for $r$).

The general procedure to generate the new embeddings and their relation to the old embeddings and the intervals is shown in \refalgo{algo:embeddingsextrusion}.
Note that a practical implementation of this algorithm has to deal with the desired attributes for each of the extruded cells rather than simply making a copy of the input ones (lines~\ref{ln:copyattributemin},~\ref{ln:coordinatemin} and~\ref{ln:copyattributemax}) and appending one more coordinate to the 0-embeddings (lines~\ref{ln:coordinatemin} and~\ref{ln:coordinatemax}).

% \begin{figure*}[tb]
\begin{algorithm}[tb]
\small
\SetKwInOut{Input}{Input}
\SetKwInOut{Output}{Output}
\DontPrintSemicolon\Input{set $E$ of the embeddings in the input cell complex,\\
map $\rho$ of the extrusion intervals for all cells of the input complex}
\Output{set $E^\prime$ of the embeddings for the output cell complex,\\
map $ex$ that links an input embedding to its extruded embeddings}
\ForEach{$e \in E$}{
  \ForEach{$r = (r_{\min}, r_{\max}) \in \rho(e)$}{
    \If{$ex(e, r_{\min}) = \emptyset$}{
      $ex(e, r_{\min}) \leftarrow e$ \;
\label{ln:copyattributemin}
      \If{$e.dimension = 0$}{
        Append $r_{\min}$ to the coordinates of $ex(e, r_{\min})$ \;
\label{ln:coordinatemin}
      }
    }
    $ex(e, r) \leftarrow e$ \;
\label{ln:copyattributeinterval}
    $ex(e, r).dimension \leftarrow ex(e, r).dimension+1$ \;
    \If{$ex(e, r_{\max}) = \emptyset$}{
      $ex(e, r_{\max}) \leftarrow e$ \;
\label{ln:copyattributemax}
      \If{$e.dimension = 0$}{
        Append $r_{\max}$ to the coordinates of $ex(e, r_{\max})$ \;
\label{ln:coordinatemax}
      }
    }
  Put $ex(e, r_{\min}), ex(e, r)$ and $ex(e, r_{\max})$ in $E^{\prime}$ \;
  }
}
\caption{\textsc{EmbeddingsExtrusion}}\label{algo:embeddingsextrusion}
\end{algorithm}
% \end{figure*}

Since this part of the algorithm iterates through all the cells in the input cell complex, and it generates at most three new embeddings per interval for each cell, the computational complexity can be $O(rn)$ per cell, where $r$ is the total number of intervals and $n$ is the dimension, \ie\ as long as the map $ex$ can be queried and the new embeddings can be created in time that is linear on the dimension (which in practice is a relatively small constant).

\subsection{Generating the new combinatorial structure and linking it to its correct embeddings}
\label{ss:combinatorial}

The extrusion of a \emph{single} dart in the input map $G$ along a single interval $r = (r_{\min}, r_{\max})$ generates a series of connected darts in $G^\prime$ connected by a sequence of involutions $\alpha_{n-1}, \alpha_{n-2}, \ldots, \alpha_{1}, \alpha_{0}, \alpha_{1}, \ldots, \alpha_{n-2}, \alpha_{n-1}$.
Intuitively, these are equivalent to stacked $n$-simplices that together form a prism\footnote{This is always true combinatorially, but it might not be true geometrically if the $(n-1)$-simplex is not embedded so as to lie in the interior of the cell, as shown in \refse{ss:ordered-topological-models}.}.
\reffig{fig:triangle} shows a simple extrusion of the cell complex from \reffig{fig:trianglecomplex} including all its darts.

\begin{figure}[tbp]
\centering
\subfloat[]{
\includegraphics[width=0.45\linewidth]{figs/triangle-1}
\label{subfig:triangle-1}}
\quad
\subfloat[]{
\includegraphics[width=0.45\linewidth]{figs/triangle-2}
\label{subfig:triangle-2}}
\caption[The darts in the cell complexes in \reffig{fig:trianglecomplex}]{The darts in the cell complexes in \reffig{fig:trianglecomplex}.
Note that one can obtain a dart's representation as a simplex by considering additional nodes at its corresponding facet and one in the interior of the volume.}
\label{fig:triangle}
\end{figure}

\marginpar{
\captionsetup{type=figure}
\centering
\setcounter{subfigure}{6}\subfloat[]{\includegraphics[width=0.7\marginparwidth]{figs/stack-6}\label{subfig:stack-6}}\\
\vspace{-10mm}
\setcounter{subfigure}{5}\subfloat[]{\includegraphics[width=0.7\marginparwidth]{figs/stack-5}\label{subfig:stack-5}}\\
\vspace{-8mm}
\setcounter{subfigure}{4}\subfloat[]{\includegraphics[width=0.7\marginparwidth]{figs/stack-4}\label{subfig:stack-4}}\\
\vspace{-6mm}
\setcounter{subfigure}{3}\subfloat[]{\includegraphics[width=0.7\marginparwidth]{figs/stack-3}\label{subfig:stack-3}}\\
\vspace{-5mm}
\setcounter{subfigure}{2}\subfloat[]{\includegraphics[width=0.7\marginparwidth]{figs/stack-2}\label{subfig:stack-2}}\\
\vspace{-6mm}
\setcounter{subfigure}{1}\subfloat[]{\includegraphics[width=0.7\marginparwidth]{figs/stack-1}\label{subfig:stack-1}}\\
\vspace{-3mm}
\setcounter{subfigure}{0}\subfloat[]{\includegraphics[width=0.7\marginparwidth]{figs/stack-0}\label{subfig:stack-0}}\\
\caption[The stack of simplices in an extruded dart]{The extrusion of a single dart (blue) results in a stack of simplices that together form a prism.
In order to visualise it more intuitively, the procedure here is shown from bottom (a) to top (g).
}
\label{fig:stack}
}

Since two darts connected by an $\alpha_i$ involution share all but the $i$-th node, and the $i$-th node in a generalised map means that a dart belongs to a certain $i$-cell\footnote{In this specific case, where cells have linear geometries.}, this series of darts represents a succession of simplices that progressively change from the cells at the `base' (at $r_{\min}$) to those at the `side' (at the interval $(r_{\min}, r_{\max})$) to those at the `top' (at $r_{\max}$).
This can be more clearly seen in \reffig{fig:stack}.
As the pattern that is followed in each stack of darts in $G^\prime$ is the same for all the darts in $G$, assuming that their extrusion intervals are the same, they can also be expressed in terms of the dart in $G$ being extruded and their position in the stack.
The darts at a certain level in the stack are thus called a \emph{layer}, and various functions will map an input dart in $G$ to the equivalent dart at a specific layer in $G^\prime$.

An intuitive justification for this is that if one considers the darts in the base and top facets in the extrusion of a cell $e$ along a single interval $r = (r_{\min}, r_{\max})$, these belong to different cells of every dimension except for their $n$-cell---which is $ex(e, r)$.
Considering a function $e_i: D \rightarrow E$ that links a dart $d \in D$ to its $i$-embedding in $E$, for every dimension $i < n$, the darts of the base facet belong to the extruded $ex\left(e_i\left(d\right), r_{\min}\right)$ cells, while the top darts belong to the extruded $ex\left(e_i\left(d\right), r_{\max}\right)$ cells.
The darts of the faces on the sides, which connect corresponding ridges of the base and top, belong instead to a mixture of cells in $ex\left(e_i\left(d\right), r_{\min}\right)$, $ex\left(e_i\left(d\right), r_{\max}\right)$ and $ex\left(e_i\left(d\right), r\right)$.
The darts closer to the base face belong to cells in $ex\left(e_i\left(d\right), r_{\min}\right)$ and $ex\left(e_i\left(d\right), r\right)$, while those closer to the top belong to cells in $ex\left(e_i\left(d\right), r_{\max}\right)$ and $ex\left(e_i\left(d\right), r\right)$.
This is natural when one considers that $\alpha_i$-linked darts differ only in one of their cells (\ie\ the $i$-cells), all other cells being the same for both darts.
This means that there must be a natural progression of layers of darts: starting from the base, they change their cells one by one from $ex\left(e_i\left(d\right), r_{\min}\right)$ to $ex\left(e_i\left(d\right), r\right)$ from the highest dimension down, and then change their cells one by one from $ex\left(e_i\left(d\right), r\right)$ to $ex\left(e_i\left(d\right), r_{\max}\right)$ from the lowest dimension up until reaching the top.

The algorithm to generate the extruded combinatorial structure therefore works by generating layers of darts that follow a pattern based on the darts in the input cell complex, starting from those for the base face, moving on to the $2n-2$ layers for the side faces, and finishing with the top face.
The output darts and the involutions between them are expressed in terms of the input generalised map $G$.
For this, a function $cur: G \rightarrow G^\prime$ maps a dart in $G$ to the corresponding dart in the currently being generated layer of the output map $G^\prime$.
Note that this means that the algorithm needs to keep track of only two layers of darts at any given time, one in $G$ and one in $G^\prime$, each of which has at most the number of darts in the input map.
This bounds the memory usage of this part of the algorithm, which is therefore on the order of $O(d)$, with $d$ the number of darts in the input space partition.

As shown by \citet{Ferrucci93}, when multiple intervals are involved this procedure can simply be repeated for all intervals, assuming that these have all been subdivided so as not to intersect one another.
However, it is possible to greatly reduce the number of darts generated by skipping the creation of some of the darts.
This is possible because the extrusion intervals have been independently propagated to each cell of every dimension.
Based on the algorithm, the lower-dimensional cells in the complex have received all the intervals from their incident higher-dimensional cells so that the intervals in the lower-dimensional cells contain all the endpoints of the intervals of their incidences.
However, the same is not true in the opposite direction: the intervals for the higher-dimensional cells have not been subdivided so as to contain all the ones of their incident lower-dimensional cells.
Nevertheless, as \reffig{fig:blocks} shows, even when an extrusion interval that would be used by the pattern described above is not in a cell, it is possible to map it to a \emph{bigger} interval that contains it.
If one considers the darts that would be generated using the above mentioned approach for all the non-intersecting intervals in the cell complex, but at the same time mapping the non-existent extrusion intervals to their immediately bigger containing ones, this can result in many darts that are equivalent (\ie\ they have nodes at the same cells).
These darts are those that can be skipped during the extrusion process.
\begin{figure*}[tbp]
\centering
\subfloat[]{
\includegraphics[width=0.45\linewidth]{figs/blocks-1}
\label{subfig:blocks-1}}
\quad
\subfloat[]{
\includegraphics[width=0.45\linewidth]{figs/blocks-2}
\label{subfig:blocks-2}}
\caption[The darts in the cell complexes in \reffig{fig:blockscomplex}]{The darts in the cell complexes in \reffig{fig:blockscomplex}.
Note that the darts of the right cube in (b), when viewed as individual stacks, are similar to the ones in \reffigs{fig:triangle} and~\ref{fig:stack}.
The darts of the left box are however different: those on the left all involve an extrusion along the interval $(a,c)$ due to the fact that there is no vertex, edge or facet extruded to $b$.
On the other hand, those in the right do have a vertex and an edge at $b$, but not a facet and still belong to the same volume.}
\label{fig:blocks}
\end{figure*}

Therefore, in order to generate the darts for all intervals of all cells, this procedure is repeated for all the intervals in $\rho$, after making them non-intersecting using the same procedure delineated in \refse{ss:propagation}, and skipping all the darts that would be equivalent to those that have already been created.
This is done using a sweep-hyperplane-like algorithm that generates up to $n$ layers of darts at the events at the beginning or end of an interval, creating darts only when the sweep-hyperplane\footnote{\ie\ a $(n-1)$-dimensional shape that is unbounded along $n-1$ dimensions in $n$D space, \eg\ a line in $\mathbb{R}^2$ or a plane in $\mathbb{R}^3$.} passes by the beginning or end of their extrusion intervals (\ie\ not while it is in their interior).
The darts are linked to their appropriate embedding according to the same pattern.
The complete procedure to generate the combinatorial structure is presented in \refalgo{algo:gmapextrusion}, which uses the \refalgo{algo:gmaplayerbase} when the sweep hyperplane passes by the beginning of an interval and the similar \refalgo{algo:gmaplayertop} when the sweep hyperplane by the end of one.
If an input dart is denoted as $d$, its corresponding dart in the currently being generated layer of the output is denoted as $cur(d)$, the dart linked to $d$ by an $i$-involution as $\alpha_{i}(d)$, and the $i$-embedding of $d$ as $e_{i}(d)$.

% \begin{figure}
\begin{algorithm}[tb]
\small
\SetKwInOut{Input}{Input}
\SetKwInOut{Output}{Output}
\DontPrintSemicolon\Input{generalised map $G$ of the input cell complex,\\
set $E$ of the embeddings in the input cell complex,\\
set $E^\prime$ of the embeddings for the output cell complex,\\
map $\rho$ of the extrusion intervals for all cells of the input complex,\\
map $ex$ that links an input embedding to its extruded embeddings}
\Output{generalised map $G^\prime$ of the output cell complex}
Compute an ordered set of non-intersecting intervals $r_{all}$ using all the intervals for all cells in $\rho$ \;
Consider a sweep plane that passes through all the intervals $r_{all}$ in increasing order along dimension $n$ \;
\If{the sweep plane passes by the beginning of an interval $r = (r_{\min}, r_{\max}) \in r_{all}$}{
  \For{$i \leftarrow n$ \KwTo$0$}{
    $\textsc{GMapLayerBegin}(G, G^{\prime}, i, E, E^{\prime}, \rho, r, ex)$ \;
  }
}
\If{the sweep plane passes by the end of an interval $r = (r_{\min}, r_{\max}) \in r_{all}$}{
  \For{$i \leftarrow 0$ \KwTo$n$}{
    $\textsc{GMapLayerEnd}(G, G^{\prime}, i, E, E^{\prime}, \rho, r, ex)$ \;
  }
}
\caption{\textsc{GMapExtrusion}}\label{algo:gmapextrusion}
\end{algorithm}
% \end{figure}

% \begin{figure}[tb]
\begin{algorithm}[tb]
\small
\SetKwInOut{Input}{Input}
\SetKwInOut{Output}{Output}
\DontPrintSemicolon\Input{generalised map $G$ of the input cell complex,\\
generalised map $G^\prime$ of the output cell complex,\\
dimension $i$ of the current layer,\\
% map $last$ that links a dart in $G$ to a dart in the most recent layer of $G^\prime$,\\
set $E$ of the embeddings in the input cell complex,\\
set $E^\prime$ of the embeddings of the output cell complex,\\
map $\rho$ of the extrusion intervals of all cells of the input complex,\\
current interval $r$,\\
map $ex$ that links an input embedding to its extruded embeddings}
\Output{generalised map $G^\prime$ of the output cell complex}
\ForEach{dart $d$ in $G$}{
  % \If{$r \subseteq \rho(e_{n-1}(d))$}{
  % \If{$\exists r^\prime \mid r \subseteq \rho(e_{n-1}(d), r^\prime)$}{
  \If{$\exists r^\prime \in \rho(e_{n-1}(d)) \mid r \subseteq r^\prime$}{
    % \If{$\rho(e_{i}(d), r_{\min}) \neq \emptyset$}{
    \If{$\exists r^{\prime\prime} \in \rho(e_{i}(d)) \mid r_{\min}^{\prime\prime} = r_{\min}$}{
      $last \leftarrow cur(d)$ \;
      $cur(d) \leftarrow$ new dart \;
      Put $cur(d)$ in $G^{\prime}$ \;
      $\alpha_{i+1}(cur(d)) \leftarrow last$ \;
      $\alpha_{i+1}(last) \leftarrow cur(d)$ \;
    }
  }
}
\ForEach{dart $d$ in $G$}{
  \If{$\exists r^\prime \in \rho(e_{n-1}(d)) \mid r \subseteq r^\prime$}{
    \If{$\exists r^{\prime\prime} \in \rho(e_{i}(d)) \mid r_{\min}^{\prime\prime} = r_{\min}$}{
      \For{$inv \leftarrow 0$ \KwTo$i-1$}{
        $\alpha_{inv}^{\prime}(cur(d)) \leftarrow cur(\alpha_{inv}(d))$ \;
        $\alpha_{inv}^{\prime}(cur(\alpha_{inv}(d))) \leftarrow cur(d)$ \;
      }
      \For{$inv \leftarrow i+2$ \KwTo$n$}{
        $\alpha_{inv}^{\prime}(cur(d)) \leftarrow cur(\alpha_{inv-1}(d))$ \;
        $\alpha_{inv}^{\prime}(cur(\alpha_{inv-1}(d))) \leftarrow cur(d)$ \;
      }
      \For{$emb \leftarrow 0$ \KwTo$i$}{
        $e_{emb}^{\prime}(cur(d)) \leftarrow ex(e_{emb}(d), r_{\min})$ \;
      }
      \For{$emb \leftarrow i+1$ \KwTo$n$}{
        $e_{emb}^{\prime}(cur(d)) \leftarrow ex(e_{emb-1}(d), r)$ \;
      }
    }
  }
}
\caption{\textsc{GMapLayerBegin}}\label{algo:gmaplayerbase}
\end{algorithm}
% \end{figure}

% \begin{figure}[tb]
\begin{algorithm}[tb]
\small
\SetKwInOut{Input}{Input}
\SetKwInOut{Output}{Output}
\DontPrintSemicolon\Input{generalised map $G$ of the input cell complex,\\
generalised map $G^\prime$ of the output cell complex,\\
dimension $i$ of the current layer,\\
% map $last$ that links a dart in $G$ to a dart in the most recent layer of $G^\prime$,\\
set $E$ of the embeddings in the input cell complex,\\
set $E^\prime$ of the embeddings of the output cell complex,\\
map $\rho$ of the extrusion intervals of all cells of the input complex,\\
current interval $r$,\\
map $ex$ that links an input embedding to its extruded embeddings}
\Output{generalised map $G^\prime$ of the output cell complex}
\ForEach{dart $d$ in $G$}{
\label{ln:newlayerbegin}
  % \If{$\exists r^\prime \mid r \subseteq \rho(e_{n-1}(d), r^\prime)$}{
  \If{$\exists r^\prime \in \rho(e_{n-1}(d)) \mid r \subseteq r^\prime$}{
    % \If{$\rho(e_{i}(d), r_{\max}) \neq \emptyset$}{
    \If{$\exists r^{\prime\prime} \in \rho(e_{i}(d)) \mid r_{\max}^{\prime\prime} = r_{\max}$}{
      $last \leftarrow cur(d)$ \;
      $cur(d) \leftarrow$ new dart \;
      Put $cur(d)$ in $G^{\prime}$ \;
      $\alpha_{i}(cur(d)) \leftarrow last$ \;
      $\alpha_{i}(last) \leftarrow cur(d)$ \;
    }
  }
}
\label{ln:newlayerend}
\ForEach{dart $d$ in $G$}{
  \If{$\exists r^\prime \in \rho(e_{n-1}(d)) \mid r \subseteq r^\prime$}{
    \If{$\exists r^{\prime\prime} \in \rho(e_{i}(d)) \mid r_{\max}^{\prime\prime} = r_{\max}$}{
      \For{$inv \leftarrow 0$ \KwTo$i-1$}{
\label{ln:setinvolutionsbegin}
        $\alpha_{inv}^{\prime}(cur(d)) \leftarrow cur(\alpha_{inv}(d))$ \;
        $\alpha_{inv}^{\prime}(cur(\alpha_{inv}(d))) \leftarrow cur(d)$ \;
      }
      \For{$inv \leftarrow i+2$ \KwTo$n$}{
        $\alpha_{inv}^{\prime}(cur(d)) \leftarrow cur(\alpha_{inv-1}(d))$ \;
        $\alpha_{inv}^{\prime}(cur(\alpha_{inv-1}(d))) \leftarrow cur(d)$ \;
      }
\label{ln:setinvolutionsend}
      \For{$emb \leftarrow 0$ \KwTo$i$}{
\label{ln:setembeddingsbegin}
        $e_{emb}^{\prime}(cur(d)) \leftarrow ex(e_{emb}(d), r_{\max})$ \;
      }
      \For{$emb \leftarrow i+1$ \KwTo$n$}{
        $e_{emb}^{\prime}(cur(d)) \leftarrow ex(e_{emb-1}(d), r)$ \;
      }
\label{ln:setembeddingsend}
    }
  }
}
\caption{\textsc{GMapLayerEnd}}\label{algo:gmaplayertop}
\end{algorithm}
% \end{figure}

For the latter two algorithms, lines~\ref{ln:newlayerbegin}--\ref{ln:newlayerend} show the generation of a new layer of darts and its linking to the previous one, lines~\ref{ln:setinvolutionsbegin}--\ref{ln:setinvolutionsend} show how the darts within the layer are linked based on the pattern of the input map, and lines~\ref{ln:setembeddingsbegin}--\ref{ln:setembeddingsend} show how the darts within the layer are related to their correct embeddings, which are also patterned after the embeddings in the input.

Notice that this method generates layers of darts in a grid-like fashion, each layer containing at most the number of darts in the input map, and calling \textsc{GMapLayerBegin} and \textsc{GMapLayerEnd} to create at most $2n$ layers per non-intersecting interval.
The time complexity of computing the set of non-intersecting intervals in \refalgo{algo:propagateintervals} is $O(r \log r)$ as before, while the number of darts in the output map is bounded by $O(ndr)$, where $n$ is the extrusion dimension, $d$ is the total number of darts in the input map and $r$ is the total number of intervals in the input.

\section{Implementation}
\label{se:extrusion-implementation}

The extrusion algorithm has been implemented in C++11 and made available under the open source MIT licence at \url{https://github.com/kenohori/lcc-tools}.
It requires and builds upon the CGAL packages Combinatorial Maps and Linear Cell Complex, among others.
The first package provides data structures and algorithms to store and to efficiently iterate over the darts of a combinatorial map, and the second links the 0-embeddings to other CGAL types in order to store the geometry of a model.

As the algorithm is described on the basis of generalised maps while the CGAL packages instead use combinatorial maps, all operations are done through a small wrapper that converts operations for the former to operations for the latter.
Since a combinatorial maps dart is equivalent to two generalised map darts (see \refse{ss:ordered-topological-models}), some redundant operations are ignored in the process, such as requests to create darts that already exist or to connect darts that are already connected.
These redundant operations are instead used as assertions to verify the validity of the map during its creation.

Both these packages and the implementation of the extrusion algorithm make heavy use of the traits programming technique \citep{Myers95} and recursive templates (TMP or template meta-programming) in order to produce efficient code.
These techniques are described in \refse{se:traits}.
One shortcoming of the current prototype implementation is that it uses the C++ type \texttt{std::map} in order to link cells to their extrusion intervals, which offers only logarithmic time access \citep[\S{}23.4]{ISO14882:2015}\footnote{See \citet{Austern00} for the consequences of this.}, rather than the constant time that would be possible by integrating this into the templated structures.
This would involve storing the set of extrusion intervals of a cell directly in the data structure that is used for its attributes.

In order to input and output data, as well as to visualise the results, the implementation uses the OGR Simple Feature Library\footnote{\url{http://gdal.org}} to read standard GIS data formats.
It is also able to output Wavefront OBJ\footnote{\url{http://www.martinreddy.net/gfx/3d/OBJ.spec}} files, in which faces or darts can be directly exported for visualisation.
In the latter case, darts are exported as triangles with vertices at the two 0-cells of a dart, as well as an added vertex at the centroid of its 2-cell.

\section{Experiments}
\label{se:extrusion-experiments}

The algorithm has been tested by extruding various 2D datasets to higher dimensions.
For this, several free and open datasets in the area of Delft are used, matching the geometries in some with the attributes present in others so as to obtain new attributes and appropriate extrusion intervals for each geometry.
The tests were performed on a Mac OS X computer with a 2.7 GHz Intel Core 2 Duo processor and 12 GB of RAM.\@
The main characteristics of the datasets tested are shown in \reftab{table:tests}.

\begin{table*}[tbp]
\caption[Extrusion test results]{Characteristics of the tested datasets. The cell counts represent the total number of cells for all dimensions.}
\centering
\small
\begin{tabular}{lccccc}
\toprule
& \multicolumn{2}{c}{Input} & \multicolumn{2}{c}{Output} & \\
\cmidrule(lr){2-3}
\cmidrule(lr){4-5}
Test & darts & cells & darts & cells & time \\
\midrule
One GBKN building to 5D & 14 & 29 & 80 640 & 783 & 3 s \\
370 buildings to 4D & 3 268 & 6 065 & 123 184 & 42 552 & 12 s \\
TOP10NL to 3D & 30 098 & 48 562 & 181 640 & 148 102 & 2 m 39 s\\
\bottomrule
\end{tabular}
\label{table:tests}
\end{table*}

Note however that since the implementation uses an \texttt{std::map} to access the extrusion intervals of each cell, the running time is dominated by the large number of times this query is performed (several times per interval and per cell).
The times provided in \reftab{table:tests} are therefore not indicative of the theoretical complexity of the algorithm, which is instead dominated by the generation and linking of the darts in the extruded dataset (\refse{ss:combinatorial}).
The generation of the non-intersecting intervals for all cells (\refse{ss:propagation}) and the generation of the extruded embeddings (\refse{ss:embeddings}) always ran in under a second, even for very large datasets.

\marginpar{
\captionsetup{type=figure}
\centering
\subfloat[]{
\includegraphics[width=\marginparwidth]{figs/aula-1}
\label{subfig:aula-1}}
\\
\subfloat[]{
\includegraphics[width=\marginparwidth]{figs/aula-2}
\label{subfig:aula-2}}
\caption[Extruding the footprint of the Aula Congress Centre in Delft to 3D]{Extruding the (a) footprint of the Aula Congress Centre in Delft to (b) a 3D representation showing individual darts. }
\label{fig:aula-ex}
}
One test involved the Aula Congress Centre in Delft, a building represented by a single polygon with 14 vertices extracted from the GBKN dataset\footnote{\url{http://www.gbkn.nl}}, as shown in \reffig{fig:aula-ex}.
It was extruded from 2D up to 5D using some manually added attributes: its height, construction date and a specified level of detail for the model.
\reffig{fig:aula4d} shows the extruded model at an intermediate stage in this process, in 4D.
The end result was a generalised map with 80 640 darts, 112 vertices, 280 edges, 260 facets, 110 volumes, 20 4-cells and 1 5-cell.
It was generated in 3 seconds using 15 MB of RAM.\@
\begin{figure*}[b]
\centering
\subfloat[]{
\includegraphics[width=0.33\linewidth]{figs/aula4d-ends}
\label{subfig:aula4d-ends}}
% \quad
\subfloat[]{
\includegraphics[width=0.33\linewidth]{figs/aula4d-sides}
\label{subfig:aula4d-sides}}
% \quad
\subfloat[]{
\includegraphics[width=0.33\linewidth]{figs/aula4d-top-bottom}
\label{subfig:aula4d-top-bottom}}
\caption[Extruding the footprint of the Aula Congress Centre in Delft to 4D]{The footprint of the Aula Congress Centre (\reffig{fig:aula-ex}) extruded twice to create a 4D model.
It is shown here in three parts for clarity: (a) the faces in the two end volumes, (b) the lateral faces connecting corresponding vertical edges, and (c) the top and bottom faces connecting corresponding horizontal edges.
Not shown here are the 16 different polyhedra that bound the polychoron and which are all bounded by different sets of these faces.}
\label{fig:aula4d}
\end{figure*}

Another test, shown in 2D and 3D in \reffig{fig:campus}, involved a previously generated dataset of the campus of the Delft University of Technology (see \citet{Ledoux11a}), consisting of 2 749 vertices, 2 946 edges, and 370 facets.
\begin{figure}[tb]
\centering
\subfloat[]{
\includegraphics[width=0.5\linewidth]{figs/campus}
\label{subfig:campus}}
% \quad
\subfloat[]{
\includegraphics[width=0.5\linewidth]{figs/campusextruded}
\label{subfig:campusextruded}}
\\
\subfloat[]{
\includegraphics[width=\linewidth]{figs/campusdarts}
\label{subfig:campusdarts}}
\caption{Extruding a dataset of the campus of the Delft University of Technology}
\label{fig:campus}
\end{figure}
This dataset, covering 2.3 km$^{2}$, was originally built from the GBKN dataset by manually forming footprint polygons from the lines in the dataset.
Building heights for each polygon were obtained from the AHN dataset\footnote{\url{http://www.ahn.nl}} (airborne laser altimetry), while building dates were obtained from the BAG dataset\footnote{\url{https://www.kadaster.nl/bag}}.
This dataset, including the added attributes, is available together with the source code of the program.
It was therefore extruded from its original 2D representation to 4D using building heights for the third dimension and dates for the fourth dimension.
The result was a generalised map with 123 184 darts, 8 613 vertices, 17 919 edges, 12 471 facets, 3 310 volumes and 239 4-cells.
It was generated in 12 seconds using 46 MB of RAM.\@

One more test used 1 836 buildings from Delft from the TOP10NL dataset\footnote{\url{http://www.kadaster.nl/web/artikel/producten/TOP10NL.htm}}, which was extruded to 3D using intervals from building dates also obtained from the BAG dataset.
The result was a generalised map with 181 640 darts, 46 464 vertices, 71 826 edges, 27 975 facets and 1 837 volumes.

An algorithm was used to verify that the constructed datasets conform to the definition of a combinatorial map\footnote{\ie\ checking that the links between darts correctly form partial permutations or involutions, and all the darts in the orbit of an $i$-cell are linked to its correct $i$-attribute and vice versa.}.
Additional tests were made to ensure that all the darts of an $i$-cell correctly point to it in their $i$-embeddings, and to verify that all the darts of an $n$-cell are linked to point embeddings within the extrusion interval given for the $n$-cell, among other tests.
The extruded datasets were also inspected visually in 2D and 3D by exporting 2-cells as polygons and verifying that they form a valid cell complex, \ie\ that 2-cells intersect only at their common boundaries, forming 1-cells that are also in the complex.
In 2D and 3D, individual darts were also exported as triangles to visually verify that they form a valid generalised map (as shown in \reffigs{subfig:aula-2} and~\ref{subfig:campusdarts}).

\section{Extrusion-based generalisation operations}
\label{se:extrusion-generalisation}

Apart from using extrusion to directly create finished higher-dimensional datasets, it is also interesting to explore the possibility to use it as a base for further operations.
For instance, it can be used as the basis of a simple set of dimension-independent generalisation operations.

Starting from a detailed $n$-dimensional cell complex, it is possible to first extrude the complex to create an $(n+1)$-dimensional cell complex, then to obtain the desired geometry by applying certain transformations to the vertices of the `top' or `bottom' facet of the extruded model, even if this procedure results in degenerate cells, and finally to remove the degenerate cells from the model.

The transformations that can be applied to the model include all those that can be applied through transformation matrices, such as those shown in \reffigp{fig:aula-transformations} (translation, rotation and scale), as well as others such as reflections and shears.
Perhaps more importantly, it is possible to gradually reduce the complexity of the model by collapsing cells of any dimension, which is achieved by simply moving all vertices of a cell to the same location, as is shown in \reffig{fig:aula-collapse}.
\marginpar{
\captionsetup{type=figure}
\centering
\subfloat[]{
\includegraphics[width=\marginparwidth]{figs/aula-collapse}
\label{subfig:aula-collapse}}
\\
\subfloat[]{
\includegraphics[width=\marginparwidth]{figs/aula-edge-collapse}
\label{subfig:aula-edge-collapse}}
\caption[Collapsing cells]{Cells can be collapsed by moving all of their vertices to the same location. Shown here are the collapse of: (a) a face and (b) an edge (in red).}
\label{fig:aula-collapse}
}

After such transformations, it is possible to easily detect and remove degenerate cells, as they can be identified because they have all their vertices at the same location.
In the case of a topological model, such as a generalised or combinatorial map, the topological relationships around the collapsed cells will have to be recomputed.
However, this is possible to achieve either by finding the changed incidences and adjacencies, or by regenerating all topological relationships using the method described in \refch{ch:incremental-construction}.
For the latter, it is simply necessary to ignore all degenerate cells (as defined by having all their vertices at the same embedding in $\mathbb{R}^n$).

\section{Conclusions}
\label{se:extrusion-conclusions}

Extrusion in the GIS sense has a natural extension into a dimension-independent formulation.
It can be used to load existing 2D or 3D data into a higher-dimensional structure, either directly or as a base for further (dimension-independent) operations, such as the generalisation operations described in \refse{se:extrusion-generalisation}.
The conceptual simplicity of extrusion makes it particularly suitable for higher-dimensional data, as the complex problem of its generation can be reduced to the definition of extrusion intervals per $n$-cell in an $n$-dimensional cell complex.
By ensuring that the input $n$-cells do not overlap---which is a general precondition in a geometric cell complex---, and the extrusion intervals per cell also do not overlap, it is easy to guarantee that the output cell complex forms a valid $(n+1)$-dimensional space partition.

The dimension-independent extrusion formulation has been realised into an algorithm, presented in this chapter, which supports multiple intervals per input object and it is also memory efficient---only three layers of darts of the same size as the input map need to be kept in main memory at the same time.
It is also relatively fast, with a worst case complexity of $O(ndr)$ in the main algorithm, where $n$ is the extrusion dimension\footnote{In practice a small constant.}, $d$ is the total number of darts in the input map and $r$ is the total number of intervals in the input, but offers better complexity in practice.

Moreover, the algorithm has been implemented using CGAL Combinatorial Maps and the source code has been made publicly available under a permissive licence.
It has also been tested with publicly available datasets commonly used in GIS.\@
Apart from being applied cell by cell, it can also be combined with other operations, such as the generalisation operations described here or building certain $n$D cells incrementally, where more complex models are required only for a subset of the objects in a model.

While the implementation presented here performs well enough for typical GIS datasets, it could be made faster by integrating the extrusion intervals into the embeddings of the cells, allowing for constant time access to the extrusion intervals.
This would make it possible to support much larger datasets and make the implementation match the theoretical complexity of the algorithm.
In order to improve memory usage, another possibility would be implementing the algorithm in a more compact representation of a simplicial complex, \eg\ \citet{Boissonnat12}.

In the future, it would be interesting to consider other types of models that can be generated using extrusion-like algorithms, such as sweeps and $n$-dimensional cells of revolution.
These are both simple extensions either using either non-linear embeddings or discretised approximations with small cells with linear geometries.
A more complex extension would involve starting from a \emph{series of cell complexes} that each form a planar partition, such as series of 3D models of the same region at different levels of detail.
While most of the algorithm described here should work directly on this latter example, managing the differing boundaries of the cells along the $n$-th dimension could be challenging---possibly requiring the computation of all intersections in an arrangement of $(n-1)$-cells.