diff --git a/thesis/chapters/implementation.tex b/thesis/chapters/implementation.tex index affd3f6..c333417 100644 --- a/thesis/chapters/implementation.tex +++ b/thesis/chapters/implementation.tex @@ -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 diff --git a/thesis/main.bib b/thesis/main.bib index f19ee0b..d2d0eb8 100644 --- a/thesis/main.bib +++ b/thesis/main.bib @@ -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} +}