\documentclass{article}
\usepackage{mathrsfs}
\usepackage{amsmath}
\usepackage{mathtools}
\usepackage{graphicx}
\usepackage{amsfonts}
\DeclarePairedDelimiter{\ceil}{\lceil}{\rceil}
\DeclarePairedDelimiter{\floor}{\lfloor}{\rfloor}

\begin{document}
\begin{center}
\textbf{\huge{Week 8}}
\end{center}

\section{Achievability in channel coding theorem for BSC}

For any $\epsilon > 0$, there exists a sequence of codes $\mathscr{C}$(one for each x) with rate $R: 1 - H_2(p)- \epsilon$ and P(error)$\to 0$ as $x \to \infty$.

Proof: We will use a `random' code. Entire argument is for a fixed value of n. We will assume n is large (so that number of flips is np).

We will pick a code $\mathscr{C}_n$ of rate $R= 1-H_2(p)- \epsilon$. So we want $|\mathscr{C}_n|= 2^{nR}.$ (such that nR is an integer)

\subsection{Random code generation}
\begin{itemize}
    \item Pick each codeword in $\mathscr{C}_n$ from $\{ 0,1\}^n$ uniformly at random. Then P(codeword is specific n-length sequence)$= \frac{1}{2}^n$
    \item Repeat this process $2^{nR}$ times.
\end{itemize}

We get,
$$ |\mathscr{C}_n|=2^{nR}$$

Now we want to prove,
$$ P(\hat{\underbar{c}} \neq \underbar{c}) \leq  2^{-n \delta} \qquad \forall \qquad \underbar{c} \in \mathscr{C}_n , \delta > 0$$

For getting a handle on the probability of error, we have to first define the decoding function (i.e. how is estimate $\hat{\underbar{c}}$ calculated from a particular recieved vector).

Let the decoding function be denoted by,
$$D : \{ 0,1 \}^n \to \mathscr{C}_n$$

For any $y \in \{ 0,1 \}^n$,
$$ D(y):= \text{argmax}_{\underbar{c}' \in \mathscr{C}_n} P(y|\underbar{c}')$$

D(y) is the estimate $\hat{\underbar{c}}$ of the code when recieved vector is y. This is called the ``Maximum likelihood decoding rule''.

To show that $P(\hat{\underbar{c}} \neq \underbar{c})$ is small, we will show that $P(D(y) \neq \underbar{c})$ is small where y is the random vector when $\underbar{c}$ is transmitted.

For the above decoder, we want to show $P( \hat{\underbar{c}} \neq \underbar{c}) \leq 2^{-n \delta}$, $\delta >0$.

For any specific $\underbar{c}$, we want to find an upper limit for $P(\hat{\underbar{c}} \neq \underbar{c})$. This occurs when $\underbar{c}$ is not the closest codeword to y.

By law of large numbers,
$$ d_H (y, \underbar{c}) \approx np$$

$$ B(y,np)= \{ \underbar{x} \in \{ 0,1 \}^n : d_H (\underbar{x}, \underbar{y}) \leq np \}$$
If there are other codewords within this ball B(y,np), the decoder can make an error. Else it will not make an error.

\begin{align*}
P(\hat{\underbar{c}} \neq \underbar{c}) &\leq P(\underbar{c}' \in B(y,np): \hat{\underbar{c}} \neq \underbar{c} ) \\
&\leq \frac{|B(y,np)|}{2^n} \\
&\leq \frac{\sum_{i=0}^{np} {n \choose i}}{2^n} = \frac{{n \choose np} + \sum_{i=0}^{np-1} {n \choose i}}{2^n} \\
&\approx \frac{2^{n H_2(p)}}{2^n} = 2^{-n(1-H_2(p))}
\end{align*}
As n grows large, this value will be dominated by the first term of value $n \choose np$.
\begin{equation}
    \Rightarrow P(\hat{\underbar{c}} \neq \underbar{c}) \leq 2^{-n(1-H_2(p))}
\end{equation}

(we assume p $<$ 0.5, otherwise we can change the channel to BSC(p') where p'= 1-p)

We would like to show this result (1) for all codewords rather than specific codewords.
We want,
$$ P \left( \bigcup_{\underbar{c} \in \mathscr{C}}(\hat{\underbar{c}} \neq \underbar{c}) \right) \leq 2^{-n \delta} \qquad \delta > 0$$
This is known as the union bound.

\subsection{Union bound}
We know,
\begin{align*}
    P \left( \bigcup_{\underbar{c} \in \mathscr{C}_n}(\hat{\underbar{c}} \neq \underbar{c}) \right) &\leq \sum_{ \underbar{c} \in \mathscr{C}_n} P(\hat{\underbar{c}} \neq \underbar{c}) \\
    &\leq P \left( \bigcup_{\underbar{c} \in \mathscr{C}}(\hat{\underbar{c}} \neq \underbar{c}) \right) \leq \sum_{ \underbar{c} \in \mathscr{C}_n} 2^{-n(1-H_2(p))} \\
    &\leq 2^{nR}2^{-n(1-H_2(p))} \\
    &\leq 2^{-n(1-H_2(p)-R)} \\
    &\leq 2^{-n\varepsilon}
\end{align*}
$$ \Rightarrow P(\hat{\underbar{c}} \neq \underbar{c}) \leq 2^{-n\epsilon} \quad \forall \underbar{c} \in \mathscr{C}_n$$

Hence proved.

In practice using random codes and minimum distance/likelihood decoder (MDD/MLD) for BSC is very complex (complexity of decoder/encoder is very high). Hence, we use structured codes which have low encoding/decoding performance, mainly linear codes.

\section{Linear codes}
The random code construction is not really useful for implementation as:
\begin{enumerate}
    \item we could end up with a bad code due to the random construction.
    \item Encoding and decoding complexity is very large.
\end{enumerate}

So we want codes which are good in rate and P(error) and also have reasonable encoding/decoding complexity. An important class of codes having above properties are linear codes.

We will look at some simple examples of liner codes for binary channel with worst-case/bounded error model. Construction of codes which are useful for implementation is dealt with in coding theory.

\subsection{Worst case/bounded error model for binary channel}

Let t, n be some integers such that t $\leq $ n.

We input some $x \in \{ 0,1 \}^n$ to a binary channel and we get $y \in \{ 0,1\}^n$. $d_H(y,x)\leq t$ $\Rightarrow$ There are atmost $t$ positions where recieved vector y is different from transmitted vector x.

For this channel, we want to design a code $\mathscr{C} \subseteq \{ 0,1\}^n$ (such that all upto t errors are corrected).

\subsubsection{Example}

Now, suppose $\mathscr{c}= \{ 0,1 \}^n$, t=1.

Let us construct a situation in which the decoder will surely make an error in decoding.

Suppose $\underbar{c}=(1,\cdots,1) \in \mathscr{C}$ was transmitted.

Suppose $y=(0,1,\cdots,1)$, $y \in \mathscr{c}$. (we will assume min Hamming distance decoder $\hat{\underbar{c}}= argmin_{\mathscr{C}} d_H(y, \underbar{c})$)

Hence iff $\underbar{c}=y$,
$$ min_{\underbar{c} \in \mathscr{C}} d_H(y,\underbar{c}) = 0$$

$\Rightarrow$ Decoding error has happened as $\hat{\underbar{c}} \neq \underbar{c}$ (estimate and transmitted are not same).

So correcting any $t \geq 1$ error requires us to pick proper subsets of $\{ 0,1\}^n$.

But we also want to pick large subsets of $\{ 0,1\}^n $ as the code because we want to maximize $R= \frac{\log |\mathscr{C}|}{n}$ bits/channel use.

But picking large $\mathscr{C}$, codewords are closer in Hamming distance, which means that it is more likely to create decoding errors.

\subsection{Lemma}
Let $\mathscr{C} \subseteq \{ 0,1\}^n$ be chosen.
Define,
$$ d_{min}(\mathscr{C})= min_{c,c' \in \mathscr{C} \& c' \neq c} d_H(c,c')$$

$\mathscr{C}$ can be correct upto t errors if and only if $d_{min}(\mathscr{C})\geq 2t+1$.

Proof:

If part: Given: $\mathscr{C}$ can correct any t errors.

To prove: $d_{min}(\mathscr{C})\geq 2t+1$.

Given statement implies any for any c, c' $\in \mathscr{C}$.

$$ B_{t}(c)= \text{Hamming ball of radius t} := \{ x \in \{ 0,1\}^n : d_H (x,c) \leq t\}$$

Then,
$$ B_t(c) \bigcap B_t(c') = \phi$$

$$ \Rightarrow d_H(c,c') > 2t \qquad \forall \qquad c, c' \in \mathscr{C} \quad c \neq c'$$
This can be proved by contradiction.

\subsection{Terminology}

\begin{itemize}
    \item Size of code $= |\mathscr{C}|$.
    \item Length of code (Block length) $=n$.
\end{itemize}
Lemma above relates the error correcting capability of the code with the minimum distance, minimum disctance calculation has nothing to do with the channel.

Suppose code has minimum distance of d, then it can be used on a channel for correcting upto $\floor{\frac{d-1}{2}}$.

This says that code design can be theoretically done independent done of the channel and it's performance can be tested based on it's minimum distance.

\subsection{Hamming Bound}

Hamming bound is the upper bound on the size of code based on a given minimum distance.

Lemma: Let $\mathscr{C}$ be any code with $d_{min}(\mathscr{C})=d$.

Then,

$$  |\mathscr{C}| \leq \frac{2^n}{\sum_{i=0}^t {n \choose i}} \qquad t= \floor{\frac{d-1}{2}}$$

Proof follows as we can pick atmost one codeword per ball.

\subsection{Linear codes (over $\mathbb{F}_2$)}

$$ \mathbb{F}_2 \to (\{ 0,1\},+,\cdot)$$

$$+ \to XOR$$

Definition: A linear code over $\mathbb{F}_2$ of length n is subset $\mathscr{C} \subseteq {\mathbb{F}_2}^n$ and also a subspace of the vector space ${\mathbb{F}_2}^n$.

$$ \Rightarrow \forall a, b \in \mathbb{F}_2 \quad c_1, c_2 \in \mathscr{C}$$
$$ ac_1 + bc_2 \in \mathscr{C}$$
Since only non-trivial values of a, b above are a=1 and b=1.

$\Leftrightarrow \mathscr{C}$ is a subspace of ${\mathbb{F}_2}^n$ iff $\forall c_1, c_2 \in \mathscr{C}$, we have $c_1 + c_2 \in \mathscr{C}$.

\end{document}


\documentclass{article}
\pagestyle{empty}
\usepackage{amsmath,amssymb,amsfonts}
\usepackage{graphicx}
\usepackage{multicol}
\setlength{\oddsidemargin}{0in} \setlength{\evensidemargin}{0in}
\setlength{\topmargin}{0in} \setlength{\textheight}{8.5in}
\setlength{\textwidth}{6.5in}

\begin{document}
\begin{flushleft}
	\bfseries{MATH 260, Linear Systems and Matrices, Fall `14}\\
	\bfseries{Activity 1:  Linear equations and systems, geometrically}\\
	%\bfseries{Honor Code:} \hspace{3.5in}\bfseries{Names:}\\
\end{flushleft}
\begin{flushleft}
\vspace{.25in}

In previous courses you learned about lines and plotting. Today we'll be reviewing a lot of that as a precursor to a more holistic view of systems and LINEar algebra.

\section*{Problem 1:  Plotting 2 variables}
\vspace{0.1in}

a) The point-slope form of a line is $y=mx+b$. This is generally easily graphed, most of our equations though will take `standard' form of: $a_1 x + a_2 y = b$. For practice plot the following line below: $3y-6x=6$.

\newpage

b) Now sketch the following pairs of equations, each pair on its own set of axes:\\
(i) $y=3+2x$ and $y=2x-4$\\
(ii) $3x+7=y$ and $y=\frac{-2}{3}x-1$\\
(iii) $y=2x+1$ and $3y-3=6x$

\vspace{4in}

c) When we plot lines, the intersection gives a pair of $(x,y)$ values which will satisfy both equations. How many such pairs do each of the above sets of lines have?\\

\vspace{1in}

Can you draw a pair of lines which has exactly TWO solutions? Can you come up with any other counts for solutions besides those depicted above?

\newpage
d) Now plot the pair of lines from (b-ii) together with a third line each listed below.\\
(i) First, graph $3x+7=y$ and $y=\frac{-2}{3}x-1$ together with $y+1=\frac{-1}{4}x$ \\
(ii) Second (on a new set of axes), graph $3x+7=y$ and $y=\frac{-2}{3}x-1$ together with $y=\frac{5}{11}$\\

\vspace{4in}

Similar to having two equations, 3 equations can produce the same types of solution sets: None, one or infinite. Only two of which you've plotted. Notice that we really only needed two equations to get the interesction for (ii), this is called ``overdetermined." Case (i) would be called ``inconsistent" or ``indeterminite."

\vspace{0.3in}
\newpage
\section*{Problem 2: Plotting 3 variables}
\vspace{0.1in}
First, actually plotting an equation with 3 variables can be very challenging.  We've shown the result (when the equation is linear) below, which creates a plane.\\

\vspace{0.1in}

\begin{center}
\includegraphics[scale=1.0]{planepic.png}
\end{center}

\vspace{0.1in}

Let's look at another system, this time with 3 variables:\\
$x=3z-2y+1$\\
$3z-2y+x=2$\\
Solve this for $x$, $y$, $z$. \textit{Hint: Solve for $z$ first by substituting the first equation into the second}\\

\vspace{4in}

Did you get numbers for each variable? What do you think is going on here?

\pagebreak

\section*{Problem 3}
Solve the following systems by substitution and/or elimination:

\vspace{0.2in}

a)
\begin{align*}
x+y&=4\\
x-y&=0
\end{align*}
\vspace{0.1in}

\vspace{2in}

b)
\begin{equation*}
\begin{array}{ccccccr}
x& + &2y&+&z&= &4\\
x& - & y& & &= &2\\
2x&- & y&+&2z&=&3\\
  &  &3y&+& z&=&2
\end{array}
\end{equation*}

\end{flushleft}
\end{document}

Fall 2014 - Capaldi A/Activities/Activity01_LinearSystems.tex


%%===========================
%% Section 1.00: Introduction
%%===========================

\documentclass[../dissertation.tex]{subfiles}

\begin{document}
% \setcounter{section}{-1}
\section{Introduction}\label{sec1:Intro}

Proving the direct scattering map $\mathscr D$ for the Inverse Scattering Transform
of the Intermediate Long Wave equation is both well-defined and Lipschitz
continous hinges on our ability to reformulate the linear spectral problem
\eqref{eq0:SpecProb} with prescribed asyptotic conditions \eqref{eq0:JostDEasymp}
as the integral equations \eqref{eq0:JostIE} and understand the behavior of
the solutions to \eqref{eq0:JostIE}. Both require a deep understanding of
the properties of the Green's functions $G_L$ and $G_R$ defined in equation
\eqref{eq0:GFs} of Section \ref{sec0:DM}. Indeed, this is the first of three
chapters devoted solely to the study of $G_L$ and $G_R$.

The focus of this chapter is to study the properties
of the lower boundary values $G_L^+$ and $G_R^+$ as functions on $\mathbb R$,
where the symbol $\mathbb R$ denotes the of all real numbers.\label{sym:Reals}
In particular, we use a contour shift to derive the alternate formulas
\eqref{eq1:GFrep} and \eqref{eq1:GRrep} for $G_L^+$ and $G_R^+$ from
Theorem \ref{thm1:GFRep} (Section \ref{sec1:GreensFunctions}), which
we use to study the asymptotic properties of $G_L^+$,
$G_R^+$ (Section \ref{sec1:AsympK}) and the singularity both functions have
at $x=0$ (Section \ref{sec1:AsympK}). We continue our study of the Green's
functions in Chapters \ref{cptr02:GFmapping} and \ref{cptr03:xContin}
where we use our analyses from this chapter
to first study mapping properties of $G_L^+$, $G_R^+$ as convolution operators
(Chapter \ref{cptr02:GFmapping}), and then to prove that $G_L^+$, $G_R^+$
extend analytically in the variable $x$ to the complex strip $\mathcal S_\delta$
(Chapter \ref{cptr03:xContin}).

We summarize the primary results of this chapter below in Theorems
\ref{thm1:GFRep} and \ref{thm1:krep}.

\begin{thm}[Green's Function Representation]\label{thm1:GFRep}
	The Green's functions given above in \eqref{eq0:GFs} can be
	written as
	\begin{subequations}
		\label{eq1:GFrepLong}
		\begin{align}\label{eq1:GLrepLong}
			G_L^+(x; \lambda, \delta)
				=
					\begin{cases}
						K^+(x; \lambda, \delta)
							+ i
							\big[
								\alpha(\lambda; \delta)
								+ \beta(\lambda; \delta) e^{i\lambda x}
							\big] \chi_L(x)
							& \lambda \ne 0 \\
						K^+(x; \lambda, \delta)
							+ i
							\left[
								\frac{2}{3} + i \frac{x}{\delta}
							\right] \chi_L(x)
							& \lambda = 0
					\end{cases}
		\end{align}
		and
		\begin{align}\label{eq1:GRrepLong}
			G_R^+(x; \lambda, \delta)
				=
					\begin{cases}
						K^+(x; \lambda, \delta)
							- i
							\big[
								\alpha(\lambda; \delta)
								+ \beta(\lambda; \delta) e^{i\lambda x}
							\big] \chi_R(x)
							& \lambda \ne 0 \\
						K^+(x; \lambda, \delta)
							- i
							\left[
								\frac{2}{3} + i \frac{x}{\delta}
							\right] \chi_R(x)
							& \lambda = 0
					\end{cases}
		\end{align}
	\end{subequations}
	where $\chi_L := \chi_{(0, \infty)}$ and $\chi_R := \chi_{(-\infty, 0)}$ respectively
	denote the characteristic functions on the intervals $(0, \infty)$ and $(-\infty, 0)$,
	\label{sym:chi}
	\begin{align*}
		\alpha(\lambda; \delta)
			&:= \frac{1}{1-2\delta\zeta}
			= \frac{1 - e^{2\delta\lambda}}
				{2\delta\lambda e^{2\delta\lambda} + 1 - e^{2\delta\lambda}},
			\\[1\baselineskip]
		\beta(\lambda; \delta)
			&:= \frac{1}{1-2 \delta \zeta^*}
			= \frac{1-e^{2\delta\lambda}}{1+2\delta\lambda-e^{2\delta\lambda}},
	\end{align*}
	\label{sym:alphabeta}
	are respectively determined by the residues of the integrand of $G_L^+$
	and $G_R^+$ at $\xi=0$ and $\xi=\lambda$, $\zeta^*$ is the non-linear reflection
	given by\label{sym:zetastar}
	\[
		\zeta^* := \zeta(-\lambda) = \zeta\big( - \lambda(\zeta) \big)
	\]
	and
	\begin{align*}
		K^+(x; \lambda, \delta)
				:= \frac{e^{-\pi |x|}}{2\pi}
					\int_{\mathbb R} e^{i x \xi}
						\frac{1}
							{
								\xi - \zeta(\lambda)
								\big(
									1-e^{-2\xi \delta}
								\big)
								+ i \sign(x) \pi
							}
					\, \mathrm{d}\xi
	\end{align*}
	\label{sym1:K}results from shifting the contour of integration for the integral in $G_L^+$ and
	$G_R^+$.
\end{thm}

\begin{thm}\label{thm1:krep}
	Suppose $\alpha$, $\beta$, and $K^+$ are as defined in Theorem \ref{thm1:GFRep}.
	Then the functions $\alpha$ and $\beta$ satisfy the following properties
	\begin{align}
		\lim_{\lambda\to0}|\alpha(\lambda; \delta)|
			= \lim_{\lambda\to0}|\beta(\lambda; \delta)|
			= \infty,\nonumber \\
		\intertext{and}
		\label{eq1:PoleColapseResidue}
		\lim_{\lambda\to0} \big[\alpha(\lambda; \delta) + \beta(\lambda; \delta)e^{ix\lambda}\big]
			=  \frac{2}{3} + i \frac{x}{\delta}.
		% \lim_{\lambda \to -\infty} \alpha(\lambda)
		% 	&= 1
		% 		& \lim_{\lambda \to \infty} \alpha(\lambda)
		% 			&= 0 \\
		% \lim_{\lambda \to -\infty} \beta(\lambda)
		% 	&= 0
		% 		& \lim_{\lambda \to \infty} \beta(\lambda)
		% % 			&= 1 \\
		% \lim_{\lambda\nearrow0} \alpha(\lambda)
		% 	&= \infty
		% 		& \lim_{\lambda\searrow0} \alpha(\lambda)
		% 			&= -\infty \\
		% \lim_{\lambda\nearrow0} \beta(\lambda)
		% 	&= -\infty
		% 		& \lim_{\lambda\searrow0} \beta(\lambda)
		% 			&= \infty,
	\end{align}
	% and $\lim_{\lambda\to0} \alpha(\lambda) + \beta(\lambda) e^{ix\lambda}
	% = \frac{2}{3} + i x$.
	Further, $K^+$ is uniformly bounded in $\lambda$ and
	\begin{align}
		K^+(x; \lambda, \delta) =
			\begin{cases}
				C \log_+\left(\frac{1}{|x|}\right) + \mc O(1), & |x| < 1 \\
				\mc O\( \frac{e^{-\pi|x|}}{|x|} \), & |x| \geq 1
			\end{cases}
	\end{align}
	for some constant $C \in \mathbb C$, where $\mathbb C$\label{sym:Complex}
	denotes the set of all complex numbers and $\log_+$ is the function defined
	by $\log_+(x):=\max\big\{ \log(x), \, 0 \big\}$.\label{sym:logplus}
\end{thm}

\begin{rmk}\label{rmk1:littlek}
	An important and immediate consequence of Theorem \ref{thm1:krep} and our
	work in Sections \ref{sec1:AsympK} and \ref{sec1:KSingularity} is that
	$K^+$ can be written as
	\begin{align*}\label{eq1:littlek}
		K^+(x; \lambda, \delta) = e^{-\pi|x|} k(x; \lambda, \delta)
	\end{align*}
	where $k(\dotarg; \lambda, \delta) \in L^2(\mathbb R)$ and $k$ is uniformly
	bounded in $\lambda$ for all real $\lambda$. Unless necessary to avoid
	confusion, we commonly write $k(x; \lambda, \delta)$ as $k(x)$.
\end{rmk}

We begin this chapter by first motivating our choice of Green's functions
in Section \ref{sec1:RootsOfP}.
Since we need to know the locations of the
Green's functions' integrand singularities to be able to both justify
the contours of integration for the Green's functions and
to justify the representation theorem above (Theorem \ref{thm1:GFRep}),
locating these singularities is also a primary task for Section
\ref{sec1:RootsOfP}.

To simplify notation, throughout the remainder of this dissertation, we use notation
\[
	p(\xi; \lambda, \delta) := \xi - \zeta(\lambda) \big( 1-e^{-2\xi \delta} \big),
	\label{sym:GFintegrand}
\]
where $e^{i\xi x} / p(\xi; \lambda, \delta)$ is the integrand for $G_L^+$ and $G_R^+$.
Since it is occasionally more useful to consider the Green's functions as parameterized
by $\zeta$ rather than $\lambda$, we use the notation $p(\xi; \lambda, \delta)$ and
$p(\xi; \zeta, \delta)$ interchangeably. Further, we will not always need to consider
the affects of the parameters $\lambda$ and $\delta$ in our subsequent analyses. In
such cases, we often use the shorter notation $p(\xi)$ or $p(\xi;\lambda)$ \textit{en lieu}
of the more cumbersome $p(\xi; \lambda, \delta)$ or $p(\xi; \zeta, \delta)$.

As we see in Section \ref{sec1:RootsOfP}, the only roots of $p(\xi; \lambda, \delta)$
in the complex strip
\[
	\mathcal R_\delta := \{z \in \mathbb C ~:~ -\pi/\delta \leq \im z \leq \pi/\delta \}
\]
\label{sym1:Rcal}
are $\xi = 0$ and $\xi = \lambda$ (provided $\lambda \ne 0$). As such, we may
use analyticity to write $G_L^+$ and $G_R^+$ as \label{sym:GFbndry}
\begin{align*}
	G_L^+(x; \lambda, \delta)
		&:=
			\frac{1}{2\pi}
			\int_{\Gamma_L}
				e^{i\xi x} \frac{1}{p(\xi; \lambda, \delta)}
			\, \mathrm{d}\xi \\
	G_R^+(x; \lambda, \delta)
		&:=
			\frac{1}{2\pi}
				\int_{\Gamma_R}
					e^{i\xi x} \frac{1}{p(\xi; \lambda, \delta)}
				\, \mathrm{d}\xi,
\end{align*}
where the symbol $\Gamma_L$ \label{sym:Gamma} is used to denote a contour from $-\infty$ to
$\infty$ along the real axis which is deformed in small circular arcs around
$\xi = 0$ and $\xi=\lambda$ so that the contour bypasses these two real roots
of $p$ from below (Figure \ref{fig1:GammaL}), and $\Gamma_R$ denotes the
corresponding contour which bypasses
the roots $\xi = 0$ and $\xi=\lambda$ from above (Figure \ref{fig1:GammaR}).

\begin{figure}[H]
	\centering
	\def\outSpacing{1.3}
	\def\innSpacing{1.3}
	% \def\ep{.65}
	\def\ep{.3}
	\def\lambdaam{\innSpacing+\ep+\ep}
	\def\arrowsize{15mm}
	\def\dotsize{1pt}
	\begin{subfigure}[t]{0.49\textwidth}
		\centering
		\begin{tikzpicture}[
				directed/.style={
					decoration={markings, mark=at position .55 with \arrow{stealth}[arrowhead=\arrowsize]},
						postaction={decorate}
				},
				cont/.style={smooth, thick}
			]

			% Draw the contour
			\draw[cont, directed] ({-\outSpacing-\ep},0) -- ({-\ep}, 0);
			\draw[cont, directed] ({\ep}, 0) -- ({\lambdaam - \ep},0);
			\draw[cont, directed]
				({\lambdaam + \ep},0) -- ({\lambdaam + \ep + \outSpacing},0);

			\draw[cont, domain=180:360, variable=\th]
				plot ({\ep*cos(\th)}, {\ep*sin(\th)});
			\draw[cont, domain=180:360, variable=\th]
				plot ({\ep*cos(\th)+\lambdaam}, {\ep*sin(\th)});

			% Draw zeros
			\tkzDefPoint(0,0){zero}
			\tkzDefPoint(\lambdaam,0){lambda}
			\tkzLabelPoint[above](zero){$\xi=0$}
			\tkzLabelPoint[above](lambda){$\xi=\lambda$}
			\tkzLabelPoint[below](zero){\phantom{$\xi=0$}}
			\tkzLabelPoint[below](lambda){\phantom{$\xi=\lambda$}}
			\foreach \n in {zero, lambda}
				\node at (\n)[circle, fill, inner sep=\dotsize]{};
		\end{tikzpicture}
		\caption{$\Gamma_L$ Contour}
		\label{fig1:GammaL}
	\end{subfigure}
	\begin{subfigure}[t]{0.49\textwidth}
		\centering
		\begin{tikzpicture}[
				directed/.style={
					decoration={markings, mark=at position .5 with \arrow{stealth}[arrowhead=\arrowsize]},
						postaction={decorate}
				},
				cont/.style={smooth, thick}
			]

			%% Draw the contour
			\draw[cont, directed] ({-\outSpacing-\ep},0) -- ({-\ep}, 0);
			\draw[cont, directed] ({\ep}, 0) -- ({\lambdaam - \ep},0);
			\draw[cont, directed]
				({\lambdaam + \ep},0) -- ({\lambdaam + \ep + \outSpacing},0);

			\draw[cont, domain=180:360, variable=\th]
				plot ({\ep*cos(\th)}, {-\ep*sin(\th)});
			\draw[cont, domain=180:360, variable=\th]
				plot ({\ep*cos(\th)+\lambdaam}, {-\ep*sin(\th)});

			%% Draw zeros
			\tkzDefPoint(0,0){zero}
			\tkzDefPoint(\lambdaam,0){lambda}
			\tkzLabelPoint[above](zero){\phantom{$\xi=0$}}
			\tkzLabelPoint[above](lambda){\phantom{$\xi=\lambda$}}
			\tkzLabelPoint[below](zero){$\xi=0$}
			\tkzLabelPoint[below](lambda){$\xi=\lambda$}
			\foreach \n in {zero, lambda}
				\node at (\n)[circle, fill, inner sep=\dotsize]{};
		\end{tikzpicture}
		\caption{$\Gamma_R$ Contour}
		\label{fig1:GammaR}
	\end{subfigure}
	\caption{Contours of integration $\Gamma_L$ and $\Gamma_R$ for $G_L$ and $G_R$.}
	\label{fig1:GammaStarContours}
\end{figure}

\begin{rmk}\label{rmk1:StarNotation}
	Throughout this dissertation, we commonly use the symbol ``$\star$''
	as a place holder for both $L$ and $R$. For example, if we write ``$G_\star$
	($\star = L \text{, or } R$) are a bounded as a convolution operators,'' then
	what we mean is that ``both $G_L$ and $G_R$ are bounded as convolution
	operators.'' As a further example of how we use this notational convention,
	please see the following two very important remarks.
\end{rmk}

\begin{rmk}\label{rmk1:ResidueLimits}
	When $\lambda = 0$, the function $\zeta(\lambda; \delta)$ is technically
	undefined. However, since
	$\lim_{\lambda\to0}\zeta(\lambda; \delta) = \frac{1}{2\delta}$, $\lambda = 0$
	is a removable singularity of $\zeta$. As such, we define
	$\zeta(\lambda; \delta) := \frac{1}{2\delta}$. Further, the case $\lambda=0$
	also corresponds to the case when the two roots $\xi = 0$ and $\xi = \lambda$
	of the function $p$\textemdash{}which are simple when
	$\lambda \ne 0$\textemdash{}coalesce to form a single double zero of $p$. Under
	the caveat that we define $\zeta(0; \delta):= \frac{1}{2\delta}$, a direct computation
	shows that the residue of $e^{ix\xi} / p(\xi; 0, \delta)$ at $\xi = 0$ is
	$\frac{2}{3} + i \frac{x}{\delta}$\textemdash{}hence the piecewise (in $\lambda$)
	definition of $G_L^+$ and $G_R^+$ in \eqref{eq1:GFrepLong}.
	Thus, even though the residue sum
	\[
		\mathpzc R_\star (x; \lambda, \delta)
			:= i
				\left[
					\alpha(\lambda; \delta) + \beta(\lambda; \delta) e^{i\lambda x}
				\right] \chi_\star
			\qquad (\star = L \text{, or } R)
	\]
	\label{sym1:ressum}is not technically defined at
	$\lambda = 0$, it nonetheless makes sense for us to agree on the convention
	that
	\[
		\mathpzc R_\star(x; \lambda = 0; \delta)
			:= \left[ i \frac{2}{3} - \frac{x}{\delta} \right] \, \chi_\star.
		\qquad (\star = L \text{, or } R)
	\]
	Under this convention, \eqref{eq1:GFrepLong} can be written slightly more succinctly as
	\begin{subequations}
		\label{eq1:GFrep}
		\begin{align}
			\label{eq1:GLrep}
			G_L^+(x; \lambda, \delta)
				&=
					K^+(x; \lambda, \delta)
					+ \mathpzc R_L(x; \lambda, \delta)\\
			\label{eq1:GRrep}
			G_R^+(x; \lambda, \delta) &=
				K^+(x; \lambda, \delta)
					- \mathpzc R_R(x; \lambda, \delta).
		\end{align}
	\end{subequations}
\end{rmk}

\begin{rmk}\label{rmk1:ContourAdjustment}
	Continuing to our discussion on the case of $\lambda = 0$ and the
	coalescing of the Green's function integrand poles $\xi = 0$, $\xi = \lambda$,
	under this scenario, we take the contours $\Gamma_\star$
	($\star = L \text{, or } R$) such that they have only one circular deformation
	away from the real line which allows them to bypass the single (double) pole
	at $\xi = 0$.
\end{rmk}

\end{document}


%% Journal of Open Research Software Latex template -- Created By Stephen Bonner and John Brennan, Durham University, UK.

\documentclass{jors}
\usepackage{amsmath, amssymb}
\usepackage{cite}
\usepackage{graphicx, subcaption}
\graphicspath{ {images/} }

%% Set the header information
\pagestyle{fancy}
\definecolor{mygray}{gray}{0.6}
\renewcommand\headrule{}
\rhead{\footnotesize 3}
\rhead{\textcolor{gray}{UP JORS software Latex paper template version 0.1}}

\begin{document}

{\bf Software paper for submission to the Journal of Open Research Software} \\

Please submit the completed paper to: editor.jors@ubiquitypress.com

\rule{\textwidth}{1pt}

\section*{(1) Overview}

\vspace{0.5cm}

\section*{Title}
spinsim: a GPU optimised simulator of spin half and spin one quantum systems

\section*{Paper Authors}
1. Tritt, Alex;\\
2. Morris, Joshua;\\
3. Hochstetter, Joel;\\
4. Anderson, R. P.;\\
5. Saunderson, James;\\
6. Turner, L. D.;\\

\section*{Paper Author Roles and Affiliations}
1. School of Physics \& Astronomy, Monash University, Victoria 3800, Australia.\\
	Primary author of the released packages.\\
2. School of Physics \& Astronomy, Monash University, Victoria 3800, Australia.\\
	Present address: Faculty of Physics, University of Vienna, 1010 Vienna, Austria.\\
	Author of first version of code.\\
3. School of Physics \& Astronomy, Monash University, Victoria 3800, Australia.\\
	Present address: School of Physics, University of Sydney, NSW 2006, Australia.\\
	Optimization and extension to spin one of first version of code.\\
4. School of Molecular Sciences, La Trobe University, PO box 199, Bendigo, Victoria 3552, Australia.\\
	Original conception of first version of code.\\
5. Department of Electrical and Computer Systems Engineering, Monash University, Victoria 3800, Australia.\\
	Advice on numerical analysis.\\
6. School of Physics \& Astronomy, Monash University, Victoria 3800, Australia.\\
	Original conception of released version of algorithm.

\section*{Abstract}
	\texttt{spinsim} is a \emph{python} package that simulates spin half and spin one quantum mechanical systems following a time dependent Shroedinger equation. It makes use of \texttt{numba.cuda} \cite{lam_numba_2015}, which is an \emph{LLVM} (Low Level Virtual Machine) \cite{lattner_llvm_2004} compiler, and other optimisations, to allow for fast and accurate evaluation on \emph{Nvidia Cuda} \cite{nickolls_scalable_2008} compatible systems using GPU parallelisation. \texttt{spinsim} is available for installation on \emph{PyPI}, and the source code is available on \emph{github}. The initial use case for the package will be to simulate quantum sensing-based Bose Einstein condensate (BEC) experiments for the Monash University School of Physics and Astronomy spinor BEC lab, but we anticipate it will be useful in simulating any range of spin half or spin one quantum systems with time dependent Hamiltonians that cannot be solved analytically. These appear in the fields of nuclear magnetic resonance (NMR), nuclear quadrupole resonance (NQR) and magnetic resonance imaging (MRI) experiments and quantum sensing, and with the spin one systems of nitrogen vacancy centres (NVCs) and BECs.

\section*{Keywords}
Time dependent Schroedinger equation; Spin one; Spin half; Integrator; GPU; Solver; python; numba;

\section*{Introduction}
\subsection*{Motivation}
	Ultracold rubidium atoms have proven their effectiveness in state of the art technologies in quantum sensing \cite{degen_quantum_2017}, the use of quantum mechanics to make precise measurements of small signals. The rotation of these atoms can be modelled as quantum spin systems, which is the quantum mechanical model for objects with angular momentum. The simplest spin system, spin half (ie spin quantum number of \(\frac12\), also referred to as a qubit), is quantised into just two quantum spin levels, and this describes the motion of some fundamental particles such as electrons. However, systems more practical for sensing, such as ultracold rubidium atoms, are more accurately described as a spin one quantum system (ie spin quantum number of \(1\), also referred to as a quitrit), which is quantised into three quantum spin levels.

	The design of sensing protocols requires many steps of verification, including simulation. This is especially important, since running real experiments can be expensive and time consuming, and thus it is more practical to debug such protocols quickly and cheaply on a computer. In general, any design of experiments using spin systems could benefit from a fast, accurate method of simulation.

	% \texttt{AtomicPy} \cite{morris_qcmonkatomicpy_2018}
	In the past, the spinor Bose Einstein condensate (spinor BEC) lab at Monash University used an in-house, \emph{cython} based script, on which this package is based, and standard differential equation solvers (such as \emph{Mathematica}'s function \texttt{NDSolve}) to solve the Schroedinger equation for quantum sensing spin systems. Spin one systems are sometimes approximated to spin half for a faster execution time, at the cost of modelling all effects of the system. However, these methods are not completely optimised for our use case, and therefore come with some issues.

	First, while the execution time for these solvers is acceptable for running a small number of experiments, for certain experiments involving large arrays of independent atom clouds (which require many thousands of simulations to be run), this time accumulates to the order of many hours, or even multiple days.

	Second, the Schroedinger equation has the geometric property of being norm persevering. In other words, the time evolution operator for a system between two points in time must be unitary. As such, numerical solutions to the Schroedinger equation should also preserve this property. For many numerical methods like those in the Runge Kutta family, the approximations used might not be norm preserving, and the evaluated quantum state may diverge towards an infinite norm, or converge to zero if run for many iterations.

	Third, our system (and similar spin systems) can be very oscillatory. In standard conditions for our application, the expected spin projection of a system that we want to solve for can rotate in physical space (alternatively viewed as a point rotating around an abstract object known as a \emph{Bloch sphere}) at a rate of 700kHz. Standard integration methods require very small time steps in order to accurately depict these oscillations.

\section*{Implementation and architecture}
	\subsection*{Mathematical methods}
		\subsubsection*{Background}
			In general, \texttt{spinsim} solves the Schroedinger equation,

			\begin{align}
				\frac{\mathrm{d}}{\mathrm{d}t}\psi(t) &= -iH(t)\psi(t),
			\end{align}

			where \(i^2 = -1\), the quantum state \(\psi(t) \in \mathbb{C}^N\) a time dependent, \(N\) dimensional, unit complex vector, and the Hamiltonian \(H(t) \in \mathbb{C}^{N \times N}\) is a time dependent \(N \times N\) complex Hermitian matrix. Here \(N\) is the number spin levels in the quantum system, so spin half is the \(N = 2\) case, and spin one refers to the \(N = 3\) case. Rather than being represented by standard coordinates in \(\mathbb{C}^{N \times N}\), in \texttt{spinsim} the Hamiltonian \(H(t)\) is instead represented with respect to a choice of basis for the corresponding Lie Algebra, \(\mathfrak{su}(N)\). For example, when set to spin half mode, the \texttt{spinsim} package solves the time dependent Schroedinger equations of the form

			\begin{align}
				\frac{\mathrm{d}}{\mathrm{d}t}\psi(t) = -i 2\pi (f_x(t) J_x + f_y(t) J_y + f_z(t) J_z) \psi(t),
			\end{align}

			where \(i^2 = -1\), \(\psi(t) \in \mathbb{C}^2\), and the spin half spin projection operators are given by

			\begin{align}
				J_x &= \frac12\begin{pmatrix}
					0 & 1 \\
					1 & 0
				\end{pmatrix},
				&J_y &= \frac12\begin{pmatrix}
					0 & -i \\
					i &  0
				\end{pmatrix},
				&\textrm{and }J_z &= \frac12\begin{pmatrix}
					1 &  0 \\
					0 & -1
				\end{pmatrix}.
			\end{align}

			The energy source \(f\) that represents the time dependent Hamiltonian \(H(t)\), is the collection of energy functions \(f_x(t), f_y(t), f_z(t)\), with \(t\) in units of s and \(f\) in units of Hz that control the dynamics of the system. The user must define a method that returns a sample of these source functions when a sampling time is input. In physical terms, these functions could represent the \(x,y,z\) components of a magnetic field applied to a magnetically sensitive.

			Similarly, when \texttt{spinsim} is set to spin one mode, it can solve the Schroedinger equation of the form

			\begin{align}
				\frac{\mathrm{d}}{\mathrm{d}t}\psi(t) = -i 2\pi (f_x(t) J_x + f_y(t) J_y + f_z(t) J_z + f_q(t) Q) \psi(t).
			\end{align}

			where now \(\psi(t) \in \mathbb{C}^3\), and the spin one operators are given by

			\begin{align}
				J_x &= \frac{1}{\sqrt{2}}\begin{pmatrix}
					0 & 1 & 0 \\
					1 & 0 & 1 \\
					0 & 1 & 0
				\end{pmatrix},&
				J_y &= \frac{1}{\sqrt{2}}\begin{pmatrix}
					0 & -i &  0 \\
					i &  0 & -i \\
					0 &  i &  0
				\end{pmatrix},\nonumber\\
				J_z &= \begin{pmatrix}
					1 & 0 &  0 \\
					0 & 0 &  0 \\
					0 & 0 & -1
				\end{pmatrix},&
				\textrm{and }Q &= \frac{1}{3}\begin{pmatrix}
					1 &  0 & 0 \\
					0 & -2 & 0 \\
					0 &  0 & 1
				\end{pmatrix}.
			\end{align}

			The matrices \(J_x, J_y, J_z\) are regular spin operators, and \(Q\) is a quadrupole operator. Note that \(Q\) is proportional to \(Q_{zz}\) as defined by Hamley et al \cite{hamley_spin-nematic_2012}, and \(Q_0\) as defined by Di et al \cite{di_dipolequadrupole_2010}.

			Frequently when one calculates the times series of the quantum state \(\psi(t)\), they are also interested in its expected spin projection \(\left\langle J\right\rangle\)(t). It is given by the vector

			\begin{align}
				\left\langle J\right\rangle(t) &= \begin{pmatrix}
					\psi(t)^\dagger J_x \psi(t)\\
					\psi(t)^\dagger J_y \psi(t)\\
					\psi(t)^\dagger J_z \psi(t)
				\end{pmatrix},
			\end{align}

			where \(\cdot^\dagger\) is the adjoint operator (also referred to as Hermitian conjugate, and is implemented as complex conjugate transpose). The expected spin projection can be interpreted as the average direction that the spin system is oriented in space when many systems of the equivalent state are measured (due to the Heisenberg uncertainty principle, only one component of the exact orientation of a quantum state can be known at any point in time, which is why we need to deal with expected values rather than absolute values). However, it can also be used to model the overall orientation of an ensemble of many quantum systems, like a BEC, for instance. \texttt{spinsim} has the functionality to calculate the expected spin projection of a system from its state.

		\subsubsection*{Parallelisation}
			Given that \(\psi(t)\) is a unit vector, it is possible to write \(\psi(t)\) in terms of a unitary transformation \(U(t, t_0)\) of the state \(\psi(t_0)\), for any time \(t_0\). In other words, for any \(t_0,t \in \mathbb{R}\), there is a unitary transformation \(U(t, t_0)\) such that

			\begin{align}
				\psi(t) &= U(t, t_0)\psi(t_0).
			\end{align}

			This means that a time series for the state of the system can be evaluated by evaluating the time evolution operator between each of the sample times. Consider quantising time with
			\begin{align}
				t_k &= t_0 + \mathrm{D}t\cdot k,
			\end{align}

			where \(\mathrm{D}t\) is the time step of the time series (in contrast to \(\mathrm{d}t\), a smaller time step for integration). If we define

			\begin{align}
				\psi_k = \psi(t_k)\textrm{ and}\\
				U_k = U(t_{k}, t_{k-1}),
			\end{align}

			then the time series of states \(\psi_k\) and time evolution operators \(U_k\) satisfies

			\begin{align}
				\psi_k &= U_k\psi_{k-1}\label{eq:integration_compilation}
			\end{align}

			This presents an opportunity for parallelism. While each of the \(\psi_k\) must be evaluated sequentially, the value of the \(U_k\) is independent of the value of any \(\psi_{k_0}\), or any other \(U_{k_0}\). This means that the time evolution operators \(U_k\) can all be calculated in parallel, and it allows \texttt{spinsim} to use GPU parallelisation on the level of time sample points, so a speed up is achieved even if just a single simulation is run.

			In summary, \texttt{spinsim} splits the time evolution of the full simulation into time evolution \(U_k\) within small time intervals \([t_{k - 1}, t_{k}]\), which are each calculated massively in parallel on a GPU. When all the \(U_k\) are calculated, the CPU then multiplies the \(U_k\) together (a comparatively less demanding job than calculating them) using Equation \eqref{eq:integration_compilation} to determine the \(\psi_k\).

		\subsubsection*{Rotating frame}
			If the rotating frame option is selected, the \(U_k\) are first calculated within a rotating frame of reference as \(U^r_k\), which, in some situations, reduces the size of the source functions used in the calculation, increasing accuracy. The rotation speed of the rotating frame is calculated locally for each parallel time step \(U_k\), and only for rotations around the \(z\) axis. The rotating from source functions \(f^r_x, f^r_y, f^r_z,\) and \(f^r_q\) are related to the source function from the user input via

			\begin{align}
				f^r_x(t) + if^r_y(t) &= e^{-i 2\pi f_r t}(f_x(t) + if_y(t)),\\
				f^r_z(t) &= f_z(t) - f_r\textrm{, and}\\
				f^r_q(t) &= f_q(t), \textrm{ for spin one.}
			\end{align}

			Where \(f_r = f_z(t_k + \frac12\mathrm{D}t)\) is sampled the midpoint value of the source over the interval \([t_{k - 1}, t_k]\). This, assuming that a midpoint sample is representative of an average value over the time interval, decreases the magnitude of \(f_z(t)\), while leaving the other source components at an equivalent magnitude. The rotation is then applied to obtain the lab frame time evolution operator \(U_k\) via

			\begin{align}
				U_k &= \exp(-i 2 \pi f_r J_z \mathrm{D}t) U^r_k.
			\end{align}

			Specifically, this relationship is

			\begin{align}
				U_k &= \begin{pmatrix}
					e^{-i 2\pi f_r \mathrm{D}t} & 0 & 0\\
					0 & 1 & 0\\
					0 & 0 & e^{i 2\pi f_r \mathrm{D}t}
				\end{pmatrix} U^r_k, \textrm{ for spin one, and}\\
				U_k &= \begin{pmatrix}
					e^{-i \pi f_r \mathrm{D}t} & 0\\
					0 & e^{i \pi f_r \mathrm{D}t}
				\end{pmatrix} U^r_k, \textrm{ for spin half.}
			\end{align}

			It is a common technique in solving quantum mechanical problems to enter rotating frames, and their more abstract counterparts of interaction pictures \cite{j_j_sakurai_jun_john_modern_1994}. Note that this is typically done in conjunction with the Rotating Wave Approximation (RWA), which is an assumption that the oscillatory components of \(f^r_x, f^r_y, f^r_z,\) and \(f^r_q\) on an average of many cycles do not have a large contribution to time evolution of the solution and can be ignored. In some cases, this allows for analytic solutions to the approximate quantum system to be obtained. Note that the RWA is \emph{not} invoked in \texttt{spinsim}, as doing this would reduce the accuracy of simulation results, defeating our purpose of using a rotating frame.

		\subsubsection*{Magnus based integration method}
			The integration method used in \texttt{spinsim} is the commutator free 4 (CF4) method from Auer et al \cite{auer_magnus_2018}, which based on the Magnus expansion. Each of the \(U_k\) are split into products of time evolution operators between times separated by a smaller time step, that is,

			\begin{align}
				U(t_k, t_{k-1}) &= U(t_k, t_k - \mathrm{d}t) \cdots U(t_{k-1} + 2\mathrm{d}t, t_{k-1} + \mathrm{d}t) U(t_{k-1} + \mathrm{d}t, t_{k-1})\\
				U_k &= u^k_{L-1} \cdots u^k_0\textrm{, where}\\
				u^k_{L-1} &= U(t_0 + (k - 1)\mathrm{D}t + (l + 1)\mathrm{d}t, t_0 + (k - 1)\mathrm{D}t + l\mathrm{d}t)
			\end{align}

			with \(\mathrm{d}t\) being the integration level time step. Note that the time steps are related to each other by \(\mathrm{D}t = L\mathrm{d}t\), where \(L\in\mathbb{N}\).

			The CF4 method is used to calculate each individual \(u^k_l\). Let the fine sample time be given by \(t_f = l\mathrm{d}t + t_k\). Then as part of the CF4 method, the source functions are sampled at particular times based on the second order Gauss-Legendre quadrature, given by

			\begin{align}
				t_1 &= t_f + \frac12 \mathrm{d}t\left(1 - \frac{1}{\sqrt{3}}\right)\textrm{, and}\\
				t_2 &= t_f + \frac12 \mathrm{d}t\left(1 + \frac{1}{\sqrt{3}}\right).
			\end{align}

			Now, let
			\begin{align}
				f(t_1) &= (f_x(t_1), f_y(t_1), f_z(t_1), f_q(t_1))\textrm{, and}
				f(t_2) &= (f_x(t_2), f_y(t_2), f_z(t_2), f_q(t_2)).
			\end{align}

			The integration time evolution operator can then be calculated using

			\begin{align}
				g_1 =& (g_{1,x}, g_{1,y}, g_{1,z}, g_{1,q})\\
				=& 2 \pi \mathrm{d}t \left(\frac{3 + 2 \sqrt{3}}{12} f(t_1) + \frac{3 - 2 \sqrt{3}}{12} f(t_2)\right)\textrm{, and}\\
				g_2 =& (g_{2,x}, g_{2,y}, g_{2,z}, g_{2,q})\\
				=& 2 \pi \mathrm{d}t \left(\frac{3 - 2 \sqrt{3}}{12} f(t_1) + \frac{3 + 2 \sqrt{3}}{12} f(t_2)\right)\textrm{, so}\\
				u =& \exp(-i \left( g_{2,x} J_x + g_{2,y} J_y + g_{2,z} J_z + g_{2,q} Q\right))\\
				&\cdot\exp(-i \left( g_{1,x} J_x + g_{1,y} J_y + g_{1,z} J_z + g_{1,q} Q\right)).
			\end{align}

		\subsubsection*{Exponentiator}
			For all exponentiation, the exponentiator computes the matrix exponential

			\begin{align}
				E(g) &= E(g_x, g_y, g_z, g_q)\\
				&= \exp(-i (g_x J_x + g_y J_y + g_z J_z + g_q Q)), \textrm{ with}
			\end{align}

			For spin half, the default exponentiator is in an analytic form. For spin one, an exponentiator based on the Lie Trotter product formula \cite{moler_nineteen_2003} is used instead. Explicitly, this formula is

			\begin{align}
				\exp\left( A + B\right) &= \lim_{n\to\infty} \left(\exp\left(\frac{A}{n}\right) \exp\left(\frac{B}{n}\right)\right)^n
			\end{align}

			Where \(A,B\in\mathbb{C}^{N\times N}\) are matrix operators, and \(n\in\mathbb{N}\). The equality holds for without the limit for all \(n\) if the operators commute, like it does for real and complex numbers. This tells us that we can approximate a matrix exponential of a linear combination of spin operators by reducing the size of the coefficients of these operators, taking the analytically known exponentials of each of the operators separately, multiplying each individual result together, and then raising the combination \(T\) to the power of the original reduction. For our spin one case, the exponential \(E(g)\) can be approximated as, for large \(2^\tau\),

            % \begin{align}
            %     E(g) &= \exp(-ig_x J_x - ig_y J_y - ig_z J_z - ig_q Q)\\
            %     &= \exp(2^{-\tau}(-ig_x J_x - ig_y J_y - ig_z J_z - ig_q Q))^{2^\tau}\\
            %     &\approx (\exp(-i(2^{-\tau} g_x) J_x) \exp(-i(2^{-\tau} g_y) J_y) \exp(-i(2^{-\tau} g_z J_z + (2^{-\tau} g_q) Q)))^{2^\tau}\\
            %     &= \begin{pmatrix}
            %         \frac{e^{-i\left(Z + \frac{P}{3}\right)}(c_X + c_Y - i s_Xs_Y)}{2} & \frac{e^{i\frac{2P}{3}} (-s_Y -i c_Y s_X)}{\sqrt{2}} & \frac{e^{-i\left(-Z + \frac{P}{3}\right)}(c_X - c_Y + i s_Xs_Y)}{2} \\
            %         \frac{e^{-i\left(Z + \frac{P}{3}\right)} (-i s_X + c_X s_Y)}{\sqrt{2}} & e^{i\frac{2P}{3}} c_X c_Y & \frac{e^{-i(Z - \frac{P}{3})} (-i s_X - c_X s_Y)}{\sqrt{2}} \\
            %         \frac{e^{-i\left(Z + \frac{P}{3}\right)}(c_X - c_Y - i s_Xs_Y)}{2} & \frac{e^{i\frac{2P}{3}} (s_Y -i c_Y s_X)}{\sqrt{2}} & \frac{e^{-i\left(-Z + \frac{P}{3}\right)}(c_X + c_Y + i s_Xs_Y)}{2}
            %     \end{pmatrix}^{2^\tau}
            % \end{align}

			\begin{align}
                E(g) =& \exp\left(-ig_x J_x - ig_y J_y - ig_z J_z - ig_q Q\right)\\
                =& \exp\left(2^{-\tau}\left(-ig_x J_x - ig_y J_y - ig_z J_z - ig_q Q\right)\right)^{2^\tau}\\
                \approx& \biggl(\exp\left(-i\left(2^{-\tau} \frac12g_z J_z + \left(2^{-\tau}\frac12g_q\right) Q\right)\right)\nonumber\\
				&\cdot\exp\left(-i\left(2^{-\tau} g_\phi J_\phi\right)\right)\nonumber\\
				&\cdot\exp\left(-i\left(2^{-\tau} \frac12g_z J_z + \left(2^{-\tau} \frac12g_q\right) Q\right)\right)\biggr)^{2^\tau}\\
                =& \begin{pmatrix}
                    \left(\frac{\Gamma}{PZ}\right)^2 & \frac{SP}{Z\Phi} & -\left(\frac{\Sigma P}{\Phi}\right)^2 \\
					\frac{SP\Phi}{Z} & CP^4 & \frac{SPZ}{\Phi} \\
					-\left(\frac{\Sigma \Phi}{P}\right)^2 & \frac{SPZ\Phi}{1} & \left(\frac{\Gamma Z}{P}\right)^2
                \end{pmatrix}^{2^\tau}\\
				=& T^{2^\tau}.
            \end{align}

			where

            \begin{align}
				g_\phi &= \sqrt{g_x^2 + g_y^2}&&\nonumber\\
				J_\phi &= \frac{g_x}{g_\phi}J_x + \frac{g_y}{g_\phi}J_y&&\nonumber\\
				\Gamma &= \cos\left(2^{-\tau} \frac{g_\phi}{2}\right) & \Phi &= e^{i2^{-\tau}g_\phi}\nonumber\\
				\Sigma &= \sin\left(2^{-\tau} \frac{g_\phi}{2}\right) & Z &= e^{i2^{-\tau}\frac{g_z}{2}}\nonumber\\
				C &= \cos(2^{-\tau} g_\phi) & P &= e^{i2^{-\tau}\frac{g_q}{6}}\nonumber\\
				S &= \frac{-i}{\sqrt2}\sin(2^{-\tau} g_\phi)&&
            \end{align}

			Once \(T\) is calculated, it is then recursively squared \(\tau\) times to obtain \(E(g)\). The approach used for spin one exponentiation means that the package cannot solve arbitrary spin one quantum systems, as that would require the ability to exponentiate a point in the full, 8 dimensional Lie algebra of \(\mathfrak{su}(3)\), rather than just the four dimensional subspace spanned by the subalgebra \(\mathfrak{su}(2)\) spanned by \(\{J_x, J_y, J_z\}\), and the single quadratic operator \(Q\). Including the full algebra could be possible as a feature update if there is demand for it, though just including this subspace is sufficient for our application, and many others, and has the advantage of being able to use this faster, more specialised method of matrix exponentiation.

			Note that, the methods for both spin half and spin one use analytic forms of exponentials to construct the result, meaning that all calculated time evolution operators are unitary. This guarantees that the results of \texttt{spinsim} maintain unitary.

	\subsection*{Software architecture}
		\subsubsection*{Integrator architecture}
			The integrator in the \texttt{spinsim} package calls a \texttt{numba.cuda.jit()}ed kernel to be run on a \emph{Cuda} capable \emph{Nvidia} GPU in parallel, with a different thread being allocated to each of the \(U_k\). This returns when each of the \(U_k\) have been evaluated.

			The thread starts by calculating \(t_k\) and, if the rotating frame is being used, \(f_r\). The latter is done by sampling a (\texttt{numba.cuda.jit()}ed version of a) user provided \emph{python} function \(f\) describing how to sample the source Hamiltonian. The code then loops over each integration time step \(\mathrm{d}t\) to calculate the integration time evolution operators \(u^k_l\).

			Within the loop, the integrator enters a device function (ie a GPU subroutine, which is inline for speed) to sample \(f(t)\), as well as calculate \(e^{-i 2 \pi f_r t}\), at the sample times needed for the integration method. After this, it enters a second device function, which makes a rotating wave transformation as needed in a third device function, before calculating \(g\) values, and finally taking the matrix exponentiation in a fourth device function. \(u^k_l\) is premultiplied to \(U^r_k\) (which is initialised to \(1\)), and the loop continues.

			When the loop has finished, if the rotating frame is being used, \(U^r_k\) is transformed to \(U_k\) as in Equation \eqref{eq:integration_compilation}, and this is returned. Once all threads have executed, the state \(\psi_k\) is calculated in a (CPU) \texttt{numba.jit()}ed function from the \(U_k\) and an initial condition \(\psi_{\mathrm{init}}\).

		\subsubsection*{Compilation of integrator}
			The \texttt{spinsim} integrator is constructed and compiled just in time, using \texttt{numba.cuda.jit()}. The particular device functions used are not predetermined, but are instead chosen based on user input to decide a closure. This structure has multiple advantages. First, the source function \(f\) is provided by the user as a plain python function (that must be \texttt{numba.cuda.jit()} compatible). This allows users to define \(f\) in a way that compiles and executes fast, does not put many restrictions on the form of the function, and returns the accurate results of analytic functions (compared to the errors seen in interpolation). Compiling the simulator also allows the user to set meta parameters, and choose the features they want to use, in a way that does not require experience with the \texttt{numba.cuda} library. This was especially useful for running benchmarks comparing old integration methods to the new ones, like CF4. The default settings should be optimal for most users, although tuning the values of \emph{Cuda} meta parameters \texttt{max\_registers} and \texttt{threads\_per\_block} could improve performance for GPUs with a differing number of registers and \emph{Cuda} cores to the mobile GTX1070 mainly used in testing here. Finally, just in time compilation also allows the user to select a target device other than \emph{Cuda} for compilation, so the simulator can run, using the same algorithm, on a multicore CPU in parallel instead of a GPU, if the user so chooses.

			This functionality is interfaced through an object of class \texttt{spinsim.Simulator}. The \emph{Cuda} kernel is defined as per the user’s instructions on construction of the instance, and it is used by calling the method \texttt{spinsim.Simulator.evaluate()}, which returns a results object including the time, state, time evolution operator, and expected spin projection (that is, Bloch vector). Note that the expected spin projection is calculated as a lazy parameter if needed, rather than returned by the simulator object.

\section*{Quality control}
	\subsection*{Benchmarks}
		\subsubsection*{Speed}
			\begin{figure}[htbp!]
				\centering
				\includegraphics[scale=0.7]{benchmark_device_aggregate.pdf}
				\caption{Evaluation speed of a typical spin one sensing experiment. Fine time step is 100ns, as determined to be ideal by the accuracy experiments. Experiments run for a duration of 100ms. Evaluation time is determined by an average of 100 similar experiments for each device.}
				\label{fig:benchmark_device_aggregate}
			\end{figure}

			Benchmarks were performed using \texttt{sense.sim.benchmark}, by comparing evaluation speed of typical spin one sensing experiments on different devices. This is shown in Figure \ref{fig:benchmark_device_aggregate}. The integration code was compiled by \texttt{numba} for single core CPUs, multicore CPUs, and \emph{Nvidia Cuda}, and run on different models of each of them. These test devices are given in Table \ref{tab:devices}.

			\begin{table}[h!]
				\caption{Devices used in the parallelisation speed test.}
				\label{tab:devices}
				\begin{tabular}{l|l|l|l|l}
					\textbf{Device}	&\textbf{Type}	&\textbf{RAM (GiB)}	&\textbf{Cores}	&\textbf{Cooling}\\
					\hline
					Core i7-6700	&Intel CPU		&16					&4				&Air\\
					Quadro K620		&Nvidia GPU		&2					&384			&Air\\
					\hline
					Core i7-8750H	&Intel CPU		&16					&6				&Air\\
					GeForce GTX 1070&Nvidia GPU		&8					&2048			&Air\\
					\hline
					Ryzen 9 5900X	&AMD CPU		&32					&12				&Air\\
					GeForce RTX 3070&Nvidia GPU		&8					&5888			&Air\\
					\hline
					Ryzen 7 5800X	&AMD CPU		&32					&8				&Liquid\\
					GeForce RTX 3080&Nvidia GPU		&10					&8704			&Air\\
				\end{tabular}
			\end{table}
			% \begin{itemize}
			% 	\item{
			% 		Computer A\begin{itemize}
			% 			\item Intel Core i7-8750H, a 6 core laptop processor. Run with 16GiB of RAM. Air cooled (laptop fan). Base clock speed of 2.2GHz.
			% 			\item Nvidia GeForce GTX 1070, a 2048 \emph{Cuda} core laptop graphics processor released in 2016. Run with 8GiB of VRAM. Air cooled (laptop fan).
			% 		\end{itemize}
			% 	}

			% 	\item{Computer B\begin{itemize}
			% 			\item AMD Ryzen 9 5900X, a 12 core desktop processor. Run with 32GiB of RAM. Air cooled. Base clock speed of 3.7GHz.
			% 			\item Nvidia GeForce RTX 3070, a 5888 \emph{Cuda} core desktop graphics processor. Run with 8GiB of VRAM. Air cooled.
			% 		\end{itemize}
			% 	}

			% 	\item{Computer C\begin{itemize}
			% 			\item AMD Ryzen 7 5800X, an 8 core desktop processor. Run with 32GiB of RAM. Liquid cooled. Base clock speed of 3.8GHz.
			% 			\item Nvidia GeForce RTX 3080, an 8704 \emph{Cuda} core desktop graphics processor. Run with 10GiB of VRAM. Air cooled.
			% 		\end{itemize}
			% 	}

			% 	\item{Computer D\begin{itemize}
			% 		\item Intel Core i7-6700, a 4 core desktop processor. Run with 16GiB of RAM. Air cooled. Base clock speed of 3.4GHz.
			% 		\item Nvidia Quadro K620, a 384 \emph{Cuda} core desktop graphics processor. Run with 2GiB of VRAM. Air cooled.
			% 	\end{itemize}
			% 	}
			% \end{itemize}

			This benchmark shows the benefit to using parallelisation when solving this problem. Moving from a 6 core processor to a 12 core processor doubles the execution speed. Moving from a single core processor to a high end GPU increases performance by well over an order of magnitude. Even the low end Quadro K620 was an improvement over the i7-6700 used by that computer. As an aside, liquid cooling allows the 8 core processor to increase its boost clock and outperform the 12 core processor.

		\subsubsection*{Evaluation of techniques}
		All subsequent benchmarks were run on the desktop computer with the Ryzen 7 5800X and GeForce RTX 3080, which from Figure \ref{fig:benchmark_device_aggregate} are the fastest CPU and GPU from the devices tested. Benchmarks were performed using \texttt{neural-sense.sim.benchmark} (where \texttt{neural-sense} \cite{alexander-tritt-monash_alexander-tritt-monashneural-sense_2020} is the quantum sensing package that \texttt{spinsim} was written for). We first wanted to test the accuracy of the different integration techniques for various integration time steps. Here we wanted to test the advantages, if any of using a Magnus based integration method. Accuracy was calculated by taking the quantum state simulation evaluations of a typical quantum sensing experiment and finding the Root Mean Squared (RMS) to a baseline simulation run by \texttt{scipy.integrate.ivp\_solve()} as part of the \emph{SciPy} python package, via

			\begin{align}
                \epsilon &= \frac{1}{K}\sqrt{\sum_{k = 0}^{K - 1}\sum_{m_j = -j}^j|\psi_{k, (m_j)} - \psi_{k, (m_j)}^{\textrm{baseline}}|^2},\label{eq:error}
            \end{align}

			where \(j \in \{\frac12, 1\}\) is the spin quantum number of the system. This simulation of the quantum sensing experiment involves continuously driving transitions in the system, while exposing it to a short pulsed signal that the system should be able to sense. It runs over a duration of 1ms.

			This baseline was computed in 3.8 hours, and was also used for comparisons to other software packages. These are shown in Figures \ref{fig:benchmark_spin_one_step_error}, and \ref{fig:benchmark_spin_half_step_error}. For each of these simulations we measured the time of execution, as although it is more accurate compared to Euler integration, the CF4 method is slower for any fixed integration time step. These are shown in Figures \ref{fig:benchmark_spin_one_execution_error}, and \ref{fig:benchmark_spin_half_execution_error}. In all of these comparisons, errors above \(10^{-3}\) were counted as a failed simulation, as the maximum possible error for a quantum state saturates given that it is a point on a unit complex sphere. Additionally, errors bellow \(10^{-11}\) were excluded, as this was the order of magnitude of the errors in the reference simulation.

			% The integration techniques tested were
			% \begin{itemize}
			% 	\item The Magnus based method, Commutator Free 4.
			% 	\item The Heun (trapezoidal) Euler method.
			% 	\item The midpoint Euler method.
			% \end{itemize}

			The integration techniques tested were the Magnus based CF4, as well as two Euler based sampling methods. A midpoint Euler method was chosen as the simplest (and fastest for a given integration time step)  possible sampling method, whereas a Heun Euler sampling method was used as a comparison to previous versions of this code, which also used it. We benchmarked these methods both while using and not using the rotating frame option. This was done separately for spin one and spin half systems, to ensure they both yield accurate results.

			From Figures \ref{fig:benchmark_spin_one} and \ref{fig:benchmark_spin_half}, we find that overall, the results that \texttt{spinsim} gives are accurate to those of \emph{SciPy}. Figures \ref{fig:benchmark_spin_one_step_error}, and \ref{fig:benchmark_spin_half_step_error} show that using the Magnus based integration method is up to 3 orders of magnitude more accurate when compared the Euler based methods. Also, using the rotating frame increased the accuracy here by 4 orders of magnitude for any individual integration method. From Figures \ref{fig:benchmark_spin_one_execution_error}, and \ref{fig:benchmark_spin_half_execution_error}, although the Magnus based method is slower than the midpoint Euler based method, it makes up for this in terms of its accuracy. Thus, by default \texttt{spinsim} sets the integrator to CF4, and uses the rotating frame. These can be modified using optional arguments when instantiating the \texttt{spinsim.Simulator} object.

			\begin{figure}[h!]
				\begin{subfigure}[b]{0.475\textwidth}
					\includegraphics[scale=0.475]{benchmark_spin_one_step_error.pdf}
					\caption{Accuracy of the spin one options of \texttt{spinsim}.}
					\label{fig:benchmark_spin_one_step_error}
				\end{subfigure}
				\hfill
				\begin{subfigure}[b]{0.475\textwidth}
					\includegraphics[scale=0.475]{benchmark_spin_one_execution_error.pdf}
					\caption{Speed vs accuracy of the spin one options of \texttt{spinsim}.}
					\label{fig:benchmark_spin_one_execution_error}
				\end{subfigure}\
				\caption{Speed and accuracy of the spin one options of \texttt{spinsim}.}
				\label{fig:benchmark_spin_one}
			\end{figure}

			% The that the accuracy of spin half simulations using the Lie Trotter based exponentiator in Figure \ref{fig:benchmark_spin_half_trotter_step_error} plateaus below \(10^{-8}\), whereas an accuracy below \(10^{-12}\) is able to be obtained when when the analytic exponentiator in Figure \ref{fig:benchmark_spin_half_step_error} is used. This also explains the plateau in accuracy from the spin one integrator, where the Lie Trotter based method is the only method implemented. Furthermore, the analytic exponentiator is much faster in Figure \ref{fig:benchmark_spin_half_execution_error}, as compared to the Lie Trotter based integrator in Figure \ref{fig:benchmark_spin_half_trotter_execution_error}. Hence, the analytic exponentiator is the default option for \texttt{spinsim} simulations when in spin half mode.

			\begin{figure}[h!]
				\begin{subfigure}[b]{0.475\textwidth}
					\includegraphics[scale=0.475]{benchmark_spin_half_step_error.pdf}
					\caption{Accuracy of the spin half options of \texttt{spinsim}.}
					\label{fig:benchmark_spin_half_step_error}
				\end{subfigure}
				\hfill
				\begin{subfigure}[b]{0.475\textwidth}
					\includegraphics[scale=0.475]{benchmark_spin_half_execution_error.pdf}
					\caption{Speed vs accuracy of the spin half options of \texttt{spinsim}.}
					\label{fig:benchmark_spin_half_execution_error}
				\end{subfigure}
				% \vfill
				% \begin{subfigure}[b]{0.45\textwidth}
				% 	\includegraphics[scale=0.45]{benchmark_spin_half_trotter_step_error.pdf}
				% 	\caption{Accuracy of the spin half options of \texttt{spinsim}, using the Lie Trotter exponentiator.}
				% 	\label{fig:benchmark_spin_half_trotter_step_error}
				% \end{subfigure}
				% \hfill
				% \begin{subfigure}[b]{0.45\textwidth}
				% 	\includegraphics[scale=0.45]{benchmark_spin_half_trotter_execution_error.pdf}
				% 	\caption{Speed vs accuracy of the spin half options of \texttt{spinsim}, using the Lie Trotter exponentiator.}
				% 	\label{fig:benchmark_spin_half_trotter_execution_error}
				% \end{subfigure}\
				\caption{Speed and accuracy of the spin half options of \texttt{spinsim}.}
				\label{fig:benchmark_spin_half}
			\end{figure}

			% \begin{figure}[h!]
			% 	\includegraphics[scale=0.9]{benchmark_comparison_spin_one_publication.pdf}
			% 	\caption{Fine time step benchmark for spin one systems. CF4 is the Magnus commutator free integrator, HS is the two sample exponential integrator used in \texttt{AtomicPy}, MP is a single sample exponential integrator, RF is use of the rotating frame, and LF is lab frame (no use of the rotating frame). HS and MP results are drawn on top of each other due to their similarities.}
			% 	\label{fig:benchmark_comparison_spin_one}
			% \end{figure}

			% Figure \ref{fig:benchmark_comparison_spin_one} shows the performance of \texttt{spinsim} when running in spin one mode. This shows that both using the Magnus based CF4 method and moving into a rotating frame give significant increases to accuracy. The HS (half step) method in the lab frame, with a time step of 10ns was the method used by \texttt{AtomicPy}, the previous code used by the group for simulating spin systems. Compared to this, the best performing \texttt{spinsim} method is 5 orders of magnitude more accurate, while executing in a time 2 orders of magnitude faster.

			% \begin{figure}[h!]
			% 	\includegraphics[scale=0.9]{benchmark_comparison_spin_half_lt_publication.pdf}
			% 	\caption{Fine time step benchmark for spin half systems, using the Lie Trotter based exponentiator. CF4 is the Magnus commutator free integrator, HS is the two sample exponential integrator used in \texttt{AtomicPy}, MP is a single sample exponential integrator, RF is use of the rotating frame, and LF is lab frame (no use of the rotating frame). HS and MP results are drawn on top of each other due to their similarities.}
			% 	\label{fig:benchmark_comparison_spin_half_lt}
			% \end{figure}

			% From Figure \ref{fig:benchmark_comparison_spin_half_lt}, one gets essentially the same accuracy for each method when working in spin half mode compared to spin one, if all else is kept constant.

			% \begin{figure}[h!]
			% 	\includegraphics[scale=0.9]{benchmark_comparison_spin_half_a_publication.pdf}
			% 	\caption{Fine time step benchmark for spin half systems, using the analytic based exponentiator. CF4 is the Magnus commutator free integrator, HS is the two sample exponential integrator used in \texttt{AtomicPy}, MP is a single sample exponential integrator, RF is use of the rotating frame, and LF is lab frame (no use of the rotating frame). HS and MP results are drawn on top of each other due to their similarities.}
			% 	\label{fig:benchmark_comparison_spin_half_a}
			% \end{figure}

			% Figure \ref{fig:benchmark_comparison_spin_half_a} shows that the Lie Trotter based exponentiator does limit the maximum accuracy obtainable, and for spin half systems, one can increase accuracy further (and decrease execution time) by using an analytic based exponentiator.

		\subsubsection*{Comparison to alternatives}
			We ran the same error (using Equation \eqref{eq:error}) and execution time benchmarks on some alternative packages to compare \texttt{spinsim}'s performance to theirs. The packages compared were:
			\begin{itemize}
				\item \texttt{spinsim} running on the \emph{Cuda} device, using the CF4 integrator and the rotating frame mode, which were the highest performing options when comparing \texttt{spinsim} integration methods.
				% \item \texttt{AtomicPy} \cite{morris_qcmonkatomicpy_2018}, the previous custom written \emph{cython} based code developed by our lab group.
				\item \texttt{NDSolve} from the \emph{Mathematica} \cite{wolfram_research_inc_mathematica_2020} software. This was chosen as it is popular with our lab group for simulating magnetometry experiments.
				\item \texttt{scipy.integrate.ivp\_solve()} from the \emph{python} library \texttt{SciPy} \cite{virtanen_scipy_2020}. This was chosen as a generic solver from within the python ecosystem.
				\item We had also planned to benchmark against \texttt{qutip.sesolve()}, a solver in the popular quantum mechanics \emph{python} library, \texttt{QuTip} \cite{johansson_qutip_2013}. However, due to a known bug with the library’s dependencies, this was not installable on Windows 10, the operating system being used for testing, and so benchmarks for it could not be run.
			\end{itemize}

			In each case, the step sizes of the alternative integrators were limited to a maximum value obtain simulation results of different accuracies. Apart from that, the integrator settings were left untouched from the default values, as a representation of what a user would experience using a generic solver for spin system problems. Similarly to with the internal \texttt{spinsim} benchmarks, the expected spin projection was evaluated in each case, but the states were compared to calculate a relative error. Also like with the internal benchmarks, we used the longest running \emph{SciPy} simulation as a ground truth for comparison, as the accuracy of \emph{Mathematica} plateaus at small time steps.

			Each benchmark was run one simulation at a time. However, it might be possible to increase the average speed of many benchmarks from alternative packages using multithreading to run multiple benchmarks at a time. When this was attempted using \emph{Mathematica}, the kernels crashed as the 32GiB of RAM was not enough to run them all at once. Multithreading was also not attempted using \emph{SciPy}, due to the fact that running the full set of benchmarks of only a single simulation per integration time step consumes a day of computational time. But to be fair, both \emph{Mathematica} and \emph{SciPy} benchmarks are plotted with an artificial reduction in execution time by a factor of 4 and 8, which is an upper bound for the speed increase that could be obtained by running them parallel on a 4 and 8 core processor, respectively. These are respectively shown in plots as both faded and dotted lines.

			From Figure \ref{fig:benchmark_external}, for any given error tolerance, \texttt{spinsim} is over 3 orders of magnitude faster than \emph{Mathematica}, and 4 orders of magnitude more accurate than \emph{SciPy}. In practice, this means that an 8 minute \emph{SciPy} simulation is reduced to 50ms, and a full week long \emph{SciPy} batch simulation of 1000 separate systems (a realistic situation for testing quantum sensing protocols) would take less than one minute in \texttt{spinsim}.

			\begin{figure}[h!]
				\includegraphics[scale=0.9]{benchmark_external_execution_error.pdf}
				\caption{Speed vs accuracy of various integration packages.}
				\label{fig:benchmark_external}
			\end{figure}
			% Compared to our previous code, \texttt{AtomicPy}, the best performing (default) spin one \texttt{spinsim} method is 5 orders of magnitude more accurate, while executing in a time 2 orders of magnitude faster on computer A. Another popular solver used by the lab group for magnetometry simulations is \emph{Mathematica}'s \cite{wolfram_research_inc_mathematica_2020} \texttt{NDSolve}. For a comparison between python packages, we also

			% We had also planned to benchmark against \texttt{qutip.sesolve()}, a solver in the popular quantum mechanics \emph{python} library, \texttt{QuTip} \cite{johansson_qutip_2013}. However, due to a known bug with the library’s dependencies, this was not installable on Windows 10, the operating system being used for testing, and so benchmarks for it could not be run.

			% We had planned to benchmark against some other popular generic solvers. One such solver was \texttt{qutip.sesolve()}, a solver in the popular quantum mechanics \emph{python} library, \texttt{QuTip} \cite{johansson_qutip_2013}. However, due to a known bug with the library’s dependencies, this was not installable on Windows 10, the operating system being used for testing, and so benchmarks for it could not be run. We also planned to benchmark accuracy against the generic solver \texttt{scipy.integrate.ivp\_solve()} in the \emph{python} library \texttt{SciPy} \cite{virtanen_scipy_2020}. However, using the same \texttt{get\_field} function as in the spin one benchmarks used for the \texttt{spinsim}, simulating with a integration time step of 500ns (the largest used during the \texttt{spinsim} benchmarks), we found that a single simulation ran in 153s, which is over three orders of magnitude slower than the most accurate \texttt{spinsim} simulations. This means that a generous projection for the time it would take to run the same benchmarks that \texttt{spinsim} runs in 11 minutes, using \texttt{scipy} would be over six days; for an integration package not designed for this problem (and would therefore likely be less accurate).

	\subsection*{Testing}
		During the accuracy tests, it was confirmed that all possible modes of \texttt{spinsim} agree with a standard \emph{SciPy} simulation up to an arbitrarily small error. The Lie Trotter matrix exponentiator was tested separately from the full system, as well as benchmarked separately. These tests and benchmarks were run as part of the \texttt{neural\_sense} package. The simulator has also been used as part of the measurement protocol being developed there, and it has been tested as part of those algorithms as well.

		The kernel execution was profiled thoroughly, and changes were made to optimise VRAM and register usage and transfer. This was done specifically for the development hardware of an \emph{Nvidia} GTX1070, so one may get some performance increases by changing some GPU specific meta parameters when instantiating the \texttt{spinsim.Simulator} object.

		A good way to confirm that \texttt{spinsim} is functioning properly after an installation is to run the tutorial code provided and compare the outputs. Otherwise, one can reproduce the benchmarks shown here using \texttt{neural\_sense.sim.benchmark}.

\section*{(2) Availability}
\vspace{0.5cm}
\section*{Operating system}
Developed and tested on Windows 10. CPU functionality tested on MacOS Big Sur (note that modern Mac computers are not compatible with \emph{Cuda} software). All packages referenced in \texttt{spinsim} are compatible with Linux, but functionality has not been tested.

\section*{Programming language}
Python (3.7 or greater)

\section*{Additional system requirements}
To use the (default) \emph{Nvidia Cuda} GPU parallelisation, one needs to have a \emph{Cuda} compatible \emph{Nvidia} GPU \cite{noauthor_cuda_2012}. For \emph{Cuda} mode to function, one also needs to install the \emph{Nvidia Cuda} toolkit \cite{noauthor_cuda_2013}. If \emph{Cuda} is not available on the system, the simulator will automatically parallelise over multicore CPUs instead.

\section*{Dependencies}
numba (0.50.1 or greater)\\
numpy (1.19.3)\\
matplotlib (for example code, 3.2)\\
neuralsense (for benchmark code)

\section*{List of contributors}

1. Alex Tritt\\
	School of Physics \& Astronomy, Monash University, Victoria 3800, Australia.\\
	Primary author of the released packages.\\
2. Joshua Morris\\
	School of Physics \& Astronomy, Monash University, Victoria 3800, Australia.\\
	Present address: Faculty of Physics, University of Vienna, 1010 Vienna, Austria.\\
	Author of first version of code.\\
3. Joel Hockstetter\\
	School of Physics \& Astronomy, Monash University, Victoria 3800, Australia.\\
	Present address: School of Physics, University of Sydney, NSW 2006, Australia.\\
	Optimization and extension to spin one of first version of code.\\
4. Russell P. Anderson\\
	School of Molecular Sciences, La Trobe University, PO box 199, Bendigo, Victoria 3552, Australia.\\
	Original conception of first version of code.\\
5. James Saunderson\\
	Department of Electrical and Computer Systems Engineering, Monash University, Victoria 3800, Australia.\\
	Advice on numerical analysis.\\
6. Lincoln D. Turner\\
	School of Physics \& Astronomy, Monash University, Victoria 3800, Australia.\\
	Original conception of released version of algorithm.

\section*{Software location:}

{\bf Archive}

\begin{description}[noitemsep,topsep=0pt]
	\item[Name:] Monash Bridges
	\item[Persistent identifier:] 10.26180/13285460
	\item[Licence:] Apache 2.0
	\item[Publisher:]  Alex Tritt
	\item[Version published:] 1.0.0
	\item[Date published:] \textcolor{blue}{dd/mm/yy}
\end{description}

{\bf Code repository}

\begin{description}[noitemsep,topsep=0pt]
	\item[Name:] GitHub
	\item[Persistent identifier:] https://github.com/alexander-tritt-monash/spinsim
	\item[Licence:] BSD 3 Clause
	\item[Date published:] 18/11/20
\end{description}

\section*{Language}

English.

\section*{(3) Reuse potential}

	\subsection*{Use potential and limitations}
		\texttt{spinsim} will be useful for any research group needing quick, accurate, and / or large numbers of simulations involving spin half or spin one systems. This is immediately relevant to developing new quantum sensing protocols with spin half and spin one systems. This package is being used in the context of Bose Einstein Condensate (BEC) magnetic sensing protocol design by our lab.

		This project is to be able to measure neural signals using BECs. The electrical pulses made by neurons are currently measured using electrical probes, which is intrusive and damages the cells. We instead propose to sense the small magnetic fields that these electrical currents produce. Rubidium BECs can potentially be made sensitive enough to these tiny magnetic fields that they can be measured by them. \texttt{spinsim} was written to simulate possible measurement protocols for this, showing the behaviour of the array of spin one atoms interacting with the magnetic fields of the neurons, control signals, and noise. The package is also now being used to simulate other BEC magnetometry experiments by the lab group.

		Another example of spin based magnetic field sensing is the use of Nitrogen Vacancy Centres (NVCs). These are spin one structures found in diamond doped with Nitrogen atoms. This leaves a vacancy in a position adjacent to the Nitrogen atom, which pairs of electrons occupy to obtain the spin one properties. Similar to BECs, NVCs can be placed and addressed in 2D arrays in order to take many samples in one measurement. A paper was only recently released covering simulation experiments of magnetic neural pulse sensing using NVCs \cite{parashar_axon_2020}, which is something that \texttt{spinsim} could be useful for.

		\texttt{spinsim} is designed to simulate small dimensional quantum systems, including large arrays of non-interacting spin systems. This means that it would not be able to integrate large arrays of entangled states or interacting particles. As a result, despite being fast at simulating qubits, it is inappropriate for the package to be used for quantum computing. In addition, \texttt{spinsim} is currently designed to integrate the time evolution of pure states only. This means that it may not be adequate for use in some Nuclear Magnetic Resonance (NMR) applications where relaxation \cite{veshtort_spinevolution_2006} is important (or other kinds of simulations involving decoherence).

		With these restrictions in mind, \texttt{spinsim} could be used for some simplified simulations in various areas of NMR. There are many atomic nuclei with spins of half (eg protons, Carbon 13) and, and fewer that have spins of one (eg Lithium 6, Nitrogen 14) \cite{fuller_nuclear_1976}, which, if relaxation and interactions between systems are not important for the application, \texttt{spinsim} could be used to simulate for spectroscopy experiments, for example. The inclusion of a quadrupole operator means that, with the same level of simplifications, \texttt{spinsim} should be able to simulate Nuclear Quadrupole Resonance (NQR) spectroscopy for spin one nuclei \cite{bain_nqr_2004}, such as Nitrogen 14, provided a suitable coordinate system is chosen. This technique measures energy level differences between levels split by electric field gradients, rather than static magnetic bias fields. Another possible use case could be for Magnetic Resonance Imaging (MRI) simulation and pulse sequence design. MRI uses measures the response of spins of an array of spin half protons to a spatially varying pulse sequence \cite{mckinnon_physics_1998}, which essentially just corresponds to many separate \texttt{spinsim} simulations of spins at different positions in space. While this package offers some advantages over state of the art simulators in the field \cite{kose_fast_2019}, with its use of quantum mechanics over classical mechanics, and its absence of rotating wave approximations, its parametrised pulse sequence definitions and geometric integrator, again, the lack of interacting particles and decoherence features are may limit its use in this area.

	\subsection*{Support}
		Documentation for \texttt{spinsim} is available on \href{https://spinsim.readthedocs.io/en/latest/}{\emph{Read the Docs}}. This documentation contains a thorough tutorial on how to use the package, and installation instructions.

		For direct support with the \texttt{spinsim} package, one can open an issue in the \emph{github} repository. One can also use this contact to suggest extensions to the package. \texttt{spinsim} is planned to be maintained by the Monash University spinor BEC lab into the future.

\section*{Acknowledgements}

Thank you to the Monash University School of Physics and Astronomy spinor BEC lab group, particularly Hamish Taylor and Travis Hartley, who have started using \texttt{spinsim} for their own projects and have given useful feedback of their user experience with the package.

\section*{Funding statement}

\textcolor{blue}{If the software resulted from funded research please give the funder and grant number.}

\section*{Competing interests}

The authors declare that they have no competing interests.

\bibliography{spinsim}{}
\bibliographystyle{vancouver}

\vspace{2cm}

\rule{\textwidth}{1pt}

{ \bf Copyright Notice} \\
Authors who publish with this journal agree to the following terms: \\

Authors retain copyright and grant the journal right of first publication with the work simultaneously licensed under a  \href{http://creativecommons.org/licenses/by/3.0/}{Creative Commons Attribution License} that allows others to share the work with an acknowledgement of the work's authorship and initial publication in this journal. \\

Authors are able to enter into separate, additional contractual arrangements for the non-exclusive distribution of the journal's published version of the work (e.g., post it to an institutional repository or publish it in a book), with an acknowledgement of its initial publication in this journal. \\

By submitting this paper you agree to the terms of this Copyright Notice, which will apply to this submission if and when it is published by this journal.

\end{document}


\documentclass[11pt,a4paper]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{authblk}

\usepackage[utf8]{inputenc}
\usepackage{multirow}
\usepackage{hyperref}
\hypersetup{
colorlinks=true,
linkcolor=black,
citecolor=black
}
\usepackage{caption}
\usepackage{subfigure}
\usepackage{mathrsfs}
\usepackage{amsfonts}
\usepackage{amsmath}
\usepackage{algorithm}
\usepackage{algcompatible}
\usepackage{algpseudocode} \usepackage{romannum}
\usepackage{amsmath}
\usepackage{verbatimbox}
\usepackage{enumitem}
\usepackage{todonotes}
\usepackage{geometry}
\geometry{left = 2.0cm, right = 2.0 cm, top = 2cm}
%% The graphicx package provides the includegraphics command.
\usepackage{graphicx}
%% The amssymb package provides various useful mathematical symbols
\usepackage{amssymb}
%% The amsthm package provides extended theorem environments
%% \usepackage{amsthm}
\usepackage{bm}
\usepackage{hyperref}

%% The lineno packages adds line numbers. Start line numbering with
%% \begin{linenumbers}, end it with \end{linenumbers}. Or switch it on
%% for the whole article with \linenumbers after \end{frontmatter}.
\usepackage{lineno}

\usepackage{authblk}

%% Title, authors and addresses

\title{Relationship between Matrix/Tensor Factorization and Linear Regression}
\author{Mengyan Zhang}

\begin{document}

\maketitle

\begin{abstract}
%% Text of abstract
Linear regression aims to model the relationship between two variables by fitting a linear equation to observed data. Matrix or tensor factorization is to factorize matrix or tensor into two or more smaller size matrices or tensors, which can be viewed as a regression problem, where the independent variable is each entry in the matrix/tensor, the corresponding dependent variable is the estimated entry. Therefore, the methods for linear regression can also be applied to the matrix/tensor factorization. This tutorial aims to present these relationships between matrix/tensor factorization and linear regression in detail.
\end{abstract}
%There are several ways to find the best parameters of the linear equation, for example, we can use least squares to find the parameters which gives the minimum residuals. In probabilistic view, we can maximize the likelihood of observing a target value given we know the input location and parameters.
% \begin{keyword}
% Science \sep Publication \sep Complicated
%% keywords here, in the form: keyword \sep keyword

%% MSC codes here, in the form: \MSC code \sep code
%% or \MSC[2008] code \sep code (2000 is the default)

% \end{keyword}

\begin{table}[h]
\small
\centering
\begin{tabular}{|l|l|l|l|l|}
\hline
 & \textbf{\begin{tabular}[c]{@{}l@{}}Least Squares\end{tabular}} & \textbf{\begin{tabular}[c]{@{}l@{}}Maximum Likelihood\end{tabular}} & \textbf{\begin{tabular}[c]{@{}l@{}}Maximum A Posterior\end{tabular}} & \textbf{\begin{tabular}[c]{@{}l@{}}Bayesian \\ Approaches\end{tabular}} \\
 \hline
\textbf{LR}   &  $\mathop{\arg\min}_{\bm{\theta}} {\| \bm{y} - X \bm{\theta}\|}_{F}^2$&   $\mathop{\arg\max}_{\bm{\theta}} p(\bm{y}| X, \bm{\theta}, \sigma)$&    $\mathop{\arg\max}_{\bm{\theta}} p(\bm{\theta}| X, \bm{y}, \sigma, \sigma_{\theta})$  &   $p(\bm{\theta}| X, \bm{y}, \sigma, \sigma_{\theta})$            \\ \hline
\textbf{MF}&  $\mathop{\arg\min}_{U,V} \|A - UV\|_F^2$ &
$\mathop{\arg\max}_{U,V} p(A| U, V, \sigma)$  &
$\mathop{\arg\max}_{U,V} p(U,V| A, \sigma, \sigma_U, \sigma_V)$&  $p(U,V| A, \sigma, \sigma_U, \sigma_V)$  \\ \hline
\textbf{TF} &  \textbf{\begin{tabular}[c]{@{}l@{}}$\mathop{\arg\min}_{E,R}$ \\ $\sum_{k=1}^K \|T_{:k:} - E R_k E^T\|_F^2$\end{tabular}} &
$\mathop{\arg\max}_{E,R} p(T| E, R, \sigma)$  & $\mathop{\arg\max}_{E,R} p(E,R| T, \sigma, \sigma_E, \sigma_R)$             &     $p(E,R| T, \sigma, \sigma_E, \sigma_R)$         \\ \hline
\end{tabular}
\caption{Relation between linear regression and matrix/tensor factorization. LR: linear regression; MF: matrix factorization; TF: tensor factorization}
\end{table}

%%
%% Start line numbering here if you want
%%
\linenumbers

\section{Linear Regression}
%% main text
For linear regression, given D dimensional inputs $\bm{x} \in \mathbb{R}^D$ and corresponding target $y \in \mathbb{R}$, we aim to find a linear model which can estimate the target value for unseen input accurately. Then linear model can be built as

\begin{equation}
\label{equ1}
\hat{y} = f(\bm{x}) + \epsilon = \bm{x}^T \bm{\theta} + \epsilon,
\end{equation}
where  $\bm{\theta} \in \mathbb{R}^D$ are the parameters we seek, and $\epsilon \sim \mathbb{N}(0, \sigma)$ is i.i.d. Gaussian observation noise. %Then for N inputs $\bm{x_n} \in \mathcal{R}^D$ and corresponding target $y_n \in \mathbb{R}$, n = 1, ... , N. Assume conditional independence
%$$p(y_i|\bm{x_i}) \bot p(y_j|\bm{x_j}),$$

\subsection{Least Squares}

Intuitively, we want to find the parameters which can estimate the target value as accurate as possible, i.e. the sum of squares of the vertical deviations as small as possible, which is known as   \href{https://en.wikipedia.org/wiki/Least_squares}{Least squares}. For N inputs $\bm{x_n} \in \mathcal{R}^D$ and corresponding target $y_n \in \mathbb{R}$, n = 1, ... , N, we find parameters $\bm{\theta}$ by,

\begin{equation}
\label{equ2}
\mathop{\arg\min}_{\bm{\theta}} \ \ \sum_{n=1}^N (y_n - \hat{y_n})^2,
\end{equation}
where $\hat{y_n}$ is defined as Equation \ref{equ1}. In matrix form, we have

\begin{equation}
\mathop{\arg\min}_{\bm{\theta}} {\ \  \| \bm{y} - X \bm{\theta} - \sigma\|}_{F}^2,
\end{equation}
where $X := [\bm{x_1, ..., x_N}]^T \in \mathbb{R} ^{N \times D}$ and $\bm{y} := [y_1, ... , y_N]^T \in \mathbb{R}^N$.

%\subsection{Maximum Likelihood Estimation}

%\subsection{Maximum A Posterior}
%\subsection{Bayesian Linear Regression}

\section{Matrix Factorization}
Matrix factorization is to factorize of a matrix into a product of matrices. For a given matrix $A \in \mathbb{R}^{N \times M}$, it can be factorized as the product as the product of $U \in \mathbb{R}^{N \times D}, V \in \mathbb{R}^{D \times M}$, i.e.

\begin{equation}
\hat{A} = UV,
\end{equation}

\subsection{Least Squares}

Similar as linear regression, we want the estimated matrix $\hat{A}$ (i.e. the product of factorized matrices U and V) as much similar as the original matrix A. Thus the simplest way is to minimize the sum of error squares,

\begin{equation}
\mathop{\arg\min}_{U,V} \ \ \sum_{i=1}^N \sum_{j=1}^M (a_{ij} - \hat{a_{ij}})^2,
\end{equation}
where $\hat{a_{ij}} = \bm{u_i}^T \bm{v_j}$ is the (i,j) entry of the estimated matrix $\hat{A}$. In matrix form,

\begin{equation}
\mathop{\arg\min}_{U,V} \ \ \|A - UV\|_F^2,
\end{equation}

\section{Tensor Factorization}

More generally, we need to deal with random dimension tensors rather than 2-d matrix. Using a three-way tensor $ T \in \mathbb{R}^{N \times K \times N} $ as example, we simplify the tensor factorization into multiple matrix factorizations, i.e. for each slice $T_{:k:}$, we have

\begin{equation}
\hat{T_{:k:}} = E R_k E^T, \ \ \ \textnormal{for} \ \ k = 1, ..., K,
\end{equation}
where $E \in \mathbb{R}^{N \times D}$, $R_k \in \mathbb{R}^{D \times D}$ are factorized matrices for slice k. Note that E will be the same for all slices.

\subsection{Least Squares}

Similar as matrix factorization, we still want to find the most similar estimated matrix by minimizing the mean squared error, i.e.

\begin{equation}
\mathop{\arg\min}_{E,R} \sum_{k=1}^K \|T_{:k:} - E R_k E^T\|_F^2,
\end{equation}

%\bibliographystyle{model1-num-names}
%\bibliography{sample.bib}

\end{document}

%%
%% End of file `elsarticle-template-1-num.tex'.


\vsssub
\subsubsection{~Parameter settings in modules}
\vsssub

Several modules have internally used parameter settings. Here only parameter
settings that are generally usable or impact model behavior are presented.

\vspace{\baselineskip} \noindent
Physical and mathematical constants : \hfill {\file constants.ftn}
\begin{vlist}
\vit{grav  }{rp}{Acceleration of gravity $g$.
                \hfill (m s$^{-2}$)}
\vit{dwat  }{rp}{Density of water. \hfill(kg m$^{-3}$)}
\vit{dair  }{rp}{Density of air. \hfill(kg m$^{-3}$)}
\vit{nu\_air}{rp}{Kinematic viscosity of air \hfill (m$^2$ s$^{-1}$)}
\vit{nu\_water}{rp}{Kinematic viscosity of water \hfill (m$^2$ s$^{-1}$)}
\vit{sed\_sd}{rp}{Specific gravity of sediment \hfill (--)}
\vit{kappa }{rp}{Von Karman's constants \hfill (--)}
\vit{pi    }{rp}{$\pi$.}
\vit{tpi   }{rp}{$2\pi$.}
\vit{hpi   }{rp}{$0.5\pi$.}
\vit{tpiinv}{rp}{$(2\pi)^{-1}$.}
\vit{hpiinv}{rp}{$(0.5\pi)^{-1}$.}
\vit{rade  }{rp}{Conversion factor from radians to degrees.}
\vit{dera  }{rp}{Conversion factor from degrees to radians.}
\vit{radius}{rp}{Radius of the earth. \hfill (m)}
\vit{g2pi3i}{rp}{$g^{-2} (2\pi)^{-3}$.}
\vit{g1pi1i}{rp}{$g^{-1}(2\pi)^{-1}$.}
\end{vlist}

\noindent
Wave model initialization module : \hfill {\file w3initmd.ftn}
\begin{vlist}
\vit{critos}{rp}{Critical fraction of resources used for output only
                     (triggers warning output).}
\vit{wwver }{cp}{Version number of the main program.}
\vit{switches}{cp}{Switches taken from {\file bin/switch}.}
\end{vlist}

\noindent
I/O module ({\file mod\_def.ww3}) : \hfill {\file w3iogrmd.ftn}
\begin{vlist}
\vit{vergrd}{cp\opt}{Version number of file {\file mod\_def.ww3}.}
\vit{idstr }{cp\opt}{ID string for file.}
\end{vlist}

\noindent
I/O module ({\file out\_grd.ww3}) : \hfill {\file w3iogomd.ftn}
\begin{vlist}
\vit{verogr}{cp\opt}{Version number of file {\file out\_grd.ww3}.}
\vit{idstr }{cp\opt}{ID string for file.}
\end{vlist}

\noindent
I/O module ({\file out\_pnt.ww3}) : \hfill {\file w3iopomd.ftn}
\begin{vlist}
\vit{veropt}{cp\opt}{Version number of file {\file out\_pnt.ww3}.}
\vit{idstr }{cp\opt}{ID string for file.}
\vit{acc   }{cp}{Relative offset below which output point is moved to grid
                 point.}
\end{vlist}

\noindent
I/O module ({\file track\_o.ww3}) : \hfill {\file w3iotrmd.ftn}
\begin{vlist}
\vit{vertrk}{cp\opt}{Version number of file {\file track\_o.ww3}.}
\vit{idstri}{cp\opt}{ID string for file {\file track\_i.ww3}.}
\vit{otype }{cp}{Array dimension.}
\end{vlist}

\noindent
I/O module ({\file restart.ww3}) : \hfill {\file w3iorsmd.ftn}
\begin{vlist}
\vit{verini}{cp\opt}{Version number of file {\file restart.ww3}.}
\vit{idstr }{cp\opt}{ID string for file.}
\end{vlist}

\noindent
I/O module ({\file nest.ww3}) : \hfill {\file w3iobcmd.ftn}
\begin{vlist}
\vit{verbpt}{cp\opt}{Version number of file {\file nest.ww3}.}
\vit{idstr }{cp\opt}{ID string for file.}
\end{vlist}

\noindent
I/O module ({\file partition.ww3}) : \hfill {\file w3iosfmd.ftn}
\begin{vlist}
\vit{vertrt}{cp\opt}{Version number of file {\file partition.ww3}.}
\vit{idstr }{cp\opt}{ID string for file.}
\end{vlist}

\noindent
Multi-grid model input update : \hfill {\file wmupdtmd.ftn}
\begin{vlist}
\vit{swpmax}{ip}{Maximum number of extrapolation sweeps allowed to make maps
                 match in conversion from input from input grid to wave model
                 grid.}
\end{vlist}

\noindent
Several routines contain interpolation tables that are set up with parameter
statements, including

\vspace{\baselineskip} \noindent
Solving the dispersion relation : \hfill {\file w3dispmd.ftn}
\begin{vlist}
\vit{nar1d }{ip}{Dimension of interpolation tables.}
\vit{dfac  }{rp}{Maximum nondimensional water depth $kd$.}
\vit{ecg1  }{ra}{Table for calculating  group velocities from
                 the frequency and the depth.}
\vit{ewn1  }{ra}{Id. wavenumbers.}
\vit{n1max }{i }{Largest index in tables.}
\vit{dsie  }{r }{Nondimensional frequency increment.}
\end{vlist}

\noindent
Shallow water quadruplet lookup table for \gmd\ : \hfill {\file w3snl3md.ftn}
\begin{vlist}
\vit{nkd   }{ip}{Number of nondimensional depths in storage array.}
\vit{kdmin }{rp}{Minimum relative depth in table.}
\vit{kdmax }{rp}{Maximum relative depth in table.}
\vit{lammax}{rp}{Maximum value for $\lambda$ or $\mu$.}
\vit{delthm}{rp}{Maximum angle gap $\theta_{12}$ ($\degree$).}
\end{vlist}

\noindent
Shallow water lookup table for nonlinear filter : \hfill {\file w3snlsmd.ftn}
\begin{vlist}
\vit{nkd   }{ip}{Number of nondimensional depths in storage array.}
\vit{kdmin }{rp}{Minimum relative depth in table.}
\vit{kdmax }{rp}{Maximum relative depth in table.}
\vit{abmax }{rp}{Maximum value for $a_{34}$.}
\end{vlist}

\noindent
Lookup table for $\beta$ in Tolman and Chalikov 1996 : \hfill {\file w3src2md.ftn}
\begin{vlist}
\vit{nrsiga}{ip}{Array dimension ($\sigma_a$).}
\vit{nrdrag}{ip}{Array dimension ($C_d$).}
\vit{sigamx}{rp}{Maximum nondimensional frequency $\tilde{\sigma}_a$.}
\vit{dragmx}{rp}{Maximum drag coefficient $C_d$}
\end{vlist}

\noindent
Lookup table for \ldots in WAM-4 / ECWAM : \hfill {\file w3src3md.ftn}
\begin{vlist}
\vit{kappa  }{rp}{von K{\'a}rm{\'a}n's constant.}
\vit{nu\_air}{rp}{air viscosity.}
\vit{itaumax}{ip}{size of stress dimension.}
\vit{jumax  }{ip}{size of wind dimension.}
\vit{iustar }{ip}{size of ustar dimension.}
\vit{ialpha }{ip}{size of Charnock dimension.}
\vit{ilevtail}{ip}{size of tail level dimension.}
\vit{umax   }{rp}{Maximum wind speed in table.}
\vit{tauwmax}{rp}{Maximum ustar in table.}
\vit{eps1   }{rp}{Small number for stress convergence.}
\vit{eps2   }{rp}{Small number for stress convergence.}
\vit{niter  }{ip}{Number of iterations in stress table.}
\vit{xm     }{ip}{power of TAUW/TAU in roughness parameterization.}
\vit{jtot   }{ip}{Number of points in discretization of tail.}
\end{vlist}

\noindent
Lookup tables Ardhuin et al. 2010 : \hfill {\file w3src3md.ftn}

Combination of previous two sets of parameters. \\

\noindent
Table of error functions in bottom friction : \hfill {\file w3sbt4md.ftn}
\begin{vlist}
\vit{sizeerftable}{ip}{Size of table for erf function.}
\vit{xerfmax}{rp }{Maximum value of x in table of erf(x).}
\vit{wsub   }{rpa}{Weights for 3-point Gauss-Hermitte quadrature.}
\vit{xsub   }{rpa}{x values for 3-point Gauss-Hermitte quadrature.}
\end{vlist}

\noindent
Some model parameters are set using parameter statements.

\vspace{\baselineskip}
\noindent
Source term computation and integration : \hfill {\file w3srcemd.ftn}
\begin{vlist}
\vit{offset}{rp\opt}{Offset $\epsilon$ in Eq.~(\ref{eq:implicit_st}).}
\end{vlist}

\noindent
Auxiliary data storage : \hfill {\file w3adatmd.ftn}
\begin{vlist}
\vit{mpibuf}{ip}{Number of buffers used in \mpi\ data transpose.}
\end{vlist}

\noindent
Some service routines contain parameters that can be used to influence, for
instance, the model output.

\vspace{\baselineskip}
\noindent
Array I/O including text outputs : \hfill {\file w3arrymd.ftn}
\begin{vlist}
\vit{icol  }{ip\opt}{Set maximum columns on output (now set to 80).}
\vit{nfrmax}{ip\opt}{Set maximum number of frequency in spectral print plots
                     (now set to 50).}
\end{vlist}

\noindent
Automatic unit number assignment : \hfill {\file wmunitmd.ftn}
\begin{vlist}
\vit{unitlw}{ip}{Lowest unit number to be considered.}
\vit{unithg}{ip}{Highest unit number to be considered.}
\vit{inplow, inphgh}{}{}
\vit{      }{ip}{Range of input file unit numbers.}
\vit{outlow, outhgh}{}{}
\vit{      }{ip}{Range of output file unit numbers.}
\vit{scrlow, scrhgh}{}{}
\vit{      }{ip}{Range of scratch file unit numbers.}
\end{vlist}

\noindent
Creating spectral bulletins : \hfill {\file w3bullmd.ftn}
\begin{vlist}
\vit{nptab, nfld, npmax, bhsmin, bhsdrop, dhsmax,}{}{}
\vit{dptmx, ddmmax, ddwmax, agemin}{}{}
\vit{}{i/rp}{Setting of size of bulletin as well as various filter values.}
\end{vlist}