\documentclass[10pt]{article}
\usepackage{cite}
\usepackage{a4}

\usepackage[utf8]{inputenc}
\usepackage[english]{babel}
\usepackage{amsmath,amssymb,amsthm}

\usepackage{url}
\usepackage{pgf}
\usepackage{tikz}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% layout commands
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newtheorem{thm}{Theorem}[section]
\newtheorem{lem}[thm]{Lemma}

\newcommand{\prog}[3]{\langle #1, #2, #3\rangle}
\newcommand{\slp}[1]{\mathbb{#1}}
\newcommand{\slpterm}[3]{\slp{#1}_{#2} = #3}
\newcommand{\slpnonterm}[4]{\slp{#1}_{#2} = \slp{#1}_{#3} \cdot \slp{#1}_{#4}}
\newcommand{\substr}[2]{[#1\dots#2]}
\newcommand{\subslp}[3]{\slp{#1}[#2\dots#3]}

\newcommand{\problem}[3]{
            \noindent {\sc Problem:} \textbf{#1} \newline
            \noindent {\sc Input:} #2 \newline
            \noindent {\sc Output:} #3
}

\renewcommand{\emptyset}{
    \font\msbm = msbm10 at 12pt
    \mbox{\msbm \char 63}
}

\begin{document}

\title{Computing All Squares in Compressed Texts}
\author{Lesha Khvorost\thanks{The author acknowledges support from the Russian Foundation for Basic Research, grant
10-01-00793.}\\
Ural Federal University\\
jaamal@mail.ru}
\date{}
\maketitle

\begin{abstract}
We consider the problem of computing all squares in a string represented by a straight-line program (SLP). An
instance of the problem is an SLP $\slp{S}$ that derives some string $S$ and we seek a solution in the form of a table
that contains information about all squares in $S$ in a compressed form. We present an algorithm that solves the
problem in $O(|\slp{S}|^4\cdot \log^2{|S|})$ time and requires $O(|\slp{S}|\cdot \max\{ |\slp{S}|, \log{|S|}\})$ space,
where $|\slp{S}|$ (respectively $|S|$) is the size of the SLP $\slp{S}$ (respectively the length of the string $S$).
\end{abstract}

\section{Introduction}

Various compressed representations of strings are known: straight-line programs (SLPs),
collage-systems, string representations using antidictionaries, etc. Nowadays text compression
based on context-free grammars such as SLPs attracts much attention. The reason for this is not only that grammars
provide well-structured compression but also that the SLP-based compression is in a sense polynomially equivalent
to the compression achieved by the Lempel-Ziv algorithm that is widely used in practice. It means that, given a
string $S$, there is a polynomial relation between the size of an SLP that derives $S$ and the size of the
dictionary stored by the Lempel-Ziv algorithm \cite{18}.

While compressed representations save storage space, there is a price to pay: some classical problems on strings
become computationally hard when one deals with compressed data and measures algorithms' speed in terms of the
size of compressed representations. As examples we mention here the problems \textbf{Hamming distance} \cite{15} and
\textbf{Literal shuffle} \cite{4}. On the other hand, there exist problems that admit algorithms working rather well on
compressed representations: \textbf{Pattern matching} \cite{15}, \textbf{Longest common substring} \cite{16},
\textbf{Computing all palindromes} \cite{16}. This dichotomy gives rise to the following research direction: to
classify important string problems by their behavior with respect to compressed data.

The \textbf{Computing All Squares} (\textbf{CAS}) problem is a well-known problem on strings. It is of importance, for
example, in molecular biology. Up to recently it is was not known whether or not \textbf{CAS} admits an algorithm polynomial
in the size of a compressed representation of a given string.\footnote{A polynomial algorithm that solves \textbf{CAS}
for strings represented by Lempel-Ziv encodings was announced in~\cite{8}. This representation is slightly more general
than that by SLPs. However no details of the algorithm have ever been appeared.} In general, a string can have
exponentially many squares with respect to the size of its compressed representation. For example, the string $a^n$
has $\Theta(n^2)$ squares, while it is easy to build an SLP of size $O(\log n)$ that derives $a^n$. So we must
store information about squares in a compressed form. Also this implies that we cannot search for squares
consecutively by moving from one square to the ``next'' one.

\section{Preliminaries}

We consider strings of characters from a fixed finite alphabet $\Sigma$. The \emph{length} of a string $S$ is the number
of its characters and is denoted by $|S|$. The \emph{concatenation} of strings $S_1$ and $S_2$ is denoted by $S_1 \cdot
S_2$.  A \emph{position} in a string $S$ is a point between consecutive characters. We number positions from left to
right by $1,2,\dots,|S|-1$. It is convenient to consider also the position 0 preceding the text and the position $|S|$
following it. For a string $S$ and an integer $i$ where $0 \leq i \leq |S|$ we define $S[i]$ as the character between the positions
$i$ and $i+1$ of $S$. A \emph{substring} of $S$ starting at a position $\ell$  and ending at a position $r$ where $0\leq \ell < r \leq |S|$
is denoted by $S[\ell \dots r]$. We say that a substring $S[\ell \dots r]$ \emph{touches} a position $t$ if $\ell \leq t \leq r$.
A string is called a \emph{square} if it can be obtained
by concatenating two copies of some string. The position $|x|$ of a square $xx$ is called the \emph{center} of $xx$ and
$x$ is referred to as the \emph{root} of $xx$. A square $xx$ is called \emph{pure} if $x$ occurs exactly two times in
$xx$. A string $S$ is called \emph{p-periodic} if for a given integer $p$ and every position $i$ such that $0 \leq i
\leq |S| - p$ one has $S[i] = S[i + p]$. The integer $p$ is called the \emph{period} of $S$.

A \emph{straight-line program} (SLP) $\slp{S}$ is a sequence of assignments of the form:
$\slp{S}_1 = expr_1,\ \slp{S}_2 = expr_2, \dots, \slp{S}_n = expr_n,$ where $\slp{S}_i$ are \emph{rules} and $expr_i$
either is a symbol of $\Sigma$ (we call such rules \emph{terminal}), or $expr_i = \slp{S}_\ell\cdot \slp{S}_r \ (\ell, r < i)$
(we call such rules \emph{nonterminal}). Every SLP $\slp{S}$ generates exactly one string $S\in\Sigma^+$ and
we refer to $S$ as the \emph{text} generated by $\slp{S}$.

We adopt the following conventions in the paper: every SLP is denoted by a capital blackboard bold letter, for
example, $\slp{S}$. Every rule of this SLP is denoted by the same letter with indices, for example,
$\slp{S}_1,\slp{S}_2,\dots$. The text that is derived from a rule is denoted by the same indexed capital letter in
the standard font, for example, the text that is derived from $\slp{S}_i$ is denoted by $S_i$. The \emph{size} of an SLP $\slp{S}$ is
the number of its rules and is denoted by $|\slp{S}|$. The \emph{cut position} of a nonterminal rule
$\slp{S}_i = \slp{S}_\ell\cdot \slp{S}_r$ is the position $|S_\ell|$ in the text $S_i$.

\section{Basic operations}

In this section we present some basic operations over SLPs widely used in the paper. The operations are well-known and presented
here for the reader's convenience.

\vspace{5pt}

\problem{Subgrammar cutting (SubCut)}
{an SLP $\slp{S}$ that derives a text $S$, integers $\ell$ and $r$ such that $0 \leq \ell < r \leq |\slp{S}|$.}
{an SLP $\slp{S}\substr{\ell}{r}$ which derives the text $S\substr{\ell}{r}$.}

\noindent \textsc{Complexity:} There is an algorithm that solves \textbf{SubCut} using $O(|\slp{S}|)$ time and $O(|\slp{S}|)$ space.

\vspace{5pt}

\problem{Pattern matching (PM)}
{SLPs $\slp{S}$ and $\slp{T}$ that derives texts $S$ and $T$ respectively, $|S| \leq |T|$.}
{$O(|\slp{T}|)$ arithmetic progressions that describe the start positions of all occurrences of $S$ in $T$.}

\noindent \textsc{Complexity:} There is an algorithm \cite{15} that solves \textbf{PM} using $O(|\slp{T}|^2|\slp{S}|)$ time and
$O(|\slp{T}||\slp{S}|)$ space.

\vspace{5pt}

\problem{Substrings extending (SubsExt)}
{an SLP $\slp{S}$, integers $\ell_1, r_1, \ell_2$ and $r_2$ where $0 \leq \ell_1 < r_1 \leq |\slp{S}|, 0
\leq \ell_2 < r_2 \leq |\slp{S}|$ such that $S\substr{\ell_1}{r_1} = S\substr{\ell_2}{r_2}$.}
{integers $\ell_{ex}$ and $r_{ex}$ where $\ell_{ex}$ is the length of the longest common suffix of $S\substr{1}{r_1}$ and $S\substr{1}{r_2}$,
$r_{ex}$ is the length of the longest common prefix of $S\substr{\ell_1}{|S|}$ and $S\substr{\ell_2}{|S|}$.}

\noindent \textsc{Complexity:} There is an algorithm that solves \textbf{SubsExt} using $O(|\slp{S}|^3 \log|S|)$ time
and $O(|\slp{S}|^2)$ space.

\vspace{5pt}

\problem{Period termination}
{an SLP $\slp{S}$, an integer $p > 0$ and positions $\ell, r$ where $0 \leq \ell < r \leq |\slp{S}|$ such that $S\substr{\ell}{r}$ is $p$-periodic substring.}
{positions $t_L, t_R$ in the text $S$ where $p$-periodicity of $S\substr{\ell}{r}$ terminates from the left and from the right correspondingly.
It means that $S\substr{t_L}{r}$ is $p$-periodic while $S\substr{t_L+1}{r}$ is not $p$-periodic.}

\noindent \textsc{Complexity:} There exists an algorithm that solves \textbf{Period termination} using $O(|\slp{S}|^3 \log|S|)$ time
and $O(|\slp{S}|^2)$ space.

\section{Square-freeness checking algorithm}

\problem{Square-freeness}{an SLP $\slp{S}$ that derives a text $S$;}{ true/false, whether or not $S$ is square-free?}

\vspace{5pt}

\noindent \textbf{Squares location idea.} Suppose $xx$ is a square that occurs in $S$ and $c$ is the center of $xx$.
There is a unique rule $\slp{S}_j$ such that $xx$ fully occurs in $S_j$ and $xx$ touches the cut position of $\slp{S}_j$.
So for every integer $j \in \{1, 2, \dots, |\slp{S}|\}$ the algorithm looks for squares that touch the cut position of $\slp{S}_j$ only.

We use the following simple idea to obtain squares. If $B$ is a substring of $x$ then $B$ occurs at least two times in
$xx$. So the algorithm may fix some substring $B$ and look for other occurrences of $B$. Every pair of occurrences of
$B$ indicates that some squares are possible. Hence the algorithm has an additional step to check whether or
not a pair of substrings indeed corresponds to squares. We would like to note that such an algorithm is unable to find
all squares that touches the cut position of $\slp{S}_j$ directly. The algorithm partitions all squares into groups by length of
root. There is a unique integer $i_0$ such that $2^{i_0-1} \leq |x| < 2^{i_0}$. So for a fixed integer $j$ and every integer
$i \in \{1, \dots, \lceil \log_2 |S| \rceil\}$ the algorithm looks for squares $xx$ that touch the cut position of $\slp{S}_j$ and
$2^{i-1} \leq |x| < 2^i$.

\vspace{5pt}

\noindent \textbf{Local search idea.} Suppose $j$ and $i$ are fixed. Let $\gamma$ be the cut position of $\slp{S}_j$.
The algorithm partitions the $2^{i+1}$-neighborhood of $\gamma$ into 16 text blocks of equal length. Thus the length of each block is
equal to $2^{i-2}$. Let us enumerate the blocks from $B_1$ to $B_{16}$. For example, the left block that
touches $\gamma$ is $B_8$, the block left of $B_8$ is $B_7$ and the block right of $B_8$ is $B_9$. Depending
on the length of $S_j$ the neighborhood may contain less than 16 blocks or extreme blocks may have lengths less than
$2^{i-2}$. For squares whose centers locate at the blocks $B_{1}, B_{2}, \dots, B_{4}$ and $B_{13}, B_{14}, \dots, B_{16}$
we get a contradiction with restrictions on length of squares or with the condition that squares touch $\gamma$.
Therefore the algorithm looks for squares whose centers locate at blocks $B_{5}, B_{6}, \dots, B_{12}$ only.

Let $c$ be the center of a square $xx$ and lec $c$ belong to one of the eight central blocks $B_k$. Since $2^{i-1}
\leq |x|$, we conclude that $xx$ contains at least three consecutive blocks $B_{k-1}, B_{k}$ and $B_{k+1}$. All occurrences of $B_{k-1}$
in $B_{k+1}\cdot B_{k+2}$ can be obtained using the \textbf{PM} algorithm. So the algorithm takes every pair consisting of a block
$B_{k-1}$ and its occurrence in $B_{k+1}\cdot B_{k+2}$ and extends them to check whether or not they form any square.

\begin{lem}[{\rm\cite{2}}]
\label{lem:blocks}
Assume that the period of a string $B$ is $p$. If $B$ occurs only at positions $p_1 < p_2 < \dots < p_k$ of a text
$S$ and $p_k - p_1 \leq \frac{|B|}{2}$ then the $p_i$'s form an arithmetic progression with difference $p$.
\end{lem}

\noindent \textsc{Algorithm:} For every block $B_{k-1}$ the algorithm computes $\slp{B}_{k-1}$ and $\slp{B}_{k+1} \cdot \slp{B}_{k+2}$
using \textbf{SubCut}. Next it invokes \textbf{PM} with $\slp{B}_{k-1}$ and $\slp{B}_{k+1} \cdot \slp{B}_{k+2}$.
Lemma~\ref{lem:blocks} implies that the occurrences can be represented using at most four arithmetic
progressions. The algorithm compresses the occurrences into four arithmetic progressions. Finally it verifies whether or
not $B_{k-1}$ and a progression $\prog{a}{p}{t}$ of its occurrences form any square. There are the following cases:

\begin{itemize}
\item If $t = 0$ then there are no squares that satisfy the restrictions and the algorithm moves to the next block;

\item If $t = 1$ then the algorithm computes $\ell_{ex}$, $r_{ex}$ invoking \textbf{SubsExt} with $B_{k-1}$ and $S_j[a\dots
a + 2^{i-2}]$. If $\ell_{ex} + r_{ex} > a - (k-1)\cdot 2^{i-2}$ then there exists at least one square and the algorithm
returns $\bf{false}$. Otherwise there are no squares that satisfy the restrictions and it moves to the next block;

\item If $t \geq 2$ there exists at least one square and the algorithm returns $\bf{false}$.
\end{itemize}

\noindent \textsc{Complexity:} For each of the eight central blocks the algorithm invokes \textbf{SubCut} two times,
\textbf{PM} once and \textbf{SubsExt} at most four times. Hence the main step requires $O(|\slp{S}|^3 \cdot \log |S|)$ time
and $O(|\slp{S}|^2)$ space. The algorithm makes at most $|\slp{S}| \cdot \log |S|$ steps. Altogether we get the following theorem:

\begin{thm}
There is an algorithm that solves square-freeness problem using $O(|\slp{S}|^4\cdot \log^2{|S|})$ time and
$O(|\slp{S}|^2)$ space.
\end{thm}

\section{S-table and its properties}

The \emph{squares table} (shortly S-table) is a rectangular table $S(\slp{S})$ that holds information about all
squares in the text in a compressed form. The size of $S(\slp{S})$ is equal to $(\lfloor\log |S|\rfloor+1) \times
(|\slp{S}|+1)$. It is convenient to start numbering rows and columns of S-tables with 0. We denote the cell in the
$i$-th row and $j$-th column of table by $S(i,j)$. The cell $S(0,0)$ is always left blank. The cells $S(0,j)$ with
$j>0$ hold the rules of the SLP $\slp{S}$ ordered such that the lengths of the texts they derive increase. (If some
rules derive texts of the same length then the rules are listed in an arbitrary but fixed order). Thus, the first cells
of the 0-th row hold terminal rules followed by rules that derive texts of length~2, etc. The cells $S(i,0)$ with
$i>0$ hold segments $[2^{i-1}, 2^i - 1]$. Every cell $S(i, j)$ with $i,j>0$ holds information about families of squares.

There exist four types of families: an empty family (stored as $\emptyset$), a simple family of squares (stored using
4-tuple $\{|x|, p, c_\ell, c_r \}$ where $|x|$ is the length of root, $c_\ell$ is the position of the leftmost square,
$c_r$ is the center position of the rightmost square), a dynamic family of pure squares, a dynamic family of squares.
Both types of dynamic families contain squares with different root lengths and different centers. We are unable to master
an explicit compressed representation for the dynamic families that would be easy to handle with. This fact restricts the range of problems
that we can solve by usage of S-tables. But both dynamic families support the following properties:
\emph{total} (total number of squares that is contained in the family), \emph{reduction by length of root}
(for a fixed value of $|x|$, this property reduces a dynamic family to an array of simple families),
\emph{reduction by position} (for a fixed position $\ell$ of $S$ this property returns range of roots of squares that start from $\ell$).

Using information from an S-table it is easy to find information about all squares of fixed length, to compute total number of squares
that are contained in $S$, to find information about all squares that start from a fixed position, to find the longest square in $S$,
to check whether on not a text $S$ is square-free. At the same time there are problems that are not easy to decide via S-tables.
As an example one can take the following problem: for a given $\slp{S}$ that derives a text $S$ to construct an SLP that derives
the concatenation of all squares that are contained in $S$.
The example shows that an S-table accumulates a quantitative information about squares rather than information
appropriate for searching some fixed squares. It is a common feature of algorithms over SLPs that accumulate information
about all objects of a specified type. The similar situation appears in \textbf{Computing all palindromes}~\cite{16}.

\section{Computing all squares algorithm}

\problem{CAS}{an SLP $\slp{S}$ that derives a text $S$;}{a data structure (an S-table) that contains
information about all squares in $S$ in a compressed form.}

\noindent \textsc{Algorithm:} To solve the problem it remains to recognize all squares among a block $B_k$ and an
arithmetic progression $\prog{a}{p}{t}$ of its occurrences. Since $t$ can be exponentially large relative to
size of $\slp{S}$, the algorithm cannot consecutively check every occurrence of $B_k$.

Let $\alpha_L, \alpha_R$ be the output of \textbf{Period termination} for $\slp{S}_j, B_k =
S_j\substr{(k-1)\cdot2^{i-2}}{k\cdot 2^{i-2} -1}$. The positions $\alpha_L, \alpha_R$ are called \emph{defined} if they satisfy the
following inequalities: $(2k-1)\cdot2^{i-2} - (a + p\cdot t) \leq \alpha_L$, $\alpha_R < a + 2^{i-2}$.
Otherwise they are called \emph{undefined}. Since $2^{i} - 1$ is the greatest length of a root, the start
positions of pure squares cannot be further right than $(2k-1)\cdot2^{i-2} - (a + p\cdot t)$. Analogously let $\gamma_L, \gamma_R$ be the output of
\textbf{Period termination} for $\slp{S}_j, S_j\substr{a}{a + p\cdot t}$. The positions $\gamma_L, \gamma_R$ are called
\emph{defined} if they satisfy the following inequalities: $(k-1)2^{i-2} \leq \gamma_L$ and $\gamma_R < 2(a + p\cdot
t) - (k-1)2^{i-2}$. Otherwise they are called \emph{undefined}. The following lemmas present crucial relations between
$\alpha_L, \alpha_R, \gamma_L$ and $\gamma_R$.

\begin{lem}[{\rm\cite{2}}]
If one of $\alpha_R$ or $\gamma_L$ is defined then the other one is defined as well and $\alpha_R - \gamma_L \leq p$.
\end{lem}

\noindent \textbf{Case 1: both {\boldmath $\alpha_R$} and {\boldmath $\gamma_L$} are defined.}

\begin{lem}[{\rm\cite{2}}]
If both $\alpha_R, \gamma_L$ are defined then:

\begin{enumerate}
\item Squares that contain $B_k$ and are centered at positions $h$ such that $h \leq \gamma_L$ may exist only if
$\alpha_L$ is defined. These squares constitute a family of squares that corresponds to the difference
$|x| = a + t'\cdot p - (k-1)2^{i-2}$, provided that there exists some $t' \in \{0\dots t\}$ such that
$\gamma_L - \alpha_L = a + t'\cdot p - (k-1)2^{i-2}$.
\item Squares that contain $B_k$ and are centered at positions $h$ such that $\alpha_R < h$ may exist only if
$\gamma_R$ is defined. These squares constitute a family of squares that corresponds to the difference
$|x| = a + t''\cdot p - (k-1)2^{i-2}$, provided that there exists some $t'' \in \{0\dots t\}$ such that
$\gamma_L - \alpha_L = a + t''\cdot p - (k-1)2^{i-2}$.
\end{enumerate}
Notice that if $\alpha_R < \gamma_L$, then squares whose center $h$ satisfies $\alpha_R < h \leq\gamma_L$ may
exist only if both $\alpha_L$ and $\gamma_R$ are defined and $\gamma_R - \alpha_R = \gamma_L - \alpha_L$.
\label{lem:simple_squares}
\end{lem}

Using Lemma~\ref{lem:simple_squares} the algorithm finds simple families of squares.
If $\alpha_R < \gamma_L$ the algorithm may find at most three simple families of squares:
$\{\gamma_L - \alpha_L, p, k \cdot 2^{i-2}, \alpha_R\}, \{\gamma_R - \alpha_R, p, \alpha_R + 1, \gamma_L\},
\{\gamma_L - \alpha_L, p, \gamma_L + 1, \min\{a,(k+1) \cdot 2^{i-2}\}\}$. Otherwise it may find at most two simple
families of squares: $\{\gamma_L - \alpha_L, p, k \cdot 2^{i-2}, \gamma_L - 1\}, \{\gamma_R - \alpha_R, p, \alpha_R,
\min\{a,(k+1) \cdot 2^{i-2}\}\}$.

\begin{lem}[{\rm\cite{2}}]
If $\alpha_R, \gamma_L$ are defined and $\gamma_L < \alpha_R$, then there might be a family of squares
associated with each of the differences $|x| = a + p\cdot t' - (k-1)\cdot 2^{i-2}$ where $t' \in \{0\dots t\}$
with centers at positions $h$ such that $\gamma_L < h \leq \alpha_R$. The squares in each such family are all
pure squares and they are centered at positions $h$ such that $\max(\alpha_L + |x|, \gamma_L) < h \leq
\min(\alpha_R, \gamma_R-|x|)$. Notice that such a family is not empty only if $|x| < \min(\alpha_R-\alpha_L,
\gamma_R-\gamma_L)$.
\label{lem:dynamic_pure_squares}
\end{lem}

Using Lemma~\ref{lem:dynamic_pure_squares} the algorithm finds at most one dynamic family of pure squares and stores
it in the following way: $\{k, \prog{a}{p}{t}, \alpha_L, \alpha_R, \gamma_L, \gamma_R\}$.

\noindent \textbf{Case 2: both {\boldmath $\alpha_R$} and {\boldmath $\gamma_L$} are undefined.}
$S\substr{\alpha_L}{\gamma_R}$ is $p$-periodic and contains squares with different centers and different lengths of
roots. The algorithm accumulates all squares into a single dynamic family of squares that is stored in the following way: $\{k,
\prog{a}{p}{t}, \alpha_L, \gamma_R\}$.

\noindent \textsc{Complexity:} For each central block the algorithm computes four arithmetic progressions that describe all
occurrences of the block. So the algorithm invokes \textbf{SubCut} two times and \textbf{PM} once. For each arithmetic progression and the
block, the algorithm calculates $\alpha_L, \alpha_R, \gamma_L$ and $\gamma_R$. So the algorithm invokes
\textbf{Period termination} two times. After that it extracts families of squares and adds them to the S-table. Totally at
the main step the algorithm invokes \textbf{SubCut} at most 16 times, \textbf{PM} at most 8 times and \textbf{Period termination} at
most 64 times. The main step requires $O(|\slp{S}|^3 \cdot \log |S|)$ time and $O(|\slp{S}|^2)$ space. The algorithm
makes $|\slp{S}| \cdot \log |S|$ steps. Altogether we get the following theorem:

\begin{thm}
There is an algorithm that solves Computing all squares problem using $O(|\slp{S}|^4 \cdot \log^2{|S|})$ time and
$O(|\slp{S}| \cdot \max(|\slp{S}|, \log{|S|}))$ space.
\end{thm}

\section{Conclusion}

We have presented an algorithm that for a given SLP $\slp{S}$ deriving a text $S$ fills out a table containing
information about all squares that occur in $S$ in time $O(|\slp{S}|^4\cdot \log^2{|S|})$ using
$O(|\slp{S}|\cdot \max\{ |\slp{S}|, \log{|S|}\})$ space.

We emphasize main features of the algorithm. The algorithm presents a new technique for SLPs processing.
It is divided into independent steps in contrast to classical algorithms in this area which consecutively accumulate information.
As a result it can be parallelized. The algorithm is quite difficult for practical implementation.
It is not excluded that constants hidden in the "O" notation are actually very big. The present upper bound for the time complexity
is rather high and is not matched by any known lower bound. The question whether the upper bound can be lowered to cubic in $|\mathbb{S}|$
remains open.

{\footnotesize
\bibliography{cas_problem_rufidim}{}
\bibliographystyle{plain}
}

\end{document}


\section{Buzzer}\label{s:buzzer}

\project{Morse code SOS using a Buzzer}{In this project, you will learn how to wire and program a buzzer, and use it to produce Morse code.

You will be using `subroutines'.
}

\subsection*{Equipment Required}

The cuircuit built in Sectino~\ref{s:button}, plus the following:
\begin{itemize}
\item Buzzer
\item 1 x M/F jumper wire
\item 1 x M/M jumper wire
\end{itemize}

\subsection*{Additional Parts}

You will be adding a buzzer to the LED and switch circuit that you made in Section~\ref{s:button}.  Let us look at the additional component.

Do not skip this section, as you will need to know how to connect the buzzer.

\subsubsection*{Buzzer}

\limage{0.15}{buzzer}

The buzzer supplied in the EduKit is an `active' buzzer, which means that it only needs an electric current to make a noise.  In this case, you are using the Raspberry Pi to supply that current.

The buzzer has positive and negative legs.  The longer leg is positive (shown in red in the diagram), the shorter leg is negative (shown in black on the diagram).

~\hfill
\vspace{5ex}
~\hfill
\newpage

\subsection*{Building the Circuit}

\limage{0.5}{buzzer-circuit}

Before you connect additional components to your circuit, you should turn off your Pi.

Leave the LED and switch circuit from Section~\ref{s:button} in place.

Place the buzzer on the breadboard straddling the middle divide.  The longer leg should be connected via a jumper wire to GPIO 16.

The other leg should be connected to the ground rail.

GPIO 16 will be an output pin and, when it is set on, the buzzer will sound.

Remember that we will need to ensure that this pin can be used as an output.  This pin is bit 4 in the user port and has a value of 16.  You will need to set this bit in the DDR to 1 to allow output.

~\hfill

~\hfill

~\hfill

~\hfill

~\hfill

~\hfill

~\hfill

~\hfill

~\hfill

\subsection*{Concepts}

You are going to be using `subroutines' in the code below.  These are pieces of code that you may want to run more than once, but by using subroutines, you only have to write them once.  You then `call' that subroutine from within your code each time you want to run it.

A subroutine is any section of code which ends with a `RETURN' statement:
\begin{basic}
200 PRINT "HELLO WORLD!"
210 RETURN
\end{basic}

To use this subroutine, you must `call' it by using a `GOSUB' statement with the line number that starts the subroutine:
\begin{basic}
50 GOSUB 200
\end{basic}

Now, every time BASIC sees `GOSUB 200' in your code, it will print ``HELLO WORLD!''.

\subsection*{Code}

Type in the following code below exactly as seen:
\begin{basic}
10 REM MORSE CODE
20 REM SETUP LOCATIONS
30 UP=56577:DDR=56579
40 REM PIN VALUES FOR BUZZER
50 Z=16
60 REM SET BUZZER PIN FOR OUTPUT
70 POKE DDR,Z
80 REM CLEAR USER PORT (ALL PINS OFF)
90 POKE UP,0
100 PRINT CHR\$(147);:REM CLEARS THE SCREEN
110 PRINT "MORSE CODE"
120 REM PROMPT THE USER FOR INPUT
130 INPUT "HOW MANY TIMES FOR SOS TO LOOP";C
140 FOR L=1 TO C
150 GOSUB 1500:REM S
160 GOSUB 1300:REM LETTER SPACE
170 GOSUB 1600:REM O
180 GOSUB 1300:REM LETTER SPACE
190 GOSUB 1500:REM S
200 GOSUB 1400:REM WORD SPACE
210 NEXT L
220 END
1000 REM A DELAY OF D TENTHS OF A SECOND
1010 T=D*72
1020 FOR I=1 TO T:NEXT I
1030 RETURN
1100 REM A SINGLE MORSE DOT
1110 POKE UP,Z
1120 D=1:GOSUB 1000
1130 POKE UP,0
1140 D=1:GOSUB 1000
1150 RETURN
1200 REM A SINGLE MORSE DASH
1210 POKE UP,Z
1220 D=3:GOSUB 1000
1230 POKE UP,0
1240 D=1:GOSUB 1000
1250 RETURN
1300 REM THE SPACE BETWEEN LETTERS
1310 D=2:GOSUB 1000
1320 RETURN
1400 REM THE SPACE BETWEEN WORDS
1410 D=6:GOSUB 1000
1420 RETURN
1500 REM THE MORSE FOR S
1510 GOSUB 1100:REM DOT
1520 GOSUB 1100:REM DOT
1530 GOSUB 1100:REM DOT
1540 RETURN
1600 REM THE MORSE FOR O
1610 GOSUB 1200:REM DASH
1620 GOSUB 1200:REM DASH
1630 GOSUB 1200:REM DASH
1640 RETURN
\end{basic}

Save the program as ``6 MORSE CODE''.

\subsection*{Running the Code}

Run the program.  You will be prompted for the number of times you want to repeat `SOS'.

\subsection*{Challenge}

Using the above code as your template, write another program that will allow you to sound any Morse code you choose.  Use the following rules:
\begin{itemize}
\item The length of a dot is one unit.
\item The length of a dash is three units.
\item The space between the parts of each letter is one unit.
\item The space between letters is three units.
\item The space between words is seven units.
\item The letter and number codes are:
\end{itemize}
\begin{center}
\begin{tabular}{llllllllllll}
A & \ds\dl & G & \dl\dl\ds & M & \dl\dl & S & \ds\ds\ds & Y & \dl\ds\dl\dl & 4 & \ds\ds\ds\ds\dl \\
B & \dl\ds\ds\ds & H & \ds\ds\ds\ds & N & \dl\ds & T & \dl & Z & \dl\dl\ds\ds & 5 & \ds\ds\ds\ds\ds \\
C & \dl\ds\dl\ds & I & \ds\ds & O & \dl\dl\dl & U & \ds\ds\dl & 0 & \dl\dl\dl\dl\dl & 6 & \dl\ds\ds\ds\ds \\
D & \dl\ds\ds & J & \ds\dl\dl\dl & P & \ds\dl\dl\ds & V & \ds\ds\ds\dl & 1 & \ds\dl\dl\dl\dl & 7 & \dl\dl\ds\ds\ds \\
E & \ds & K & \dl\ds\dl & Q & \dl\dl\ds\dl & W & \ds\dl\dl & 2 & \ds\ds\dl\dl\dl & 8 & \dl\dl\dl\ds\ds \\
F & \ds\ds\dl\ds & L & \ds\dl\ds\ds & R & \ds\dl\ds & X & \dl\ds\ds\dl & 3 & \ds\ds\ds\dl\dl & 9 & \dl\dl\dl\dl\ds
\end{tabular}
\end{center}

\subsection*{Advanced Challenge}

Using what you have learned so far, especially from Section~\ref{s:button}, make your own Morse code machine by making the buzzer sound when you press the button.


\documentclass[a4paper,10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{fullpage}
\usepackage{amsmath}

%opening
\title{MoData - A Distributed Hash Table Based Filestore for Everyone}
\author{Merritt Boyd, Russell Cohen, Joseph Lynch}

\begin{document}

\maketitle

\section{Problem}
Persistent, reliable, online storage solutions such as Dropbox, Box, and Google
Drive are all for-pay services controlled by large multinational companies.
Many users do not wish to pay for these services and do not want their data
controlled by large companies.  At the same time, most computer users have
excess disk storage and network bandwidth. It seems that a system where people
share their bandwidth or storage in exchange for a free, peer-hosted cloud
storage alternative is very viable. We strive to create a system to allow
access to your files wherever you go, without relying on a central party
required to host files.

The storage solution should prevent the users files from being compromised
either by malicious corruption and make best possible efforts to prevent loss.

\section{Solution}
We present a decentralized peer-to-peer key-value storage system targeted
towards nodes with low availability. The software is intended to be run on
personal computers, especially laptops, which may frequently disconnected from
the network and possibly powered off.  By heavily replicating user data
across the cluster, we aim to maintain availability of user data from any device
even in the absence of much of the peak size of the network.

Our system stores files indexed by a key which is simply a hash of the file’s
contents.  As we are not optimizing for peer-to-peer file sharing, we provide no
in-system mechanism for listing a user’s files -- this metadata must be
maintained and transferred by the user out-of-band, for instance on a USB flash
drive.  This provides extra security by requiring a token not stored in the
cloud to access files.

\section{Implementation}
The project is split into two main components, the server and the client.  The
server is a straightforward RESTful API that implements a Kademlia based DHT,
and the client is a collection of python scripts that provide an easy to use
file interface as well as additional redundancy.

\subsection{Server - Kademlia DHT}
The server implements the standard Kademlia Distributed Hash Table algorithm
\cite{kademlia}\cite{xlattice}.  Kademlia can automatically handle nodes
joining, leaving and publishing key/value pairs to the network.  The algorithm
is fundamentally peer
to peer, and nodes join by bootstrapping in on old nodes.  Each node is given
an identifier, and then consistent hashing based on the XOR metric is used to
evenly distribute keys among available nodes.  All keys and node-ids are 160
bit identifiers. The ``closeness''  metric of XOR is used to define that a key
K's closeness to a node N is defined as $K \oplus N$.  Because XOR satisfies the
triangle identity, this guarantees that there is a globally correct set of
closest nodes for any given key.

All distributed operations must first do a distributed find node, which
collects nodes nearby to the key by calling primitive find-node on hosts that a
particular peer knows about.  By chaining these requests together, we can build
a list of nearest nodes in O(log(n)) time, where n is the size of the network.
After finding the list of nearest nodes, stores then send primitive store
operations to those nodes, and find-values send primitive find-value calls.
All changes are persisted to disk.

Our server exposes the following REST API to meet the Kademlia specification.
\begin{center}
\begin{tabular}{| l | c | p{5cm} |}
\hline
\textbf{Endpoint} & \textbf{Type}& \textbf{Action}\\
\hline
/find-node/\{node-id\} & GET & Returns locally known nodes near the node-id\\
\hline
/find-value/\{key\} & GET & Returns the locally known value for a key\\
\hline
/store?key=\{key\}\&data=\{data\} & POST & Locally stores a value for a key\\
\hline
/ping & GET & Health check, also updates contacts\\
\hline
/distributed/find-node/\{node-id\} & GET & Returns globally known nodes near
the node-id\\
\hline
/distributed/find-value/\{key\} & GET & Returns the globally known value for a
key\\
\hline
/distributed/store?key=\{key\}\&data=\{data\} & POST & Stores the value for the
key on nearby nodes

\end{tabular}
\end{center}

\subsection{Client - Erasure Coding File Transfer}
To help cope with low availability, files are erasure encoded. This gives us a
knob which we can turn to set the percentage of chunks that the system can
loose, but still recover the file. Our client uses using Reed-Solomon codes, an
optimal erasure encoding scheme. It produces a number of chunks. From those
chunks it creates a metadata file containing the hash for each chunk. A hash is
enough information to retrieve the data from the DHT. The client then
attempts to get sufficient chunks to decode the file, decoding the resulting
chunks client-side.

\section{Challenges and Analysis}
The most challenging part of this project was getting a functional kademlia
based DHT and building additional availability guarantees into the system.

Because we are assuming that the target consumer will be using laptops, we
chose usage analysis of wifi networks as the starting point for availability
analysis. In particular, we assume that most wifi users behave in similar
fashions to that of the Mountain View wide wifi provided by Google \cite{wifi}.
Using these assumptions, we can do a quick back of the envelope calculation for
data loss. Assuming that we republish keys every hour, we only have to care
about losing data in a given hourly period, since at the end of that period we
will re-replicate the key.  We can choose the replication factor of Kademlia to
trade off bandwidth with availability, and a commonly chosen value is 20.  Due
to consistent hashing, we can say that node failures are independent, and that
the probability of a given node failure is equal to the probability of failure
conditioned on the node type.  Node type is split into long lived, which are on
all day, medium lived which are on for between 100 and 1000 minutes, and short
lived which are on for less than an hour.
\begin{multline}
Pr(lose\_key) = Pr(k\_nodes\_fail) = Pr(single\_failure)^{20}
\\
Pr(single\_failure) =
Pr(failure | long\_lived)*Pr(long\_lived) +
\\
Pr(failure | medium\_lived)*Pr(medium\_lived) +
\\
Pr(failure | short\_lived)*Pr(short\_lived)
\\
\end{multline}

We can estimate the duration probabilities from the Wifi paper Figure 8
\cite{wifi} and to be as conservative as possible we say that $Pr(failure)=1$
for all types except long lived, for which $Pr(failure)=0$, this yields
$Pr(single\_failure)= 0*.2 + 1*.6 + 1*.2 = .8$, and
therefore $Pr(lose\_key) \approx 0.01$.  Due to erasure coding with code rate
of 1/2, the probability of losing a file with N chunks is
$Pr(lose\_key)^{\frac{N}{2}}$.
This means that to lose a 1 Megabyte file, one must lose 125 keys (assuming a
4kb chunk size). Losing access to a file therefore has probability
$Pr(data\_loss) \approx 5*10^{-243} \approx 0$.  Even if access is lost due to
massive correlated failure, it will be restored once nodes return to the
network.

\pagebreak
\section{Bibliography}
\bibliographystyle{IEEEtran}
\bibliography{writeup}

\end{document}


\documentclass[main_montangero.tex]{subfiles}
\begin{document}

\section{Time-dependent perturbation theory}

We have an atom or some quantum system, and we manipulate it by sending an EM pulse against it. How will it change?

Say we have some discrete energy levels, and a continuous spectrum after some threshold energy.
The photon can excite the ground state \(\ket{i} \) to some excited state \(\ket{f} \), or vice versa.
This can happen between discrete energies, or with the continuous energies.

We need to solve the time-dep Schrödinger equation:

\begin{equation}
    i \hbar \dv{}{t} \ket{\psi(t)} = \qty[H_0 + \lambda W(t)]\ket{\psi(t)}
\end{equation}

We work with the unperturbed eigenstates \(H_0 \ket{\varphi_n}  = E_n \ket{\varphi_n}  \), we assume \(\lambda \ll 1\),
and we say that the starting state at \(t=0\) is an unperturbed eigenstate.

What is the probability of getting a state \(f\)?

\begin{equation}
    \P _{if}(t) = \abs{\braket{\varphi_f}{\psi(t)} }^2
\end{equation}

we can get resonance.
For continuous states this changes a bit but we can generalize.

We expand

\begin{equation}
    \ket{\psi(t)} = \sum c_n(t) \ket{\varphi_n}   \qquad c_n(t) = \braket{\varphi_n}{\psi(t)}
\end{equation}

We can compute the matrix elements of the perturbation: \(\bra{\varphi_n} W(t) \ket{\varphi_k} = W_{nk}(t)\) and of the Hamiltonian:
\(\bra{\varphi_n} H_0 \ket{\varphi_k} = \delta_{nk} E_n\). Putting these in the Schrödinger equation, we get

\begin{equation}
    i \hbar \dv{}{t} c_n(t) = E_n c_n(t) + \sum _{k} \lambda W_{nk} c_k (t)
\end{equation}

We go in interaction picture: \(b_n(t) = c_n(t) \exp(+i E_n t / \hbar) \), which nullifies the unperturbed evolution.
Putting this inside the equation we get

\begin{equation}
    i \hbar \dot{b}_n(t) = \lambda \sum _k \exp(i \omega_{nk}) W_{nk} b_k (t)
\end{equation}

with \(\omega_{nk = (E_n - E_k) / \hbar}\). We can expand the \(b_n(t)\) in \(\lambda\):

\begin{equation}
    b_n(t) = \sum _{i}  b_n ^{(i)} \lambda^i (t)
\end{equation}

We know that for some \(i\) we must have \(b_n ^{(r)}(t=0) = \delta_{ni} \delta_{r0} \) and so:

\begin{align}
    i \hbar \dot{b}_n ^{(0)}(t) &= 0  \\
    i \hbar \dot{b}_n ^{(r)}(t) &= \sum _{k} \exp(i \omega_{nk} t) W_{nk} b_n ^{r-1}(t)
\end{align}

Then to order \(\lambda^1\):

\begin{equation}
    i \hbar \dot{b}_n (t) = \exp(i \omega_{nk}t) W_{nk}(t)
\end{equation}

\begin{equation}
    b_n^{(1)}(t) = \frac{1}{i \hbar} \int _{0}   ^{t} \dd{\tau} \exp(i \omega_{ni} \tau)W_{ni}(\tau)
\end{equation}

So \(\P _{if}(t) = \abs{c_f(t)}^2 = \abs{b_f(t)}^2\)

\begin{equation}
    \P _{if}(t) = \frac{\lambda^2}{\hbar^2} \abs{\int _{0}   ^{t} \dd{\tau} \exp(i \omega_{fi} \tau)W_{gi}(\tau)  }^2
\end{equation}

\paragraph{Example}

Let us take a \(W(t) = - W \sin(\omega t)\). Then,

\begin{equation}
    b_n^{(1)}(t) = - \frac{W_{ni}}{2 \hbar} \int _{0}   ^{t} \dd{\tau} \qty(\exp(i (\omega_{ni} - \omega) \tau) - \exp(-i (\omega_{ni} - \omega) \tau))
\end{equation}

So,

\begin{equation}
    \P _{if} (t, \omega) = \frac{\abs{W_{if}}^2 }{4 \hbar^2} F(t, \omega - \omega_{fi})
\end{equation}

where

\begin{equation}
    F(\omega, t) = \qty(\frac{\sin(\omega t/2)}{\omega/2})^2
\end{equation}

This is a sinc squared.

\subsection{Fermi's golden rule}

Is applying what we saw to continuous spectrums. Now we have some \(\braket{\alpha}{\alpha'} = \delta(\alpha - \alpha') \). We want to see what is the probability of the final state being in a neighbourhood of \(\alpha\).

We define the state density by \(\dd{\alpha} = \rho(\beta, E ) \dd{\beta} \dd{E} \) where the index \(\beta\) takes account of the degeneracy, which can be continuous.

\begin{equation}
    \delta \P \qty(\alpha_f, t) = \int   \dd{\alpha} \abs{\braket{\alpha}{\psi(t)} }^2
\end{equation}

where \(\alpha \in D_f\). So, we can change variable into

\begin{equation}
    \delta \P \qty(\alpha_f, t) = \int  \abs{\braket{\beta, E}{\psi(t)} }^2 \rho(E, \beta)  \dd{E} \dd{\beta}
\end{equation}

We can write

\begin{equation}
    \abs{\braket{\beta, E}{\psi(t)} }^2
    = \frac{1}{\hbar^2} \abs{\bra{\beta, E} W \ket{\varphi_i}  }^2 F\qty(t, \frac{E-E_i}{\hbar})
\end{equation}

where \(\lim_{t \rightarrow \infty} F\qty(t, \frac{E-E_i}{\hbar}) = 2 \pi i \hbar \delta(E - E_i)\).
Then

\begin{equation}
    \delta \P (\varphi_i, \alpha_f, t)
    = \delta \beta_f \frac{2 \pi i t}{\hbar} \abs{\bra{\beta_f, E_f = E_i} W \ket{\varphi_i}}^2
    \rho(\beta, E_f)
\end{equation}

Then

\begin{equation}
    W(\varphi_i, \alpha_f) = \dv{}{t} \fdv{\P}{\beta} = \frac{\pi}{2 \hbar}
    \abs{\bra{\beta_f, E_f = E_i + \hbar \omega} W \ket{\varphi_i}}^2
    \rho (\beta_f, E_f = E_i + \hbar \omega)
\end{equation}

The more states we have in the final configuration, the greater the probability. We are assuming here that the state density is constant in the degeneracy, and we can split the degeneracy and energy contributions.

\section{How to build a quantum computer}

Di Vincenzo criteria (2000): what is needed to have a true quantum computer.

\begin{enumerate}
    \item Scalability, well defined qubit;
    \item Reset: we must be able to reset the computer surely into a state \(\ket{0} \);
    \item Long coherence time wrt gate duration;
    \item Universal set of gates;
    \item Efficient readout;
\end{enumerate}

If our decoherence time is \(\tau_d\) and our gate time is \(\tau_g\), we need \(\tau_d / \tau_g \gtrsim 10^4\) in order to have time to do error correction.

Proposals:

\begin{itemize}
    \item Cauidiy: QED;
    \item Solid-state electron spins;
    \item Cold atoms;
    \item Trapped ions;
    \item Superconductive circuits.
\end{itemize}

\subsection{Trapped ions}

We can trap them with electric fields: Paul trap. We cannot do the intuitive thing, because of Gausses' law. We can work around it by making them time-dependent. Think of it like this: saddle which spins, an object in the saddle point will be stable if the rotation is fast enough.

We get three harmonic oscillators, with \(\omega_{x,y} \gg \omega_z\). The \(z\) direction is the 'quantum' degree of freedom: the state comes from the atom state \(i\) and the oscillator state \(n\).

Can we put many qubits in there? Our Hamiltonian will be

\begin{equation}
    H  = \sum  \frac{p_i^2}{2m} + \sum  \frac{1}{2} \omega_z^2 z_i^2
    + \sum_i \sum_{j<i} \frac{q^2}{4 \pi \varepsilon_0 \abs{r_i - r_j} }
\end{equation}

They repel each other, we can diagonalize this matrix and get the modes of oscillation.

So we have \(\ket{\alpha_1 \alpha_2 \dots \alpha_N n} \) where the \(n\) is the global oscillation. Our single qubit is \(\ket{\alpha_i n} \). We have the states \(\ket{g, 0} \), \(\ket{g, 1} \), \(\ket{g, 2} \) \dots and \(\ket{e, 0} \), \(\ket{e, 1} \) \dots

We can use a laser to excite the ground state into a vibrational excited state... we choose the right frequency to go from \(\ket{g, k} \) to \(\ket{e, k-1} \) which spontaneously decays into \(\ket{g, k-1} \). This is \emph{side-band cooling}. This can prepare a state with \(\P > 99.9\%\).

Cirac-Zoller Gate: allows us to entangle states with stuff like a CPHASE by interacting with the global vibration.

\subsection{Superconductive qubit}

Something like Bose-condensing electrons: Cooper pairs, with opposing momentums: so the entanglement is in the Fourier space, they are very delocalized in the position space.
Cooper pair currents are the superconductive currents.

We use Josephson juctions inside regular circuits:
two superconductors, separated by a thin insulant. Cooper pairs can tunnel through the insulant.

Charge qubit: quantum numbers inside the superconductor are \(n\), \(\varphi\), with \([n, \varphi] = i\).

\begin{equation}
    H = E_C \qty(n-n_g)^2 - E_J \cos \varphi
\end{equation}

with \(n_g - c_g V /(2e)\), and \(E_C = (2e)^2 / (2(C_J + C_g))\). We can write the eigenstates as \(\ket{n} \), and

\begin{equation}
    H = E_C \sum  (n-n_g) \dyad{n} - \frac{1}{2} E_J \sum \qty(\ketbra{n+1}{n} + \ketbra{n}{n+1}  )
\end{equation}

\end{document}


\documentclass[a4paper,10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{amssymb,amsmath,amsfonts}
\usepackage{hyperref}
\usepackage[a4paper, margin=.5in]{geometry}

%opening
\title{Documentation: A Unifying Mechanistic Model of Excitatory-Inhibitory Interactions in the Auditory Cortex}
\author{Youngmin Park}

\newcommand{\y}[1]{{\texttt{#1}}}

\begin{document}

\maketitle

%\begin{abstract}

%\end{abstract}

\section{Introduction}
The primary tools of this paper are Python (with numpy, scipy, matplotlib), XPPAUTO (XPPAUT or XPP for short) \cite{ermentrout2002simulating}, a Python binding for XPP, \y{Py\_XPPCALL} \cite{xppy}, and Brian2 \cite{Stimberg595710}. Please contact me with any questions about these programs: \y{ympark1988@gmail.com}\footnote{I used XPP extensively in my PhD, and XPP was created by and continues to be developed by Bard Ermentrout, my doctoral advisor. In addition, I am one of the primary contributors to \y{Py\_XPPCALL}.}.

I highly recommend using Ubuntu, since the most stable versions of XPP are currently on Ubuntu. At the time of writing, I have used Ubuntu 16.04 (Python 2.7.12, numpy 1.15.2, scipy 1.1.0, matplotlib 2.2.3), Ubuntu 18.04.2 (Python 2.7.15rc1, numpy 1.15.2, scipy 1.1.0, matplotlib 2.2.3), and XPPAUT version 8 to successfully run all code.

\section{Rate Models}

Rate models are implemented in XPPAUTO. In order to plot the simulations, I run XPPAUTO through the Python binding \y{Py\_XPPCALL}.

\subsection{XPPAUTO}
All rate models were implemented in \texttt{XPPAUTO} for convenience. XPP auto uses an almost plain-text file format for simulating ordinary differential equations (ODEs). There is extensive documentation on XPPAUTO on Bard's website:
\url{http://www.math.pitt.edu/~bard/xpp/help/xppodes.html}. The linked page provides full documentation of ode file syntax. XPPAUTO also comes with a graphical user interface (GUI), but this will not be needed for this documentation. The XPP .ode files for this project are located in the directory \url{https://github.com/geffenlab/park_geffen/rate_models/xpp}.

Let us take a look at one of the ode files, \texttt{cols3\_fs.ode}, which is the three-unit rate model for the forward suppression paradigm. The file begins with a function definition and a bunch of parameters:
\begin{verbatim}
f(x)=al*heav(x)*x*heav(1/al-x)+heav(x-1/al)
dan(x)=exp(-tl*x)
p al = 3

p wee=1.1,wep=2,wes=1
# either wpe=1.2, or wpp=1.8 to reduce SOM disinhibition activity.
p wpe=1.,wpp=2,wps=2

p wse=6,wss=0,wsp=0
p wee2=1,wpe2=1.25,wse2=.125
#p wee2=1,wpe2=1.5,wse2=.25

par tau1=1,tau2=1
par et=.7,pt=1,st=1
par pv_opto=0,som_opto=0

p q=1.3,tl=1
p taud1=150,taud2=10
p tde1=150,tde2=2
p lat=.65
\end{verbatim}
Comment lines are denoted by the pound symbol (\#). The function \texttt{f} is the firing-rate function, which corresponds to Equation (2) in the manuscript (There is a typo in the current manuscript. All simulations were run using the correct $f$ as shown in the code). The function is zero until $x=0$, at which point the function increases linearly with slope $\text{al}=3$ as a function of $x$, until the function reaches the value 1 (when $x=1/\text{al}$, at which point the function ``saturates'' at the value 1. The second function, which I named \y{dan}, is a decaying exponential with rate \y{tl}, which we will later use to modulate the square-wave inputs into the model. We use the same firing rate function for all models, which is a common choice in modeling studies \cite{natan2015complementary,yarden2017stimulus}.

The notation \texttt{p} and \texttt{par} both denote a line consisting of parameters. The first set of parameters:
\begin{verbatim}
p wee=1.1,wep=2,wes=1
p wpe=1.,wpp=2,wps=2

p wse=6,wss=0,wsp=0
p wee2=1,wpe2=1.25,wse2=.125
\end{verbatim}
are for recurrent excitation (\texttt{wee}), PV-to-Pyr inhibition (\texttt{wep}), SOM-to-Pyr inhibition (\texttt{wes}), Pyr-to-PV excitation (\texttt{wpe}), recurrent PV inhibition (\y{wpp}), SOM-to-PV inhibition (\y{wps}), Pyr-to-SOM excitation (\y{wse}), PV-to-SOM inhibition (\y{wsp}), and recurrent SOM inhibition (\y{wss}). The remaining terms are for the lateral weights. Lateral Pyr-to-Pyr (\y{wee2}), lateral Pyr-to-PV (\y{wpe2}), and lateral Pyr-to-SOM (\y{wse2}). These parameters appear in Equation 4, and in the unit equations on page 2.

The next set of parameters:
\begin{verbatim}
par tau1=1,tau2=1
par et=.7,pt=1,st=1
par pv_opto=0,som_opto=0
\end{verbatim}
Are time constants \y{tau1} and \y{tau2} are for the inhibitory populations, PV, and SOM, respectively. This rate model is written so that 1 time unit is 10ms, i.e., \y{tau1=1} means $\tau_1 = 10$ms \cite{tsodyks1997neural,natan2015complementary}. If needed, one could perform the necessary transformation in time so the model displays the correct time units by default.

The next line is for thresholds in the excitatory activity \y{et}, PV activity \y{pt}, and SOM activity \y{st}. These thresholds are minimum values beyond which the population activity can influence the postsynaptic population. Finally, the \y{pv\_opto} and \y{som\_opto} parameters set the level of optogenetic \textit{inactivation}, i.e., positive values of \y{pv\_opto} inactivation PVs, and likewise for \y{som\_opto}. In the paper I flip these numbers for readability.

Next up:
\begin{verbatim}
p q=1.3,tl=1
p taud1=150,taud2=10
p tde1=150,tde2=2
p lat=.65
\end{verbatim}
\y{q} is the strength of the thalamic inputs into the model. \y{tl} is the decay time constant in the exponential function \y{dan}. The depression time constants are \y{taud1} and \y{taud2}, again in the same units, so $\tau_{D_1} = 1500$ms and $\tau_{D_2} = 100$ms. We can ignore \y{tde1,tde2} as they are not used in the code. The parameter \y{lat} determines the strength of lateral thalamic inputs.

The next chunk of code sets up the stimuli in the forward suppression paradigm.
\begin{verbatim}
par t0=10,dur=5,isi=2

t1on=t0
t1off=t1on+dur
t2on=t1off+isi
t2off=t2on+dur

t3on=t2off+isi
t3off=t3on+dur
t4on=t3off+isi
t4off=t4on+dur

t5on=t4off+isi
t5off=t5on+dur
t6on=t5off+isi
t6off=t6on+dur

t7on=t6off+isi
t7off=t7on+dur
t8on=t7off+isi
t8off=t8on+dur

# thalamic inputs with fast timescale depression
gt1(x)=heav(x-t1on)*heav(t1off-x)*dan(x-t1on)
gt2(x)=heav(x-t2on)*heav(t2off-x)*dan(x-t2on)
gt3(x)=heav(x-t3on)*heav(t3off-x)*dan(x-t3on)
gt4(x)=heav(x-t4on)*heav(t4off-x)*dan(x-t4on)

gt5(x)=heav(x-t5on)*heav(t5off-x)*dan(x-t5on)
gt6(x)=heav(x-t6on)*heav(t6off-x)*dan(x-t6on)
gt7(x)=heav(x-t7on)*heav(t7off-x)*dan(x-t7on)
gt8(x)=heav(x-t8on)*heav(t8off-x)*dan(x-t8on)

par mode=1
i1(x)=g1*q*if(mode-1)then(0)else(gt1(x))
i2(x)=g2*q*if(mode-2)then(gt2(x))else(gt1(x)+gt2(x))
i3(x)=g3*q*if(mode-3)then(0)else(gt1(x))
\end{verbatim}

The functions \y{gt1(x)} through \y{gt8(x)} represent 8 different stimuli with stimulus onset times of \y{t1on} through \y{t8on}, stimulus offset times of \y{t1off} through \y{t8off}. The \y{heav} functions are heaviside functions, and the multiplication of two of them as written forms a square pulse. This pulse is then modulated by the exponential decay function \y{dan}. For the forward suppression paradigm, we only need two stimuli, so we only use \y{gt1} and \y{gt2} for the rest of the code.

The \y{mode} parameter sets which unit receives the first input. If \y{mode=1}, then
\begin{verbatim}
i1(x)=g1*q*gt1(x)
i2(x)=g2*q*gt2(x)
i3(x)=0
\end{verbatim}
For more information on how the if statement works in XPP, see the bottom of \url{http://www.math.pitt.edu/~bard/xpp/help/xppodes.html}. If the \y{mode} parameter is set to \y{mode=2}, then
\begin{verbatim}
i1(x)=0
i2(x)=g2*q*(gt1(x)+gt2(x))
i3(x)=0
\end{verbatim}
and so on. The terms \y{g1} and \y{g2} are variables and satisfy the equations
\begin{verbatim}
g1'=(1-g1)/taud1-i1(y)/taud2
g2'=(1-g2)/taud1-i2(y)/taud2
g3'=(1-g3)/taud1-i3(y)/taud2
\end{verbatim}
where \y{y'=1} and all \y{g1,g2,g3} are initialized with a value of 1. The trivial ODE \y{y'=1} is needed for technical reasons related to XPP that isn't too important for now. Anyway, as \y{i1(y)} activates, it ``depletes'' vesicles and forces \y{g1} to decay on a fast timescale. With no other activation of \y{i1}, \y{g1} recovers slowly back to its original value of 1.

Now we finally reach the actual model equations:
\begin{verbatim}
u1'=-u1+f(wee*u1-(wep-damp*(1-g1))*p1-(wes+samp*(1-g1))*s1-et+i1(y)+i2(y)*lat+wee2*u2/1.5)
p1'=(-p1+f(wpe*u1-wpp*p1-wps*s1-pt +i1(y)+i2(y)*lat +wpe2*u2-pv_opto ))/tau1
s1'=(-s1+f(wse*u1-wsp*p1-wss*s1-st                  +wse2*u2-som_opto ))/tau2

u2'=-u2+f(wee*u2-(wep-damp*(1-g2))*p2-(wes+samp*(1-g2))*s2-et+(i1(y)+i3(y))*lat+i2(y)+wee2*(u1+u3)/2)
p2'=(-p2+f(wpe*u2-wpp*p2-wps*s2-pt +(i1(y)+i3(y))*lat+i2(y)+wpe2*(u1+u3)/2 -pv_opto ))/tau1
s2'=(-s2+f(wse*u2-wsp*p2-wss*s2-st                         +wse2*(u1+u3)/2 -som_opto ))/tau2

u3'=-u3+f(wee*u3-(wep-damp*(1-g3))*p3-(wes+samp*(1-g3))*s3-et+i2(y)*lat+i3(y)+wee2*u2/1.5)
p3'=(-p3+f(wpe*u3-wpp*p3-wps*s3-pt +i2(y)*lat+i3(y) +wpe2*u2-pv_opto ))/tau1
s3'=(-s3+f(wse*u3-wsp*p3-wss*s3-st                  +wse2*u2-som_opto ))/tau2
\end{verbatim}
These are the implemented versions of the 3 unit equations from the manuscript:
Th first or left unit satisfies
\begin{align*}
 \tau_u u_1' &= -u_1 + f( w_{ee} u_1 - (w_{ep}(t)-aD_1)p_1 - (w_{es}(t)+b F_1)s_1 + qI_1(t) + w_{ee}^* u_2),\\
 \tau_p p_1' &= -p_1 + f( w_{pe} u_1 - w_{pp}p_1 - w_{ps}s_1 + I_\text{Opt,PV} + qI_1(t) + w_{pe}^* u_2),\\
 \tau_s s_1' &= -s_1 + f( w_{se} u_1 - w_{sp}p_1 - w_{ss}s_1 + I_\text{Opt,SOM} + w_{se}^* u_2),
\end{align*}
where $I_1 = i_1(t) +i_2(t)\alpha$. The second, or center unit, satisfies
\begin{align*}
 \tau_u u_2' &= -u_2 + f( w_{ee} u_2 - (w_{ep}(t)-aD_2)p_2 - (w_{es}(t)+b F_2)s_2 + qI_2(t) + w_{ee}^* (u_1+u_3)/2),\\
 \tau_p p_2' &= -p_2 + f( w_{pe} u_2 - w_{pp}p_2 - w_{ps}s_2 + I_\text{Opt,PV} + qI_2(t) + w_{pe}^* (u_1+u_3)/2),\\
 \tau_s s_2' &= -s_2 + f( w_{se} u_2 - w_{sp}p_2 - w_{ss}s_2 + I_\text{Opt,SOM} + w_{se}^* u_2),
\end{align*}
where $I_2(t) = (i_1(t)+i_3(t))\alpha +i_2(t)$. Finally, the third, or right unit, satisfies
\begin{align*}
 \tau_u u_3' &= -u_3 + f( w_{ee} u_3 - (w_{ep}(t)-aD_3)p_3 - (w_{es}(t)+b F_3)s_3 + qI_3(t) + w_{ee}^* u_2),\\
 \tau_p p_3' &= -p_3 + f( w_{pe} u_3 - w_{pp}p_3 - w_{ps}s_3 + I_\text{Opt,PV} + qI_3(t) + w_{pe}^* u_2),\\
 \tau_s s_3' &= -s_3 + f( w_{se} u_3 - w_{sp}p_3 - w_{ss}s_3 + I_\text{Opt,SOM} + w_{se}^* u_2),
\end{align*}
where $I_3 = i_2(t) +i_3(t)\alpha$.

The remaining lines are mostly related to using the XPPAUTO GUI. Choices that affect the integration are
\begin{verbatim}
@ bounds=100000
@ maxstor=1000000
@ total=200
@ dt=.1
\end{verbatim}
\y{bounds} is simply the maximum possible value of any solution before XPPAUTO gives up. \y{maxstor} sets the max storage XPPAUTO is allowed to take from memory. \y{total} is the total time of the simulation, and \y{dt} is the time step.

\subsection{Python Visualization}
These XPP ode files can be run using the XPP GUI, but we will run them using Python using \y{Py\_XPPCALL}. I have tried to include enough documentation to help users understand the basics \url{https://github.com/youngmp/Py_XPPCALL}. The Python files that run the XPP files are are located in \url{https://github.com/geffenlab/park_geffen/rate_models}. The Python file that reads the ODE file from the example above is called \y{cols3\_fs.py}. You should be able to run the python file directly.
\begin{verbatim}
$ python cols3_fs.py
\end{verbatim}
There will be lots of text that appears. These were mostly for debugging purposes and can be turned off by commenting the print statements in this file and in \y{xppcall.py}. After the script runs, a few plots should appear. I like to set up the plotting framework in the individual Python files before finalizing them in \y{generate\_figures.py}.

The \y{main} function calls all the relevant files. In brief, the loop runs three different stimulus patterns. The first stimulates the left unit then the center unit with 50ms tones and a 20ms inter-stimulus-interval. The second stimulates the center unit twice with the same time intervals. The third stimulates the right unit then the center unit with the same time intervals. This is a simple version of the forward suppression paradigm. These three sets of stimuli are repeated for PV inactivation and SOM inactivation. The max firing rate response is then recorded into a matrix and plotted.

Much of this logic appears in its final form in the function \y{r3\_s3\_fs\_full} in \y{generate\_figures.py}. The difference is that the function \y{r3\_s3\_fs\_full} includes the spiking model simulation and plots. I've tried to comment on most things... Let me know if you have any questions.

The remaining Python files for simulating the rate model, \y{cols3\_ssa} and \y{natan2015\_simple\_linear} have a similar construction. The \y{main} function in each script contains all the preliminary plotting/visualization code, which you can use to tinker and learn the ins and outs of the python/xpp interface. Seriously, play with those all you want.

The final version of the plotting functions appear in \y{generate\_figures.py}. Don't change those unless you're familiar with the code.

\section{Spiking Models}

\section{Generating Figures}

\y{generate\_figures.py} is the master plotting function for the paper. Most figure papers are generated here, except for a couple that were created in Inkscape. This file serves as a technical documentation of the code. In the main function, comments note which function belong to which figure.

\begin{thebibliography}{1}

\bibitem{ermentrout2002simulating}
Bard Ermentrout.
\newblock {\em Simulating, analyzing, and animating dynamical systems: a guide
  to XPPAUT for researchers and students}, volume~14.
\newblock Siam, 2002.

\bibitem{natan2015complementary}
Ryan~G Natan, John~J Briguglio, Laetitia Mwilambwe-Tshilobo, Sara~I Jones, Mark
  Aizenberg, Ethan~M Goldberg, and Maria~Neimark Geffen.
\newblock Complementary control of sensory adaptation by two types of cortical
  interneurons.
\newblock {\em Elife}, 4, 2015.

\bibitem{xppy}
Ilya Prokin and Youngmin Park.
\newblock Pyxppcall.
\newblock \url{https://github.com/iprokin/Py_XPPCALL}, 2017.

\bibitem{Stimberg595710}
Marcel Stimberg, Romain Brette, and Dan F.~M. Goodman.
\newblock Brian 2: an intuitive and efficient neural simulator.
\newblock {\em bioRxiv}, 2019.

\bibitem{tsodyks1997neural}
Misha~V Tsodyks and Henry Markram.
\newblock The neural code between neocortical pyramidal neurons depends on
  neurotransmitter release probability.
\newblock {\em Proceedings of the national academy of sciences},
  94(2):719--723, 1997.

\bibitem{yarden2017stimulus}
Tohar~S Yarden and Israel Nelken.
\newblock Stimulus-specific adaptation in a recurrent network model of primary
  auditory cortex.
\newblock {\em PLoS computational biology}, 13(3):e1005437, 2017.

\end{thebibliography}
\end{document}


\input source_header.tex

\begin{document}
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	\docheader{2021}{Source}{\S 4 GPU}{Martin Henz, Rahul Rajesh, Zhang Yuntong, Nicholas Nge, Zhu Ziying}
	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\input source_intro.tex

\section{Changes}

Source \S 4 GPU allows for Source programs to be accelerated on the GPU if certain conditions are met.
The exact specifications for this is outlined on page \pageref{gpu_supp}. Source \S 4 GPU  defines a formal specification
to identify areas in the program that are embarrssingly parallel (e.g. for loops etc.) . These will then
be run in parallel across GPU threads. Experimentation has shown that Source \S 4 GPU is orders of magnitude faster
than Source \S 4 for heavy CPU bound tasks (matrix multiplication of large matrices)\\

This document also records the improvements made to the \S 4 Source GPU in Semester 1 of 2021. The improvements have been incorporated into the GPU section of this specification, and a separate section has been included detailing the changes made.

\input source_bnf.tex

\input source_3_bnf.tex

\newpage

\input source_return

\input source_import

\input source_boolean_operators

\input source_loops

\input source_names_lang

\input source_numbers

\input source_strings

\input source_arrays

\input source_comments

\input source_typing_3

\section{Standard Libraries}

The following libraries are always available in this language.

\input source_misc

\input source_math

\input source_lists

\input source_pair_mutators

\input source_array_support

\input source_streams

\input source_interpreter

\input source_js_differences

\newpage

\section*{GPU Acceleration}
\label{gpu_supp}
This section outlines the specifications for programs to be accelerated using the GPU.\
\input source_gpu_bnf.tex

\newpage

\section*{Restrictions}

Even if the BNF syntax is met, GPU acceleration can only take place if all the restrictions below are satisfied. If all criteria are met, the \textit{gpu\_statement} loops are embarrassingly parallel.

\subsection*{Special For Loops}

In the BNF, we have special loops that take on this form:
\begin{alignat*}{9}
&& \textbf{\texttt{for}}\ \textbf{\texttt{(}}
                          \ \textit{gpu\_for\_let} \textbf{\texttt{;}} \\
&& \ \ \textit{gpu\_condition} \textbf{\texttt{;}} \\
&& \textit{gpu\_for\_assignment} \ \textbf{\texttt{)}}
\end{alignat*}

These are the loops that will be taken into consideration for parallelization. However, on top of the BNF syntax, the below requirement must also be statisfied:

\begin{itemize}
    \item{the names declared in each \textit{gpu\_for\_let} have to be different across the loops}
    \item{in each loop, the \textit{gpu\_condition} and the \textit{gpu\_for\_assignment} must use the name declared
    in the respective \textit{gpu\_for\_let} statement}
\end{itemize}

\subsection*{GPU Function}

A \textit{gpu\_function} has to be a \textit{math\_\texttt{*}} function or meet the following criteria:

\begin{itemize}
    \item{no function call to another function within the function loop (including recursive calls to itself)}
    \item{function is defined by the user (no use of library functions)}
\end{itemize}

Notably, the common library functions such as \textit{pair}, \textit{list} etc not are supported. Given the above restrictions, only simple functions such as arithmetic are permitted currently.

\subsection*{Core Statement}

Within \textit{core\_statement}, there are some constraints:

\begin{itemize}
    \item{no assignment to any global variables (all assignments can only be done to variables defined in the \textit{gpu\_block}})
    \item{no assignment to a variable in \textit{gpu\_result\_assignment} at an offset from the current index e.g. cannot be i - 1}
\end{itemize}

Notably, referencing other arrays and other constants defined outside the scope of the function body is allowed, but assignment to them is not. This follows from the nature of the GPU architecture, where GPU cores return a Float32 number for each computation (shader), meaning that side effects such as assignment to another global variable is not reflected.

\subsection*{GPU Result Statement}

The \textit{gpu\_result\_assignment} is the statement that stores a value calculated in core statements into a result array.
It access an array at a certain coordinate e.g. ${array[{i_1}][{i_2}][{i_3}]}$. For this:

\begin{itemize}
    \item{This result array has to be defined outside the \textit{gpu\_block}.}
    \item{Creation of the nested arrays in nested for-loops can be included in the body of a for-loop}
    \item{The sequence of coordinates which we access in the result array ${{i_1}, {i_2}, {i_3} ... i_{k}}$ must be a
        prefix of the special for loop counters ${[c_1,c_2 ... c_n]}$.}
    \item{ If you have ${n}$ special for loops, the array expression can take on ${k}$ coordinates where ${0 < k \leq n}$.
    The order matters as well, it has to follow the same order as the special for loops: you cannot have ${name[c_2][c_1]}$.}
\end{itemize}

Notably, in nested for-loop declarations, the only statement allowed in between loop-declarations is the creation of nested arrays in the output array. This is reflected in the \textit{gpu\_nested\_array\_init} in the specification in the earlier section.

\section*{Examples}

Below are some examples of valid and invalid source gpu programs:\\

\textbf{Valid} - Using first loop counter. (meaning the loop will be run across N threads; the first loop is parallelized away):
\begin{verbatim}
for (let i = 0; i < N; i = i + 1) {
    res[i] = [];
    for (let k = 0; k < M; k = k + 1) {
        res[i][k] = i + k + 1;
    }
}
\end{verbatim}

\textbf{Invalid} - Counter used is not a prefix of for loop counters:
\begin{verbatim}
for (let i = 0; i < N; i = i + 1) {
    res[i] = [];
    for (let k = 0; k < M; k = k + 1) {
        res[k] = arr[i % 2] + 1;
    }
}
\end{verbatim}

\textbf{Valid} - Using first three loop counters (meaning the loop will be run across N*M*C threads, if available):
\begin{verbatim}
for (let i = 0; i < N; i = i + 1) {
    res[i] = [];
    for (let j = 0; j < M; j = j + 1) {
        res[i][j] = [];
        for (let k = 0; k < C; k = k + 1) {
            let x = math_pow(2, 10);
            let y = x * (1000);
            arr[i][j][k] = (x + y * 2);
        }
    }
}
\end{verbatim}

\textbf{Invalid} - Indices are in wrong order (must respect for loop counter orders):
\begin{verbatim}
for (let i = 0; i < N; i = i + 1) {
    res[i] = [];
    for (let j = 0; j < M; j = j + 1) {
        res[i][j] = [];
        for (let k = 0; k < C; k = k + 1) {
            let x = math_pow(2, 10);
            let y = x * (1000);
            res[k][j][i] = (x + y * 2);
        }
    }
}
\end{verbatim}

\textbf{Invalid} - Using an index that is not part of a special for loop (see above):
\begin{verbatim}
for (let i = 0; i < N; i = i + 1) {
    res[i] = [];
    for (let j = 0; j < M; j = j + 1) {
        res[i][j] = [];
        for (let k = 1; k < C; k = k + 2) {
            res[k] = arr1[i] + arr2[j];
        }
    }
}
\end{verbatim}

\textbf{Valid} - Use of allowed GPU functions:
\begin{verbatim}
function fn (x, y){
	return x + y * 2;
}

for (let i = 0; i < N; i = i + 1) {
    res[i] = [];
    for (let k = 0; k < M; k = k + 1) {
        res[i][k] = fn(i, k);
    }
}
\end{verbatim}

\textbf{Invalid} - Use of recursive functions, or functions that call other functions:
\begin{verbatim}
function fib (x){
	return x <= 0 ? 0 : fib(x-1) + 1;
}

for (let i = 0; i < N; i = i + 1) {
    res[i] = fib(i);
}
\end{verbatim}

\textbf{Valid} - Referencing a global variable (in the case of the second loop). In this case, both for loops will be optimized by the GPU. Note that the second loop is assigning to a different array, but assigning to the same array will also be permittable, provided there are no 'side effect' assignments
\begin{verbatim}
for (let i = 0; i < N; i = i + 1) {
    res[i] = [];
    for (let j = 0; j < M; j = j + 1) {
        res[i][j] = i + j;
    }
}

for (let i = 0; i < N; i = i + 1) {
    res2[i] = [];
    for (let j = 0; j < M; j = j + 1) {
        let x = res[i][j];
        let y = math_abs(x * -5);
        res2[i][j] = x + y;
    }
}
\end{verbatim}

\textbf{Valid} - Multiple references to global variables and target variable, and multiple assignments to target variable (Recall that multiple references to global variables is permitted, but only multiple assignments to the target variable is permitted).
\begin{verbatim}
for (let i = 0; i < N; i = i + 1) {
    res[i] = [];
    for (let j = 0; j < M; j = j + 1) {
        res[i][j] = i + j;
    }
}

for (let i = 0; i < N; i = i + 1) {
    res2[i] = [];
    for (let j = 0; j < M; j = j + 1) {
        res2[i][j] = res[i][j];
        res2[i][j] = res2[i][j] * 2;
        res2[i][j] = res[i][j] + res2[i][j] + 3;
    }
}
\end{verbatim}

\section*{Improvements}

This section documents the changes made in Semester 1 2021 by Lab 4 GPU group Nicholas and Ziying as part of the CS4215 project. Technically, this is not officially part of the specification but serves as a "developer guide" for our changes made.

\subsection*{Nested Array Creation}

In the previous iteration of \S 4 GPU, one overlooked detail was how nested array creation was messing up our detection of nested loops. Whenever a statement for the creation of the nested array was positioned within the body of a for-loop, the detection of deeper, nested for-loops terminated early, leading to reduced optimization (eg. In a 2-layer for-loop, only the first is optimized)

\begin{verbatim}
for (let i = 0; i < N; i = i + 1) {
    for (let j = 0; j < M; j = j + 1) {
        res[i][j] = i + j;
    }
}
\end{verbatim}
In this first case, both loops are optimized. (The nested arrays may have be declared elsewhere)

\begin{verbatim}
for (let i = 0; i < N; i = i + 1) {
    res[i] = [];
    for (let j = 0; j < M; j = j + 1) {
        res[i][j] = i + j;
    }
}
\end{verbatim}
In this second case, the second loop had been run sequentially. Our changes made it such that nested loops would be unaffected by the nested array creation (Now \textit{gpu\_nested\_array\_init} is part of the specification).

\subsection*{Custom functions}

Previously, only \textit{math\_\texttt{*}} functions were supported by the implementation. We included the ability to include custom functions with certain restrictions as detailed in the above section.\\

One clear limitation is that the set of functions permitted is still small after this change, since we cannot use complex functions or functions defined in other libraries. In my view, there are two challenges ahead if we are to expand this set of functions. \\

Firstly, we are still currently working with Float32 array outputs from GPU.js. This limits the kind of outputs we can have, and I was not skilled enough to find an alternative...\\

Secondly, GPU cores are pretty bad at handling deep call stacks. Currently, recursion is forbidden in GPU.js (and probably for good reason), and our team did not have time to implement support for custom functions that call other custom functions. Perhaps this is a possible area for improvement?

\subsection*{Multiple references/assignments within loop body}

In previous iteration, an array assignment to the target variable was mutated into a return statement in the resultant transpiled shader function. We improved upon that by allowing multiple references/assignments to the target variable within the loop body, which was previously not allowed (since that would create multiple return statements).\\

First, we introduce a temporary variable in the loop body and let references/assignments to the target variable refer to this temporary variable instead. Then, we return this variable at the end of the loop body.\\

Some subtle details: In other not to wrongly turn a reference to the original value of the target variable to a reference of the temporary variable (initialized as 0), we require the following rules:
\begin{itemize}
    \item{If target variable is an \textit{assignment}, change \textit{identifier} to \textit{identifier} of temporary variable}
    \item{If target variable is a \textit{reference}, change \textit{identifier} to \textit{identifier} of temporary variable only if already target variable is already assigned within statements in loop body}
\end{itemize}

\subsection*{Other Assorted Bug Fixes}
In the previous iteration of \S 4 GPU, smaller loops under the size of 100 are left undisturbed and sequentially run since the overhead for GPU optimization would outweigh the savings from parallelization.\\

However, this was especially problematic as we found that many of the existing test cases were actually failing while appearing to be passing, due to the minimum size of arrays not being hit and sequential execution hiding the faults. Hence, our changes also include various bug fixes, though they will not be elaborated upon.

\newpage

\input source_list_library

\newpage

\input source_stream_library

\end{document}


%\documentclass[fleqn]{article}
%\usepackage{mathptmx}
%
%\DeclareMathSymbol{\Gamma}  {\mathalpha}{letters}{"00}
%\DeclareMathSymbol{\Delta}  {\mathalpha}{letters}{"01}
%\DeclareMathSymbol{\Theta}  {\mathalpha}{letters}{"02}
%\DeclareMathSymbol{\Lambda} {\mathalpha}{letters}{"03}
%\DeclareMathSymbol{\Xi}     {\mathalpha}{letters}{"04}
%\DeclareMathSymbol{\Pi}     {\mathalpha}{letters}{"05}
%\DeclareMathSymbol{\Sigma}  {\mathalpha}{letters}{"06}
%\DeclareMathSymbol{\Upsilon}{\mathalpha}{letters}{"07}
%\DeclareMathSymbol{\Phi}    {\mathalpha}{letters}{"08}
%\DeclareMathSymbol{\Psi}    {\mathalpha}{letters}{"09}
%\DeclareMathSymbol{\Omega}  {\mathalpha}{letters}{"0A}
%
%\DeclareMathSymbol{\alpha}  {\mathalpha}{letters}{"0B}
%\DeclareMathSymbol{\beta}   {\mathalpha}{letters}{"0C}
%\DeclareMathSymbol{\gamma}  {\mathalpha}{letters}{"0D}
%\DeclareMathSymbol{\delta}  {\mathalpha}{letters}{"0E}
%\DeclareMathSymbol{\epsilon}{\mathalpha}{letters}{"0F}
%\DeclareMathSymbol{\zeta}   {\mathalpha}{letters}{"10}
%\DeclareMathSymbol{\eta}    {\mathalpha}{letters}{"11}
%\DeclareMathSymbol{\theta}  {\mathalpha}{letters}{"12}
%\DeclareMathSymbol{\iota}   {\mathalpha}{letters}{"13}
%\DeclareMathSymbol{\kappa}  {\mathalpha}{letters}{"14}
%\DeclareMathSymbol{\lambda} {\mathalpha}{letters}{"15}
%\DeclareMathSymbol{\mu}     {\mathalpha}{letters}{"16}
%\DeclareMathSymbol{\nu}     {\mathalpha}{letters}{"17}
%\DeclareMathSymbol{\xi}     {\mathalpha}{letters}{"18}
%\DeclareMathSymbol{\pi}     {\mathalpha}{letters}{"19}
%\DeclareMathSymbol{\rho}    {\mathalpha}{letters}{"1A}
%\DeclareMathSymbol{\sigma}  {\mathalpha}{letters}{"1B}
%\DeclareMathSymbol{\tau}    {\mathalpha}{letters}{"1C}
%\DeclareMathSymbol{\upsilon}{\mathalpha}{letters}{"1D}
%\DeclareMathSymbol{\phi}    {\mathalpha}{letters}{"1E}
%\DeclareMathSymbol{\chi}    {\mathalpha}{letters}{"1F}
%\DeclareMathSymbol{\psi}    {\mathalpha}{letters}{"20}
%\DeclareMathSymbol{\omega}  {\mathalpha}{letters}{"21}
%\DeclareMathSymbol{\varepsilon} {\mathalpha}{letters}{"22}
%\DeclareMathSymbol{\vartheta}   {\mathalpha}{letters}{"23}
%\DeclareMathSymbol{\varpi}      {\mathalpha}{letters}{"24}
%\DeclareMathSymbol{\varrho}     {\mathalpha}{letters}{"25}
%\DeclareMathSymbol{\varsigma}   {\mathalpha}{letters}{"26}
%\DeclareMathSymbol{\varphi}     {\mathalpha}{letters}{"27}
%
%\DeclareMathSymbol{\dit}{\mathord}{letters}{`d}
%\DeclareMathSymbol{\dup}{\mathord}{operators}{`d}
%
%\nofiles
%
%\parindent 0pt
%\mathindent 1em

\def\test#1{#1}

\def\testnums{%
  \test 0 \test 1 \test 2 \test 3 \test 4 \test 5 \test 6 \test 7
  \test 8 \test 9 }
\def\testupperi{%
  \test A \test B \test C \test D \test E \test F \test G \test H
  \test I \test J \test K \test L \test M }
\def\testupperii{%
  \test N \test O \test P \test Q \test R \test S \test T \test U
  \test V \test W \test X \test Y \test Z }
\def\testupper{%
  \testupperi\testupperii}

\def\testloweri{%
  \test a \test b \test c \test d \test e \test f \test g \test h
  \test i \test j \test k \test l \test m }
\def\testlowerii{%
  \test n \test o \test p \test q \test r \test s \test t \test u
  \test v \test w \test x \test y \test z
  \test\imath \test\jmath }
\def\testlower{%
  \testloweri\testlowerii}

\def\testupgreeki{%
  \test A \test B \test\Gamma \test\Delta \test E \test Z \test H
  \test\Theta \test I \test K \test\Lambda \test M }
\def\testupgreekii{%
  \test N \test\Xi \test O \test\Pi \test P \test\Sigma \test T
  \test\Upsilon \test\Phi \test X \test\Psi \test\Omega
  \test\nabla }
\def\testupgreek{%
  \testupgreeki\testupgreekii}

\def\testlowgreeki{%
  \test\alpha \test\beta \test\gamma \test\delta \test\epsilon
  \test\zeta \test\eta \test\theta \test\iota \test\kappa \test\lambda
  \test\mu }
\def\testlowgreekii{%
  \test\nu \test\xi \test o \test\pi \test\rho \test\sigma \test\tau
  \test\upsilon \test\phi \test\chi \test\psi \test\omega }
\def\testlowgreekiii{%
  \test\varepsilon \test\vartheta \test\varpi \test\varrho
  \test\varsigma \test\varphi}
\def\testlowgreek{%
  \testlowgreeki\testlowgreekii\testlowgreekiii}

%\begin{document}

\section{Math Alphabets}

Math Italic (\texttt{\string\mathnormal})
\def\test#1{\mathnormal{#1},}
\begin{eqnarray*}
  && {\testnums}\\
  && {\testupper}\\
  && {\testlower}\\
  && {\testupgreek}\\
  && {\testlowgreek}
\end{eqnarray*}%

Math Roman (\texttt{\string\mathrm})
\def\test#1{\mathrm{#1},}
\begin{eqnarray*}
  && {\testnums}\\
  && {\testupper}\\
  && {\testlower}\\
  && {\testupgreek}
\end{eqnarray*}%

%Math Italic Bold
%\def\test#1{\mathbm{#1},}
%\begin{eqnarray*}
%  && {\testnums}\\
%  && {\testupper}\\
%  && {\testlower}\\
%  && {\testupgreek}\\
%  && {\testlowgreek}
%\end{eqnarray*}%

%Math Bold (\texttt{\string\mathbf})
%\def\test#1{\mathbf{#1},}
%\begin{eqnarray*}
%  && {\testnums}\\
%  && {\testupper}\\
%  && {\testlower}\\
%  && {\testupgreek}
%\end{eqnarray*}%

Caligraphic (\texttt{\string\mathcal})
\def\test#1{\mathcal{#1},}
\begin{eqnarray*}
  && {\testupper}
\end{eqnarray*}%

%Script (\texttt{\string\mathscr})
%\def\test#1{\mathscr{#1},}
%\begin{eqnarray*}
%  && {\testupper}
%\end{eqnarray*}%

%Fraktur (\texttt{\string\mathfrak})
%\def\test#1{\mathfrak{#1},}
%\begin{eqnarray*}
%  && {\testupper}\\
%  && {\testlower}
%\end{eqnarray*}%

%Blackboard Bold (\texttt{\string\mathbb})
%\def\test#1{\mathbb{#1},}
%\begin{eqnarray*}
%  && {\testupper}
%\end{eqnarray*}%

\clearpage
\section{Character Sidebearings}

\def\test#1{|#1|+}
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}\\
  && {\testlowgreeki}\\
  && {\testlowgreekii}\\
  && {\testlowgreekiii}
\end{eqnarray*}%
%
\def\test#1{|\mathrm{#1}|+}%
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}
\end{eqnarray*}%
%
%\def\test#1{|\mathbm{#1}|+}%
%\begin{eqnarray*}
%  && {\testupperi}\\
%  && {\testupperii}\\
%  && {\testloweri}\\
%  && {\testlowerii}\\
%  && {\testupgreeki}\\
%  && {\testupgreekii}\\
%  && {\testlowgreeki}\\
%  && {\testlowgreekii}\\
%  && {\testlowgreekiii}
%\end{eqnarray*}%
%%
%\def\test#1{|\mathbf{#1}|+}%
%\begin{eqnarray*}
%  && {\testupperi}\\
%  && {\testupperii}\\
%  && {\testloweri}\\
%  && {\testlowerii}\\
%  && {\testupgreeki}\\
%  && {\testupgreekii}
%\end{eqnarray*}%
%
\def\test#1{|\mathcal{#1}|+}%
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}
\end{eqnarray*}%

\clearpage
\section{Superscript positioning}

\def\test#1{#1^{2}+}%
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}\\
  && {\testlowgreeki}\\
  && {\testlowgreekii}\\
  && {\testlowgreekiii}
\end{eqnarray*}%
%
\def\test#1{\mathrm{#1}^{2}+}%
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}
\end{eqnarray*}%
%
%\def\test#1{\mathbm{#1}^{2}+}%
%\begin{eqnarray*}
%  && {\testupperi}\\
%  && {\testupperii}\\
%  && {\testloweri}\\
%  && {\testlowerii}\\
%  && {\testupgreeki}\\
%  && {\testupgreekii}\\
%  && {\testlowgreeki}\\
%  && {\testlowgreekii}\\
%  && {\testlowgreekiii}
%\end{eqnarray*}%
%
%\def\test#1{\mathbf{#1}^{2}+}%
%\begin{eqnarray*}
%  && {\testupperi}\\
%  && {\testupperii}\\
%  && {\testloweri}\\
%  && {\testlowerii}\\
%  && {\testupgreeki}\\
%  && {\testupgreekii}
%\end{eqnarray*}
%
\def\test#1{\mathcal{#1}^{2}+}%
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}
\end{eqnarray*}%

\clearpage
\section{Subscript positioning}

\def\test#1{\mathnormal{#1}_{i}+}%
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}\\
  && {\testlowgreeki}\\
  && {\testlowgreekii}\\
  && {\testlowgreekiii}
\end{eqnarray*}%
%
\def\test#1{\mathrm{#1}_{i}+}%
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}
\end{eqnarray*}%
%
%\def\test#1{\mathbm{#1}_{i}+}%
%\begin{eqnarray*}
%  && {\testupperi}\\
%  && {\testupperii}\\
%  && {\testloweri}\\
%  && {\testlowerii}\\
%  && {\testupgreeki}\\
%  && {\testupgreekii}\\
%  && {\testlowgreeki}\\
%  && {\testlowgreekii}\\
%  && {\testlowgreekiii}
%\end{eqnarray*}
%%
%\def\test#1{\mathbf{#1}_{i}+}%
%\begin{eqnarray*}
%  && {\testupperi}\\
%  && {\testupperii}\\
%  && {\testloweri}\\
%  && {\testlowerii}\\
%  && {\testupgreeki}\\
%  && {\testupgreekii}
%\end{eqnarray*}%
%
\def\test#1{\mathcal{#1}_{i}+}%
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}
\end{eqnarray*}%

\clearpage
\section{Accent positioning}

\def\test#1{\hat{#1}+}%
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}\\
  && {\testlowgreeki}\\
  && {\testlowgreekii}\\
  && {\testlowgreekiii}
\end{eqnarray*}%
%
\def\test#1{\hat{\mathrm{#1}}+}%
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}
\end{eqnarray*}%
%
%\def\test#1{\hat{\mathbm{#1}}+}%
%\begin{eqnarray*}
%  && {\testupperi}\\
%  && {\testupperii}\\
%  && {\testloweri}\\
%  && {\testlowerii}\\
%  && {\testupgreeki}\\
%  && {\testupgreekii}\\
%  && {\testlowgreeki}\\
%  && {\testlowgreekii}\\
%  && {\testlowgreekiii}
%\end{eqnarray*}%
%%
%\def\test#1{\hat{\mathbf{#1}}+}%
%\begin{eqnarray*}
%  && {\testupperi}\\
%  && {\testupperii}\\
%  && {\testloweri}\\
%  && {\testlowerii}\\
%  && {\testupgreeki}\\
%  && {\testupgreekii}
%\end{eqnarray*}
%
\def\test#1{\hat{\mathcal{#1}}+}%
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}
\end{eqnarray*}%

\clearpage
\section{Differentials}

\begin{eqnarray*}
\gdef\test#1{\dit #1+}%
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}\\
  && {\testlowgreeki}\\
  && {\testlowgreekii}\\
  && {\testlowgreekiii}\\
\gdef\test#1{\dit \mathrm{#1}+}%
  && {\testupgreeki}\\
  && {\testupgreekii}
\end{eqnarray*}%
%
\begin{eqnarray*}
\gdef\test#1{\dup #1+}%
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}\\
  && {\testlowgreeki}\\
  && {\testlowgreekii}\\
  && {\testlowgreekiii}\\
\gdef\test#1{\dup \mathrm{#1}+}%
  && {\testupgreeki}\\
  && {\testupgreekii}
\end{eqnarray*}%
%
\begin{eqnarray*}
\gdef\test#1{\partial #1+}%
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}\\
  && {\testlowgreeki}\\
  && {\testlowgreekii}\\
  && {\testlowgreekiii}\\
\gdef\test#1{\partial \mathrm{#1}+}%
  && {\testupgreeki}\\
  && {\testupgreekii}
\end{eqnarray*}%

\clearpage
\section{Slash kerning}

\def\test#1{1/#1+}
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}\\
  && {\testlowgreeki}\\
  && {\testlowgreekii}\\
  && {\testlowgreekiii}
\end{eqnarray*}

\def\test#1{#1/2+}
\begin{eqnarray*}
  && {\testupperi}\\
  && {\testupperii}\\
  && {\testloweri}\\
  && {\testlowerii}\\
  && {\testupgreeki}\\
  && {\testupgreekii}\\
  && {\testlowgreeki}\\
  && {\testlowgreekii}\\
  && {\testlowgreekiii}
\end{eqnarray*}

\clearpage
\section{Big operators}

\def\testop#1{#1_{i=1}^{n} x^{n} \quad}
\begin{displaymath}
  \testop\sum
  \testop\prod
  \testop\coprod
  \testop\int
  \testop\oint
\end{displaymath}
\begin{displaymath}
  \testop\bigotimes
  \testop\bigoplus
  \testop\bigodot
  \testop\bigwedge
  \testop\bigvee
  \testop\biguplus
  \testop\bigcup
  \testop\bigcap
  \testop\bigsqcup
% \testop\bigsqcap
\end{displaymath}

\section{Radicals}

\begin{displaymath}
  \sqrt{x+y} \qquad \sqrt{x^{2}+y^{2}} \qquad
  \sqrt{x_{i}^{2}+y_{j}^{2}} \qquad
  \sqrt{\left(\frac{\cos x}{2}\right)} \qquad
  \sqrt{\left(\frac{\sin x}{2}\right)}
\end{displaymath}

\begingroup
\delimitershortfall-1pt
\begin{displaymath}
  \sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{x+y}}}}}}}
\end{displaymath}
\endgroup % \delimitershortfall

\section{Over- and underbraces}

\begin{displaymath}
  \overbrace{x} \quad
  \overbrace{x+y} \quad
  \overbrace{x^{2}+y^{2}} \quad
  \overbrace{x_{i}^{2}+y_{j}^{2}} \quad
  \underbrace{x} \quad
  \underbrace{x+y} \quad
  \underbrace{x_{i}+y_{j}} \quad
  \underbrace{x_{i}^{2}+y_{j}^{2}} \quad
\end{displaymath}

\section{Normal and wide accents}

\begin{displaymath}
  \dot{x} \quad
  \ddot{x} \quad
  \vec{x} \quad
  \bar{x} \quad
  \overline{x} \quad
  \overline{xx} \quad
  \tilde{x} \quad
  \widetilde{x} \quad
  \widetilde{xx} \quad
  \widetilde{xxx} \quad
  \hat{x} \quad
  \widehat{x} \quad
  \widehat{xx} \quad
  \widehat{xxx} \quad
\end{displaymath}

\section{Long arrows}

\begin{displaymath}
  \leftarrow \mathrel{-} \rightarrow \quad
  \leftrightarrow \quad
  \longleftarrow  \quad
  \longrightarrow \quad
  \longleftrightarrow \quad
  \Leftarrow = \Rightarrow \quad
  \Leftrightarrow \quad
  \Longleftarrow  \quad
  \Longrightarrow \quad
  \Longleftrightarrow \quad
\end{displaymath}

\section{Left and right delimters}

\def\testdelim#1#2{ - #1 f #2 - }
\begin{displaymath}
  \testdelim()
  \testdelim[]
  \testdelim\lfloor\rfloor
  \testdelim\lceil\rceil
  \testdelim\langle\rangle
  \testdelim\{\}
\end{displaymath}

\def\testdelim#1#2{ - \left#1 f \right#2 - }
\begin{displaymath}
  \testdelim()
  \testdelim[]
  \testdelim\lfloor\rfloor
  \testdelim\lceil\rceil
  \testdelim\langle\rangle
  \testdelim\{\}
% \testdelim\lgroup\rgroup
% \testdelim\lmoustache\rmoustache
\end{displaymath}
\begin{displaymath}
  \testdelim)(
  \testdelim][
  \testdelim//
  \testdelim\backslash\backslash
  \testdelim/\backslash
  \testdelim\backslash/
\end{displaymath}

\clearpage
\section{Big-g-g delimters}

\def\testdelim#1#2{%
  - \left#1\left#1\left#1\left#1\left#1\left#1\left#1\left#1 -
  \right#2\right#2\right#2\right#2\right#2\right#2\right#2\right#2 -}

\begingroup
\delimitershortfall-1pt
\begin{displaymath}
  \testdelim\lfloor\rfloor
  \qquad
  \testdelim()
\end{displaymath}
\begin{displaymath}
  \testdelim\lceil\rceil
  \qquad
  \testdelim\{\}
\end{displaymath}
\begin{displaymath}
  \testdelim[]
  \qquad
  \testdelim\lgroup\rgroup
\end{displaymath}
\begin{displaymath}
  \testdelim\langle\rangle
  \qquad
  \testdelim\lmoustache\rmoustache
\end{displaymath}
\begin{displaymath}
  \testdelim\uparrow\downarrow \quad
  \testdelim\Uparrow\Downarrow \quad
\end{displaymath}
\endgroup % \delimitershortfall

%\end{document}

%%% Local Variables:
%%% mode: latex
%%% TeX-master: t
%%% End: