Some work here

This commit is contained in:
Daniel Knüttel 2020-03-14 14:56:07 +01:00
parent d03c076c8e
commit f5c7fe824d
2 changed files with 179 additions and 17 deletions

View File

@ -232,20 +232,20 @@ implemented in \lstinline{C} and are exported to python3 in the class
\lstinline{RawGraphState}. This class has three main methods to implement the
three classes of operations.
%\begin{description}
% \item[\lstinline{RawGraphState.apply_C_L}]{This method
% implements local clifford gates. It takes the qbit index and the index
% of the local Clifford operator (ranging form $0$ to $23$).}
% \item[\lstinline{RawGraphState.apply_CZ}]{Applies the $CZ$ gate to the
% state. The first argument is the act-qbit, the second the control
% qbit (note that this is just for consistency to the $CX$ gate).}
% \item[\lstinline{RawGraphState.measure}]{Using this method one can
% measure a qbit. It takes the qbit index as first argument and
% a floating point (double precision) random number as second
% argument. This random number is used to decide the measurement outcome
% in non-deterministic measurements. This method returns either $1$ or $0$ as
% a measurement result.}
%\end{description}
\begin{description}
\item[\lstinline{RawGraphState.apply_C_L}]{This method
implements local clifford gates. It takes the qbit index and the index
of the local Clifford operator (ranging form $0$ to $23$).}
\item[\lstinline{RawGraphState.apply_CZ}]{Applies the $CZ$ gate to the
state. The first argument is the act-qbit, the second the control
qbit (note that this is just for consistency to the $CX$ gate).}
\item[\lstinline{RawGraphState.measure}]{Using this method one can
measure a qbit. It takes the qbit index as first argument and
a floating point (double precision) random number as second
argument. This random number is used to decide the measurement outcome
in non-deterministic measurements. This method returns either $1$ or $0$ as
a measurement result.}
\end{description}
Because this way of modifying the state is rather unconvenient and might lead to many
errors the \lstinline{RawGraphState} is wrapped by the pure python class
@ -253,7 +253,7 @@ errors the \lstinline{RawGraphState} is wrapped by the pure python class
in \ref{ref:pyqcs_circuits} and provides the method \lstinline{GraphState.to_naive_state}
to convert the graphical state to a dense vector state.
\subsubsection{Pure \lstinline{C} Implementation}
\subsubsection{Pure C Implementation}
Because python tends to be rather slow and might not run on any architecture
a pure \lstinline{C} implementation of the graphical simulator is also provided.
@ -273,8 +273,162 @@ always done in three steps:
\subsection{Utilities}
TODO
To make both using the simulators more convenient and to help with using them in
as scientific or educational context several utilities have been written. This chapter
explains some of them.
\subsubsection{Sampling and Circuit Generation}
The function \lstinline{pyqcs.sample} provides a simple way to sample from a state.
Copies of the state are made when necessary and the results are returned
in a \lstinline{collections.Counter} object. Several qbits can be sampled at once; they can be passed
to the function either as an integer which will be interpreted as a bit mask and the
least significant bit will be sampled first. When passing the qbits to sample as a list
of integers the integers are interpreted as qbit indices and are measured in the order
they appear.
If the keyword argument \lstinline{keep_states} is \lstinline{True} the sampling
function will include the resulting states in the result. At the moment this works
for dense vectors only. Checking for equality on graphical states has yet to be implemented
but can be done in polynomial time \cite{dahlberg_ea2019}.
Writing circuits out by hand can be rather painful. The function \lstinline{pyqcs.list_to_circuit}
Converts a list of circuits to a circuit. This is particularely helpful in combination
with python's \lstinline{listcomp}:
\begin{lstlisting}
circuit_H = list_to_circuit([H(i) for i in range(nqbits)])
\end{lstlisting}
The module \lstinline{pyqcs.util.random_circuits} provides the method described in \ref{ref:performance}
to generate random circuits for both graphical and dense vector simulation. Using the module
\lstinline{pyqcs.util.random_graphs} one can generate random graphical states which is more performant
than using random circuits.
\subsubsection{Exporting Circuits, Graphical States}
\subsection{Performance}
\label{ref:performance}
To test the performance and compare it to the dense vector simulator the python
module is used. Although the pure \lstinline{C} implementation has potential
for better performance the python module is better comparable to the dense
vector simulator which is a python module as well.
For performance tests (and for tests against the dense vector simulator) random
circuits are used. Length $m$ circuits are generated from the probability space
\begin{equation}
\Omega = \left(\{1, ..., 4n\} \otimes \{1, ..., n-1\} \otimes [0, 2\pi)\right)^{\otimes m}
\end{equation}
with the uniform distribution. The continous part $[0, 2\pi)$ is unused when
generating random circuits for the graphical simulator; when generating random
circuits for dense vector simulations this is the argument $\phi$ of the
$R_\phi$ gate.
For $m=1$ an outcome is mapped to a gate using
\begin{equation}
\begin{aligned}
F(i, k, x) = \left\{\begin{array}{cc} X(i - 1) & \mbox{, if } i \le n \\
H(i - n - 1) & \mbox{, if } i \le 2n\\
S(i - 2n - 1) & \mbox{, if } i \le 3n\\
CZ(i - 3n - 1, k - 1) & \mbox{, if } k \le i - 3n - 1 \\
CZ(i - 3n - 1, k) & \mbox{, if } k > i - 3n - 1\\
\end{array}\right.
.
\end{aligned}
\end{equation}
This method provides equal probability for $X, H, S$ and $CZ$ gate. For the
dense vector simulator $S$ can be replaced by $R_\phi$ with the parameter $x$.
Using this method circuits are generated and applied both to graphical and
dense vector states and the time required to execute the operations
\cite{timeit} is measured. The resulting graph can be seen in
\ref{fig:scaling_qbits_linear} and \ref{fig:scaling_qbits_log}. Note in both cases the length of the circuits
have been scaled linearely with the amount of qbits and the measured time was
divided by the number of qbits:
\begin{equation}
\begin{aligned}
L_{\mbox{circuit}} &= \alpha n \\
T_{\mbox{rescaled}} &= \frac{T_{\mbox{execution}}(L_{\mbox{circuit}})}{n}\\
\end{aligned}
\end{equation}
\begin{figure}
\centering
\includegraphics[width=\linewidth]{../performance/scaling_qbits_linear.png}
\caption[Runtime Behaviour for Scaling Qbit Number]{Runtime Behaviour for Scaling Qbit Number}
\label{fig:scaling_qbits_linear}
\end{figure}
\begin{figure}
\centering
\includegraphics[width=\linewidth]{../performance/scaling_qbits_log.png}
\caption[Runtime Behaviour for Scaling Qbit Number (Logarithmic Scale)]{Runtime Behaviour for Scaling Qbit Number (Logarithmic Scale)}
\label{fig:scaling_qbits_log}
\end{figure}
The reason for this scaling will be clear later; one can observe that the
performance of the graphical simulator increases in some cases with growing
number of qbits when the circuit length is constant.
As described by \cite{andersbriegel2005} the graphical simulator is exponentially
faster than the dense vector simulator. According to \cite{andersbriegel2005} it
is considerably faster than a simulator using the straight forward approach simulating
the stabilizer tableaux like CHP \cite{CHP}.
One should be aware that the gate execution time (the time required to apply a gate
to the state) highly depends on the state it is applied to. For the dense vector
simulator and CHP this is not true: Gate execution time is constant for all gates
and states. Because the graphical simulator has to toggle neighbourhoods the
gate execution time of the $CZ$ gate varies greatly. The plot \ref{fig:scaling_circuits_linear}
shows the circuit execution time for two different numbers of qbits. One can observe three
regimes:
\begin{figure}
\centering
\includegraphics[width=\linewidth]{../performance/regimes/scaling_circuits_linear.png}
\caption[Circuit Execution Time for Scaling Circuit Length]{Circuit Execution Time for Scaling Circuit Length}
\label{fig:scaling_circuits_linear}
\end{figure}
\begin{description}
\item[Low-Linear Regime] {Here the circuit execution time scales approximately linearely
with the number of gates in the circuit (i.e. the $CZ$ gate execution time is approximately constant).
}
\item[Intermediate Regime]{The circuit execution time has a nonlinear dependence on the circuit length.}
\item[High-Linear Regime]{This regime shows a linear dependence on the circuit length; the slope is
higher than in the low-linear regime.}
\end{description}
\begin{figure}
\centering
\includegraphics[width=\linewidth]{../performance/regimes/graph_low_linear_regime.png}
\caption[Typical Graphical State in the Low-Linear Regime]{Typical Graphical State in the Low-Linear Regime}
\label{fig:graph_low_linear_regime}
\end{figure}
\begin{figure}
\centering
\includegraphics[width=\linewidth]{../performance/regimes/graph_high_linear_regime.png}
\caption[Typical Graphical State in the High-Linear Regime]{Typical Graphical State in the High-Linear Regime}
\label{fig:graph_high_linear_regime}
\end{figure}
These two regimes can be explained when considering the graphical states that typical live in these
regimes. With increased circuit length the amount of edges increases which makes toggling neighbourhoods
harder. Two graphs from the low-linear and high-linear regime can be seen in \ref{fig:graph_low_linear_regime}
and \ref{fig:graph_high_linear_regime}. The latter is hardly visible; this is due to the great amount of
edges in this regime. Further these two regimes are only visibly for $n>30$ qbits so choosing smaller graphs is
not possible.
Because states with more qbits reach the intermediate regime at higher circuit lengths it is important to
account for this virtual performance boost when comparing with other simulation methods. This explains
why the circuit length in \ref{fig:scaling_qbits_linear} had to be scaled with the qbit number.
TODO

View File

@ -166,3 +166,11 @@
note={Unpublished Work}
}
@online{
timeit,
title={timeit — Measure execution time of small code snippets},
url={https://docs.python.org/3.5/library/timeit.html},
urldate={13.03.2020},
year=2020,
note={https://docs.python.org/3.5/library/timeit.html}
}