\section{Transfer Learning}

In the experiments part of the paper was describe a practical use of the purpose of the project with transfer learning.

The formal definition of transfer learning is: \textquotedblleft Given a source domain $\mathcal{D}_{S}$, a corresponding source task $\mathcal{T}_{S}$, as well a target domain $\mathcal{D}_{T}$ and a target task $\mathcal{T}_{T}$, the objective of transfer learning now is to enable us to learn the target conditional probability distribution $\mathcal{P(Y_{T}|X_{T})}$ in $\mathcal{D}_{T}$ with the information gained from $\mathcal{D}_{S}$ to $\mathcal{T}_{S}$ where $\mathcal{D}_{S} \neq {D}_{T}$ or $\mathcal{T}_{S} \neq {T}_{T}$ "

So, transfer learning is a machine learning technique where a model trained on one task is re-purposed on a second related task. In the paper, the second related task is classification object and we chose to keep it.

The neural network for this part is the same of the first part, but we add an additional dense layer at the end, as in the paper.

We use the CFN weights that we have found at the end of the training of the CFN to initialize the \texttt{conv} layers of the standard AlexNet network. The other layers have Gaussian noise as initial weights. Then, those the \texttt{conv} layers are frozen during the process of training. In this way, this process allows rapid progress and improved performance when modelling the second task.

\begin{figure}[!ht]
    \centering
    \includegraphics[scale=0.50]{images/FT_net.png}
    \caption{Architecture of the transfer learning neural network.}
    \label{fig:FT_net}
\end{figure}

The transfer learning experiment that is describe in the paper use a dataset named \textquotedblleft PASCAL VOC 2007". This dataset has 20 classes and $9,963$ images. We chose to use a different dataset to compare the results at the end of the training.

We select a dataset named \textquotedblleft Food 101" \cite{food_images} that have 100 classes and 1000 of images for each class. We choose to use a \textit{.h5} file for it but to read the images from files. We provide to build a list of relative path to every image of the dataset with the corresponding associate class. Every class is traduce to an integer number.

The dataset was divided into 70\% training, 25\% validation and 5\% test.
We edit the images of the dataset in this way:

\begin{itemize}
    \item central squared crop of every image;
    \item resize at $225 \times 225$ pixel;
    \item random flip up/down and left/right;
    \item random contrast between 3 and 10.
\end{itemize}

% We aren't able to have some results for this part.

% Now we present a comparison between the results of those two databases:

% TODO: Tabella di confronto tra risultati Pascal e Food


\section{Vector space model}
\label{vect-vect-model}

\paragraph{Text transformation}
The first step to process queries on text is to transform
it into a model that can be computed by a machine.

Such a model should be suitable for any kind of text, should be able
to capture the semantic of words and then should support the notion of
\emph{text similarity}.

The main idea of a vector space model is to map documents in a vector,
so they appear as points in a certain space.

For instance, we can collect some words and index them, then build a vector
for each document $$d_k = [x_0, \dots, x_n]$$
where the value $x_i$ stores the occurrences of the word indexed with $i$
in that document.

\paragraph{Similarity}
This model somehow implements the notion of text similarity, represented
by some sort of distance function between two documents in space, perhaps
the \emph{Euclidean distance} or the difference between the angle of the two
vectors.
There are a lot of distance measures, and they vary in applications.
Some of them assume normalization in the document vectors.

\paragraph{Document-Term matrix}
If we arrange document vectors in a vector we obtain the
\emph{document-term matrix}, or the \emph{term-document matrix} if
we take the opposite.
The number of dimensions in the space is equal to the
number of words in the vocabulary. \\
That can be a problem without some sort of lemmatisation and stemming,
as sparsity and dimension of the matrix increases.

\paragraph{Vector length problem}
By considering the length of the vector in a similarity measure,
we are introducing some problems, let's just consider a text and its
abstract, the Euclidean distance would be huge, as most of the words do not
appear that often. \\
To solve the problem we can consider the \emph{Cosine similarity} or
normalize vector lengths.

The main phases in the generation of a vector space models are:
tokenization, normalization, weight, and indexing.

\subsection{Tokenization}
The goal is to split the text in words, for instance we could split the
document at the spaces.

In practice this can be obtained with \emph{Regex}, \emph{Corpus} based and \emph{Machine Learning} based
methods.
\subsection{Normalization}
\label{normalization}
The idea is to normalize each token, that could mean writing verbs in the normal
form, or plurals at the singular.

\paragraph{Stemming}
One form of normalization is stemming, that simply truncate words
to obtain singular or infinite forms.
The problems here could be creation of meaningless words and also
close words in meaning could be completely different. An example
is the \emph{Porter} stemming algorithm.

\paragraph{Lemmatisation}
Another way to normalize is to lemmatise,
It's similar to stemming, but the words are replaced with the dictionary
root, this also has a problem, indeed sometime mapping of same words to
different lemmas can happen. A way to lemmatise is to use a
\emph{Dictionary based} lemmatisation, or something more complicated
such as \emph{Wordnet}.

\paragraph{Wordnet}
Wordnet is a large lexical database, verbs, nouns, adjectives and adverbs are
grouped into cognitive synonyms, called synsets, each expressing
a different concept.
Synsets are connected to each other by conceptual relations and they are also
connected to a lemma.

\subsection{Term Weighting}
Weighting the words is a crucial point in text processing,
an easy way could be counting the frequency of the terms in the document.

\paragraph{Term frequency}
An example of weighing is the term frequency,
which counts the frequency of a term given a document:
\begin{itemize}
    \item \emph{Boolean}: so a 0 or 1 if the word is present or not
    \item \emph{Natural}: $\mathit{tf}_{t,d} = $  count of a specific word
    \item \emph{Log}: $1 + \log(\mathit{tf}_{t,d})$
    \item \emph{Augmented}: $0.5 + \frac{0.5\mathit{tf}_{t,d}}{\max_{t^\prime} \mathit{tf}_{t^\prime,d}}$
    \item \emph{Log average}:  $0.5 + \frac{0.5 \log(\mathit{tf}_{t,d})}{1 + \log(\mathit{avg}_{t^\prime} \mathit{tf}_{t^\prime,d})}$
    \item \emph{Max tf norm}: $k + (1-k)\frac{\mathit{tf}_{t,d}}{\mathit{tf}_{\max}(d)}$
\end{itemize}

\paragraph{Stop words problem}
A problem in this model is the excessive presence of stop words and punctuations.
To compensate, we can remove them in the normalization phase. \\
But sometimes the stop words can be important, for instance with phrasal verbs.
A solution can be to count the number of documents that contains that given word.

\paragraph{Inverse document frequency}
The idea is to count the number of documents that contains a
given words, and to prefer less frequent words: $$\mathit{idf} = \log\frac{N}{\mathit{df}_t}$$
There are many variants:
\begin{itemize}
    \item \emph{Smooth}: $\log(\frac{N}{1 + \mathit{df}_t}) + 1$
    \item \emph{Max}: $\log(\frac{\max_{t^\prime \in d} \mathit{df}_t}{1 + \mathit{df}_t}) + 1$
    \item \emph{Probabilistic}: $\log \frac{N - \mathit{df}_t}{\mathit{df}_t}$
\end{itemize}

\paragraph{TfIdf}
By multyplying term frequency and inverse term frequency we obtain this metric.
$$TfIdf(t, d) = \mathit{tf}_{t,d} \cdot \mathit{idf}_t$$
Regarding the value of terms:
\begin{itemize}
    \item the terms with a high \emph{TfIdf} usually appears in a small number of documents
    \item the metric is low when a term appears a few times in a document or when it appears in
    many documents
\end{itemize}


\documentclass{article}

\usepackage{arxiv}

\usepackage[utf8]{inputenc} % allow utf-8 input
\usepackage[T1]{fontenc}    % use 8-bit T1 fonts
\usepackage{hyperref}       % hyperlinks
\usepackage{url}            % simple URL typesetting
\usepackage{booktabs}       % professional-quality tables
\usepackage{amsfonts}       % blackboard math symbols
\usepackage{nicefrac}       % compact symbols for 1/2, etc.
\usepackage{microtype}      % microtypography
\usepackage{lipsum}		% Can be removed after putting your text content
\usepackage{amssymb,amsmath,amsthm}
\usepackage{listings}
\usepackage{graphicx}
\usepackage{subfig}
\usepackage{apacite}

\newtheorem{theorem}{Theorem}

\title{Sampling from the Bayesian poster of an agent-based model given partial observations}

%\date{September 9, 1985}	% Here you can change the date presented in the paper title
%\date{} 					% Or removing it

\author{
  Daniel Tang\\
  Leeds Institute for Data Analytics\thanks{This project has received funding from the European Research Council (ERC) under the European Union’s Horizon 2020 research and innovation programme (grant agreement No. 757455)}\\
  University of Leeds\\
  Leeds, UK\\
  \texttt{D.Tang@leeds.ac.uk} \\
  %% examples of more authors
  %% \AND
  %% Coauthor \\
  %% Affiliation \\
  %% Address \\
}

\begin{document}
\maketitle

\begin{abstract}
abstract
\end{abstract}

% keywords can be removed
\keywords{Data assimilation, Bayesian inference, Agent based model, Integer linear programming, predator prey model}

\section{Introduction}
%##########################################

Suppose we have a closed, convex polyhedron defined as
\begin{equation}
AX = B
\label{polyhedron}
\end{equation}
subject to
\[
x_i \in \mathbb{Z}_{\ge 0}
\]
for all $i$, where $X = x_1...x_n$. And a probability distribution over the space of X
\begin{equation}
P(X) = \prod_i \omega_i^{x_i}
\label{probability}
\end{equation}
Our aim is to sample from valid points (i.e. those that satisfy the constraints) with the given probability distribution.

\section{Tree sampling}
%######################
Suppose we have an oracle, $\Omega(M,Y)$, which (deterministically) returns some $X\in \mathbb{Z}_{\ge0}$ such that $MX=Y$ or returns some null vector if no such solution exists. We can use this oracle to find a solution with a given prefix (or to show that no such solution exists). Suppose we have a prefix vector $P$ of length $m$ so we can write equation \ref{polyhedron} as
\[
\begin{pmatrix}
R|S
\end{pmatrix}
\begin{pmatrix}
V \\
W
\end{pmatrix}
= B
\]
where $R$ consists of the first $m$ columns of $A$ and $S$ the last $n-m$ columns, then we have
\[
SW = B - RV
\]
so if we let $W = \Omega(S,B-RV)$ then either $W$ is the null vector (and no solution exists with $V$ as prefix) or
\[
AX = A\begin{pmatrix}
V \\
W
\end{pmatrix}
= B
\]
Given this, we can use the shorthand notation $\Omega_{AB}(V) = X$.

Consider now a tree whose nodes are associated with prefix vectors $V$. Each node is a valid prefix so induces a valid solution $X = \Omega_{AB}(V)$ is a valid solution. The children of a node with prefix $V$ and solution $X$ have prefixes of the form $V_c = (X_q|x)$ where $X_q$ is a prefix of $X$ of length $q$, where $q$ is greater than or equal to the length of $V$ and $x$ is a single element, adding one more dimension to the prefix such that $V_c \ne X_{q+1}$.

The root of the tree is the empty prefix, $\emptyset$, and all valid children of a parent are present in the tree, so the tree contains all valid solutions.

We can make this tree into a Markov chain by defining transition probabilities between nodes. Each node induces a target probability given by equation \ref{probability} on its induced solution. We also define the node's \textit{prefix probability} as
\[
P(V) = \prod_i \omega_i^{v_i}
\]
and a node's extension probability as
\[
P_e(V) = \omega_m^{v_m}
\]
where $m$ is the length of $V$ and $v_m$ is the $m^{th}$ element of $V$.

Given a node with prefix $V$, children $V'_1...V'_n$ and parent $V_p$, the probability of transition from parent to child $V'_q$ is given by
\[
\tau_{V\rightarrow V'_q} = CP_e(V'_q)
\]
the probability of transition to the node's parent is given by
\[
\tau_{V\rightarrow V_p} = \min\left(\tau_c, \frac{C_pP_e(V)P(X_p)}{P(X)}\right)
\]
and $C$ is a normalisation factor given by
\[
C =  \frac{1 - \tau_{V\rightarrow V_p}}{\sum_q P_e(V'_q)}
\]
given this, the acceptance probability of transition to the $q^{th}$ child is
\[
P_a = \min\left(1, \frac{P(X'_q)\tau_{V'_q\rightarrow V}}{P(X)\tau_{V\rightarrow V'_q}}\right)
\]
there are two regimes here: if
\[
\frac{CP_e(V'_q)P(X)}{P(X'_q)} < \tau_c
\]
then the acceptance probability is 1.

Acceptance probability of transition to parent is
\[
P_a = \min\left(1, \frac{P(X_p)\tau_{V_p\rightarrow V}}{P(X)\tau_{V\rightarrow V_p}}\right)
\]
which is 1 as long as
\[
\frac{C_pP_e(V)P(X_p)}{P(X)} < \tau_c
\]

In the case that a node is a leaf, then the probability of transition to parent, $\tau_{V\rightarrow V_p}$, must be 1 which means acceptance probability is
\[
\frac{P(X_p)C_pP_e(V)}{P(X)}
\]

%\bibliographystyle{unsrtnat}
%\bibliographystyle{apalike}
\bibliographystyle{apacite}
\bibliography{references}

\end{document}


\section{Variational Inference}
\label{sec:vb_eqns}

We derive the variational lower bound as follows:
\begin{flalign}
& \mathcal{L}(q) = \sum_{i=1}^{L} \mathbb{E}_{q}\left[ \log p\left( v_i \succ u_i | f(v_i), f(u_i) \right) \right] \nonumber&&\\
& + \mathbb{E}_{q}\left[ \log \frac{p\left( \bs f | \bs\mu, \bs K/s \right)}{q\left(\bs f\right)} \right]
+ \mathbb{E}_{q}\left[ \log \frac{p\left( s | a_0, b_0\right)}{q\left(s \right)} \right]
\label{eq:vblb}
\end{flalign}
Substituting the forms of the distributions with their variational parameters, we get:
\begin{flalign}
\mathcal{L}(q) = & \mathbb{E}_{q}\Bigg[ \sum_{i=1}^{L} [v_i \succ u_i]\log\Phi(z_i) && \nonumber\\
& + [v_i \prec u_i]\left(1-\log\Phi(z_i)\right) \Bigg] \nonumber&&\\
& + \log \mathcal{N}\left(\hat{\bs f}; \bs\mu, \bs K/\hat{s} \right)
- \log\mathcal{N}\left(\hat{\bs f}; \hat{\bs f}, \bs C \right) \nonumber&&\\
& + \mathbb{E}_{q}\left[ \log\mathcal{G}\left( s; a_0, b_0\right) - \log\mathcal{G}\left(s; a, b \right) \right]  &&
\end{flalign}
We now replace the likelihood with a Gaussian approximation:
\begin{flalign}
\mathcal{L}(q) & \approx  \mathbb{E}_{q}\left[ \mathcal{N}( \bs y | \Phi(\bs z), \bs Q) \right]
&\nonumber\\
& + \log \mathcal{N}\left(\bs f; \bs\mu, \bs K/\hat{s} \right) - \log\mathcal{N}\left(\bs f; \hat{\bs f}, \bs C \right)
&\nonumber\\
& + \mathbb{E}_q\left[ \log\mathcal{G}\left( s; a_0, b_0\right) - \log\mathcal{G}\left(s; a, b \right) \right] \nonumber&\\
& \approx  - \frac{1}{2} \left\{ L \log 2\pi + \log |\bs Q| - \log|\bs C| \right. \nonumber&\\
& \left. + \log|\bs K/s| + (\hat{\bs f} - \bs\mu)\hat{s}\bs K^{-1}
(\hat{\bs f} - \bs\mu) \right. \nonumber&\\
& \left. + \mathbb{E}_q\left[ (\bs y - \Phi(\bs z))^T \bs Q^{-1} (\bs y - \Phi(\bs z)) \right] \right\} \nonumber&\\
& - \Gamma(a_0) + a_0(\log b_0) + (a_0-a)\mathbb{E}[\log s] \nonumber&\\
& + \Gamma(a) + (b-b_0) \hat{s} - a \log b  &
\end{flalign}
Finally, we use a Taylor-series linearisation to make the remaining expectation tractable:
\begin{flalign}
\mathcal{L}(q) & \approx - \frac{1}{2} \left\{ L \log 2\pi + \log |\bs Q| - \log|\bs C| \right. \nonumber&&\\
& \left. + \log|\bs K/\hat{s}| + (\hat{\bs f} - \bs\mu)\hat{s}\bs K^{-1}(\hat{\bs f} - \bs\mu) \right. \nonumber&&\\
& \left. + (\bs y - \Phi(\hat{\bs z}))^T \bs Q^{-1} (\bs y - \Phi(\hat{\bs z}))\right\} \nonumber&&\\
& - \Gamma(a_0) + a_0(\log b_0) + (a_0-a)\mathbb{E}[\log s] \nonumber&&\\
& + \Gamma(a) + (b-b_0) \hat{s} - a \log b, &&
\label{eq:vblb_terms}
\end{flalign}
where $\Gamma()$ is the gamma function,
$\mathbb{E}[\log s] = \Psi(a) - \log(b)$, and $\Psi()$ is the digamma function.

The gradient of $\mathcal{L}(q)$ with respect to the lengthscale, $l_d$, is as follows:
\begin{flalign}
\nabla_{l_d} \mathcal{L}(q) & =  - \frac{1}{2} \left\lbrace
\frac{\partial \log|\bs K/\hat{s}|}{\partial l_d} - \frac{\partial \log|\bs C|}{\partial l_d}
\nonumber \right. \\
& \left.  - (\hat{\bs f}-\bs\mu)\hat{s} \frac{\partial K^{-1}}{\partial l_d} (\hat{\bs f}-\bs\mu)
\right\rbrace \nonumber & \\
%& = \frac{1}{2} \hat{s} \left\lbrace \frac{\partial \log |\bs C \bs K^{-1}|}{\partial l_d}
%\right. \\
%& \left.  - (\hat{\bs f}-\bs\mu) \bs K^{-1} \frac{\partial \bs K}{\partial l_d} \bs K^{-1} (\hat{\bs f}-\bs\mu)
%\right\rbrace  \nonumber \\
& =  -\frac{1}{2} \left\lbrace  \frac{\partial \log | \frac{1}{\hat{s}}\bs K \bs C^{-1} |}{\partial l_d} \right. \nonumber & \\
& \left.  + \hat{s} (\hat{\bs f}-\bs\mu) \bs K^{-1} \frac{\partial \bs K}{\partial l_d} \bs K^{-1} (\hat{\bs f}-\bs\mu)
\right\rbrace   &
%& =  - \frac{1}{2} \left\lbrace \frac{\partial \log|\bs K/s| }{\partial l_d} + \frac{\partial \log |\bs K^{-1}s + \bs G\bs Q^{-1}\bs G^T|}{\partial l_d}
%\right. \\
%& \left.  - \hat{s} (\hat{\bs f}-\bs\mu) \bs K^{-1} \frac{\partial \bs K}{\partial l_d} \bs K^{-1} (\hat{\bs f}-\bs\mu)
%\right\rbrace  \nonumber\\
%& =  -\frac{1}{2} \left\lbrace \frac{\partial \log |\bs I + \bs K/s\bs G\bs Q^{-1}\bs G^T|}{\partial l_d}
%\right. \\
%& \left.  - \hat{s} (\hat{\bs f}-\bs\mu) \bs K^{-1} \frac{\partial \bs K}{\partial l_d} \bs K^{-1} (\hat{\bs f}-\bs\mu)
%\right\rbrace  \nonumber
\end{flalign}
Using the fact that $\log | A | = \mathrm{tr}(\log A)$, $\bs C = \left[\bs K^{-1} - \bs G \bs Q^{-1} \bs G^T \right]^{-1}$, and $\bs C = \bs C^{T}$, we obtain:
\begin{flalign}
& =  -\frac{1}{2} \mathrm{tr}\left(\left(\hat{s}\bs K^{-1}\bs C\right) \bs G\bs Q^{-1}\bs G^T \frac{\partial \bs K}{\partial l_d}
\right) \nonumber \\
& + \frac{1}{2}\hat{s} (\hat{\bs f}-\bs\mu) \bs K^{-1} \frac{\partial \bs K}{\partial l_d} \bs K^{-1} (\hat{\bs f}-\bs\mu)  \nonumber\\
& =  -\frac{1}{2} \mathrm{tr}\left(\left(\hat{s}\bs K^{-1}\bs C\right)
\left(\bs C^{-1} - \bs K^{-1}/\hat{s}\right) \frac{\partial \bs K}{\partial l_d}
\right) \nonumber \\
& + \frac{1}{2}\hat{s} (\hat{\bs f}-\bs\mu) \bs K^{-1} \frac{\partial \bs K}{\partial l_d} \bs K^{-1} (\hat{\bs f}-\bs\mu).  \label{eq:gradient_ls}
\end{flalign}
Assuming a product over kernels for each feature, $\bs K=\prod_{d=1}^{D} \bs K_d$, we can compute the kernel gradient
as follows for the Mat\'ern $\frac{3}{2}$ kernel function:
\begin{flalign}
\frac{\partial \bs K}{\partial l_d} & = \prod_{d'=1,d'\neq d}^D K_{d} \frac{\partial K_{l_d}}{\partial l_d} \\
\frac{\partial K_{l_d}}{\partial l_d} & = \frac{3\bs |\bs x_d - \bs x_d'|^2}{l_d^3} \exp\left( - \frac{\sqrt{3} \bs |\bs x_d - \bs x_d'|}{l_d} \right)
\label{eq:kernel_der}
\end{flalign}
where $|\bs x_d - \bs x_d'|$ is the distance between input points.


\chapter{Background}
\label{chap:background}
\glsreset{nn}
%FIXME sections
This chapter provides some background concepts to understand the material
presented in this thesis.
We start Section \ref{sec:ddr} with a review about differential drive robots and
their kinematics, providing some useful notions about the types of sensors used
and finally summarising the theory of control.
We conclude with a refresher on \glspl{nn}, in Section \ref{sec:nn}.

\section{Differential drive robots}
\label{sec:ddr}
\glsreset{icc}
The robot we use for this study is Thymio II, a non-holonomic differential drive
robot.

A differential wheeled vehicle is mobile robot, that typically consists of a rigid
body
\begin{figure}[!htb]
	\centering
	\includegraphics[width=.55\textwidth]{contents/images/Non-holonomic-differential-drive-mobile-robot}
	\caption[Non-holonomic differential drive mobile robot.]{Configuration of a
		non-holonomic differential drive mobile robot
		\cite[][]{shojaei2011adaptive}.}
	\label{fig:differentialdrive}
\end{figure}

\noindent
and a mobile base with a system of wheels that allows movement in the
environment.
Its movements are based on two, independently powered and
controlled, fixed wheels, placed on either side of the robot body, with a common
axis of rotation, and one passive caster wheel, whose job is to keep the robot
statically balanced.
Thus, both drive and steering functions are provided. In fact, it is possible to
impose different values of velocity for the two fixed wheels, allowing the robot to
rotate and move back and forth \cite[][]{siciliano2010robotics}. It is important to
note that the robot is non-holonomic since it cannot translate laterally.

The \gls{icc}, is the point which lies along the horizontal axis, common to the left
and right wheels, perpendicular to the plane of each wheel. Its position changes
over time as a function of the individual wheel velocities, in particular of their
relative difference. Since the rate of rotation $\omega$ is the same for both
wheels, the following expressions hold:
\begin{Equation}[!h]
	\centering
	\begin{equation}
	\omega \, (R + b) = V_{rx}
	\end{equation}
	\begin{equation}
	\omega \, (R - b) = V_{lx}
	\end{equation}
	\caption[Right and left linear velocities of a differential drive robot.]{Right and
	left linear velocities of a differential drive robot, computed as function of the
	rotation rate, the distance between the wheels, and the distance from the
	\gls{icc} and the robot reference point.}
	\label{eq:velocities}
\end{Equation}

\noindent
where $b$ is the distance between the centres of the two wheels, $V_{rx}$ and
$V_{lx}$ are the right and left wheel velocities, and $R$ is the signed distance
from the \gls{icc} to the midpoint between the wheels $P_O$
\cite[][]{dudek2010computational}.
Moreover, at any specific time instant $t$ we can compute $R$ and  $\omega$ as
follows:
\begin{Equation}[!h]
	\centering
	\begin{equation}
	R = b \, \frac{V_{rx} + V_{lx}}{V_{rx} - V_{lx}}
	\end{equation}
	\caption[Function to compute the distance from the ICC to the robot
	reference point.]{Function to compute $R$, the signed distance from the
	\gls{icc} to the midpoint between the wheels $P_O$, or robot reference point,
	using the right and left linear velocities and the distance between the centres of
	the two wheels.}
	\label{eq:r}
\end{Equation}

\begin{Equation}[!h]
	\centering
	\begin{equation}
	\omega = \frac{V_{rx} - V_{lx}}{2b}
	\end{equation}
	\caption[Function to compute the angular velocity of the robot.]{Function to
	compute $\omega$, the angular velocity of the robot, using the right and left
	linear velocities and the distance between the centres of the two wheels.}
	\label{eq:omega}
\end{Equation}

\bigskip
As a consequence, by varying the speed of the two wheels, $V_{rx}$ and
$V_{lx}$, the trajectories that the robot takes changes as well:
\begin{itemize}
	\item $V_{rx} = V_{lx}$: if the same speed is set to both wheels, we have a
	forward linear motion in a straight line. $R$ becomes infinite, and there
	is effectively no rotation $\omega = 0$.

	\item $V_{rx} = - V_{lx}$: if both wheels are driven with equal speed but in the
	opposite direction, we have a rotation about the midpoint of the wheel axis, or
	in-place rotation. $R=0$, the \gls{icc} coincide with $P_O$ and $\omega = -
	\frac{V}{b}$.

	\item $V_{lx} = 0$: if the left wheel is not powered, we have a
	counter-clockwise rotation about the left wheel. $R=b$ and
	$\omega=\frac{V_{rx}}{2b}$.

	\item $V_{rx} = 0$: if the right wheel is not powered, we have a clockwise
	rotation about the right wheel. $R=-b$ and $\omega=-\frac{V_{lx}}{2b}$.
\end{itemize}

Differential drive robots, however, are sensitive to slight changes in velocity, and
even small errors can affect the robot trajectory. Moreover, they are also
susceptible to variations in the ground.

\subsection{Sensors}
\label{subsec:sensors}

A significant feature of the Thymio II robot, is the a large number of sensors with
which it is equipped.

The adoption of external sensing mechanism is of crucial importance to allow a
robot to interact with its environment and achieve high-performance
\cite[][]{fu1987robotics, siciliano2010robotics}.

It is possible to classify the sensors in two principal categories, according to their
function: \emph{proprioceptive} sensors, that measure the internal state and deal
with the the detection of variables used for the control, such as the robot position,
and \emph{exteroceptive} sensors that measure the external state of the
environment, dealing with the detection of variables such as range and proximity,
often used for robot guidance as well as object detection.

For the purposes of this thesis we are interested in the study of proximity sensors,
in particular the \gls{ir} sensors, that used by Thymio II.

Proximity sensors are an example of exteroceptive sensors: they gather
information from the environment around the robot, such as distance to objects.
They are
also \emph{active} sensors: they emit their own energy, usually light, and measure
the reflection.
Among the advantages of this type of sensors is the fact that the infrared
beams generated by the sources can be used unobtrusively, since they are
invisible to the human eye.

\gls{ir} sensors are composed of an emitter, which radiates invisible infrared light,
and a receiver, that measures the intensity of the reflection and the quantity of
light that comes back.
If the reflection is strong enough — a large part of the light is reflected from
the object and returns to the robot — it can be inferred that the obstacle is
relatively close and lies within a certain range of the sensor, depending on
the received intensity. If the object is farther away, only a small
part of the light comes back \cite[][]{fu1987robotics}.
However, this estimate can be significantly affected by some property of the
obstacle, such as its colour and reflectivity, but also by the presence of external
light sources and the temperature of the environment — e.g. a black object
reflects less light than a white one, placed at the same distance
\cite[][]{mordechai2018elements}.

\subsection{Control theory}
\label{subsec:control}
The problem of controlling a robot is of a primary importance: to achieve a given
task, an agent must acts based on the perception received from the environment.
To do so, robots use a controller that takes decisions according to algorithms
developed to accomplish the goal.

We can distinguish two main techniques of control: \emph{open-loop control}
sets in advance the parameters of the algorithm and never observes the result of
its actions to adjust them to the actual state, \emph{closed-loop control} or
feedback-based control, measures the error between the desired state of the
system and the actual one, and uses this feedback to to adjust the control and
decide the next action to take \cite[][]{mordechai2018elements}.

These methods can be used to compute trajectories that lead the robot from an
initial configuration to a final one. To achieve a more appropriate behaviour we
are interested in the use of closed-loop control systems
\cite[][]{siegwart2011introduction}.

\begin{figure}[!htb]
	\centering
	\includegraphics[width=.8\textwidth]{contents/images/closed-loop-control-system}
	\caption{Closed-loop control system.}
	\label{fig:closedloopcontrol}
\end{figure}
This model can be formally defined using the variables introduced below:
\begin{itemize}
	\item $x(t)$, called command or set point (SP), represents the reference
	value, or a desired output. It cannot be imposed directly on the robot, instead it
	is transformed into a control value $u(t)$.

	\item $u(t)$, called control variable, is the output of the control and the
	input of the robot.

	\item $y(t)$, called process variable (PV), represents an observable part of the
	the actual state of the robot. It is the feedback signal combined with the set
	point to compute the error value.

	\item $e(t)$ is the error. It is computed as the difference between the value of
	the set point and the process variable, as shown in Equation
	\ref{eq:systemerror}. The error is used to generate the new control signal $u(t)$.
	\begin{Equation}[!h]
		\centering
		\begin{equation}
		e(t) = x(t) - y(t)
		\end{equation}
		\caption{Calculation of the error value $e(t)$ of the system.}
		\label{eq:systemerror}
	\end{Equation}
\end{itemize}

The closed-loop control algorithms sometimes can be very sophisticated. For the
purpose of this study, we design two algorithms, the first one is a \gls{pid}
controller, while the second a Bang Bang controller.

The implementation of any feedback controller requires the availability of the
robot configuration at each time instant.

\subsubsection{Proportional (P) controller}
\label{subsubsec:pid}

Considering real situations in which agents do not have access to their states but
only to their local observations, the controller we design for achieve the goal of
the first task is a Proportional (P) Controller,  a particular variant of \gls{pid}
Controller, with only the $K_p$ term, more details are provided in the Section
\ref{subsubsec:manualtask1}.

The closed-loop control uses a feedback to adjust the control while the action
takes place in proportion to the existing error. This function, given a desired
output $x(t)$, or set point, produces an output $y(t)$, or process variable, such
that the error $e(t)$ is obtained as the difference between the value of the set
point and the process variable. Finally, the control variable $u(t)$ is the output of
the \gls{pid} controller and is computed as follows:
\begin{Equation}[!h]
	\centering
	\begin{equation}
	u(t) = K_p * e(t)
	\end{equation}
	\caption[Proportioal PID controller.]{Proportional \gls{pid} controller.}
	\label{eq:pid}
\end{Equation}

The value of the proportional gain can be tuned to yield satisfactory
performance so that the system is stable.

\subsubsection{Bang-bang controller}
\label{subsubsec:bangbang}
The controller we design to achieve the goal of the first task, of which more
details are provided in the Section \ref{subsubsec:experttask1}, is a variant of the
Bang-bang algorithm.

In this case we considered instead a situation in which agents have access to their
states: given the set point and the variable measured, the goal and the actual
position of the robot, the error is computed as the difference between the two
quantities.
What we want to achieve is that the error is 0, to do so, when the error is negative,
the robot should move forward to reach the goal, on the contrary if is positive it
should move backwards. Its main feature is that the motor powers are turned to
full forwards or full backwards depending on the sign of the error.

This approach has many advantages, such as its simplicity and no need for
calibration.
However, since this controller is not always precise, especially when a derivative
term is needed to avoid oscillations or when we are in steady-state, close to
desired value, we implemented a variant that moves the the robot at full speed
unless they are closer than a certain value, avoiding to approach the goal at full
speed and overshoot it.

\section{Artificial Neural Networks}
\label{sec:nn}
In the field of \gls{ml}, \glspl{ann} are mathematical models based on the
simplification of Biological Neural Networks \cite[][]{zou2008overview}.

%FIXME missing reference of the image
\begin{figure}[htb]
	\centering
	\includegraphics[width=.7\textwidth]{contents/images/Neuron}
	\caption{Structure of a Biological Neuron.}
	\label{fig:bioneuron}
\end{figure}

A \gls{nn} can be considered as a dynamic system having the topology of an
oriented graph, whose nodes model the neurons in a biological brain, while the
edges represent the synapses — interconnections of information.
Each connection can transmit a signal from one artificial neuron to another,
which are typically aggregated in layers. The stimuli are received by a level of
input nodes, called processing unit, which processes the signal and transmits it to
other neurons connected to it.

As we anticipated, \glspl{nn} can be seen as mathematical models that define a
function $f : X \rightarrow Y$.
The network function of a neuron $f(x)$ is defined as a composition of
other functions $g_i(x)$, which can in turn be decomposed into others.
A widely used representation for the description of traditional \glspl{ann} is the
weighted sum, shown in Equation \ref{eq:mathmodel}.

\begin{Equation}[!h]
	\centering
	\begin{equation}
	f(x)=\phi \bigg( \sum_{i}w_{i}x_i + \theta \bigg)
	\end{equation}
	\caption[Mathematical description of traditional \glspl{ann}.]{Function that
	describes mathematically the traditional \glspl{ann} in terms of weighted sum.}
	\label{eq:mathmodel}
\end{Equation}
Each input signal $x_i$ is multiplied by its corresponding weight $w_{i}$, which
assumes a positive or negative value depending on whether you want to excite or
inhibit the neuron.
The bias $\theta$ varies according to the propensity of the neuron to activate,
influencing its output.
Additionally, a predefined function $\phi$ can be applied, also called activation
function, which is explained in the following paragraph.

\begin{figure}[htb]
	\centering
	\includegraphics[width=.7\textwidth]{contents/images/ArtificialNeuronModel}
	\caption{Mathematical model of an Artificial Neuron.}
	\label{fig:neuron}
	\vspace{-0.5cm}
\end{figure}

\subsection{Activation functions}
\label{subsec:activationfun}

An activation function is a fundamental component of the model. It allows the
network to learn non-linear transformations, in order to be able to compute
non-trivial problems.
In the course of this study, we used two of the most popular activation functions
in deep learning, the {hyperbolic tangent} (Tanh) \cite[][]{kalman1992tanh}
and the {sigmoid} \cite[][]{han1995influence}, visualised in Figure
\ref{fig:activation}.

\paragraph*{Tanh}
The tanh is a zero-centred function, whose range lies between $(-1, 1)$, and its
output is given by the following formula:
\begin{Equation}[H]
	\centering
	\begin{equation}
	f(x)= \frac{\sinh (x)}{\cosh (x)} = \bigg( \frac{e^x - e^{-x}}{e^x +
		e^{-x}}\bigg)
	\end{equation}
	\caption{Hyperbolic Tangent Function (Tanh).}
	\label{eq:tanh}
\end{Equation}

\paragraph*{Sigmoid}
The sigmoid models the frequency of the stimuli emitted by an inactive neuron,
$\sigma(x)=0$, to one fully saturated with the maximum activation frequency,
$\sigma(x)=1$. Its  output is given by the following formula:
\begin{Equation}[H]
	\centering
	\begin{equation}
	\sigma(x)= \frac{1}{1 + e^{-x}}
	\end{equation}
	\caption{Sigmoid Function.}
	\label{eq:sigmoid}
\end{Equation}

\begin{figure}[!htb]
	\begin{center}
		\begin{subfigure}[h]{0.495\textwidth}
			\includegraphics[width=.8\textwidth]{contents/images/sigmoid2}
			\caption{Tanh activation function.}
		\end{subfigure}
		\hfill
		\begin{subfigure}[h]{0.495\textwidth}
			\includegraphics[width=.8\textwidth]{contents/images/tanh2}
			\caption{Sigmoid activation function.}
		\end{subfigure}
	\end{center}
	\caption{Trends of two non-linear activation functions.}
	\label{fig:activation}
\end{figure}

%\section{Architetture}
%\label{sec:architetture}
%
%I neuroni vengono organizzati in una struttura detta architettura della rete.
%I dati, partendo da un livello iniziale, chiamato layer di input, attraversano i
%multipli strati interni della rete, gli hidden layer, raggiungendo l'ultimo livello
%detto layer di output.
%
%Quando i collegamenti tra i neuroni formano una struttura senza cicli si parla di
%reti \emph{feed-forward} \cite{svozil1997introduction}.
%
%\subsection{Layer fully-connected}
%\label{subsec:fc}
%
%Un’architettura molto comune nelle reti neurali è una struttura ``densa'', che
%utilizza \emph{layer fully-connected}, in cui tutti i neuroni del livello precedente
%sono collegati ad ogni neurone dello strato successivo
%\cite{sainath2015convolutional}.
%
%Lo scopo di un layer completamente connesso è imparare combinazioni non
%lineari di feature ad alto livello provenienti dal layer precedente.
%Una struttura di questo tipo è però caratterizzata da un numero di connessioni
%che cresce molto velocemente, causando un accrescimento del numero di
%parametri che la rete deve apprendere.
%Questo comporta un aumento del costo computazionale e un alto rischio di
%overfitting, approfondito nella sezione \ref{subsec:overfitting}.
%
%Per questo motivo questi vengono spesso sostituiti dai layer convoluzionali.

\subsection{Loss functions}
\label{subsec:lossfunctions}
\glsreset{mse}
\glsreset{bce}
The learning process is structured as a non-convex optimisation problem in which
the aim is to minimise a cost function, which measures the distance between a
particular solution and an optimal one.

In the course of this study we used two different objective functions, depending
on the strategy to be adopted: to solve the first task, that can be modelled as a
regression problem, we used the \gls{mse} \cite[][]{wang2009mean}, while for the
second, that is a binary classification problem, we used the \gls{bce}
\cite[][]{gomez2018understanding}.

\paragraph*{Mean Squared Error}
The \gls{mse} computes the deviation between the values observed $\hat y_i$ and
those predicted by the network $y_i$, over the number of predictions $n$, as
shown in Equation \ref{eq:mse}.
\begin{Equation}[!htb]
	\centering
	\begin{equation}
	\mathtt{MSE} = \frac{\sum_{i=1}^n (y_i-\hat y_i)^2}{n}
	\end{equation}
	\caption{Mean Squared Error (MSE) loss function.}
	\label{eq:mse}
\end{Equation}
Formally, this criterion measures the average of squared error between
predictions and targets, and learns to reduce it by penalising big errors in the
model predictions.

\paragraph*{Binary Cross Entropy}
The \gls{bce} is a combination of the sigmoid activation and the \gls{ce}. It sets up
a binary classification problem between two classes, with the following
formulation:

\begin{Equation}[!htb]
	\centering
	\begin{equation}
	\mathtt{BCE} = -\frac{1}{n} \sum_{i=1}^n y_i \cdot \log(\hat y_i) + (1-y_i)
	\cdot \log(1 - \hat y_i)
	\end{equation}
	\caption[Binary Cross Entropy (BCE) loss function.\bigskip]{Binary Cross
	Entropy
	(\gls{bce}) loss function \cite[][]{sadowski2016notes}.}
	\label{eq:bce}
\end{Equation}

\noindent
where $\hat y_i$ is the $i$-th scalar value in the model output, $y_i$ is the
corresponding target value, and $n$ is the number of scalar value in the model
output\footnote{\url{https://peltarion.com/knowledge-center/documentation/modeling-view/build-an-ai-model/loss-functions/binary-crossentropy}}.

This loss function should return high values for bad predictions and low values for
good ones.

\subsection{Optimisation algorithms}
\label{subsec:optimiser}
Optimisation algorithms are needed to minimise the result of a given objective
function, which depends on the parameters the model has to learn during
training.
They strongly influence the effectiveness of the learning process as they update
and calculate the appropriate and optimal values of that model.
In particular, the extent of the update is determined by the learning rate, which
guarantees convergence to the global minimum, for convex error surfaces, and to
a local minimum, for non-convex surfaces.

\paragraph*{Adam}

The optimiser we have chosen for this thesis project is Adam, {an algorithm for
first-order gradient-based optimisation of stochastic objective functions, based
on adaptive estimates of lower-order moments} \cite[][]{kingma2014adam,
loshchilov2017decoupled}.


\documentclass[11pt,oneside]{article}	%use"amsart"insteadof"article"forAMSLaTeXformat
\usepackage{geometry}		%Seegeometry.pdftolearnthelayoutoptions.Therearelots.
\geometry{letterpaper}		%...ora4paperora5paperor...
%\geometry{landscape}		%Activateforforrotatedpagegeometry
%\usepackage[parfill]{parskip}		%Activatetobeginparagraphswithanemptylineratherthananindent
\usepackage{graphicx}				%Usepdf,png,jpg,orepswithpdflatex;useepsinDVImode
								%TeXwillautomaticallyconverteps-->pdfinpdflatex
\usepackage{amssymb}
\usepackage[colorlinks]{hyperref}

%----macros begin---------------------------------------------------------------
\usepackage{color}
\usepackage{amsthm}
\usepackage{amsmath}

\def\conv{\mbox{\textrm{conv}\,}}
\def\aff{\mbox{\textrm{aff}\,}}
\def\E{\mathbb{E}}
\def\R{\mathbb{R}}
\def\Z{\mathbb{Z}}
\def\tex{\TeX}
\def\latex{\LaTeX}
\def\v#1{{\bf #1}}
\def\p#1{{\bf #1}}
\def\T#1{{\bf #1}}

\def\vet#1{{\left(\begin{array}{cccccccccccccccccccc}#1\end{array}\right)}}
\def\mat#1{{\left(\begin{array}{cccccccccccccccccccc}#1\end{array}\right)}}

\def\lin{\mbox{\rm lin}\,}
\def\aff{\mbox{\rm aff}\,}
\def\pos{\mbox{\rm pos}\,}
\def\cone{\mbox{\rm cone}\,}
\def\conv{\mbox{\rm conv}\,}
\newcommand{\homog}[0]{\mbox{\rm homog}\,}
\newcommand{\relint}[0]{\mbox{\rm relint}\,}

%----macros end-----------------------------------------------------------------

\title{Hypercuboidal grids and topological products in LARCC
\footnote{This document is part of the \emph{Linear Algebraic Representation with CoChains} (LARCC) framework~\cite{cclar-proj:2013:00}. \today}
}
\author{LARCC team}
%\date{}							%Activatetodisplayagivendateornodate

\begin{document}
\maketitle
\nonstopmode

\begin{abstract}
Here we develop an efficient implementation of multidimensional grid generation of cuboidal and simplicial cell complexes, and a fast implementation of the more general Cartesian product of cellular complexes. Both kind of operators, depending on the dimension of their input, may generate either full-dimensional (i.e.~solid) output complexes or cellular complexes of dimension $d$ embedded in Euclidean space of dimension $n$, with $d\leq n$.
\end{abstract}

\tableofcontents
\newpage

\section{Introduction}

This report aims to discuss the design and the implementation of the \texttt{largrid} module of the LAR-CC library, including also the Cartesian product of general cellular complexes.
In particular, we show that both $n$-dimensional grids of (hyper)-cuboidal cells and their  $d$-dimensional skeletons ($0\leq d\leq n$), embedded in $\E^n$, may be properly and efficiently generated by assembling the cells produced by a number $n$ of either $0$- or $1$-dimensional cell complexes, that in such lowest dimensions coincide with simplicial complexes.

In Section~\ref{sec:0-1-complexes} we give the simple implementation of generation of lower-dimensional (say, either 0- or 1-dimensional) regular cellular complexes with integer coordinates.
In Section~\ref{sec:cuboids} a functional decomposition of the generation of either full-dimensional cuboidal complexes in $\E^n$ and of their $d$-skeletons ($0\leq d\leq n$) is given, showing in particular that every skeleton can be efficiently generated as a partition in cell subsets produced by the Cartesian product of a proper disposition of 0-1 complexes, according to the binary representation of a subset of the integer interval $[0,2^n]$.
In Section~\ref{sec:product} we provide a very simple and general implementation of the topological product of \emph{two} cellular complexes of any topology. When applied to embedded linear cellular complexes (i.e.~when the coordinates of 0-cells of arguments are fixed and given) the algorithm produces a Cartesian product of its two arguments.
In Section~\ref{sec:largrid} the exporting of the module to different languages is provided.
The Section~\ref{sec:tests} contains the unit tests associated to the various algorithms, that are exported by the used literate environment in the proper test subdirectory---depending on the implementation language.
In Section~\ref{sec:indices} the indexing structure of the macro sources and variables is exposed by the sake of the reader.
The Appendix~\ref{sec:utilities} contains some programming utilities possibly needed by the developers.

\section{0D- and 1D-complexes}
\label{sec:0-1-complexes}

We are going to use 0- and 1-dimensional cell complexes as the basic material for several operations, including generation of simplicial and cellular grids and topological and Cartesian product of cell complexes.

\subsection{Generation of cells}

\paragraph{Uniform 0D complex}
The \texttt{grid0} second-order function generates a 0-dimensional uniform complex embedding $n+1$ equally-spaced (at unit intervals) 0-cells within the 1D interval. It returns the cells of this 0-complex.

%-------------------------------------------------------------------------------
@d Generation of uniform 0D cellular complex
@{def grid0(n):
    cells = AA(LIST)(range(n+1))
    return cells
@}
%-------------------------------------------------------------------------------

\paragraph{Uniform 1D complex}
A similar \texttt{grid1} function returns a uniform 1D cellular complex with $n$ 1D \texttt{cells}.

%-------------------------------------------------------------------------------
@d Generation of uniform 1D cellular complex
@{def grid1(n):
    ints = range(n+1)
    cells = TRANS([ints[:-1],ints[1:]])
    return cells
@}
%-------------------------------------------------------------------------------

\paragraph{Uniform 0D or 1D complex}
A \texttt{larGrid} function is finally given to generate the LAR representation of the cells of either a 0- or a 1-dimensional complex, depending on the value of the \texttt{d} parameter, to take values in the set $\{0,1\}$, and providing the \emph{order} of the output complex.
%-------------------------------------------------------------------------------
@d Generation of cellular complex of 0/1 dimension $d$
@{def larGrid(n):
    def larGrid1(d):
        if d==0: return grid0(n)
        elif d==1: return grid1(n)
    return larGrid1
@}
%-------------------------------------------------------------------------------

\subsection{Generation of embedding vertices}

\paragraph{Generation of grid vertices}
The second-order \texttt{larSplit} function is used to subdivide the real interval $[0,dom]$ into $n$ equal parts. It returns the list of $n+1$ \texttt{vertices} 1D of this decomposition, each represented as a singleton list.

%-------------------------------------------------------------------------------
@d Generation of vertices of decompositions of 1D intervals
@{def larSplit(dom):
    def larSplit1(n):
        # assert n > 0 and isinstance(n,int)
        item = float(dom)/n
        ints = range(n+1)
        items = [item]*(n+1)
        vertices = [[int*item] for (int,item) in zip(ints,items)]
        return vertices
    return larSplit1
@}
%-------------------------------------------------------------------------------

\section{Cuboidal grids}
\label{sec:cuboids}

More interesting is the generation of \emph{hyper-cubical grids} of intrinsic dimension $d$ embedded in $n$-dimensional space, via the Cartesian product of $d$ 1-complexes and $(n-d)$ 0-complexes. When $d=n$ the resulting grid is said \emph{solid}; when $d=0$ the output grid is 0-dimensional, and corresponds to a grid-arrangement of a discrete set of points in $\E^n$.

\subsection{Full-dimensional grids}

\subsubsection{Vertex generation}

First the grid vertices are produced by the \texttt{larVertProd} function, via Cartesian product of vertices of the $n$ 1-dimensional arguments (vertex lists in \texttt{vertLists}), orderly corresponding to $x_0$, $x_1$, ..., $x_{n-1}$ in the output points $(x_0, x_1,\ldots,x_{n-1})$.
%-------------------------------------------------------------------------------
@d Generation of grid vertices
@{def larVertProd(vertLists):
    return AA(CAT)(CART(vertLists))
@}
%-------------------------------------------------------------------------------

\subsubsection{Mapping of indices to storage}

\paragraph{Multi-index to address transformation}
The second-order utility \texttt{index2addr} function transforms a \texttt{shape} list for a multidimensional array into a function that, when applied to a multindex array, i.e.~to a list of integers within the \texttt{shape}'s bounds, returns the integer address of the array component within the linear storage of the multidimensional array.

The transformation formula for a $d$-dimensional array with \texttt{shape} $(n_0,n_1,...,n_{d-1})$ is a linear combination of the 0-based\footnote{0-based array, like in C, java and python, as opposed to 1-based, like in fortran or matlab.} multi-index $(i_0,i_1,...,i_{d-1})$ with \texttt{weights} equal to $(w_0,w_1,...,w_{d-2},1)$:
\[
addr = i_0\times w_0 +i_1\times w_1 +\cdots +i_{d-1}\times w_{d-1}
\]
where
\[
w_k = n_{k+1} \times n_{k+2} \times\cdots\times  n_{d-1}, \qquad 0\leq k\leq d-2.
\]

Therefore, we get $\texttt{index2addr([4,3,6])([2,2,0])}=48= 2\times(3\times 6)+2\times(6\times 1)+0$,
where \texttt{[2,2,0]} represent the numbers of (pages, rows, columns) indexing an element in the three-dimensional array of shape \texttt{[4,3,6]}.

%-------------------------------------------------------------------------------
@d Transformation from multindex to address in a linear array storage
@{def index2addr (shape):
    n = len(shape)
    shape = shape[1:]+[1]
    weights = [PROD(shape[k:]) for k in range(n)]
    def index2addr0 (multindex):
        return INNERPROD([multindex, weights])
    return index2addr0
@}
%-------------------------------------------------------------------------------

\paragraph{\texttt{index2addr} examples}
In the following example, \texttt{[3,6]} is the \texttt{shape} of a two-dimen\-sion\-al array with 3 rows and 6 columns, stored in row-major order (i.e.~by rows). The expression \texttt{index2addr([3,6])([2,0])} returns $12=2\times(6\times 1)+0$, since the array element characterised by the multi-index value \texttt{[2,0]} is addressed at position 12 (starting from 0) in the linear storage of the array. Analogously, the function \texttt{index2addr([3,6])}, when applied to all the index values addressing the array of shape \texttt{[3,6]}, produces the integers between 0 and $17 = 3\times 6 -1$. In the last example, the function \texttt{index2addr([4,3,6])} is applied to all the 0-based triples indexing a three-dimensional array of the given shape. Of course, the mapping works correctly even when the array shape is one-dimensional, as shown by the last example below.

%-------------------------------------------------------------------------------
@d Test example
@{>>> index2addr([3,6])([2,0])
12
>>> [index2addr([3,6])(index) for index in CART([ range(3), range(6) ])]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
>>> convert = index2addr([4,3,6])
<function index2address0>
>>> [convert(index) for index in CART( AA(range)([4,3,6]) )]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71]
>>> index2addr([4])([2])
2
@}
%-------------------------------------------------------------------------------

\subsubsection{Multidimensional cell generation}

In this section we discuss the implementation of the generation of cells as lists of indices to grid vertices. First, we study the case that the output complex is generated by the Cartesian product of \emph{any} number of either 0- or 1-dimensional cell complexes. Then, we discuss an efficient extraction of $d$-dimensional skeleton of a (solid) $n$-dimensional grid, for $0\leq d\leq n$.

\paragraph{Example}
In order to better understand the generation of cuboidal grids from products of 0- or 1-dimensional complexes, below we show a simple example of 2D grids embedded in $\E^3$.
In particular, \texttt{v1 = [[0.],[1.],[2.],[3.]]} and \texttt{v0 = [[0.],[1.],[2.]]} are two arrays of 1D vertices, \texttt{c1 = [[0,1],[1,2],[2,3]]} and \texttt{c0 = [[0],[1],[2]]} are the LAR representation of a 1-complex and a 0-complex, respectively. The solid 2-complex named \texttt{grid2D} given below is shown in Figure~\ref{fig:firstgrid23D}a.
\begin{align*}\scriptsize
&\texttt{grid2D = larVertProd([v1,v1]),larCellProd([c1,c1])}\\
&\texttt{VIEW(EXPLODE(1.2,1.2,1.2)(MKPOLS(grid2D)))}
\end{align*}

\begin{figure}[htbp] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=0.458\linewidth]{images/grid2D}
   \includegraphics[width=0.532\linewidth]{images/grid3D}
   \caption{Exploded views of models \texttt{grid2D} and \texttt{grid3D}.}
   \label{fig:firstgrid23D}
\end{figure}

Notice that \texttt{grid2D}, generated by product of two 1-complexes, is \emph{solid} in $\E^2$, whereas \texttt{grid3D} shown in Figure~\ref{fig:firstgrid23D}b, generated by product of two 1-complexes and one 0-complex, is two-dimensional and embedded in $\E^3$.

%-------------------------------------------------------------------------------
@D Example of cuboidal grid of dimensions $(2,3)$
@{v1, c1 = [[0.],[1.],[2.],[3.]],[[0,1],[1,2],[2,3]]
v0, c0 = [[0.],[1.],[2.]], [[0],[1],[2]]
vertGrid = larVertProd([v1, v1, v0])
cellGrid = larCellProd([c1, c1, c0])
grid3D = vertGrid,cellGrid
VIEW(EXPLODE(1.2,1.2,1.2)(MKPOLS(grid3D)))
@}
%-------------------------------------------------------------------------------

\paragraph{Cartesian product of 0/1-complexes}
Here, the input is given by the array \texttt{cellLists} of lists of cells of the argument complexes. Hence, the \texttt{shapes} variable contains the (list of) numbers $m_0, m_1, ...$ of cells in each argument complex, and the \texttt{indices} variable (generated by Cartesian product) collects the whole set $M_0 \times M_1 \times \cdots$ of 0-based multi-indices corresponding to the cells of the output complex, with $M_k = \{0,1,...,m_{k}-1\}$.

The \texttt{jointCells} variable is used to contain the list of outputs of Cartesian products of \texttt{cells} corresponding to every \texttt{index} in \texttt{indices}.

%-------------------------------------------------------------------------------
@D Generation of grid cells
@{def larCellProd(cellLists):
    shapes = [len(item) for item in cellLists]
    indices = CART([range(shape) for shape in shapes])
    jointCells = [CART([cells[k] for k,cells in zip(index,cellLists)])
                  for index in indices]
    convert = index2addr([ shape+1 if (len(cellLists[k][0]) > 1) else shape
                             for k,shape in enumerate(shapes) ])
    return [AA(convert)(cell) for cell in jointCells]
@}
%-------------------------------------------------------------------------------

With reference to the evaluation of the expression \texttt{larCellProd([c1,c1])}, where \texttt{c1} is the LAR representation of a 1-complex with 3 cells, defined by 4 vertices (0-cells), we have the  trace given below.
Of course, the function invocation returns the list of cells of the topological product of the input complexes, each one expressed as a list of vertices of the Cartesian product of the corresponding component vertices. The partially evaluated function \texttt{index2addr0}, stored in the \texttt{convert} variable, is used to execute the mapping, for each output \texttt{cell} in \texttt{jointCells}, from vertex multi-indices to their linear storage address. The mindful reader should notice that the number of generated cells is always equal to the product of terms in \texttt{shape}, in turn equal to the number of elements in \texttt{indices} and in \texttt{jointCells}. In this case we have $|\texttt{larCellProd([c1,c1])}| = 3\times 3=9$.

%-------------------------------------------------------------------------------
@D Tracing the evaluation of expression ``\texttt{larCellProd([c1,c1])}''
@{c1 = [[0,1], [1,2], [2,3]]
cellLists = [[[0,1], [1,2], [2,3]], [[0,1], [1,2], [2,3]]]
shapes = [3,3]
indices = [[0,0], [0,1], [0,2], [1,0], [1,1], [1,2], [2,0], [2,1], [2,2]]
jointCells = [
 [[0,0], [0,1], [1,0], [1,1]],
 [[0,1], [0,2], [1,1], [1,2]],
 [[0,2], [0,3], [1,2], [1,3]],
 [[1,0], [1,1], [2,0], [2,1]],
 [[1,1], [1,2], [2,1], [2,2]],
 [[1,2], [1,3], [2,2], [2,3]],
 [[2,0], [2,1], [3,0], [3,1]],
 [[2,1], [2,2], [3,1], [3,2]],
 [[2,2], [2,3], [3,2], [3,3]]]
convert = <function index2address0>
return [
 [0,1,4,5],
 [1,2,5,6],
 [2,3,6,7],
 [4,5,8,9],
 [5,6,9,10],
 [6,7,10,11],
 [8,9,12,13],
 [9,10,13,14],
 [10,11,14,15]]
@}
%-------------------------------------------------------------------------------

\subsection{Lower-dimensional grid skeletons}

In order to compute the $d$-skeletons of a $n$-dimensional cuboidal ``grid'' complex, with $0\leq d\leq n$, let us start by remarking a similarity with the generation of the boolean representation of numbers between 0 and $2^n -1$, generated as a list of strings by the \texttt{binaryRange} function, given in Section~\ref{sec:binaryRange}.

The binary representations of such numbers are in fact filtered according to the number of their ones in Section~\ref{sec:filterByOrder}, and used to generate the distinct components of different order skeletons of the assembled grid complexes in Section~\ref{sec:assembly}.

\subsubsection{Generation of skeleton components}
\label{sec:binaryRange}

The \texttt{binaryRange} function, applied to an integer $n$, returns the string representation of all binary numerals between 0 and $2^n -1$. All the strings have the same length $n$. The bits in each strings will be used to select between either a 0- or a 1-dimensional complex as generator (via a Cartesian product of complexes) of a component of an embedded grid skeleton of proper intrinsic dimension.

%-------------------------------------------------------------------------------
@D Enumeration of binary ranges of given order
@{def binaryRange(n):
    return [('{0:0'+str(n)+'b}').format(k) for k in range(2**n)]
@}
%-------------------------------------------------------------------------------

\paragraph{Examples of generation of bit strings}
Below we show the outputs returned by application of the \texttt{binaryRange} function to the first 4 integers.
%-------------------------------------------------------------------------------
@D Binary range examples
@{>>> print binaryRange(4),
['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111',
 '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
>>> print binaryRange(3),
['000', '001', '010', '011', '100', '101', '110', '111']
>>> print binaryRange(2),
['00', '01', '10', '11']
>>> print binaryRange(1),
['0', '1']
@}
%-------------------------------------------------------------------------------

\subsubsection{Filtering grid skeleton components}
\label{sec:filterByOrder}

The function \texttt{filterByOrder} is used to partition the previous binary strings into $n+1$ subsets, such that the bits into each string sum to the same number, ranging from 0 to $n$ included, respectively.

%-------------------------------------------------------------------------------
@D Filtering binary ranges by order
@{def filterByOrder(n):
    terms = [AA(int)(list(term)) for term in binaryRange(n)]
    return [[term for term in terms if sum(term) == k] for k in range(n+1)]
@}
%-------------------------------------------------------------------------------

\paragraph{Examples of bit lists filtering}
Some examples of application of the \texttt{filterByOrder} function to the first few integers are shown below.
Of course, the number of elements in each class (i.e.~in each returned list) is ${n \choose d}$, and the total number of elements for each fixed $n$ is $\sum_{d=0}^n {n \choose d} = 2^n$.

%-------------------------------------------------------------------------------
@D Skeleton component examples
@{>>> filterByOrder(4)
[[[0,0,0,0]],
 [[0,0,0,1], [0,0,1,0], [0,1,0,0], [1,0,0,0]],
 [[0,0,1,1], [0,1,0,1], [0,1,1,0], [1,0,0,1], [1,0,1,0], [1,1,0,0]],
 [[0,1,1,1], [1,0,1,1], [1,1,0,1], [1,1,1,0]],
 [[1,1,1,1]]]
>>> filterByOrder(3)
[[[0,0,0]],
 [[0,0,1], [0,1,0], [1,0,0]],
 [[0,1,1], [1,0,1], [1,1,0]],
 [[1,1,1]]]
>>> filterByOrder(2)
[[[0,0]], [[0,1], [1,0]], [[1,1]]]
>>> filterByOrder(1)
[[[0]], [[1]]]
@}
%-------------------------------------------------------------------------------

\subsubsection{Assembling grid skeleton components}
\label{sec:assembly}

We are now finally able to generate the various subsets of cells of a $d$-dimensional cuboidal grid skeleton, produced respectively by the expression \texttt{larCellProd(cellLists)} for every permutation of 0- and 1-complexes, according to the partition classes of permtation of $n$ bits previously produced. To understand why this assembling step of cells is necessary, the reader should look at Figure~\ref{fig:sleletons}, where three subsets of 2-cells of the 2-skeleton, respectively generated by the bit dispositions \texttt{[[0,1,1], [1,0,1], [1,1,0]]}, are separately displayed.
Notice also that, whereas the dimension $n$ of the embedding space is implicittly provided by the \texttt{length} of the \texttt{shape} parameter, the intrinsic dimension $d$ of the skeleton to be produced must be given explicitly.

\begin{figure}[htbp] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[height=0.245\linewidth,width=0.242\linewidth]{images/skel2a}
   \includegraphics[height=0.245\linewidth,width=0.242\linewidth]{images/skel2b}
   \includegraphics[height=0.245\linewidth,width=0.242\linewidth]{images/skel2c}
   \includegraphics[height=0.245\linewidth,width=0.242\linewidth]{images/skel2}
   \caption{(a,b,c) Exploded views of subsets (orthogonal to coordinate axes) of 2-cells of a 2-skeleton grid; (d) their assembled set.}
   \label{fig:sleletons}
\end{figure}

%-------------------------------------------------------------------------------
@D Assembling grid skeletons
@{def larGridSkeleton(shape):
    n = len(shape)
    def larGridSkeleton0(d):
        components = filterByOrder(n)[d]
        componentCellLists = [AA(APPLY)(zip( AA(larGrid)(shape),(component) ))
                              for component in components]
        return CAT([ larCellProd(cellLists)  for cellLists in componentCellLists ])
    return larGridSkeleton0
@}
%-------------------------------------------------------------------------------

\begin{figure}[htbp] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[height=0.245\linewidth,width=0.242\linewidth]{images/skel0}
   \includegraphics[height=0.245\linewidth,width=0.242\linewidth]{images/skel1}
   \includegraphics[height=0.245\linewidth,width=0.242\linewidth]{images/skel2}
   \includegraphics[height=0.245\linewidth,width=0.242\linewidth]{images/skel3}
   \caption{Exploded views of 0-, 1-, 2-, and 3-dimensional skeletons.}
   \label{fig:grid23D}
\end{figure}

\subsection{Highest-level grid interface}

The highest-level user interface for (hyper)-cuboidal grid generation is given by the function \texttt{larCuboids}  applied to the \texttt{shape} parameter.
For the sake of storage efficiency, the generated vertex coordinates are integer and 0-based in the lowest corner. The model may be properly scaled and/or translated \emph{a posteriori} when needed.

\paragraph{Generation of (hyper)-cuboidal grids}

The generated complex is always full-dimension, i.e.~\emph{solid}, and possibly includes the cells of all dimensions, depending on the Boolean value of the \texttt{full} parameter.
The grid's intrinsic dimension, as well as the dimension of its embedding space, are specified by the length of the \texttt{shape} parameter. See the examples in Figure~\ref{fig:grid23D}, but remember that the PLaSM visualiser always embed in 3D the displayed model.

%-------------------------------------------------------------------------------
@D Multidimensional grid generation
@{def larImageVerts(shape):
	def vertexDomain(n):
		return [[k] for k in range(n)]
	vertLists = [vertexDomain(k+1) for k in shape]
	vertGrid = larVertProd(vertLists)
	return vertGrid

def larCuboids(shape, full=False):
	vertGrid = larImageVerts(shape)
	gridMap = larGridSkeleton(shape)
	if not full:
		cells = gridMap(len(shape))
	else:
		skeletonIds = range(len(shape)+1)
		cells = [ gridMap(id) for id in skeletonIds ]
	return vertGrid, cells
@}
%-------------------------------------------------------------------------------

\paragraph{Multidimensional visualisation examples}
Visualisation examples of grid of dimension 1,2, and 3 are given below and are displayed  in Figure~\ref{fig:grid23D}. The same input pattern may be used for higher-dimensional grids (say, of dimension 4 and beyond), but to be visualised they should be carefully and properly projected in 3D.

%-------------------------------------------------------------------------------
@d Multidimensional visualisation examples
@{def mergeSkeletons(larSkeletons): return larSkeletons[0],CAT(larSkeletons[1])
VIEW(EXPLODE(1.5,1.5,1.5)(MKPOLS(mergeSkeletons(larCuboids([3],True)))))
VIEW(EXPLODE(1.5,1.5,1.5)(MKPOLS(mergeSkeletons(larCuboids([3,2],True)))))
VIEW(EXPLODE(1.5,1.5,1.5)(MKPOLS(mergeSkeletons(larCuboids([3,2,1],True)))))
@}
%-------------------------------------------------------------------------------

\begin{figure}[htbp] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=0.313\linewidth]{images/complex3}
   \includegraphics[width=0.33\linewidth]{images/complex32}
   \includegraphics[width=0.305\linewidth]{images/complex321}
   \caption{Exploded views of 1D, 2D, and 3D cellular complexes (including cells of dimension 0,1,2, and 3).}
   \label{fig:grid23D}
\end{figure}

\subsection{Chain of boundary operators}

As we know, a \emph{chain complex} is a sequence of (linear) chain spaces $C_k$ ($d\geq k\geq 0$) and a sequence
of boundary operators $\partial_k: C_k \to C_{k-1}$ ($d\geq k\geq 1$) between adjacent spaces (see Figure~\ref{fig:chainComplexMap}). In this section, we aim to generate the sequence of boundary matrices \texttt{CSR($[\partial_k]$)} ($1\leq k\leq d$).

\begin{figure}[htbp] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[width=0.8\linewidth]{images/chainComplexMap}
   \caption{Chain and cochain complexes.}
   \label{fig:chainComplexMap}
\end{figure}

\paragraph{Cuboidal skeletons}
A list of \texttt{BRC} characteristic matrices of cellular $k$-complexes ($0\leq k\leq d$) with dimension $d$, where $d={}$\texttt{len(shape)}, is returned by the function \texttt{gridSkeletons} in the macro below, where the input is given by the \emph{shape} of the grid, i.e.~by the list of cell items in each coordinate direction. Some simple test examples of skeletons of cuboidal complexes are also printed when the \texttt{largrid} module run as the \texttt{main}. Just notice that the number of returned $d$-cells is equal to \texttt{PROD(shape)}.

%-------------------------------------------------------------------------------
@D Multidimensional grid skeletons
@{def gridSkeletons(shape):
	gridMap = larGridSkeleton(shape)
	skeletonIds = range(len(shape)+1)
	skeletons = [ gridMap(id) for id in skeletonIds ]
	return skeletons

if __name__=="__main__":
	print "\ngridSkeletons([3]) =\n", gridSkeletons([3])
	print "\ngridSkeletons([3,2]) =\n", gridSkeletons([3,2])
	print "\ngridSkeletons([3,2,1]) =\n", gridSkeletons([3,2,1])
@}
%-------------------------------------------------------------------------------

\paragraph{Boundary complex of a cuboidal grid}
The list of boundary matrices \texttt{CSR($[\partial_k]$)} ($1\leq k\leq d$) is returned by the function
\texttt{gridBoundaryMatrices}.

%-------------------------------------------------------------------------------
@D Generation of grid boundary complex
@{def gridBoundaryMatrices(shape):
	skeletons = gridSkeletons(shape)
	boundaryMatrices = [larBoundary(skeletons[k+1],faces)
						 for k,faces in enumerate(skeletons[:-1])]
	return boundaryMatrices

if __name__=="__main__":
	for k in range(1):
		print "\ngridBoundaryMatrices([3]) =\n", \
				csr2DenseMatrix(gridBoundaryMatrices([3])[k])
	for k in range(2):
		print "\ngridBoundaryMatrices([3,2]) =\n", \
				csr2DenseMatrix(gridBoundaryMatrices([3,2])[k])
	for k in range(3):
		print "\ngridBoundaryMatrices([3,2,1]) =\n", \
				csr2DenseMatrix(gridBoundaryMatrices([3,2,1])[k])
@}
%-------------------------------------------------------------------------------

%===============================================================================
\section{Face stack of cellular complexes}
\label{sec:facestack}
%===============================================================================

%-------------------------------------------------------------------------------
\subsection{Simplicial complexes}
%-------------------------------------------------------------------------------

The stack of faces of a simplicial $d$-complex is easy to compute making use of the combinatorial properties of the simplex boundary. If the input is the compressed sparse row representation \texttt{CSR}$(M_d)$ of the binary characteristic matrix $M_d$ of the highest rank cells ($d$-simplices), we repeatedly apply the \texttt{larSimplexFacets} function.

\paragraph{Simplicial face stack computation}
The whole stack of \texttt{LAR} cell-vertex arrays is computed below for the multidimensional case, and returned ordered from 0-cells to $d$-cells.

%-------------------------------------------------------------------------------
@D Simplicial face stack computation
@{""" Simplicial face stack computation """
def larSimplicialStack(simplices):
	dim = len(simplices[0])-1
	faceStack = [simplices]
	for k in range(dim):
		faces = larSimplexFacets(faceStack[-1])
		faceStack.append(faces)
	return REVERSE(faceStack)
@}
%-------------------------------------------------------------------------------

\paragraph{Oriented boundary: Example 2D}
The file \texttt{test/py/largrid/test04.py} gives an example of computation of the oriented 1D boundary of a 2D simplicial grid. In the variable \texttt{bases} we store the stack of bases of $k$-chains, for $0\leq k\leq 2$. The variable \texttt{boundaryCells} contains the indices of boundary cells, signed according to their absolute orientation. To get a coherent orientation of the model boundary, the boundary 2-cells with negative indices must undergo to reversing their orientation.

%-------------------------------------------------------------------------------
@O test/py/largrid/test04.py
@{""" Computation of the boundary of a simplicial grid """
from larlib import *

V,simplices = larSimplexGrid1((2,2))
bases = larSimplicialStack(simplices)
boundaryCells = signedBoundaryCells(V,bases[-1],bases[-2])

def swap(mylist):
    return [mylist[1]]+[mylist[0]]+mylist[2:]

orientedBoundary = [bases[-2][-k] if k<0 else swap(list(bases[-2][k]))
						for k in boundaryCells]
VIEW(EXPLODE(1.2,1.2,1.2)(MKPOLS((V,orientedBoundary))))
submodel = STRUCT(MKPOLS((V,orientedBoundary)))
VIEW(larModelNumbering()(V,bases,submodel))
@}
%-------------------------------------------------------------------------------

\paragraph{Oriented boundary: Example 3D}
A very similar example is given below for a 3D simplicial grid, in order to show
how to use the components of the LAR cell stack, computed as \texttt{larSimplicialStack(CV)}, and stored in the \texttt{bases} variable. T

%-------------------------------------------------------------------------------
@O test/py/largrid/test03.py
@{""" Computation of the boundary of a simplicial grid """
from larlib import *

V,CV = larSimplexGrid1((2,2,2))
bases = larSimplicialStack(CV)
VV,EV,FV,CV = bases
boundaryCells = signedBoundaryCells(V,CV,FV)

def swap(mylist): return [mylist[1]]+[mylist[0]]+mylist[2:]
orientedBoundary = [FV[-k] if k<0 else swap(list(FV[k])) for k in boundaryCells]
VIEW(EXPLODE(1.2,1.2,1.2)(MKPOLS((V,orientedBoundary))))
submodel = EXPLODE(1.05,1.05,1.05)(MKPOLS((V,orientedBoundary)))
VIEW(larModelNumbering()(V,bases,submodel))
@}
%-------------------------------------------------------------------------------

%-------------------------------------------------------------------------------
\subsection{Cuboidal complexes}
%-------------------------------------------------------------------------------

\paragraph{Example 2D}

%-------------------------------------------------------------------------------
@O test/py/largrid/test05.py
@{""" Extraction of oriented boundary of a cuboidal 2-complex """
from larlib import *
from random import random

shape = 20,20
V,cells = larCuboids(shape)
cellSpan = prod(shape)
fraction = 0.9
remove = [int(random()*cellSpan) for k in range(int(cellSpan*fraction)) ]
cells = [cells[k] for k in range(cellSpan) if not k in remove]
V,EV = larCuboidsFacets((V,cells))
VIEW(EXPLODE(1.2,1.2,1)(MKPOLS((V,EV))))

boundaryCells = signedBoundaryCells(V,cells,EV)
def swap(mylist): return [mylist[1]]+[mylist[0]]+mylist[2:]
orientedBoundary = [EV[-k] if k<0 else swap(EV[k]) for k in boundaryCells]
VIEW(EXPLODE(1.2,1.2,1.2)(MKPOLS((V,orientedBoundary))))

@}
%-------------------------------------------------------------------------------

\begin{figure}[htbp] %  figure placement: here, top, bottom, or page
   \centering
   \includegraphics[height=0.245\linewidth,width=0.244\linewidth]{images/2Dsigned0}
   \includegraphics[height=0.245\linewidth,width=0.244\linewidth]{images/2Dsigned1}
   \includegraphics[height=0.245\linewidth,width=0.244\linewidth]{images/2Dsigned2}
   \includegraphics[height=0.245\linewidth,width=0.244\linewidth]{images/2Dsigned3}
   \caption{Extraction of oriented boundary of a cuboidal 2-complex: (a) The cellular 2-complex; (b) complex of 1-cells; (c) oriented boundary; (d) exploded boundary.}
	\vspace{3mm}
   \centering
   \includegraphics[height=0.245\linewidth,width=0.244\linewidth]{images/3Dsigned0}
   \includegraphics[height=0.245\linewidth,width=0.244\linewidth]{images/3Dsigned1}
   \includegraphics[height=0.245\linewidth,width=0.244\linewidth]{images/3Dsigned2}
   \includegraphics[height=0.245\linewidth,width=0.244\linewidth]{images/3Dsigned3}
   \caption{Extraction of oriented boundary of a cuboidal 3-complex: (a) Cellular 3-complex; (b) complex of 2-cells; (c) (exploded) oriented boundary; (d) view from the boundary interior.}
   \label{fig:2-3-complex}
\end{figure}

\paragraph{Example 3D}

%-------------------------------------------------------------------------------
@O test/py/largrid/test06.py
@{""" Extraction of oriented boundary of a cuboidal 3-complex """
from larlib import *
from random import random

shape = (10,10,10)
V,cells = larCuboids(shape)
cellSpan = prod(shape)
fraction = 0.9
remove = [int(random()*cellSpan) for k in range(int(cellSpan*fraction)) ]
cells = [cells[k] for k in range(cellSpan) if not k in remove]
V,FV = larCuboidsFacets((V,cells))
VIEW(EXPLODE(1.2,1.2,1.2)(MKPOLS((V,FV))))
@}
%-------------------------------------------------------------------------------

\subsubsection{Random polytopal complexes}

\paragraph{Extraction of facets from cuboidal complexes}

%-------------------------------------------------------------------------------
@D Extraction of facets from cuboidal complexes
@{""" Extraction of facets from cuboidal complexes """
def larCuboidsFacets((V,cells)):
	dim = len(V[0])
	n = int(2**(dim-1))
	facets = []
	for cell in cells:
		coords = [AR([V[v],v]) for v in cell] # decorate coords with vertex index
		doubleFacets = [sorted(coords,key=(lambda x: x[k])) for k in range(dim)]
		facets += AA(AA(LAST))(CAT([[pair[:n],pair[n:]] for pair in doubleFacets]))
	facets = AA(eval)(set(AA(str)(facets))) # remove duplicates
	return V,sorted(facets)

if __name__ == "__main__":
	VIEW(EXPLODE(1.2,1.2,1.2)(MKPOLS(larCuboidsFacets(larCuboids([3,3,3])))))
@}
%-------------------------------------------------------------------------------

%-------------------------------------------------------------------------------
\subsection{Polytopal complexes}
%-------------------------------------------------------------------------------

TODO

%-------------------------------------------------------------------------------
%===============================================================================
\section{Cartesian product of cellular complexes}
\label{sec:product}
%===============================================================================

\paragraph{LAR model of cellular complexes}

The external representation of a LAR model (necessarily geometrical, i.e.~embedded in some $\E^n$, in order to be possible to draw it) is a pair (\emph{geometry},\emph{topology}), where \emph{geometry} is the list of coordinates of vertices, i.e.~a two-dimensional array of numbers, where vertices are given by row, and \emph{topology} is a list of cells of fixed dimension $d$. When $d=n$ the model is \emph{solid}; otherwise  the model is some emberdded $d$-skeleton ($0\leq d <n$).

\paragraph{Binary product of cellular complexes}
The \texttt{larModelProduct} function takes as input a pair of LAR models and returns the model of their Cartesian product. Since this is a pair (\emph{geometry}, \emph{topology}), its second element returns the topological product of the input topologies.

%-------------------------------------------------------------------------------
@d Cartesian product of two lar models
@{def larModelProduct(twoModels):
    (V, cells1), (W, cells2) = twoModels
    @< Cartesian product of vertices @>
    @< Topological product of cells    @>
    model = [list(v) for v in vertices.keys()], cells
    return model
@}
%-------------------------------------------------------------------------------

\paragraph{Cartesian product of argument vertices}
The following macro is used to generate a dictionary mapping between integer ids of new vertices and the sets $V$ and $W$ of vertices of the input complexes.

%-------------------------------------------------------------------------------
@d Cartesian product of vertices
@{vertices = collections.OrderedDict(); k = 0
for v in V:
    for w in W:
        id = tuple(v+w)
        if not vertices.has_key(id):
            vertices[id] = k
            k += 1	@}
%-------------------------------------------------------------------------------

\paragraph{Topological product of argument vertices}
Another macro generates the cells of the topological product, represented as lists of new vertices.

%-------------------------------------------------------------------------------
@d Topological product of cells
@{cells = [ [vertices[tuple(V[v] + W[w])] for v in c1 for w in c2]
         for c1 in cells1 for c2 in cells2]	@}
%-------------------------------------------------------------------------------

%-------------------------------------------------------------------------------
@d Test examples of Cartesian product
@{if __name__ == "__main__":
    geom_0,topol_0 = [[0.],[1.],[2.],[3.],[4.]],[[0,1],[1,2],[2,3],[3,4]]
    geom_1,topol_1 = [[0.],[1.],[2.]], [[0,1],[1,2]]
    mod_0 = (geom_0,topol_0)
    mod_1 = (geom_1,topol_1)
    squares = larModelProduct([mod_0,mod_1])
    VIEW(EXPLODE(1.2,1.2,1.2)(MKPOLS(squares)))
    cubes = larModelProduct([squares,mod_0])
    VIEW(EXPLODE(1.2,1.2,1.2)(MKPOLS(cubes)))
@}
%-------------------------------------------------------------------------------

\section{Largrid exporting}
\label{sec:largrid}
In this section we assemble top-down the \texttt{largrid} module, by orderly listing the macros it is composed of. As might be expected, the present one is the module version corresponding to the current state of the system, i.e.~to a very initial state. Other functions will be added when needed, and the module translation in different languages (C/C++, Javascript, Haskell, OpenCL kernels) will be (hopefully soon) appended.
%------------------------------------------------------------------
@O larlib/larlib/largrid.py
@{"""Module with functions for grid generation and Cartesian product"""
import collections
from larlib import *

@< Generation of vertices of decompositions of 1D intervals  @>
@< Generation of uniform 0D cellular complex  @>
@< Generation of uniform 1D cellular complex  @>
@< Generation of cellular complex of 0/1 dimension $d$ @>
@< Generation of grid vertices  @>
@< Transformation from multindex to address in a linear array storage @>
@< Generation of grid cells  @>
@< Enumeration of binary ranges of given order @>
@< Filtering binary ranges by order @>
@< Assembling grid skeletons @>
@< Multidimensional grid generation @>
@< Multidimensional grid skeletons @>
@< Generation of grid boundary complex @>
@< Cartesian product of two lar models   @>
@< Simplicial face stack computation @>
@< Extraction of facets from cuboidal complexes @>
if __name__=="__main__":
	@< Multidimensional visualisation examples @>
	@< Test examples of Cartesian product @>
@}
%------------------------------------------------------------------

\section{Unit tests}
\label{sec:tests}

\subsection{Creation of repository of unit tests}

A possible unit test strategy is to create a directory for unit tests associated to each source file in \texttt{nuweb}. Therefore we create here a directory in \texttt{test/py/} with the same name of the present document. Of course other

%------------------------------------------------------------------
@d Create directory and echo of creation
@{@< Create directory from path @>
@%i lib/py/largrid
createDir('@1')
print "'@1' repository created"
@}
%------------------------------------------------------------------

%------------------------------------------------------------------
@o test/py/largrid/test01.py
@{@< Create directory  and echo of creation: @(test/py/largrid/@) @>
@}
%------------------------------------------------------------------

\paragraph{Vertices of 1D decompositions}
Some test examples of the \texttt{larSplit} function are given in the following. First the unit interval $[0,1]$ is splitter into 10 sub intervals, then the $[0,2\pi]$ interval is split into 12 parts, used to generate a polyonal approximatetion of the unit circle $S_1$, centred in the origin and with unit radius.

%-------------------------------------------------------------------------------
@O test/py/largrid/test01.py
@{""" Vertices of 1D decompositions """
from larlib import *

@<Generation of vertices of decompositions of 1D intervals@>
assert larSplit(1)(3) == [[0.0], [0.3333333333333333], [0.6666666666666666], [1.0]]
assert larSplit(1)(1) == [[0.0], [1.0]]
assert larSplit(2*PI)(12) == [[0.0], [0.5235987755982988], [1.0471975511965976],
[1.5707963267948966], [2.0943951023931953], [2.617993877991494],
[3.141592653589793], [3.665191429188092], [4.1887902047863905],
[4.71238898038469], [5.235987755982988], [5.759586531581287],
[6.283185307179586]]
@}
%-------------------------------------------------------------------------------

%-------------------------------------------------------------------------------
@O test/py/largrid/test02.py
@{""" Test file """
from larlib import *

mod_1 = larSplit(1)(4), larGrid(4)(1)
squares = larModelProduct([mod_1,mod_1])
VIEW(EXPLODE(1.2,1.2,1.2)(MKPOLS(squares)))
cubes = larModelProduct([squares,mod_1])
VIEW(EXPLODE(1.2,1.2,1.2)(MKPOLS(cubes)))
@}
%-------------------------------------------------------------------------------

\section{Indices}
\label{sec:indices}

The list of macros follow.
%-------------------------------------------------------------------------------
@m
%-------------------------------------------------------------------------------

\appendix
\section{Appendix}
\label{sec:utilities}

\subsection{Utilities}

\bibliographystyle{amsalpha}
\bibliography{largrid}

\end{document}


%%%%%%%%%%%%%%%%%%%%%definitions%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\input{../../doc/related_pages/header.tex}
\input{../../doc/related_pages/newcommands.tex}
\usepackage{minted}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%DOCUMENT%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}

\title{The poet project}
\author{M.~Held}
\maketitle

\begin{abstract}
  This is a program for 2d isothermal delta-f and full-f gyro-fluid simulations with different treatments of the polarization charge
\end{abstract}

\section{Equations}
Currently we implemented $5$ slightly different sets of equations. $n$ is the electron density, $N$ is the ion gyrocentre density. $\phi$ is the electric potential. We
use Cartesian coordinates $x$, $y$.
\subsection{Models}
\subsubsection{Delta-F gyro-fluid models}
The two delta-f models ("df-lwl" \& "df-O2") share the same evolution equations\footnote{The densities are for delta-f models are understood as fluctuating quantities with respect to a background}
\begin{subequations}
\begin{align}
 \frac{\partial n}{\partial t}     &=
    \{ n, \phi\}
  + \kappa \frac{\partial \phi}{\partial y}
  -\kappa \frac{\partial n}{\partial y}
  - \nu \Delta_{\perp}^2 n  \\
  \frac{\partial N}{\partial t} &=
  \{ N, \psi\}
  + \kappa \frac{\partial \psi}{\partial y}
  + \tau \kappa\frac{\partial N}{\partial y} -\nu\Delta_{\perp}^2 N \\
   \vec{\nabla}\cdot \vec{P}_2 &=  \Gamma_1 N -n,
\end{align}
\end{subequations}
and differ only in the polarization equation given in Section~\ref{sec:polarization}:
%%%%%%%%%
\subsubsection{Full-F gyro-fluid models}
Likewise the full-f models ("ff-lwl" \& "ff-O2" \& "ff-O4") share the same evolution equations
\begin{subequations}
\begin{align}
 \frac{\partial n}{\partial t}     &=
    \frac{1}{B}\{ n, \phi\}
  + \kappa n\frac{\partial \phi}{\partial y}
  -\kappa \frac{\partial n}{\partial y}
  - \nu \Delta_\perp^2 n  \\
  \frac{\partial N}{\partial t} &=
  \frac{1}{B}\{ N, \psi\}
  + \kappa N\frac{\partial \psi}{\partial y}
  + \tau \kappa\frac{\partial N}{\partial y} -\nu \Delta_\perp^2 N \\
   \vec{\nabla}\cdot \vec{P}_2 &= \Gamma_1 N-n
\end{align}
\end{subequations}
and are based upon a ``radially'' varying magnetic field magnitude
\begin{align}
 B(x)^{-1} = \kappa x +1-\kappa X
\end{align}
The full-f models differ only in the treatment the  polarization terms \(\psi_2\) and \(\vec{P}_2\), given in Sec.~\ref{sec:polarization}
%%%%%
\subsubsection{Polarization and FLR terms}
\label{sec:polarization}
The FLR and polarization operators enter the gyro-fluid potential (\(\psi)\) as well as the polarization density.
The operators and gyro-fluid potential are
\begin{align}
 \Gamma_1 &= ( 1- \tau/2 \Delta_{\perp})^{-1} &
 \Gamma_0 &= ( 1- \tau\Delta_{\perp})^{-1} &
   \psi = \Gamma_1 \phi + \psi_2
\end{align}
The  (negative) polarization charge is
\begin{align}
  \vec{\nabla}\cdot \vec{P}_2 &=
\begin{cases}
-\Delta_{\perp} \phi ,
        &\ \text{if "df-lwl"} \\
-\Gamma_0\Delta_{\perp} \phi,
      &\ \text{if "df-O2"} \\
-\nabla\cdot \left(\frac{N}{B^2} \nabla_\perp \phi\right)
       &\ \text{if "ff-lwl"} \\
-\sqrt{\Gamma_0}\nabla\cdot \left(\frac{N}{B^2} \nabla_\perp\sqrt{\Gamma_0} \phi\right)
         &\ \text{if "ff-O2"} \\
-\Gamma_1 \left[\nabla\cdot \left(\frac{N}{B^2} \nabla_\perp\right)-2   \nabla\cdot\nabla\cdot \left(\frac{\tau N}{B^4} \nabla_\perp^2\right)+  \Delta_{\perp} \left(\frac{\tau N}{B^4} \Delta_{\perp}\right)\right]\Gamma_1 \phi
        &\ \text{if "ff-O4"} \\
\end{cases}
\end{align}
The polarization part of the gyro-fluid potential is
\begin{align}
\psi_2&=
\begin{cases}
0 ,
        &\ \text{if "df-lwl"} \\
0,
      &\ \text{if "df-O2"} \\
- \frac{1}{2} \frac{(\nabla\phi)^2}{B^2}
       &\ \text{if "ff-lwl"} \\
- \frac{1}{2} \frac{(\nabla\sqrt{\Gamma_0}\phi)^2}{B^2}
         &\ \text{if "ff-O2"} \\
- \frac{1}{2 B^2} \left[|\nabla_\perp \Gamma_1\phi|^2 + \frac{\tau}{2 B^2} \left[|\nabla_\perp^2 \Gamma_1\phi |^2 - (\Delta_{\perp} \Gamma_1\phi)^2 /2 \right]\right]
        &\ \text{if "ff-O4"} \\
\end{cases}
\end{align}
\subsection{Initialization}
We follow the strategy to enforce the initial fields of the physical variables, the electron density \(n\) and the electric potential \(\phi\), in order to compute the initial ion gyro-center density.
\subsubsection{Non-rotating Gaussian ("blob")}
Initialization of $n$ is a Gaussian
\begin{align}
    n(x,y,0) &= 1 + A\exp\left( -\frac{(x-X)^2 + (y-Y)^2}{2\sigma^2}\right) \\
    \phi(x,y)&=const.
\end{align}
where $X = p_x l_x$ and $Y=p_yl_y$ are the initial centre of mass position coordinates, $A$ is the amplitude and $\sigma$ the
radius of the blob.
We initialize
\begin{align}
    N &= \Gamma_1^{-1} n
\end{align}
\subsubsection{Gaussian with zero polarization charge density("blob")}
Initialization of $n$ is a Gaussian
\begin{align}
    n(x,y,0) &= 1 + A\exp\left( -\frac{(x-X)^2 + (y-Y)^2}{2\sigma^2}\right) \\
\end{align}
where $X = p_x l_x$ and $Y=p_yl_y$ are the initial centre of mass position coordinates, $A$ is the amplitude and $\sigma$ the radius of the blob. We initialize then
\begin{align}
    N &= n
\end{align}
so that the total polarization charge vanishes  \(\vec{\nabla}\cdot \vec{P}=0\).

\subsubsection{Double Rotating Gaussian }
We initialize two blobs
\begin{align}
    n(x,y) &= 1 + A\exp\left( -\frac{(x-X)^2 + (y-Y)^2}{2\sigma^2}\right) \\
    \Omega_E:= \vec{\nabla} \cdot \left(\frac{1}{B} \vec{\nabla}_\perp \phi\right) &= \delta \hspace{1mm} (n-1)
\end{align}
where \(\delta = 10\) is a parameter for the rotation.
Thus we have
\begin{align}
  \phi(x,y) &= \Delta_\perp^{-1} \Omega_E
\end{align}

the ion gyro-center density follows from the respective polarization equation.

\subsubsection{Shear flow (double shear layer)}
\begin{align}
 n(x,y) &= n_{e0}\\
    \Omega_E:= \vec{\nabla} \cdot \left(\frac{1}{B} \vec{\nabla}_\perp \phi\right) &= A
    \begin{cases}
        \delta \cos(2 \pi y/l_y) - \frac{1}{\rho} \text{sech}^2 \left(\frac{2 \pi x/l_x-\pi/2}{\rho}\right),\ x \leq l_x/2 \\
        \delta \cos(2 \pi y/l_y) + \frac{1}{\rho} \text{sech}^2 \left(\frac{3 \pi /2-2 \pi x/l_x}{\rho}\right),\ x > l_x/2 \\
    \end{cases}
%  \phi(x,y) &= \dots \\
\end{align}
where \(\rho=\pi/15\) is the width of the shear layer and \(\delta=0.05\). The A parameter serves to control the magnitude.
\begin{align}
  \phi(x,y) &= \Delta_\perp^{-1} \Omega_E
\end{align}
the ion gyro-center density follows from the respective polarization equation, which requires a non-linear solve \(f(N,\phi) = n_e\). An initial guess for the ion gyro-cente rdensity \(N\) is obtained via the lwl approximated polarization equation.

\subsection{Diagnostics}
Diagnostics are the mass \(M\), the center of mass position \(\vec{X}_{com}\) and the (non-normalized) compactness \(I_c\)
\begin{align}
    M(t) &:= \int dA (n-1)  \\
    M \vec{X}_{com} &:= \int dA \vec{x} (n-1) \\
    I_c(t)  &:= \int dA (n(\vec{x},t)-1) h(\vec{x},t) \\
    h(\vec{x},t) &:= \begin{cases}
          1,
        &\ \text{if} \hspace{2mm}||\vec{x} - \vec{X}_{max}||^2 < \sigma^2 \\
0,  &\ \text{else}
           \end{cases}
\end{align}
\section{Numerical methods}
discontinuous Galerkin on structured grid
\rowcolors{2}{gray!25}{white} %%% Use this line in front of longtable
\begin{longtable}{ll>{\RaggedRight}p{7cm}}
\toprule
\rowcolor{gray!50}\textbf{Term} &  \textbf{Method} & \textbf{Description}  \\ \midrule
coordinate system & Cartesian 2D & equidistant discretization of $[0,l_x] \times [0,l_y]$, equal number of Gaussian nodes in x and y \\
matrix inversions & multigrid conjugate gradient &  \\
matrix functions & cauchy integral  method & \\
\ExB advection & centered upwind-scheme\\
curvature terms & centered difference & \\
time &  adaptive explicit RK or explicit multistep  &  \\
\bottomrule
\end{longtable}

\section{Compilation and useage}
There are two programs poet.cu and poet\_hpc.cu . Compilation with
\begin{verbatim}
make <poet poet_hpc poet_mpi> device = <omp gpu>
\end{verbatim}
Run with
\begin{verbatim}
path/to/feltor/src/poet/poet input.json
path/to/feltor/src/poet/poet_hpc input.json output.nc
echo np_x np_y | mpirun -n np_x*np_y path/to/feltor/src/poet/poet_mpi\
    input.json output.nc
\end{verbatim}
All programs write performance informations to std::cout.
The first is for shared memory systems (OpenMP/GPU) and opens a terminal window with life simulation results.
 The
second can be compiled for both shared and distributed memory systems and uses serial netcdf in both cases
to write results to a file.
For distributed
memory systems (MPI+OpenMP/GPU) the program expects the distribution of processes in the
x and y directions as command line input parameters.

\subsection{Input file structure}
Input file format: json
\begin{minted}[texcomments]{js}
"grid":
{
    "n" :  5,    //Legendre polynomial order in x and y
    "Nx" : 32,   //grid points in x
    "Ny" : 32,   //grid points in y
    "lx"  : 64,  //Box size in x in units of $\rho_s$
    "ly"  : 64   //Box size in y in units of $\rho_s$
},
"timestepper":
{
    "type": "adaptive", //"adaptive" (explicit adaptive RK) or "multistep" (explicit multistep)
    "tableau": "Bogacki-Shampine-4-2-3", // recommended "Bogacki-Shampine-4-2-3" (default adaptive) or "TVB-3-3" (multistep)
    "rtol": 1e-10, //relative tolerance of adaptive time stepper
    "atol": 1e-12, //absolute tolerance of adaptive time stepper
    "dt" : 0.1   //time step in units of $c_s/\rho_s$ for multistep. Also determines together with itstep output step $dt_{out} = dt itstp$
},
"output":
{
    "type": "glfw",  // output format "glfw" & "netcdf",
    "itstp"  : 1,    //time steps between outputs
    "maxout" : 2,    //\# of netcdf outputs
    "n" : 5,         //Legendre polynomial order in x and y for netcdf output
    "Nx" : 32,       //grid points in x for netcdf output
    "Ny" : 32        //grid points in y for netcdf output
},
"elliptic":
{
    "stages"     : 3, //\# of stages of the multigrid solver for the (tensor) elliptic operator
    "eps_pol"    : [1e-6,1.0,1.0], //accuracy at each stage of the multigrid solver
    "jumpfactor": 1 //jump factor of the (tensor) elliptic operator
},
"helmholtz":
{
    "eps_gamma1" :   1e-8, //accuracy of the $\Gamma_1$ operator
    "eps_gamma0" :   1e-6, //accuracy of the $\Gamma_0$ or $\sqrt{\Gamma_0}$ operator
    "maxiter_sqrt":  200,  //max iterations of the $\sqrt{\Gamma_0}$ computation
    "maxiter_cauchy": 35,  //max iterations of the Cauchy terms in $\sqrt{\Gamma_0}$ computation
    "eps_cauchy" :  1e-12  //accuracy of the Cauchy integral in the $\sqrt{\Gamma_0}$ computation
},
"physical":
{
    "curvature"  : 0.00015, //$\kappa$
    "tau"  : 4.0,           //$\tau_i = T_{i0}/T_{e0}$
    "equations": "ff-O2"    //model $\in$ ("df-lwl" ,"df-O2" ,"ff-lwl" ,"ff-O2" ,"ff-O4" )
},
"init":
{
    "type"       : "blob",  // Gaussian blob initialization
    "amplitude"  :1.0,      //$A$ of the Gaussian blob
    "sigma"  : 5,           //$\sigma$ of Gaussian blob units of $\rho_s$
    "posX"  : 0.5,          //x initial position $\in (0,1)$
    "posY"  : 0.5           //y initial position $\in (0,1)$
},
"nu_perp"  : 0e-5,          //hyper-diffusion parameter
"bc_x"  : "DIR",            //Boundary condtion in x
"bc_y"  : "PER"             //Boundary condtion in y
\end{minted}
\subsection{Structure of output file}
Output file format: netcdf-4/hdf5
%
%Name | Type | Dimensionality | Description
%---|---|---|---|
\begin{longtable}{lll>{\RaggedRight}p{7cm}}
\toprule
\rowcolor{gray!50}\textbf{Name} &
 \textbf{Type} & \textbf{Dimension} & \textbf{Description}  \\ \midrule
inputfile  &             text attribute & 1 & verbose input file as a string \\
energy\_time             & Dataset & 1 & timesteps at which 1d variables are written \\
time                     & Dataset & 1 & time at which fields are written \\
x                        & Dataset & 1 & x-coordinate  \\
y                        & Dataset & 1 & y-coordinate \\
electrons                & Dataset & 3 (time, y, x) & electon density $n$ \\
ions                     & Dataset & 3 (time, y, x) & ion density $N$ \\
potential                & Dataset & 3 (time, y, x) & electric potential $\phi$  \\
vorticity                & Dataset & 3 (time, y, x) & z-component of ExB vorticity  $\Omega_E = \vec{\nabla}\cdot (B^{-1} \vec{\nabla}_{\perp}\phi)$  \\
lperpinv                 & Dataset & 3 (time, y, x) & inverse perp density gradient length scale $L_\perp^{-1} := |\nabla_\perp n| / n$ \\
lperpinvphi                 & Dataset & 3 (time, y, x) & inverse perp eletric potential gradient length scale $L_{\perp,\phi}^{-1} := |\nabla_\perp \phi| $ \\
% dEdt                     & Dataset & 1 (energy\_time) & change of energy per time  \\
% dissipation              & Dataset & 1 (energy\_time) & diffusion integrals  \\
% energy                   & Dataset & 1 (energy\_time) & total energy integral  \\
% mass                     & Dataset & 1 (energy\_time) & mass integral   \\
\bottomrule
\end{longtable}
%..................................................................
\bibliography{../../doc/related_pages/references}
%..................................................................

\end{document}