some work

This commit is contained in:
Daniel Knüttel 2020-03-16 12:59:37 +01:00
parent ba500e334e
commit edaa8ac4a4
1 changed files with 69 additions and 40 deletions

View File

@ -64,7 +64,7 @@ in Python.
The logic of gates is usually easy to implement using the integer basis. The
example below implements the Hadamard gate \ref{ref:singleqbitgates}:
\adjustbox{max width=\textwidth}{\lstinputlisting[language=C, firstline=153, lastline=178]{../pyqcs/src/pyqcs/gates/implementations/basic_gates.c}}
\lstinputlisting[title={Implementation of the Hadamard Gate in C}, language=C, firstline=153, lastline=178, breaklines=true]{../pyqcs/src/pyqcs/gates/implementations/basic_gates.c}
A basic set of gates is implemented in PyQCS:
@ -103,8 +103,7 @@ circuits and can be constructing using the built-in generators. The generators
take the act-qbit as first argument, parameters such as the control qbit or an
angle as second argument:
%\adjustbox{max width=\textwidth}{
\begin{lstlisting}[language=Python]
\begin{lstlisting}[language=Python, breaklines=true, caption={Using Single Gate Circuits}]
In [1]: from pyqcs import CX, CZ, H, R, Z, X
...: from pyqcs import State
...:
@ -114,9 +113,9 @@ In [1]: from pyqcs import CX, CZ, H, R, Z, X
...: bell_state = CX(1, 0) * intermediate_state
In [2]: bell_state
Out[2]: (0.7071067811865476+0j)*|0b0> + (0.7071067811865476+0j)*|0b11>
Out[2]: (0.7071067811865476+0j)*|0b0>
+ (0.7071067811865476+0j)*|0b11>
\end{lstlisting}
%}
Large circuits can be constructed using the binary OR operator \lstinline{|} in
an analogy to the pipeline operator on many *NIX systems. As usual circuits are
@ -124,7 +123,7 @@ read from left to right similar to pipelines on *NIX systems:
%\adjustbox{max width=\textwidth}{
\begin{lstlisting}[language=Python]
\begin{lstlisting}[language=Python, breaklines=true, caption={Constructing Circuits Using \lstinline{|}}]
In [1]: from pyqcs import CX, CZ, H, R, Z, X
...: from pyqcs import State
...:
@ -137,7 +136,8 @@ In [1]: from pyqcs import CX, CZ, H, R, Z, X
...: bell_state = circuit * state
In [2]: bell_state
Out[2]: (0.7071067811865477+0j)*|0b0> + (0.7071067811865477+0j)*|0b11>
Out[2]: (0.7071067811865477+0j)*|0b0>
+ (0.7071067811865477+0j)*|0b11>
\end{lstlisting}
%}
@ -145,7 +145,7 @@ A quick way to generate circuits programatically is to use the \lstinline{list_t
function:
%\adjustbox{max width=\textwidth}{
\begin{lstlisting}[language=Python]
\begin{lstlisting}[language=Python, breaklines=true, caption={Constructing Circuits Using Python Lists}]
In [1]: from pyqcs import CX, CZ, H, R, Z, X
...: from pyqcs import State, list_to_circuit
...:
@ -154,7 +154,8 @@ In [1]: from pyqcs import CX, CZ, H, R, Z, X
...: state = (H(0) | circuit_CX) * State.new_zero_state(5)
In [2]: state
Out[2]: (0.7071067811865476+0j)*|0b0> + (0.7071067811865476+0j)*|0b11111>
Out[2]: (0.7071067811865476+0j)*|0b0>
+ (0.7071067811865476+0j)*|0b11111>
\end{lstlisting}
%}
@ -232,26 +233,31 @@ 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.}
\item[\hspace{-1em}]{\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[\hspace{-1em}]{\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[\hspace{-1em}]{\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
\lstinline{pyqcs.graph.state.GraphState}. It allows the use of circuits as described
in \ref{ref:pyqcs_circuits} and provides the method \lstinline{GraphState.to_naive_state}
to convert the graphical state to a dense vector state.
errors the \lstinline{RawGraphState} is wrapped by the pure python class\\
\lstinline{pyqcs.graph.state.GraphState}. It allows the use of circuits as
described 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 C Implementation}
@ -293,12 +299,12 @@ 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
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}
\begin{lstlisting}[caption={Generating a Large Circuit Efficiently}]
circuit_H = list_to_circuit([H(i) for i in range(nqbits)])
\end{lstlisting}
@ -308,17 +314,30 @@ 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 and Graphical States}
The function \lstinline{pyqcs.util.to_circuit.graph_state_to_circuit} converts
graphical states into circuits (mapping the $\ket{0b0..0}$ to this state.
Using these circuits the graphical state can be copied or converted to a
dense vector state. Further it is a way to optimize circuits to run them on
other simulators. Also the circuits can be exported to \lstinline{qcircuit} code
(see below) which is a relatively readable way to represent graphical states.
\subsubsection{Exporting and Flattening Circuits}
Circuits can be drawn using the \LaTeX package \lstinline{qcircuit}; all
circuits in this documents use \lstinline{qcircuit}. To visualize the circuits
built using \lstinline{pyqcs} the function
built using \lstinline{pyqcs} the function\\
\lstinline{pyqcs.util.to_diagram.circuit_to_diagram} can be used to generate
\lstinline{qcircuit} code that can be used in \LaTeX documents or exported to
PDFs directly. The diagrams produced by this function is not optimized and the
diagrams can be unnecessary long. Usually this can be fixed easily by editing
the produced code manually.
The circuits constructed using the \lstinline{|} operator have a tree structure
which is rather unconvenient when optimizing circuits or exporting them.
The function \\
\lstinline{pyqcs.util.flatten.flatten} converts a circuit
to a list of single gate circuits that can be analyzed or exported easily.
\subsection{Performance}
\label{ref:performance}
@ -361,7 +380,7 @@ 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
Figure \ref{fig:scaling_qbits_linear} and Figure \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:
@ -399,7 +418,7 @@ One should be aware that the gate execution time (the time required to apply a g
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}
gate execution time of the $CZ$ gate varies greatly. The plot Figure \ref{fig:scaling_circuits_linear}
shows the circuit execution time for two different numbers of qbits. One can observe three
regimes:
@ -426,6 +445,13 @@ regimes:
\label{fig:graph_low_linear_regime}
\end{figure}
\begin{figure}
\centering
\includegraphics[width=\linewidth]{../performance/regimes/graph_intermediate_regime.png}
\caption[Typical Graphical State in the Intermediate Regime]{Typical Graphical State in the Intermediate Regime}
\label{fig:graph_intermediate_regime}
\end{figure}
\begin{figure}
\centering
\includegraphics[width=\linewidth]{../performance/regimes/graph_high_linear_regime.png}
@ -433,14 +459,17 @@ regimes:
\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.
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. Graphs from the
low-linear, intermediate and high-linear regime can be seen in
Figure \ref{fig:graph_low_linear_regime}, Figure \ref{fig:graph_intermediate_regime} and
Figure \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.
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 Figure \ref{fig:scaling_qbits_linear} had to be scaled with the qbit number.