some more stuff
This commit is contained in:
parent
75aeb83766
commit
cd2a837f06
|
@ -1,23 +1,23 @@
|
|||
% vim: ft=tex
|
||||
\section{Implementation}
|
||||
|
||||
This chapter discusses how the concepts introduced before are implemented
|
||||
into a simulator. Futher the infrastructure around the simulation and some
|
||||
tools are explained.
|
||||
This chapter discusses how the concepts introduced before are implemented into
|
||||
a simulator. Futher the infrastructure around the simulation and some tools are
|
||||
explained.
|
||||
|
||||
The implementation is written as a \lstinline{python3} module. This allows
|
||||
users to quickly construct circuit, apply them to a state and measure amplitudes.
|
||||
Full access to the state (including intermediate) state has been priorized over
|
||||
execution speed. To keep the simulation speed as high as possible under these
|
||||
constraints some parts are implemented in \lstinline{C}
|
||||
The implementation is written as a \lstinline{python3} module. This allows
|
||||
users to quickly construct circuit, apply them to a state and measure
|
||||
amplitudes. Full access to the state (including intermediate) state has been
|
||||
priorized over execution speed. To keep the simulation speed as high as
|
||||
possible under these constraints some parts are implemented in \lstinline{C}
|
||||
|
||||
\subsection{Dense State Vector Simulation}
|
||||
|
||||
\subsubsection{Representation of Dense State Vectors}
|
||||
|
||||
Recalling \eqref{eq:ci} any $n$-qbit state can be represented as a
|
||||
$2^n$ component vector in the integer state basis. This representation
|
||||
has some useful features when it comes to computations:
|
||||
Recalling \eqref{eq:ci} any $n$-qbit state can be represented as a $2^n$
|
||||
component vector in the integer state basis. This representation has some
|
||||
useful features when it comes to computations:
|
||||
|
||||
\begin{itemize}
|
||||
\item{The projection on the integer states is trivial.}
|
||||
|
@ -26,34 +26,43 @@ has some useful features when it comes to computations:
|
|||
\item{For a qbit $j$ the coefficients $c_i$ and $c_{i \hat{} (1 << j)}$ are the conjugated coefficients.}
|
||||
\end{itemize}
|
||||
|
||||
Where $\hat{}$ is the binary XOR, $\&$ the binary AND and $<<$ the binary leftshift operator.
|
||||
Where $\hat{}$ is the binary XOR, $\&$ the binary AND and $<<$ the binary
|
||||
leftshift operator.
|
||||
|
||||
While implementing the dense state vectors two key points were allowing a simple and readable
|
||||
way to use them and simple access to the states by users that want more information than an
|
||||
abstracted view could allow. To meet both requirements the states are implemented as Python objects
|
||||
providing abstract features such as normalization checking, checking for sufficient qbit number when applying
|
||||
a circuit, computing overlaps with other states, a stringify method and stored measurement results.
|
||||
To store the measurement results a NumPy \lstinline{int8} array \cite{numpy_array} is used; this is called
|
||||
the classical state.
|
||||
The Python states also have a NumPy \lstinline{cdouble} array that stores the quantum mechanical state.
|
||||
Using NumPy arrays has the advantage that access to the data is simple and safe while operations
|
||||
on the states can be implemented in \lstinline{C} \cite{numpy_ufunc} providing a considerable speedup.
|
||||
While implementing the dense state vectors two key points were allowing
|
||||
a simple and readable way to use them and simple access to the states by users
|
||||
that want more information than an abstracted view could allow. To meet both
|
||||
requirements the states are implemented as Python objects providing abstract
|
||||
features such as normalization checking, checking for sufficient qbit number
|
||||
when applying a circuit, computing overlaps with other states, a stringify
|
||||
method and stored measurement results. To store the measurement results
|
||||
a NumPy \lstinline{int8} array \cite{numpy_array} is used; this is called the
|
||||
classical state. The Python states also have a NumPy \lstinline{cdouble} array
|
||||
that stores the quantum mechanical state. Using NumPy arrays has the advantage
|
||||
that access to the data is simple and safe while operations on the states can
|
||||
be implemented in \lstinline{C} \cite{numpy_ufunc} providing a considerable
|
||||
speedup.
|
||||
|
||||
This quantum mechanical state is the component vector in integer basis therefore it has $2^n$ components.
|
||||
Storing those components is acceptable in a range from $1$ to $30$ qbits; above this range the state requires
|
||||
space in the order of $1 \mbox{ GiB}$ which is in the range of usual RAM sizes for personal computers. For higher
|
||||
qbit numbers moving to high performance computers and other simulators is necessary.
|
||||
This quantum mechanical state is the component vector in integer basis
|
||||
therefore it has $2^n$ components. Storing those components is acceptable in
|
||||
a range from $1$ to $30$ qbits; above this range the state requires space in
|
||||
the order of $1 \mbox{ GiB}$ which is in the range of usual RAM sizes for
|
||||
personal computers. For higher qbit numbers moving to high performance
|
||||
computers and other simulators is necessary.
|
||||
|
||||
\subsubsection{Gates}
|
||||
|
||||
Gates on dense state vectors are implemented as NumPy Universal Functions (ufuncs) \cite{numpy_ufunc} mapping a classical
|
||||
and a quantum state to a new classical state, a new quantum state and a $64 \mbox{ bit}$ integer indicating what qbits have
|
||||
been measured. Using ufuncs has the great advantage that managing memory is done by NumPy and an application programmer
|
||||
just has to implement the logic of the function. Because ufuncs are written in \lstinline{C} they provide a considerable
|
||||
speedup compared to an implementation in Python.
|
||||
Gates on dense state vectors are implemented as NumPy Universal Functions
|
||||
(ufuncs) \cite{numpy_ufunc} mapping a classical and a quantum state to a new
|
||||
classical state, a new quantum state and a $64 \mbox{ bit}$ integer indicating
|
||||
what qbits have been measured. Using ufuncs has the great advantage that
|
||||
managing memory is done by NumPy and an application programmer just has to
|
||||
implement the logic of the function. Because ufuncs are written in
|
||||
\lstinline{C} they provide a considerable speedup compared to an implementation
|
||||
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}:
|
||||
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}}
|
||||
|
||||
|
@ -70,25 +79,28 @@ A basic set of gates is implemented in PyQCS:
|
|||
\item{The measurement "gate" $M$.}
|
||||
\end{itemize}
|
||||
|
||||
To allow the implementation of possible hardware related gates the class \lstinline{GenericGate} takes
|
||||
a unitary $2\times2$ matrix as a NumPy \lstinline{cdouble} array and builds a gate from it.
|
||||
To allow the implementation of possible hardware related gates the class
|
||||
\lstinline{GenericGate} takes a unitary $2\times2$ matrix as a NumPy
|
||||
\lstinline{cdouble} array and builds a gate from it.
|
||||
|
||||
\subsubsection{Circuits}
|
||||
|
||||
As mentioned in \ref{ref:quantum_circuits} quantum circuits are central in quantum programming.
|
||||
In the implementation great care was taken to make writing circuits as convenient and readable as
|
||||
possible. Users will almost never access the actual gates that perform the operation on a state;
|
||||
instead they will handle circuits.\\
|
||||
Circuits can be applied to a state by multiplying them from the left on a state object:
|
||||
As mentioned in \ref{ref:quantum_circuits} quantum circuits are central in
|
||||
quantum programming. In the implementation great care was taken to make
|
||||
writing circuits as convenient and readable as possible. Users will almost
|
||||
never access the actual gates that perform the operation on a state; instead
|
||||
they will handle circuits.\\ Circuits can be applied to a state by multiplying
|
||||
them from the left on a state object:
|
||||
|
||||
\begin{lstlisting}[language=Python]
|
||||
new_state = circuit * state
|
||||
\end{lstlisting}
|
||||
|
||||
|
||||
The elementary gates such as $H, R_\phi, CX$ are implemented as single gate 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:
|
||||
The elementary gates such as $H, R_\phi, CX$ are implemented as single gate
|
||||
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]
|
||||
|
@ -105,25 +117,25 @@ 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 read from left to right similar to pipelines on
|
||||
*NIX systems:
|
||||
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
|
||||
read from left to right similar to pipelines on *NIX systems:
|
||||
|
||||
|
||||
%\adjustbox{max width=\textwidth}{
|
||||
\begin{lstlisting}[language=Python]
|
||||
In [1]: from pyqcs import CX, CZ, H, R, Z, X
|
||||
...: from pyqcs import State
|
||||
...:
|
||||
...: state = State.new_zero_state(2)
|
||||
...:
|
||||
...: # This is the same as
|
||||
...: # circuit = H(0) | CX(1, 0)
|
||||
...: circuit = H(0) | H(1) | CZ(1, 0) | H(1)
|
||||
...:
|
||||
...: bell_state = circuit * state
|
||||
In [1]: from pyqcs import CX, CZ, H, R, Z, X
|
||||
...: from pyqcs import State
|
||||
...:
|
||||
...: state = State.new_zero_state(2)
|
||||
...:
|
||||
...: # This is the same as
|
||||
...: # circuit = H(0) | CX(1, 0)
|
||||
...: circuit = H(0) | H(1) | CZ(1, 0) | H(1)
|
||||
...:
|
||||
...: bell_state = circuit * state
|
||||
|
||||
In [2]: bell_state
|
||||
In [2]: bell_state
|
||||
Out[2]: (0.7071067811865477+0j)*|0b0> + (0.7071067811865477+0j)*|0b11>
|
||||
\end{lstlisting}
|
||||
%}
|
||||
|
@ -138,9 +150,9 @@ In [1]: from pyqcs import CX, CZ, H, R, Z, X
|
|||
...:
|
||||
...: circuit_CX = list_to_circuit([CX(i, i-1) for i in range(1, 5)])
|
||||
...:
|
||||
...: state = (H(0) | circuit_CX) * State.new_zero_state(5)
|
||||
...: state = (H(0) | circuit_CX) * State.new_zero_state(5)
|
||||
|
||||
In [2]: state
|
||||
In [2]: state
|
||||
Out[2]: (0.7071067811865476+0j)*|0b0> + (0.7071067811865476+0j)*|0b11111>
|
||||
|
||||
\end{lstlisting}
|
||||
|
@ -150,3 +162,53 @@ Out[2]: (0.7071067811865476+0j)*|0b0> + (0.7071067811865476+0j)*|0b11111>
|
|||
|
||||
\subsubsection{Graphical States}
|
||||
|
||||
For the graphical state $(V, E, O)$ the list of vertices $V$ can be stored implicitly
|
||||
by demanding $V = \{0, ..., n - 1\}$. This leaves two components that have to be stored:
|
||||
The edges $E$ and the vertex operators $O$. Storing the vertex operators is done using
|
||||
a \lstinline{uint8_t} array. Every local Clifford operator is associated from $0$ to $24$,
|
||||
their order is
|
||||
|
||||
\begin{equation}
|
||||
\begin{aligned}
|
||||
&\left(\begin{matrix}\frac{\sqrt{2}}{2} & \frac{\sqrt{2}}{2}\\\frac{\sqrt{2}}{2} & - \frac{\sqrt{2}}{2}\end{matrix}\right),
|
||||
\left(\begin{matrix}1 & 0\\0 & i\end{matrix}\right),
|
||||
\left(\begin{matrix}1 & 0\\0 & 1\end{matrix}\right),
|
||||
\left(\begin{matrix}\frac{\sqrt{2}}{2} & \frac{\sqrt{2}}{2}\\\frac{\sqrt{2} i}{2} & - \frac{\sqrt{2} i}{2}\end{matrix}\right), \\
|
||||
&\left(\begin{matrix}\frac{\sqrt{2}}{2} & \frac{\sqrt{2} i}{2}\\\frac{\sqrt{2}}{2} & - \frac{\sqrt{2} i}{2}\end{matrix}\right),
|
||||
\left(\begin{matrix}1 & 0\\0 & -1\end{matrix}\right),
|
||||
\left(\begin{matrix}\frac{\sqrt{2}}{2} & \frac{\sqrt{2} i}{2}\\\frac{\sqrt{2} i}{2} & \frac{\sqrt{2}}{2}\end{matrix}\right),
|
||||
\left(\begin{matrix}\frac{\sqrt{2}}{2} & - \frac{\sqrt{2}}{2}\\\frac{\sqrt{2}}{2} & \frac{\sqrt{2}}{2}\end{matrix}\right), \\
|
||||
&\left(\begin{matrix}1 & 0\\0 & - i\end{matrix}\right),
|
||||
\left(\begin{matrix}\frac{\sqrt{2}}{2} & - \frac{\sqrt{2}}{2}\\\frac{\sqrt{2} i}{2} & \frac{\sqrt{2} i}{2}\end{matrix}\right),
|
||||
\left(\begin{matrix}\frac{\sqrt{2}}{2} & - \frac{\sqrt{2} i}{2}\\\frac{\sqrt{2}}{2} & \frac{\sqrt{2} i}{2}\end{matrix}\right),
|
||||
\left(\begin{matrix}\frac{\sqrt{2}}{2} & - \frac{\sqrt{2} i}{2}\\\frac{\sqrt{2} i}{2} & - \frac{\sqrt{2}}{2}\end{matrix}\right), \\
|
||||
&\left(\begin{matrix}\frac{1}{2} + \frac{i}{2} & \frac{1}{2} - \frac{i}{2}\\\frac{1}{2} - \frac{i}{2} & \frac{1}{2} + \frac{i}{2}\end{matrix}\right),
|
||||
\left(\begin{matrix}\frac{\sqrt{2}}{2} & \frac{\sqrt{2}}{2}\\- \frac{\sqrt{2}}{2} & \frac{\sqrt{2}}{2}\end{matrix}\right),
|
||||
\left(\begin{matrix}0 & 1\\1 & 0\end{matrix}\right),
|
||||
\left(\begin{matrix}\frac{\sqrt{2}}{2} & \frac{\sqrt{2}}{2}\\- \frac{\sqrt{2} i}{2} & \frac{\sqrt{2} i}{2}\end{matrix}\right), \\
|
||||
&\left(\begin{matrix}0 & 1\\i & 0\end{matrix}\right),
|
||||
\left(\begin{matrix}\frac{1}{2} - \frac{i}{2} & \frac{1}{2} + \frac{i}{2}\\- \frac{1}{2} + \frac{i}{2} & \frac{1}{2} + \frac{i}{2}\end{matrix}\right),
|
||||
\left(\begin{matrix}0 & i\\1 & 0\end{matrix}\right),
|
||||
\left(\begin{matrix}\frac{\sqrt{2}}{2} & \frac{\sqrt{2} i}{2}\\- \frac{\sqrt{2} i}{2} & - \frac{\sqrt{2}}{2}\end{matrix}\right), \\
|
||||
&\left(\begin{matrix}\frac{1}{2} - \frac{i}{2} & - \frac{1}{2} + \frac{i}{2}\\- \frac{1}{2} + \frac{i}{2} & - \frac{1}{2} + \frac{i}{2}\end{matrix}\right),
|
||||
\left(\begin{matrix}0 & -1\\1 & 0\end{matrix}\right),
|
||||
\left(\begin{matrix}\frac{\sqrt{2}}{2} & - \frac{\sqrt{2}}{2}\\- \frac{\sqrt{2} i}{2} & - \frac{\sqrt{2} i}{2}\end{matrix}\right),
|
||||
\left(\begin{matrix}\frac{1}{2} - \frac{i}{2} & \frac{i \left(-1 + i\right)}{2}\\- \frac{1}{2} + \frac{i}{2} & \frac{i \left(-1 + i\right)}{2}\end{matrix}\right)
|
||||
\end{aligned}
|
||||
\end{equation}
|
||||
|
||||
The edges are stored in an adjacency matrix
|
||||
|
||||
\begin{equation}
|
||||
A = (a_{i,j})_{i,j = 0, ..., n-1}
|
||||
\end{equation}
|
||||
|
||||
\begin{equation}
|
||||
\begin{aligned}
|
||||
a_{i,j} = \left\{ \begin{array}{c} 1 \mbox{, if } \{i,j\} \in E\\
|
||||
0 \mbox{, if} \{i,j\} \notin E \end{array}\right.
|
||||
.
|
||||
\end{aligned}
|
||||
\end{equation}
|
||||
|
||||
Because it is
|
||||
|
|
Loading…
Reference in New Issue
Block a user