This directory contains two projects. The first, qvm
, is a classical
implementation of the Quantum Abstract Machine (QAM), called a
"Quantum Virtual Machine" (QVM). The second, qvm-app
, is the
application interface to interacting with the QVM, either directly
through the qvm
binary or via its server interface.
The definition of the QAM was developed at Rigetti in a paper titled A Practical Quantum Instruction Set Architecture.
The QVM library is contained within ./src/
, and provides the
implementation of the Quantum Abstract Machine. It evaluates Quil
programs (parsed and compiled by quilc) on a virtual machine that can
model various characteristics of (though without needing access to) a
true quantum computer.
The library is released under the Apache license 2.0.
The QVM library is best loaded using Quicklisp. Please read and follow
the instructions in lisp-setup.md#install-quicklisp
to get Quicklisp
installed. Pay particular attention to the section "Telling Quicklisp
Where Your Code Is".
Note:
qvm
is not yet available through Quicklisp's distribution mechanism, and must be installed manually.
Download both this repository and quilc into the
ql:*local-project-directories*
location. If all is correct, the qvm
library can be loaded with
$ sbcl
* (ql:quickload :qvm)
(:QVM)
QVM objects are created with (qvm:make-qvm n)
where n
is the number of
qubits the QVM should support; a program can then be loaded into the
QVM object with (qvm:load-program *qvm* *program*)
where *qvm*
is a
QVM object and *program*
is a cl-quil:parsed-program
object.
Alternatively, the qvm:run-program
function will handle QVM object
creation. For example,
* (setq *qvm* (qvm:run-program 2 (cl-quil:parse-quil-string "H 0")))
creates a 2-qubit QVM object and on it runs the Quil program H 0
.
The qubit amplitudes can be inspected
* (qvm::amplitudes *qvm*)
#(#C(0.7071067811865475d0 0.0d0) #C(0.7071067811865475d0 0.0d0)
#C(0.0d0 0.0d0) #C(0.0d0 0.0d0))
which shows, as expected, that H 0
has put qubit-0 (the first two
complex numbers above) into an equal superposition of states |0>
and
|1>
.
Measurement of a quantum state causes it to collapse into one of its
basis states (|0>
or |1>
). This can be simulated with
* (qvm:measure-all *qvm*)
#<PURE-STATE-QVM {1004039753}>
(0 0)
Inspecting the QVM object's state shows that this effect mutates the information stored on the QVM; i.e. the previous state information is lost
* (qvm::amplitudes *qvm*)
#(#C(1.0d0 0.0d0) #C(0.0d0 0.0d0)
#C(0.0d0 0.0d0) #C(0.0d0 0.0d0))
Qubit zero's state has collapsed into the state |0>
. Repeating this
process (from creating the QVM object to measuring qubits) would show
that both states would each come up with probability 0.5.
* (loop :with results := (vector 0 0)
:with program := (cl-quil:parse-quil-string "H 0")
:repeat 100
:for (qvm state) := (multiple-value-list (qvm:measure (qvm:run-program 1 program) 0 nil))
:do (incf (aref results state))
:finally (return results))
#(54 46)
The QVM comes with some example code to illustrate usage of the
QVM. The example code can be found under ./examples/
. To run the
example code, first load qvm-examples
* (ql:quickload :qvm-examples)
(:QVM-EXAMPLES)
The function bit-reversal-circuit
takes a list of qubit indices and
returns a list of instructions that will reverse the qubit amplitudes
in "bit-reversal order" (e.g., the coefficient of |1110>
gets
mapped to |0111>
):
that the amplitudes get reversed
(qvm-examples:bit-reversal-circuit '(1 2 3 4))
(#<SWAP 1 4> #<SWAP 2 3>)
For a given list of qubit indices, the function qft-circuit
returns a
Quantum Fourier transform Quil program ready to be passed to quilc for
compilation.
* (qvm-examples:qft-circuit '(1 2 3 4))
#<CL-QUIL:PARSED-PROGRAM {10040ABEE3}>
To inspect the object, we can use the cl-quil::print-parsed-program
function
* (cl-quil::print-parsed-program (qvm-examples:qft-circuit '(1 2 3 4)))
H 4
CPHASE(pi/2) 3 4
H 3
CPHASE(pi/4) 2 4
CPHASE(pi/2) 2 3
H 2
CPHASE(pi/8) 1 4
CPHASE(pi/4) 1 3
CPHASE(pi/2) 1 2
H 1
SWAP 1 4
SWAP 2 3
The QVM application is contained with ./app/src/
, and provides a
stand-alone interface to the QVM library. It can be invoked directly
with the binary executable, or alternatively it can provide a server
that can be used over the network. Each has their benefits: the former
permits a simplified interface using the command-line switches (see
output of qvm --help
), while the latter allows many remote connections
to a single in-memory QVM.
The application is released under the GNU Affero General Public License v3.0.
To build the QVM application follow instructions in
lisp-setup.md
. In the top-level directory, run
the Makefile
with
$ make qvm
This will produce a binary executable qvm
in the same directory.
In some situtations, using a large number of qubits may caus heap exhaustion. To increase the memory available for the QVM, recompile and specify the workspace size (in MB)
$ make QVM_WORKSPACE=4096 qvm
The QVM application has a few command-line switches used to configure the QVM. To explore those options, see the output of the following command:
$ ./qvm --help
To provide a Quil program directly to the QVM, provide the program on
stdin and use the -e
switch
$ echo "H 0" | ./qvm -e
******************************
* Welcome to the Rigetti QVM *
******************************
Copyright (c) 2016-2019 Rigetti Computing.
(Configured with 2048 MiB of workspace and 8 workers.)
<134>1 2019-01-28T17:00:53Z workstation.local qvm 98179 - - Selected simulation method: pure-state
<134>1 2019-01-28T17:00:53Z workstation.local qvm 98179 - - Reading program.
<134>1 2019-01-28T17:00:53Z workstation.local qvm 98179 - - Allocating memory for QVM of 1 qubits.
<134>1 2019-01-28T17:00:53Z workstation.local qvm 98179 - - Allocation completed in 3 ms.
<134>1 2019-01-28T17:00:53Z workstation.local qvm 98179 - - Loading quantum program.
<134>1 2019-01-28T17:00:53Z workstation.local qvm 98179 - - Executing quantum program.
<134>1 2019-01-28T17:00:53Z workstation.local qvm 98179 - - Execution completed in 3 ms.
<134>1 2019-01-28T17:00:53Z workstation.local qvm 98179 - - Printing 1-qubit state.
<134>1 2019-01-28T17:00:53Z workstation.local qvm 98179 - - Amplitudes:
<134>1 2019-01-28T17:00:53Z workstation.local qvm 98179 - - |0>: 0.7071067811865475, P= 50.0%
<134>1 2019-01-28T17:00:53Z workstation.local qvm 98179 - - |1>: 0.7071067811865475, P= 50.0%
<134>1 2019-01-28T17:00:53Z workstation.local qvm 98179 - - No classical memory present.
Alternatively the QVM can be started as a server that will accept instructions over a network connection
$ ./qvm -S
******************************
* Welcome to the Rigetti QVM *
******************************
Copyright (c) 2016-2019 Rigetti Computing.
(Configured with 2048 MiB of workspace and 8 workers.)
<134>1 2019-01-28T19:06:07Z workstation.local qvm 3118 - - Selected simulation method: pure-state
<134>1 2019-01-28T19:06:07Z workstation.local qvm 3118 - - Starting server on port 5000.
This is how the pyQuil Python library communicates with a QVM.
Tests can be run from the Makefile
make test
or from within SBCL
* (asdf:test-system :qvm)
Any contribution to this project should foremost not break any current tests (run tests before making a pull request), and should be accompanied by relevant new tests.
Lisp caches a lot of builds so that not every single file needs to be recompiled. In rare instances, there's confusion and the cache doesn't get properly invalidated. (This can happen when moving files across machines, for example.) Lisp's cache and Quicklisp's system index can be cleaned by doing the following command:
make cleanall
This will delete any built executables as well.
The CI pipeline for qvm
produces a Docker image, available at
rigetti/qvm
.
To get the latest stable
version of qvm
, run docker pull rigetti/qvm
.
As outlined above, the QVM supports two modes of operation: stdin and server.
To run the qvm
in stdin mode, do the following:
echo "H 0" | docker run --rm -i rigetti/qvm -e
To run the qvm
in server mode, do the following:
docker run --rm -it -p 5000:5000 rigetti/qvm -S
If you would like to change the port of the server to PORT, you can alter the command as follows:
docker run --rm -it -p PORT:PORT rigetti/qvm -R -p PORT
- Update
VERSION.txt
and dependency versions (if applicable) and push the commit tomaster
. - Push a git tag
vX.Y.Z
that contains the same version number as inVERSION.txt
. - Verify that the resulting build (triggered by pushing the tag) completes successfully.
- Publish a release using the tag as the name.
- Close the milestone associated with this release, and migrate incomplete issues to the next one.